From 9693eb03b715ec34af22872b60962dee2dd92881 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 22 Mar 2023 09:39:56 -0700 Subject: [PATCH 01/40] Add test_file osm. --- resources/CMakeLists.txt | 1 + resources/model/test_file.osm | 6651 +++++++++++++++++++++++++++++++++ 2 files changed, 6652 insertions(+) create mode 100644 resources/model/test_file.osm diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 6ff9a5e3d33..5257587a9ae 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -174,6 +174,7 @@ set(model_resources_src model/ParkUnder_Retail_Office_C2.osm model/ASHRAECourthouse.osm model/A205ExampleChiller.RS0001.a205.cbor + model/test_file.osm ) diff --git a/resources/model/test_file.osm b/resources/model/test_file.osm new file mode 100644 index 00000000000..afa7111bcc1 --- /dev/null +++ b/resources/model/test_file.osm @@ -0,0 +1,6651 @@ + +OS:Version, + {62f0c617-ad37-4221-874e-7ae5fb7d5276}, !- Handle + 3.2.1; !- Version Identifier + +OS:ScheduleTypeLimits, + {708d20c3-2aac-42fc-b8c9-c265280f5517}, !- Handle + Always On Discrete Limits, !- Name + 0, !- Lower Limit Value + 1, !- Upper Limit Value + Discrete, !- Numeric Type + Availability; !- Unit Type + +OS:Timestep, + {b0fa043b-3e91-4705-b798-a26bbea47620}, !- Handle + 6; !- Number of Timesteps per Hour + +OS:Connection, + {b742b2ef-79b6-4b4e-bc85-5c20c1c8300f}, !- Handle + , !- Source Object + 11, !- Outlet Port + , !- Target Object + 2; !- Inlet Port + +OS:Space, + {39655c19-15b3-4081-92c2-4613ae84d8e6}, !- Handle + Zone3 Bulk Storage, !- Name + {a6aa64ea-d7e8-4be2-93e7-411cbc4acca9}, !- Space Type Name + , !- Default Construction Set Name + , !- Default Schedule Set Name + 0, !- Direction of Relative North {deg} + 0, !- X Origin {m} + 0, !- Y Origin {m} + 0, !- Z Origin {m} + {db75d8b1-6332-4998-b7c2-ad46d4bbd08b}, !- Building Story Name + {60569c67-8392-4395-8052-94b9e792b96b}, !- Thermal Zone Name + Yes; !- Part of Total Floor Area + +OS:Surface, + {516ff702-eb03-4a25-9228-e1ad9dc5895c}, !- Handle + Bulk Storage Roof, !- Name + RoofCeiling, !- Surface Type + , !- Construction Name + {39655c19-15b3-4081-92c2-4613ae84d8e6}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 45.7177703814647, 30.4785135876431, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 100.579094839222, 8.53398380454007, !- X,Y,Z Vertex 2 {m} + 0, 100.579094839222, 8.53398380454007, !- X,Y,Z Vertex 3 {m} + 0, 30.4785135876431, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:WindowProperty:FrameAndDivider, + {6bce9be8-2ab5-46ae-a571-5c172afed1ee}, !- Handle + Skylight_Frame, !- Name + 0.7129, !- Frame Width {m} + , !- Frame Outside Projection {m} + , !- Frame Inside Projection {m} + 283.91, !- Frame Conductance {W/m2-K} + 1, !- Ratio of Frame-Edge Glass Conductance to Center-Of-Glass Conductance + 0.7, !- Frame Solar Absorptance + 0.7, !- Frame Visible Absorptance + 0.9, !- Frame Thermal Hemispherical Emissivity + , !- Divider Type + , !- Divider Width {m} + , !- Number of Horizontal Dividers + , !- Number of Vertical Dividers + , !- Divider Outside Projection {m} + , !- Divider Inside Projection {m} + , !- Divider Conductance {W/m2-K} + 1, !- Ratio of Divider-Edge Glass Conductance to Center-Of-Glass Conductance + , !- Divider Solar Absorptance + , !- Divider Visible Absorptance + 0.9; !- Divider Thermal Hemispherical Emissivity + +OS:Surface, + {e7c4e556-9445-43b4-bfcc-f9fc21f24f21}, !- Handle + Fine Storage Left Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 0, 30.4785135876431, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 0, 30.4785135876431, 0, !- X,Y,Z Vertex 2 {m} + 0, 9.14355407629293, 0, !- X,Y,Z Vertex 3 {m} + 0, 9.14355407629293, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Connection, + {dc04fefb-3f18-45be-8f68-9d2cd3eb4a21}, !- Handle + , !- Source Object + 11, !- Outlet Port + , !- Target Object + 2; !- Inlet Port + +OS:Space, + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Handle + Zone2 Fine Storage, !- Name + {f6907e5f-7752-47ad-bfcd-c6fb8b1f86ab}, !- Space Type Name + , !- Default Construction Set Name + , !- Default Schedule Set Name + 0, !- Direction of Relative North {deg} + 0, !- X Origin {m} + 0, !- Y Origin {m} + 0, !- Z Origin {m} + {db75d8b1-6332-4998-b7c2-ad46d4bbd08b}, !- Building Story Name + {d0cebe41-1ec4-4dd7-8f92-397f53b49203}, !- Thermal Zone Name + Yes; !- Part of Total Floor Area + +OS:Surface, + {b8444fba-ff4e-4e81-b369-e9f3efc4a2d6}, !- Handle + Office Roof, !- Name + RoofCeiling, !- Surface Type + , !- Construction Name + {12c3d4a0-20ec-4e1f-8040-e70cdfba4a69}, !- Space Name + Surface, !- Outside Boundary Condition + {a273ffc4-632f-4b89-9d6d-f94185f45049}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 25.9067365494966, 0, 4.26699190227003, !- X,Y,Z Vertex 1 {m} + 25.9067365494966, 9.14355407629293, 4.26699190227003, !- X,Y,Z Vertex 2 {m} + 0, 9.14355407629293, 4.26699190227003, !- X,Y,Z Vertex 3 {m} + 0, 0, 4.26699190227003; !- X,Y,Z Vertex 4 {m} + +OS:Connection, + {3386e9fe-e830-491d-a1bc-dbb0ba0af916}, !- Handle + , !- Source Object + 11, !- Outlet Port + , !- Target Object + 2; !- Inlet Port + +OS:Space, + {12c3d4a0-20ec-4e1f-8040-e70cdfba4a69}, !- Handle + Zone1 Office, !- Name + {b0aef65a-6c0f-43e9-b00a-681a7595a4b8}, !- Space Type Name + , !- Default Construction Set Name + , !- Default Schedule Set Name + 0, !- Direction of Relative North {deg} + 0, !- X Origin {m} + 0, !- Y Origin {m} + 0, !- Z Origin {m} + {db75d8b1-6332-4998-b7c2-ad46d4bbd08b}, !- Building Story Name + {6c1adbbd-b731-4330-93ba-8c172088a4d0}, !- Thermal Zone Name + Yes; !- Part of Total Floor Area + +OS:Surface, + {a273ffc4-632f-4b89-9d6d-f94185f45049}, !- Handle + Office Roof Reversed, !- Name + Floor, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Surface, !- Outside Boundary Condition + {b8444fba-ff4e-4e81-b369-e9f3efc4a2d6}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 0, 0, 4.26699190227003, !- X,Y,Z Vertex 1 {m} + 0, 9.14355407629293, 4.26699190227003, !- X,Y,Z Vertex 2 {m} + 25.9067365494966, 9.14355407629293, 4.26699190227003, !- X,Y,Z Vertex 3 {m} + 25.9067365494966, 0, 4.26699190227003; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {b8b06532-b20c-4b27-b353-fb685ea15ba8}, !- Handle + Bulk Storage Rear Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {39655c19-15b3-4081-92c2-4613ae84d8e6}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 45.7177703814647, 100.579094839222, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 100.579094839222, 0, !- X,Y,Z Vertex 2 {m} + 0, 100.579094839222, 0, !- X,Y,Z Vertex 3 {m} + 0, 100.579094839222, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {e86312f3-df9c-4a72-8bf5-276fd9968053}, !- Handle + Bulk Storage Floor, !- Name + Floor, !- Surface Type + {91f0c0a2-5b5c-4175-b0e3-98454b378893}, !- Construction Name + {39655c19-15b3-4081-92c2-4613ae84d8e6}, !- Space Name + Foundation, !- Outside Boundary Condition + {b5fc88e0-f5c3-4584-8ef5-78c180b10c07}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 45.7177703814647, 100.579094839222, 0, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 30.4785135876431, 0, !- X,Y,Z Vertex 2 {m} + 0, 30.4785135876431, 0, !- X,Y,Z Vertex 3 {m} + 0, 100.579094839222, 0; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {2eb36d53-8956-4573-9d42-f3de2486a693}, !- Handle + Bulk Storage Left Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {39655c19-15b3-4081-92c2-4613ae84d8e6}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 0, 100.579094839222, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 0, 100.579094839222, 0, !- X,Y,Z Vertex 2 {m} + 0, 30.4785135876431, 0, !- X,Y,Z Vertex 3 {m} + 0, 30.4785135876431, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {eb38baf8-4819-4f38-99d7-de17082804a6}, !- Handle + Fine Storage Floor, !- Name + Floor, !- Surface Type + {91f0c0a2-5b5c-4175-b0e3-98454b378893}, !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Foundation, !- Outside Boundary Condition + {b5fc88e0-f5c3-4584-8ef5-78c180b10c07}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 45.7177703814647, 30.4785135876431, 0, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 0, 0, !- X,Y,Z Vertex 2 {m} + 25.9067365494966, 0, 0, !- X,Y,Z Vertex 3 {m} + 25.9067365494966, 9.14355407629293, 0, !- X,Y,Z Vertex 4 {m} + 0, 9.14355407629293, 0, !- X,Y,Z Vertex 5 {m} + 0, 30.4785135876431, 0; !- X,Y,Z Vertex 6 {m} + +OS:Surface, + {a0ba0fa9-aa51-4fbe-bdcc-bf0a22e397dd}, !- Handle + Fine Storage Right Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 45.7177703814647, 0, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 0, 0, !- X,Y,Z Vertex 2 {m} + 45.7177703814647, 30.4785135876431, 0, !- X,Y,Z Vertex 3 {m} + 45.7177703814647, 30.4785135876431, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {dcc10c35-212a-4ba7-8909-e38fa0c8d3e8}, !- Handle + Fine Storage Roof, !- Name + RoofCeiling, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 45.7177703814647, 0, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 30.4785135876431, 8.53398380454007, !- X,Y,Z Vertex 2 {m} + 0, 30.4785135876431, 8.53398380454007, !- X,Y,Z Vertex 3 {m} + 0, 0, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {af7ffab5-cb7d-4793-a68a-918ca67f7479}, !- Handle + Office Left Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {12c3d4a0-20ec-4e1f-8040-e70cdfba4a69}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 0, 9.14355407629293, 4.26699190227003, !- X,Y,Z Vertex 1 {m} + 0, 9.14355407629293, 0, !- X,Y,Z Vertex 2 {m} + 0, 0, 0, !- X,Y,Z Vertex 3 {m} + 0, 0, 4.26699190227003; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {a966bae9-9301-4492-ae85-a3416cb9da09}, !- Handle + Office Floor, !- Name + Floor, !- Surface Type + {91f0c0a2-5b5c-4175-b0e3-98454b378893}, !- Construction Name + {12c3d4a0-20ec-4e1f-8040-e70cdfba4a69}, !- Space Name + Foundation, !- Outside Boundary Condition + {b5fc88e0-f5c3-4584-8ef5-78c180b10c07}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 25.9067365494966, 9.14355407629293, 0, !- X,Y,Z Vertex 1 {m} + 25.9067365494966, 0, 0, !- X,Y,Z Vertex 2 {m} + 0, 0, 0, !- X,Y,Z Vertex 3 {m} + 0, 9.14355407629293, 0; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {7f4aebb1-9044-44cb-91ee-e1a559b436a0}, !- Handle + Office Right Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {12c3d4a0-20ec-4e1f-8040-e70cdfba4a69}, !- Space Name + Surface, !- Outside Boundary Condition + {12dbc2fb-3517-42f9-9f00-f6147aaade5b}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 25.9067365494966, 0, 4.26699190227003, !- X,Y,Z Vertex 1 {m} + 25.9067365494966, 0, 0, !- X,Y,Z Vertex 2 {m} + 25.9067365494966, 9.14355407629293, 0, !- X,Y,Z Vertex 3 {m} + 25.9067365494966, 9.14355407629293, 4.26699190227003; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {12dbc2fb-3517-42f9-9f00-f6147aaade5b}, !- Handle + Office Right Wall Reversed, !- Name + Wall, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Surface, !- Outside Boundary Condition + {7f4aebb1-9044-44cb-91ee-e1a559b436a0}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 25.9067365494966, 9.14355407629293, 4.26699190227003, !- X,Y,Z Vertex 1 {m} + 25.9067365494966, 9.14355407629293, 0, !- X,Y,Z Vertex 2 {m} + 25.9067365494966, 0, 0, !- X,Y,Z Vertex 3 {m} + 25.9067365494966, 0, 4.26699190227003; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {a722f50f-fda4-4b2c-843f-44ea72a832c9}, !- Handle + Office Front Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {12c3d4a0-20ec-4e1f-8040-e70cdfba4a69}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 0, 0, 4.26699190227003, !- X,Y,Z Vertex 1 {m} + 0, 0, 0, !- X,Y,Z Vertex 2 {m} + 25.9067365494966, 0, 0, !- X,Y,Z Vertex 3 {m} + 25.9067365494966, 0, 4.26699190227003; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {2ce21271-4aa0-4b4e-af87-47994c8beac1}, !- Handle + Bulk Storage Front Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {39655c19-15b3-4081-92c2-4613ae84d8e6}, !- Space Name + Surface, !- Outside Boundary Condition + {139e955e-746e-43dc-9033-026507021b5a}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 45.7177703814647, 30.4785135876431, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 30.4785135876431, 0, !- X,Y,Z Vertex 2 {m} + 0, 30.4785135876431, 0, !- X,Y,Z Vertex 3 {m} + 0, 30.4785135876431, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {139e955e-746e-43dc-9033-026507021b5a}, !- Handle + Bulk Storage Front Wall Reversed, !- Name + Wall, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Surface, !- Outside Boundary Condition + {2ce21271-4aa0-4b4e-af87-47994c8beac1}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 0, 30.4785135876431, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 0, 30.4785135876431, 0, !- X,Y,Z Vertex 2 {m} + 45.7177703814647, 30.4785135876431, 0, !- X,Y,Z Vertex 3 {m} + 45.7177703814647, 30.4785135876431, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {145bfd04-ce48-4581-a2a9-e8970362044f}, !- Handle + Fine Storage Office Left Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 0, 9.14355407629293, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 0, 9.14355407629293, 4.26699190227003, !- X,Y,Z Vertex 2 {m} + 0, 0, 4.26699190227003, !- X,Y,Z Vertex 3 {m} + 0, 0, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {93a00761-ab33-4e9d-bff7-fed32e66feb1}, !- Handle + Bulk Storage Right Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {39655c19-15b3-4081-92c2-4613ae84d8e6}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 45.7177703814647, 30.4785135876431, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 30.4785135876431, 0, !- X,Y,Z Vertex 2 {m} + 45.7177703814647, 100.579094839222, 0, !- X,Y,Z Vertex 3 {m} + 45.7177703814647, 100.579094839222, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {857f9ef3-3061-45eb-b04c-b4a4b76ff6cd}, !- Handle + Office Rear Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {12c3d4a0-20ec-4e1f-8040-e70cdfba4a69}, !- Space Name + Surface, !- Outside Boundary Condition + {4047aa22-d7b0-4e4a-a8a7-99a21122cc53}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 25.9067365494966, 9.14355407629293, 4.26699190227003, !- X,Y,Z Vertex 1 {m} + 25.9067365494966, 9.14355407629293, 0, !- X,Y,Z Vertex 2 {m} + 0, 9.14355407629293, 0, !- X,Y,Z Vertex 3 {m} + 0, 9.14355407629293, 4.26699190227003; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {4047aa22-d7b0-4e4a-a8a7-99a21122cc53}, !- Handle + Office Rear Wall Reversed, !- Name + Wall, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Surface, !- Outside Boundary Condition + {857f9ef3-3061-45eb-b04c-b4a4b76ff6cd}, !- Outside Boundary Condition Object + NoSun, !- Sun Exposure + NoWind, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 0, 9.14355407629293, 4.26699190227003, !- X,Y,Z Vertex 1 {m} + 0, 9.14355407629293, 0, !- X,Y,Z Vertex 2 {m} + 25.9067365494966, 9.14355407629293, 0, !- X,Y,Z Vertex 3 {m} + 25.9067365494966, 9.14355407629293, 4.26699190227003; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {a50eff28-8688-422b-9443-0a4fe183df9f}, !- Handle + Fine Storage Front Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 25.9067365494966, 0, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 25.9067365494966, 0, 0, !- X,Y,Z Vertex 2 {m} + 45.7177703814647, 0, 0, !- X,Y,Z Vertex 3 {m} + 45.7177703814647, 0, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:Surface, + {5b1ce779-a299-4910-83a2-6fb6d1cee24f}, !- Handle + Fine Storage Office Front Wall, !- Name + Wall, !- Surface Type + , !- Construction Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + Outdoors, !- Outside Boundary Condition + , !- Outside Boundary Condition Object + SunExposed, !- Sun Exposure + WindExposed, !- Wind Exposure + , !- View Factor to Ground + , !- Number of Vertices + 0, 0, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 0, 0, 4.26699190227003, !- X,Y,Z Vertex 2 {m} + 25.9067365494966, 0, 4.26699190227003, !- X,Y,Z Vertex 3 {m} + 25.9067365494966, 0, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:ClimateZones, + {376b058c-4e5c-42e7-91c5-a7e3e46c14bb}, !- Handle + ASHRAE, !- Climate Zone Institution Name 1 + ANSI/ASHRAE Standard 169, !- Climate Zone Document Name 1 + 2006, !- Climate Zone Document Year 1 + , !- Climate Zone Value 1 + CEC, !- Climate Zone Institution Name 2 + California Climate Zone Descriptions, !- Climate Zone Document Name 2 + 1995, !- Climate Zone Document Year 2 + ; !- Climate Zone Value 2 + +OS:LifeCycleCost:Parameters, + {9b956084-335f-4719-be60-6c3e1f278aa5}, !- Handle + FEMP, !- Analysis Type + , !- Discounting Convention + , !- Inflation Approach + , !- Real Discount Rate + , !- Nominal Discount Rate + , !- Inflation + , !- Base Date Month + , !- Base Date Year + , !- Service Date Month + , !- Service Date Year + , !- Length of Study Period in Years + , !- Tax Rate + , !- Depreciation Method + Yes; !- Use NIST Fuel Escalation Rates + +OS:YearDescription, + {429de7de-6704-419c-b62c-ed3f08bd405f}, !- Handle + , !- Calendar Year + Sunday; !- Day of Week for Start Day + +OS:Building, + {c23ded4b-6f18-4e30-b6db-cc00e1198751}, !- Handle + Warehouse, !- Name + , !- Building Sector Type + , !- North Axis {deg} + , !- Nominal Floor to Floor Height {m} + , !- Space Type Name + {ef6356a1-8948-4234-8bf8-69a9c9dc8c24}, !- Default Construction Set Name + , !- Default Schedule Set Name + 1, !- Standards Number of Stories + 1, !- Standards Number of Above Ground Stories + NECB2011, !- Standards Template + Warehouse; !- Standards Building Type + +OS:Facility, + {df4e9cbf-49a4-4de4-b2f6-6cba678a29a8}; !- Handle + +OS:BuildingStory, + {db75d8b1-6332-4998-b7c2-ad46d4bbd08b}, !- Handle + Building Story 1, !- Name + 0, !- Nominal Z Coordinate {m} + , !- Nominal Floor to Floor Height {m} + , !- Default Construction Set Name + , !- Default Schedule Set Name + ; !- Group Rendering Name + +OS:WeatherFile, + {d330a933-d91d-402e-a299-cce3daeb0147}, !- Handle + Calgary Intl AP, !- City + AB, !- State Province Region + CAN, !- Country + CWEC2016, !- Data Source + 718770, !- WMO Number + 51.114, !- Latitude {deg} + -114.02, !- Longitude {deg} + -7, !- Time Zone {hr} + 1084.1, !- Elevation {m} + /home/osdev/openstudio-standards/data/weather/CAN_AB_Calgary.Intl.AP.718770_CWEC2016.epw, !- Url + 93FEA5D3; !- Checksum + +OS:Site, + {3f226781-5670-4b8b-98cd-6493912cc260}, !- Handle + Calgary Intl AP_AB_CAN, !- Name + 51.114, !- Latitude {deg} + -114.02, !- Longitude {deg} + -7, !- Time Zone {hr} + 1084.1, !- Elevation {m} + ; !- Terrain + +OS:Site:WaterMainsTemperature, + {938b584d-3e4d-4a98-bf7a-ec7f0b18609b}, !- Handle + Correlation, !- Calculation Method + , !- Temperature Schedule Name + 5, !- Annual Average Outdoor Air Temperature {C} + 23.3; !- Maximum Difference In Monthly Average Outdoor Air Temperatures {deltaC} + +OS:Site:GroundTemperature:BuildingSurface, + {09ad5aee-04df-4ab6-a9c4-861c1be2af1c}, !- Handle + 19.527, !- January Ground Temperature {C} + 19.502, !- February Ground Temperature {C} + 19.536, !- March Ground Temperature {C} + 19.598, !- April Ground Temperature {C} + 20.002, !- May Ground Temperature {C} + 21.64, !- June Ground Temperature {C} + 22.225, !- July Ground Temperature {C} + 22.375, !- August Ground Temperature {C} + 21.449, !- September Ground Temperature {C} + 20.121, !- October Ground Temperature {C} + 19.802, !- November Ground Temperature {C} + 19.633; !- December Ground Temperature {C} + +OS:SpaceType, + {a6aa64ea-d7e8-4be2-93e7-411cbc4acca9}, !- Handle + Space Function Warehouse - med/blk, !- Name + , !- Default Construction Set Name + {11066c45-f5d8-4345-96fc-08c071cb2e5f}, !- Default Schedule Set Name + {b30e9dd9-9195-42cf-a37e-7037e2856ce8}, !- Group Rendering Name + {799a10f3-d978-4c06-960c-2a7e8ba018a3}, !- Design Specification Outdoor Air Object Name + , !- Standards Template + Space Function, !- Standards Building Type + Warehouse - med/blk; !- Standards Space Type + +OS:Rendering:Color, + {7ef8e62a-e56f-49cf-bdef-a2ed2a634f78}, !- Handle + Space Function Warehouse - med/blk, !- Name + 255, !- Rendering Red Value + 255, !- Rendering Green Value + 255; !- Rendering Blue Value + +OS:SpaceType, + {f6907e5f-7752-47ad-bfcd-c6fb8b1f86ab}, !- Handle + Space Function Warehouse - fine, !- Name + , !- Default Construction Set Name + {01c5526a-f72c-4c0f-a925-383ea53dd0f2}, !- Default Schedule Set Name + {ca6ff41b-13d3-433f-982a-441b87254e54}, !- Group Rendering Name + {3c9babf0-90fd-406e-aab0-21768e1172ee}, !- Design Specification Outdoor Air Object Name + , !- Standards Template + Space Function, !- Standards Building Type + Warehouse - fine; !- Standards Space Type + +OS:Rendering:Color, + {8936df75-08a5-4da0-85c6-8b63015e2643}, !- Handle + Space Function Warehouse - fine, !- Name + 255, !- Rendering Red Value + 255, !- Rendering Green Value + 255; !- Rendering Blue Value + +OS:SpaceType, + {b0aef65a-6c0f-43e9-b00a-681a7595a4b8}, !- Handle + Space Function Office - enclosed, !- Name + , !- Default Construction Set Name + {b0037545-3c4e-4fa9-8e52-7e91b582d2dc}, !- Default Schedule Set Name + {e9352c49-8076-44de-a25e-5c9129534bc3}, !- Group Rendering Name + {2566dc90-f095-4f45-85e6-3e318fddc674}, !- Design Specification Outdoor Air Object Name + , !- Standards Template + Space Function, !- Standards Building Type + Office - enclosed; !- Standards Space Type + +OS:Rendering:Color, + {f20c7626-c2b9-4128-b80e-20a346a7162a}, !- Handle + Space Function Office - enclosed, !- Name + 255, !- Rendering Red Value + 255, !- Rendering Green Value + 255; !- Rendering Blue Value + +OS:SizingPeriod:DesignDay, + {3e2261b8-26ef-4be6-a280-8e580dab5265}, !- Handle + Calgary Intl AP Ann Clg .4% Condns DB=>MWB, !- Name + 28.5, !- Maximum Dry-Bulb Temperature {C} + 12.1, !- Daily Dry-Bulb Temperature Range {deltaC} + 16.1, !- Humidity Indicating Conditions at Maximum Dry-Bulb + 88961, !- Barometric Pressure {Pa} + 4.5, !- Wind Speed {m/s} + 160, !- Wind Direction {deg} + 0, !- Sky Clearness + 0, !- Rain Indicator + 0, !- Snow Indicator + 21, !- Day of Month + 7, !- Month + SummerDesignDay, !- Day Type + 0, !- Daylight Saving Time Indicator + Wetbulb, !- Humidity Indicating Type + , !- Humidity Indicating Day Schedule Name + DefaultMultipliers, !- Dry-Bulb Temperature Range Modifier Type + , !- Dry-Bulb Temperature Range Modifier Schedule Name + ASHRAETau, !- Solar Model Indicator + , !- Beam Solar Day Schedule Name + , !- Diffuse Solar Day Schedule Name + 0.339, !- ASHRAE Taub {dimensionless} + 2.421; !- ASHRAE Taud {dimensionless} + +OS:SizingPeriod:DesignDay, + {e9e85432-36df-4c6c-a96e-a625be41667f}, !- Handle + Calgary Intl AP Ann Htg 99.6% Condns DB, !- Name + -28.5, !- Maximum Dry-Bulb Temperature {C} + 0, !- Daily Dry-Bulb Temperature Range {deltaC} + -28.5, !- Humidity Indicating Conditions at Maximum Dry-Bulb + 88961, !- Barometric Pressure {Pa} + 2.9, !- Wind Speed {m/s} + 200, !- Wind Direction {deg} + 0, !- Sky Clearness + 0, !- Rain Indicator + 0, !- Snow Indicator + 21, !- Day of Month + 1, !- Month + WinterDesignDay, !- Day Type + 0, !- Daylight Saving Time Indicator + Wetbulb, !- Humidity Indicating Type + , !- Humidity Indicating Day Schedule Name + DefaultMultipliers, !- Dry-Bulb Temperature Range Modifier Type + , !- Dry-Bulb Temperature Range Modifier Schedule Name + ASHRAEClearSky; !- Solar Model Indicator + +OS:Rendering:Color, + {134c5ecb-3c96-4ecb-ae3e-3289e689f33f}, !- Handle + Space Function Office - enclosed 1, !- Name + 255, !- Rendering Red Value + 255, !- Rendering Green Value + 255; !- Rendering Blue Value + +OS:People:Definition, + {88939426-6296-4f1b-b258-12dbfc36f1f3}, !- Handle + Space Function Office - enclosed People Definition, !- Name + People/Area, !- Number of People Calculation Method + , !- Number of People {people} + 0.0500521834377002, !- People per Space Floor Area {person/m2} + , !- Space Floor Area per Person {m2/person} + 0.3; !- Fraction Radiant + +OS:People, + {e0ee00bf-1fa6-4923-b4a4-494f66878d84}, !- Handle + Space Function Office - enclosed People, !- Name + {88939426-6296-4f1b-b258-12dbfc36f1f3}, !- People Definition Name + {b0aef65a-6c0f-43e9-b00a-681a7595a4b8}, !- Space or SpaceType Name + , !- Number of People Schedule Name + , !- Activity Level Schedule Name + , !- Surface Name/Angle Factor List Name + {7ae29b43-c43a-474c-a886-04ebfbf40244}, !- Work Efficiency Schedule Name + {5bf448d8-7167-4abd-a154-79a417231d5c}, !- Clothing Insulation Schedule Name + {1f8c4ef3-05fc-4c39-8818-de76ffbafad7}, !- Air Velocity Schedule Name + 1; !- Multiplier + +OS:Schedule:Ruleset, + {5bf448d8-7167-4abd-a154-79a417231d5c}, !- Handle + Clothing Schedule, !- Name + {cb849f4f-5c0a-4164-93df-7237753b50b8}, !- Schedule Type Limits Name + {c1154424-0762-440a-99aa-5487d1b0a3f6}; !- Default Day Schedule Name + +OS:Schedule:Day, + {c1154424-0762-440a-99aa-5487d1b0a3f6}, !- Handle + Clothing Schedule Default Winter Clothes, !- Name + {cb849f4f-5c0a-4164-93df-7237753b50b8}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 1; !- Value Until Time 1 + +OS:Schedule:Rule, + {f4bea4d9-3ef0-4e7b-8c0f-3bdde062b699}, !- Handle + Schedule Rule 1, !- Name + {5bf448d8-7167-4abd-a154-79a417231d5c}, !- Schedule Ruleset Name + 0, !- Rule Order + {2715a48e-f67b-4fc8-9271-0fd644c01b13}, !- Day Schedule Name + , !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 5, !- Start Month + 1, !- Start Day + 9, !- End Month + 30; !- End Day + +OS:Schedule:Day, + {2715a48e-f67b-4fc8-9271-0fd644c01b13}, !- Handle + Clothing Schedule Summer Clothes, !- Name + {cb849f4f-5c0a-4164-93df-7237753b50b8}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.5; !- Value Until Time 1 + +OS:ScheduleTypeLimits, + {cb849f4f-5c0a-4164-93df-7237753b50b8}, !- Handle + ClothingInsulation, !- Name + 0, !- Lower Limit Value + , !- Upper Limit Value + Continuous, !- Numeric Type + ClothingInsulation; !- Unit Type + +OS:Schedule:Ruleset, + {1f8c4ef3-05fc-4c39-8818-de76ffbafad7}, !- Handle + Air Velocity Schedule, !- Name + {cfc3b692-1a83-417d-974b-edf2f8902623}, !- Schedule Type Limits Name + {3f12432e-dc0c-45ff-bd8d-db39149bed6b}; !- Default Day Schedule Name + +OS:Schedule:Day, + {3f12432e-dc0c-45ff-bd8d-db39149bed6b}, !- Handle + Air Velocity Schedule Default, !- Name + {cfc3b692-1a83-417d-974b-edf2f8902623}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.2; !- Value Until Time 1 + +OS:ScheduleTypeLimits, + {cfc3b692-1a83-417d-974b-edf2f8902623}, !- Handle + Velocity, !- Name + 0, !- Lower Limit Value + , !- Upper Limit Value + Continuous, !- Numeric Type + Velocity; !- Unit Type + +OS:Schedule:Ruleset, + {7ae29b43-c43a-474c-a886-04ebfbf40244}, !- Handle + Work Efficiency Schedule, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + {6fc0489b-fedb-4031-be4c-ecc26dc3db3c}; !- Default Day Schedule Name + +OS:Schedule:Day, + {6fc0489b-fedb-4031-be4c-ecc26dc3db3c}, !- Handle + Work Efficiency Schedule Default, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:ScheduleTypeLimits, + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Handle + Fractional, !- Name + 0, !- Lower Limit Value + 1, !- Upper Limit Value + Continuous; !- Numeric Type + +OS:Lights:Definition, + {c5204d02-882d-452d-bbd3-638a85ec6315}, !- Handle + Space Function Office - enclosed Lights Definition, !- Name + Watts/Area, !- Design Level Calculation Method + , !- Lighting Level {W} + 11.8999009612603, !- Watts per Space Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.5, !- Fraction Radiant + 0.2; !- Fraction Visible + +OS:Lights, + {b96d28bc-fcbb-46f6-87b9-ddba68a2e5cf}, !- Handle + Space Function Office - enclosed Lights, !- Name + {c5204d02-882d-452d-bbd3-638a85ec6315}, !- Lights Definition Name + {b0aef65a-6c0f-43e9-b00a-681a7595a4b8}, !- Space or SpaceType Name + , !- Schedule Name + 1, !- Fraction Replaceable + , !- Multiplier + General; !- End-Use Subcategory + +OS:ElectricEquipment:Definition, + {c34a7c6c-1fd5-4047-a74a-8bb7c2b2f0f8}, !- Handle + Space Function Office - enclosed Elec Equip Definition, !- Name + Watts/Area, !- Design Level Calculation Method + , !- Design Level {W} + 7.49993758008349, !- Watts per Space Floor Area {W/m2} + , !- Watts per Person {W/person} + , !- Fraction Latent + 0.5; !- Fraction Radiant + +OS:ElectricEquipment, + {d7362932-f603-49a8-b053-b1227dafa1ff}, !- Handle + Space Function Office - enclosed Elec Equip, !- Name + {c34a7c6c-1fd5-4047-a74a-8bb7c2b2f0f8}, !- Electric Equipment Definition Name + {b0aef65a-6c0f-43e9-b00a-681a7595a4b8}, !- Space or SpaceType Name + , !- Schedule Name + , !- Multiplier + General; !- End-Use Subcategory + +OS:DesignSpecification:OutdoorAir, + {2566dc90-f095-4f45-85e6-3e318fddc674}, !- Handle + Space Function Office - enclosed Ventilation, !- Name + Sum, !- Outdoor Air Method + 0.0142091703329032, !- Outdoor Air Flow per Person {m3/s-person} + , !- Outdoor Air Flow per Floor Area {m3/s-m2} + , !- Outdoor Air Flow Rate {m3/s} + , !- Outdoor Air Flow Air Changes per Hour {1/hr} + ; !- Outdoor Air Flow Rate Fraction Schedule Name + +OS:DefaultScheduleSet, + {b0037545-3c4e-4fa9-8e52-7e91b582d2dc}, !- Handle + Space Function Office - enclosed Schedule Set, !- Name + , !- Hours of Operation Schedule Name + {eb31d729-9d95-4285-ac6e-b993be41a03f}, !- Number of People Schedule Name + {f4d586bd-b7df-4a3a-b459-6c72238aa952}, !- People Activity Level Schedule Name + {91678012-d5b1-434f-a32a-397ef1056f10}, !- Lighting Schedule Name + {d71457c3-7470-417a-b385-6ccf17afbafe}, !- Electric Equipment Schedule Name + , !- Gas Equipment Schedule Name + , !- Hot Water Equipment Schedule Name + {6d6f7284-7ae2-4a38-9fba-0844dbd0ecc5}, !- Infiltration Schedule Name + , !- Steam Equipment Schedule Name + ; !- Other Equipment Schedule Name + +OS:Schedule:Ruleset, + {eb31d729-9d95-4285-ac6e-b993be41a03f}, !- Handle + NECB-A-Occupancy, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + {3440f498-49ca-4fab-81c0-36e2ab1bf715}; !- Default Day Schedule Name + +OS:Schedule:Day, + {3440f498-49ca-4fab-81c0-36e2ab1bf715}, !- Handle + NECB-A-Occupancy Default, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 7, !- Hour 1 + 0, !- Minute 1 + 0, !- Value Until Time 1 + 8, !- Hour 2 + 0, !- Minute 2 + 0.1, !- Value Until Time 2 + 9, !- Hour 3 + 0, !- Minute 3 + 0.7, !- Value Until Time 3 + 12, !- Hour 4 + 0, !- Minute 4 + 0.9, !- Value Until Time 4 + 14, !- Hour 5 + 0, !- Minute 5 + 0.5, !- Value Until Time 5 + 17, !- Hour 6 + 0, !- Minute 6 + 0.9, !- Value Until Time 6 + 18, !- Hour 7 + 0, !- Minute 7 + 0.7, !- Value Until Time 7 + 19, !- Hour 8 + 0, !- Minute 8 + 0.3, !- Value Until Time 8 + 23, !- Hour 9 + 0, !- Minute 9 + 0.1, !- Value Until Time 9 + 24, !- Hour 10 + 0, !- Minute 10 + 0; !- Value Until Time 10 + +OS:Schedule:Rule, + {76151b10-445a-471a-bc58-1f06e9fe11e0}, !- Handle + Schedule Rule 2, !- Name + {eb31d729-9d95-4285-ac6e-b993be41a03f}, !- Schedule Ruleset Name + 2, !- Rule Order + {d68da82f-5740-469b-823b-a96803bd092c}, !- Day Schedule Name + , !- Apply Sunday + Yes, !- Apply Monday + Yes, !- Apply Tuesday + Yes, !- Apply Wednesday + Yes, !- Apply Thursday + Yes, !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {d68da82f-5740-469b-823b-a96803bd092c}, !- Handle + NECB-A-Occupancy Default|Wkdy Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 7, !- Hour 1 + 0, !- Minute 1 + 0, !- Value Until Time 1 + 8, !- Hour 2 + 0, !- Minute 2 + 0.1, !- Value Until Time 2 + 9, !- Hour 3 + 0, !- Minute 3 + 0.7, !- Value Until Time 3 + 12, !- Hour 4 + 0, !- Minute 4 + 0.9, !- Value Until Time 4 + 14, !- Hour 5 + 0, !- Minute 5 + 0.5, !- Value Until Time 5 + 17, !- Hour 6 + 0, !- Minute 6 + 0.9, !- Value Until Time 6 + 18, !- Hour 7 + 0, !- Minute 7 + 0.7, !- Value Until Time 7 + 19, !- Hour 8 + 0, !- Minute 8 + 0.3, !- Value Until Time 8 + 23, !- Hour 9 + 0, !- Minute 9 + 0.1, !- Value Until Time 9 + 24, !- Hour 10 + 0, !- Minute 10 + 0; !- Value Until Time 10 + +OS:Schedule:Rule, + {6a125bb7-f240-4af2-8bd9-9ddbd7ef141d}, !- Handle + Schedule Rule 3, !- Name + {eb31d729-9d95-4285-ac6e-b993be41a03f}, !- Schedule Ruleset Name + 1, !- Rule Order + {61bf7147-7461-41fe-98ad-f429738364b9}, !- Day Schedule Name + , !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + Yes, !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {61bf7147-7461-41fe-98ad-f429738364b9}, !- Handle + NECB-A-Occupancy Sat Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Rule, + {49e22c3b-6110-4400-8f85-bbe9be95be84}, !- Handle + Schedule Rule 4, !- Name + {eb31d729-9d95-4285-ac6e-b993be41a03f}, !- Schedule Ruleset Name + 0, !- Rule Order + {d5ba8f34-97cb-43ff-a892-431b587f6dcc}, !- Day Schedule Name + Yes, !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {d5ba8f34-97cb-43ff-a892-431b587f6dcc}, !- Handle + NECB-A-Occupancy Sun|Hol Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {f4d586bd-b7df-4a3a-b459-6c72238aa952}, !- Handle + NECB-Activity, !- Name + {4436cb3d-e197-45e3-9c9d-c692f5e9a81d}, !- Schedule Type Limits Name + {7e4e4c31-8f51-4795-b5f6-43f9b3ad173f}, !- Default Day Schedule Name + {6997a172-80eb-4325-a18a-fe2420e18bdc}, !- Summer Design Day Schedule Name + {d1f7103b-d0bb-437f-a961-a0ce477fb1ef}; !- Winter Design Day Schedule Name + +OS:Schedule:Day, + {7e4e4c31-8f51-4795-b5f6-43f9b3ad173f}, !- Handle + NECB-Activity Default, !- Name + {4436cb3d-e197-45e3-9c9d-c692f5e9a81d}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 130; !- Value Until Time 1 + +OS:Schedule:Day, + {5a82dc45-bc6f-42c9-b622-684be9872886}, !- Handle + Schedule Day 1, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Day, + {d1f7103b-d0bb-437f-a961-a0ce477fb1ef}, !- Handle + NECB-Activity Winter Design Day, !- Name + {4436cb3d-e197-45e3-9c9d-c692f5e9a81d}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 130; !- Value Until Time 1 + +OS:Schedule:Day, + {e7036a9a-cc5d-4605-941d-d59159ab5869}, !- Handle + Schedule Day 2, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Day, + {6997a172-80eb-4325-a18a-fe2420e18bdc}, !- Handle + NECB-Activity Summer Design Day, !- Name + {4436cb3d-e197-45e3-9c9d-c692f5e9a81d}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 130; !- Value Until Time 1 + +OS:ScheduleTypeLimits, + {4436cb3d-e197-45e3-9c9d-c692f5e9a81d}, !- Handle + ActivityLevel, !- Name + 0, !- Lower Limit Value + , !- Upper Limit Value + Continuous, !- Numeric Type + ActivityLevel; !- Unit Type + +OS:Schedule:Ruleset, + {91678012-d5b1-434f-a32a-397ef1056f10}, !- Handle + NECB-A-Lighting, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + {99ffe669-a8dd-4eba-92f6-f6424a541da4}; !- Default Day Schedule Name + +OS:Schedule:Day, + {99ffe669-a8dd-4eba-92f6-f6424a541da4}, !- Handle + NECB-A-Lighting Default, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 7, !- Hour 1 + 0, !- Minute 1 + 0.05, !- Value Until Time 1 + 8, !- Hour 2 + 0, !- Minute 2 + 0.3, !- Value Until Time 2 + 9, !- Hour 3 + 0, !- Minute 3 + 0.8, !- Value Until Time 3 + 17, !- Hour 4 + 0, !- Minute 4 + 0.9, !- Value Until Time 4 + 18, !- Hour 5 + 0, !- Minute 5 + 0.8, !- Value Until Time 5 + 19, !- Hour 6 + 0, !- Minute 6 + 0.5, !- Value Until Time 6 + 21, !- Hour 7 + 0, !- Minute 7 + 0.3, !- Value Until Time 7 + 23, !- Hour 8 + 0, !- Minute 8 + 0.1, !- Value Until Time 8 + 24, !- Hour 9 + 0, !- Minute 9 + 0.05; !- Value Until Time 9 + +OS:Schedule:Rule, + {de346ec6-af3a-4b6b-b657-846c71a04bb0}, !- Handle + Schedule Rule 5, !- Name + {91678012-d5b1-434f-a32a-397ef1056f10}, !- Schedule Ruleset Name + 2, !- Rule Order + {9f00776a-6911-4abb-85a9-5c769e679818}, !- Day Schedule Name + , !- Apply Sunday + Yes, !- Apply Monday + Yes, !- Apply Tuesday + Yes, !- Apply Wednesday + Yes, !- Apply Thursday + Yes, !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {9f00776a-6911-4abb-85a9-5c769e679818}, !- Handle + NECB-A-Lighting Default|Wkdy Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 7, !- Hour 1 + 0, !- Minute 1 + 0.05, !- Value Until Time 1 + 8, !- Hour 2 + 0, !- Minute 2 + 0.3, !- Value Until Time 2 + 9, !- Hour 3 + 0, !- Minute 3 + 0.8, !- Value Until Time 3 + 17, !- Hour 4 + 0, !- Minute 4 + 0.9, !- Value Until Time 4 + 18, !- Hour 5 + 0, !- Minute 5 + 0.8, !- Value Until Time 5 + 19, !- Hour 6 + 0, !- Minute 6 + 0.5, !- Value Until Time 6 + 21, !- Hour 7 + 0, !- Minute 7 + 0.3, !- Value Until Time 7 + 23, !- Hour 8 + 0, !- Minute 8 + 0.1, !- Value Until Time 8 + 24, !- Hour 9 + 0, !- Minute 9 + 0.05; !- Value Until Time 9 + +OS:Schedule:Rule, + {0359e807-923e-4bf4-8294-fb5fb6720117}, !- Handle + Schedule Rule 6, !- Name + {91678012-d5b1-434f-a32a-397ef1056f10}, !- Schedule Ruleset Name + 1, !- Rule Order + {a062ccde-0f29-4017-ab71-59f1c7957d6d}, !- Day Schedule Name + , !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + Yes, !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {a062ccde-0f29-4017-ab71-59f1c7957d6d}, !- Handle + NECB-A-Lighting Sat Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.05; !- Value Until Time 1 + +OS:Schedule:Rule, + {373915de-2b3a-4fdb-8f62-1366078635ad}, !- Handle + Schedule Rule 7, !- Name + {91678012-d5b1-434f-a32a-397ef1056f10}, !- Schedule Ruleset Name + 0, !- Rule Order + {59acb16a-6034-4988-92a7-965ce26638e7}, !- Day Schedule Name + Yes, !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {59acb16a-6034-4988-92a7-965ce26638e7}, !- Handle + NECB-A-Lighting Sun|Hol Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.05; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {d71457c3-7470-417a-b385-6ccf17afbafe}, !- Handle + NECB-A-Electric-Equipment, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + {8a8c5889-8bac-40eb-b6e9-93b752be1326}; !- Default Day Schedule Name + +OS:Schedule:Day, + {8a8c5889-8bac-40eb-b6e9-93b752be1326}, !- Handle + NECB-A-Electric-Equipment Default, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 7, !- Hour 1 + 0, !- Minute 1 + 0.2, !- Value Until Time 1 + 8, !- Hour 2 + 0, !- Minute 2 + 0.3, !- Value Until Time 2 + 9, !- Hour 3 + 0, !- Minute 3 + 0.8, !- Value Until Time 3 + 18, !- Hour 4 + 0, !- Minute 4 + 0.9, !- Value Until Time 4 + 19, !- Hour 5 + 0, !- Minute 5 + 0.5, !- Value Until Time 5 + 21, !- Hour 6 + 0, !- Minute 6 + 0.3, !- Value Until Time 6 + 24, !- Hour 7 + 0, !- Minute 7 + 0.2; !- Value Until Time 7 + +OS:Schedule:Rule, + {5166a219-2965-48c5-8386-1a7062bfb28a}, !- Handle + Schedule Rule 8, !- Name + {d71457c3-7470-417a-b385-6ccf17afbafe}, !- Schedule Ruleset Name + 2, !- Rule Order + {2d7dcb01-be64-414f-bca7-376cdb5abd9d}, !- Day Schedule Name + , !- Apply Sunday + Yes, !- Apply Monday + Yes, !- Apply Tuesday + Yes, !- Apply Wednesday + Yes, !- Apply Thursday + Yes, !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {2d7dcb01-be64-414f-bca7-376cdb5abd9d}, !- Handle + NECB-A-Electric-Equipment Default|Wkdy Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 7, !- Hour 1 + 0, !- Minute 1 + 0.2, !- Value Until Time 1 + 8, !- Hour 2 + 0, !- Minute 2 + 0.3, !- Value Until Time 2 + 9, !- Hour 3 + 0, !- Minute 3 + 0.8, !- Value Until Time 3 + 18, !- Hour 4 + 0, !- Minute 4 + 0.9, !- Value Until Time 4 + 19, !- Hour 5 + 0, !- Minute 5 + 0.5, !- Value Until Time 5 + 21, !- Hour 6 + 0, !- Minute 6 + 0.3, !- Value Until Time 6 + 24, !- Hour 7 + 0, !- Minute 7 + 0.2; !- Value Until Time 7 + +OS:Schedule:Rule, + {0eb24fc4-2ca2-46dd-aed8-ef37f5346dcf}, !- Handle + Schedule Rule 9, !- Name + {d71457c3-7470-417a-b385-6ccf17afbafe}, !- Schedule Ruleset Name + 1, !- Rule Order + {e1bed34a-07c6-4c7f-9411-6c66b5c5a4e9}, !- Day Schedule Name + , !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + Yes, !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {e1bed34a-07c6-4c7f-9411-6c66b5c5a4e9}, !- Handle + NECB-A-Electric-Equipment Sat Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.2; !- Value Until Time 1 + +OS:Schedule:Rule, + {88e4afb5-25cd-453f-a11e-87111011bd41}, !- Handle + Schedule Rule 10, !- Name + {d71457c3-7470-417a-b385-6ccf17afbafe}, !- Schedule Ruleset Name + 0, !- Rule Order + {eb0de256-794e-4ed2-ae27-ec8fa5455c01}, !- Day Schedule Name + Yes, !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {eb0de256-794e-4ed2-ae27-ec8fa5455c01}, !- Handle + NECB-A-Electric-Equipment Sun|Hol Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.2; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {6d6f7284-7ae2-4a38-9fba-0844dbd0ecc5}, !- Handle + Always On, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + {44ea27c4-e58b-4f1f-a7e1-339255165236}; !- Default Day Schedule Name + +OS:Schedule:Day, + {44ea27c4-e58b-4f1f-a7e1-339255165236}, !- Handle + Always On Default, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 1; !- Value Until Time 1 + +OS:ThermostatSetpoint:DualSetpoint, + {f23d7d7e-5577-4578-acfc-d2cd154e6886}, !- Handle + Space Function Office - enclosed Thermostat, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:Schedule:Ruleset, + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Handle + NECB-A-Thermostat Setpoint-Heating, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + {dbe3de4e-ce60-42b8-954d-26be906bccc9}; !- Default Day Schedule Name + +OS:Schedule:Day, + {dbe3de4e-ce60-42b8-954d-26be906bccc9}, !- Handle + NECB-A-Thermostat Setpoint-Heating Default, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 6, !- Hour 1 + 0, !- Minute 1 + 18, !- Value Until Time 1 + 7, !- Hour 2 + 0, !- Minute 2 + 20, !- Value Until Time 2 + 21, !- Hour 3 + 0, !- Minute 3 + 22, !- Value Until Time 3 + 24, !- Hour 4 + 0, !- Minute 4 + 18; !- Value Until Time 4 + +OS:Schedule:Rule, + {78e7d09d-9b7c-4c43-99a0-5252a655e219}, !- Handle + Schedule Rule 11, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Schedule Ruleset Name + 2, !- Rule Order + {ebd5f288-8d82-4999-add0-96d12185bf77}, !- Day Schedule Name + , !- Apply Sunday + Yes, !- Apply Monday + Yes, !- Apply Tuesday + Yes, !- Apply Wednesday + Yes, !- Apply Thursday + Yes, !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {ebd5f288-8d82-4999-add0-96d12185bf77}, !- Handle + NECB-A-Thermostat Setpoint-Heating Default|Wkdy Day, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 6, !- Hour 1 + 0, !- Minute 1 + 18, !- Value Until Time 1 + 7, !- Hour 2 + 0, !- Minute 2 + 20, !- Value Until Time 2 + 21, !- Hour 3 + 0, !- Minute 3 + 22, !- Value Until Time 3 + 24, !- Hour 4 + 0, !- Minute 4 + 18; !- Value Until Time 4 + +OS:Schedule:Rule, + {a34f026f-eee3-45c9-a1b4-d582b4d44eaa}, !- Handle + Schedule Rule 12, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Schedule Ruleset Name + 1, !- Rule Order + {406f8b71-d90d-4ee7-8c0a-285776d903c4}, !- Day Schedule Name + , !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + Yes, !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {406f8b71-d90d-4ee7-8c0a-285776d903c4}, !- Handle + NECB-A-Thermostat Setpoint-Heating Sat Day, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 18; !- Value Until Time 1 + +OS:Schedule:Rule, + {d4d64d45-e9ba-4320-ac45-a1051e4dce5c}, !- Handle + Schedule Rule 13, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Schedule Ruleset Name + 0, !- Rule Order + {9a95aeef-56f7-4950-ab81-6417425719b5}, !- Day Schedule Name + Yes, !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {9a95aeef-56f7-4950-ab81-6417425719b5}, !- Handle + NECB-A-Thermostat Setpoint-Heating Sun|Hol Day, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 18; !- Value Until Time 1 + +OS:ScheduleTypeLimits, + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Handle + Temperature, !- Name + , !- Lower Limit Value + , !- Upper Limit Value + Continuous, !- Numeric Type + Temperature; !- Unit Type + +OS:Schedule:Ruleset, + {464561eb-f631-4a8d-a753-4d87291d0357}, !- Handle + NECB-A-Thermostat Setpoint-Cooling, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + {ce542d11-12cc-4b38-8769-7d66ec91e753}; !- Default Day Schedule Name + +OS:Schedule:Day, + {ce542d11-12cc-4b38-8769-7d66ec91e753}, !- Handle + NECB-A-Thermostat Setpoint-Cooling Default, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 6, !- Hour 1 + 0, !- Minute 1 + 35, !- Value Until Time 1 + 21, !- Hour 2 + 0, !- Minute 2 + 24, !- Value Until Time 2 + 24, !- Hour 3 + 0, !- Minute 3 + 35; !- Value Until Time 3 + +OS:Schedule:Rule, + {292bd3c3-3969-40fe-a20b-c6fd4536d25a}, !- Handle + Schedule Rule 14, !- Name + {464561eb-f631-4a8d-a753-4d87291d0357}, !- Schedule Ruleset Name + 2, !- Rule Order + {2cbf34ba-0fc8-4752-b681-b080e4acdba9}, !- Day Schedule Name + , !- Apply Sunday + Yes, !- Apply Monday + Yes, !- Apply Tuesday + Yes, !- Apply Wednesday + Yes, !- Apply Thursday + Yes, !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {2cbf34ba-0fc8-4752-b681-b080e4acdba9}, !- Handle + NECB-A-Thermostat Setpoint-Cooling Default|Wkdy Day, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 6, !- Hour 1 + 0, !- Minute 1 + 35, !- Value Until Time 1 + 21, !- Hour 2 + 0, !- Minute 2 + 24, !- Value Until Time 2 + 24, !- Hour 3 + 0, !- Minute 3 + 35; !- Value Until Time 3 + +OS:Schedule:Rule, + {2d9b17dc-da17-4e09-8140-dec06de015ef}, !- Handle + Schedule Rule 15, !- Name + {464561eb-f631-4a8d-a753-4d87291d0357}, !- Schedule Ruleset Name + 1, !- Rule Order + {7519d386-e636-45d1-a82c-20da91f5489f}, !- Day Schedule Name + , !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + Yes, !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {7519d386-e636-45d1-a82c-20da91f5489f}, !- Handle + NECB-A-Thermostat Setpoint-Cooling Sat Day, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 35; !- Value Until Time 1 + +OS:Schedule:Rule, + {7ac4a9d5-f0e3-499e-9dea-d42d2fc5d804}, !- Handle + Schedule Rule 16, !- Name + {464561eb-f631-4a8d-a753-4d87291d0357}, !- Schedule Ruleset Name + 0, !- Rule Order + {d973eedc-4b8e-4da5-ab87-ee471da23cf2}, !- Day Schedule Name + Yes, !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {d973eedc-4b8e-4da5-ab87-ee471da23cf2}, !- Handle + NECB-A-Thermostat Setpoint-Cooling Sun|Hol Day, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 35; !- Value Until Time 1 + +OS:Rendering:Color, + {06ead6c0-030b-4890-af11-ba44a169b402}, !- Handle + Space Function Warehouse - fine 1, !- Name + 255, !- Rendering Red Value + 255, !- Rendering Green Value + 255; !- Rendering Blue Value + +OS:People:Definition, + {34c314f7-9144-4baa-9f25-7cd855c697aa}, !- Handle + Space Function Warehouse - fine People Definition, !- Name + People/Area, !- Number of People Calculation Method + , !- Number of People {people} + 0.0200208733750801, !- People per Space Floor Area {person/m2} + , !- Space Floor Area per Person {m2/person} + 0.3; !- Fraction Radiant + +OS:People, + {f2ecf49f-a9e4-4305-aa3d-c0eba4ab2977}, !- Handle + Space Function Warehouse - fine People, !- Name + {34c314f7-9144-4baa-9f25-7cd855c697aa}, !- People Definition Name + {f6907e5f-7752-47ad-bfcd-c6fb8b1f86ab}, !- Space or SpaceType Name + , !- Number of People Schedule Name + , !- Activity Level Schedule Name + , !- Surface Name/Angle Factor List Name + {7ae29b43-c43a-474c-a886-04ebfbf40244}, !- Work Efficiency Schedule Name + {5bf448d8-7167-4abd-a154-79a417231d5c}, !- Clothing Insulation Schedule Name + {1f8c4ef3-05fc-4c39-8818-de76ffbafad7}, !- Air Velocity Schedule Name + 1; !- Multiplier + +OS:Lights:Definition, + {c3e8ce3f-5364-4ec3-a947-00cb1cbee8e5}, !- Handle + Space Function Warehouse - fine Lights Definition, !- Name + Watts/Area, !- Design Level Calculation Method + , !- Lighting Level {W} + 10.1999151158025, !- Watts per Space Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.5, !- Fraction Radiant + 0.2; !- Fraction Visible + +OS:Lights, + {8a9da3e2-89cb-4e37-9733-a575bdff723b}, !- Handle + Space Function Warehouse - fine Lights, !- Name + {c3e8ce3f-5364-4ec3-a947-00cb1cbee8e5}, !- Lights Definition Name + {f6907e5f-7752-47ad-bfcd-c6fb8b1f86ab}, !- Space or SpaceType Name + , !- Schedule Name + 1, !- Fraction Replaceable + , !- Multiplier + General; !- End-Use Subcategory + +OS:ElectricEquipment:Definition, + {a4cc9186-ea1e-409c-a462-e5c788ac77f3}, !- Handle + Space Function Warehouse - fine Elec Equip Definition, !- Name + Watts/Area, !- Design Level Calculation Method + , !- Design Level {W} + 0.999991679497248, !- Watts per Space Floor Area {W/m2} + , !- Watts per Person {W/person} + , !- Fraction Latent + 0.5; !- Fraction Radiant + +OS:ElectricEquipment, + {c08b162c-5032-4f99-8724-1b8ef391f9c7}, !- Handle + Space Function Warehouse - fine Elec Equip, !- Name + {a4cc9186-ea1e-409c-a462-e5c788ac77f3}, !- Electric Equipment Definition Name + {f6907e5f-7752-47ad-bfcd-c6fb8b1f86ab}, !- Space or SpaceType Name + , !- Schedule Name + , !- Multiplier + General; !- End-Use Subcategory + +OS:DesignSpecification:OutdoorAir, + {3c9babf0-90fd-406e-aab0-21768e1172ee}, !- Handle + Space Function Warehouse - fine Ventilation, !- Name + Sum, !- Outdoor Air Method + , !- Outdoor Air Flow per Person {m3/s-person} + 0.000254, !- Outdoor Air Flow per Floor Area {m3/s-m2} + , !- Outdoor Air Flow Rate {m3/s} + , !- Outdoor Air Flow Air Changes per Hour {1/hr} + ; !- Outdoor Air Flow Rate Fraction Schedule Name + +OS:DefaultScheduleSet, + {01c5526a-f72c-4c0f-a925-383ea53dd0f2}, !- Handle + Space Function Warehouse - fine Schedule Set, !- Name + , !- Hours of Operation Schedule Name + {eb31d729-9d95-4285-ac6e-b993be41a03f}, !- Number of People Schedule Name + {f4d586bd-b7df-4a3a-b459-6c72238aa952}, !- People Activity Level Schedule Name + {91678012-d5b1-434f-a32a-397ef1056f10}, !- Lighting Schedule Name + {d71457c3-7470-417a-b385-6ccf17afbafe}, !- Electric Equipment Schedule Name + , !- Gas Equipment Schedule Name + , !- Hot Water Equipment Schedule Name + {6d6f7284-7ae2-4a38-9fba-0844dbd0ecc5}, !- Infiltration Schedule Name + , !- Steam Equipment Schedule Name + ; !- Other Equipment Schedule Name + +OS:ThermostatSetpoint:DualSetpoint, + {abf0ae2c-ae10-4dca-a056-26d5fb615963}, !- Handle + Space Function Warehouse - fine Thermostat, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:Rendering:Color, + {7f3e2f17-d16f-40b0-9d6c-2236be0f5372}, !- Handle + Space Function Warehouse - med/blk 1, !- Name + 255, !- Rendering Red Value + 255, !- Rendering Green Value + 255; !- Rendering Blue Value + +OS:People:Definition, + {e9f4a57b-9c2a-496a-bdce-a3a4f5c35034}, !- Handle + Space Function Warehouse - med/blk People Definition, !- Name + People/Area, !- Number of People Calculation Method + , !- Number of People {people} + 0.01001043668754, !- People per Space Floor Area {person/m2} + , !- Space Floor Area per Person {m2/person} + 0.3; !- Fraction Radiant + +OS:People, + {ca916c71-8a8f-44ea-bd35-ba2fd52ab216}, !- Handle + Space Function Warehouse - med/blk People, !- Name + {e9f4a57b-9c2a-496a-bdce-a3a4f5c35034}, !- People Definition Name + {a6aa64ea-d7e8-4be2-93e7-411cbc4acca9}, !- Space or SpaceType Name + , !- Number of People Schedule Name + , !- Activity Level Schedule Name + , !- Surface Name/Angle Factor List Name + {7ae29b43-c43a-474c-a886-04ebfbf40244}, !- Work Efficiency Schedule Name + {5bf448d8-7167-4abd-a154-79a417231d5c}, !- Clothing Insulation Schedule Name + {1f8c4ef3-05fc-4c39-8818-de76ffbafad7}, !- Air Velocity Schedule Name + 1; !- Multiplier + +OS:Lights:Definition, + {c35e0b68-1e13-4eb5-8060-c30a637b4409}, !- Handle + Space Function Warehouse - med/blk Lights Definition, !- Name + Watts/Area, !- Design Level Calculation Method + , !- Lighting Level {W} + 6.39994674017126, !- Watts per Space Floor Area {W/m2} + , !- Watts per Person {W/person} + 0.5, !- Fraction Radiant + 0.2; !- Fraction Visible + +OS:Lights, + {3528d620-d45b-43db-9d60-3121690745e7}, !- Handle + Space Function Warehouse - med/blk Lights, !- Name + {c35e0b68-1e13-4eb5-8060-c30a637b4409}, !- Lights Definition Name + {a6aa64ea-d7e8-4be2-93e7-411cbc4acca9}, !- Space or SpaceType Name + , !- Schedule Name + 1, !- Fraction Replaceable + , !- Multiplier + General; !- End-Use Subcategory + +OS:ElectricEquipment:Definition, + {31911c8d-ba0e-4331-88d5-85a8fbb66e17}, !- Handle + Space Function Warehouse - med/blk Elec Equip Definition, !- Name + Watts/Area, !- Design Level Calculation Method + , !- Design Level {W} + 0.999991679497248, !- Watts per Space Floor Area {W/m2} + , !- Watts per Person {W/person} + , !- Fraction Latent + 0.5; !- Fraction Radiant + +OS:ElectricEquipment, + {0a434875-81fc-4156-a12e-fa4cceb03140}, !- Handle + Space Function Warehouse - med/blk Elec Equip, !- Name + {31911c8d-ba0e-4331-88d5-85a8fbb66e17}, !- Electric Equipment Definition Name + {a6aa64ea-d7e8-4be2-93e7-411cbc4acca9}, !- Space or SpaceType Name + , !- Schedule Name + , !- Multiplier + General; !- End-Use Subcategory + +OS:DesignSpecification:OutdoorAir, + {799a10f3-d978-4c06-960c-2a7e8ba018a3}, !- Handle + Space Function Warehouse - med/blk Ventilation, !- Name + Sum, !- Outdoor Air Method + , !- Outdoor Air Flow per Person {m3/s-person} + 0.000254, !- Outdoor Air Flow per Floor Area {m3/s-m2} + , !- Outdoor Air Flow Rate {m3/s} + , !- Outdoor Air Flow Air Changes per Hour {1/hr} + ; !- Outdoor Air Flow Rate Fraction Schedule Name + +OS:DefaultScheduleSet, + {11066c45-f5d8-4345-96fc-08c071cb2e5f}, !- Handle + Space Function Warehouse - med/blk Schedule Set, !- Name + , !- Hours of Operation Schedule Name + {eb31d729-9d95-4285-ac6e-b993be41a03f}, !- Number of People Schedule Name + {f4d586bd-b7df-4a3a-b459-6c72238aa952}, !- People Activity Level Schedule Name + {91678012-d5b1-434f-a32a-397ef1056f10}, !- Lighting Schedule Name + {d71457c3-7470-417a-b385-6ccf17afbafe}, !- Electric Equipment Schedule Name + , !- Gas Equipment Schedule Name + , !- Hot Water Equipment Schedule Name + {6d6f7284-7ae2-4a38-9fba-0844dbd0ecc5}, !- Infiltration Schedule Name + , !- Steam Equipment Schedule Name + ; !- Other Equipment Schedule Name + +OS:ThermostatSetpoint:DualSetpoint, + {d443d8b3-21fb-4145-8bf1-be9b11a2f7a2}, !- Handle + Space Function Warehouse - med/blk Thermostat, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:Schedule:Constant, + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Handle + Always On Discrete, !- Name + {24b15a3b-5b97-4d40-adda-f697acb63d99}, !- Schedule Type Limits Name + 1; !- Value + +OS:ScheduleTypeLimits, + {24b15a3b-5b97-4d40-adda-f697acb63d99}, !- Handle + OnOff, !- Name + 0, !- Lower Limit Value + 1, !- Upper Limit Value + Discrete, !- Numeric Type + Availability; !- Unit Type + +OS:SpaceInfiltration:DesignFlowRate, + {6938b1db-d8bd-4484-9808-54bf2689ee44}, !- Handle + Zone1 Office Infiltration, !- Name + {12c3d4a0-20ec-4e1f-8040-e70cdfba4a69}, !- Space or SpaceType Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Schedule Name + Flow/ExteriorArea, !- Design Flow Rate Calculation Method + , !- Design Flow Rate {m3/s} + , !- Flow per Space Floor Area {m3/s-m2} + 0.00025, !- Flow per Exterior Surface Area {m3/s-m2} + , !- Air Changes per Hour {1/hr} + 0, !- Constant Term Coefficient + 0, !- Temperature Term Coefficient + 0.224, !- Velocity Term Coefficient + 0; !- Velocity Squared Term Coefficient + +OS:SpaceInfiltration:DesignFlowRate, + {b85062e9-24ff-4f0d-abb9-9238e82e495a}, !- Handle + Zone2 Fine Storage Infiltration, !- Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space or SpaceType Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Schedule Name + Flow/ExteriorArea, !- Design Flow Rate Calculation Method + , !- Design Flow Rate {m3/s} + , !- Flow per Space Floor Area {m3/s-m2} + 0.00025, !- Flow per Exterior Surface Area {m3/s-m2} + , !- Air Changes per Hour {1/hr} + 0, !- Constant Term Coefficient + 0, !- Temperature Term Coefficient + 0.224, !- Velocity Term Coefficient + 0; !- Velocity Squared Term Coefficient + +OS:SpaceInfiltration:DesignFlowRate, + {194e32f5-04a8-4165-a691-7df048f64ec9}, !- Handle + Zone3 Bulk Storage Infiltration, !- Name + {39655c19-15b3-4081-92c2-4613ae84d8e6}, !- Space or SpaceType Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Schedule Name + Flow/ExteriorArea, !- Design Flow Rate Calculation Method + , !- Design Flow Rate {m3/s} + , !- Flow per Space Floor Area {m3/s-m2} + 0.00025, !- Flow per Exterior Surface Area {m3/s-m2} + , !- Air Changes per Hour {1/hr} + 0, !- Constant Term Coefficient + 0, !- Temperature Term Coefficient + 0.224, !- Velocity Term Coefficient + 0; !- Velocity Squared Term Coefficient + +OS:SurfaceConvectionAlgorithm:Inside, + {481a241c-1422-4ce3-a103-275b18391c7e}, !- Handle + TARP; !- Algorithm + +OS:SurfaceConvectionAlgorithm:Outside, + {3287b6b9-e910-4ae9-90b5-1e1ae7566e60}, !- Handle + TARP; !- Algorithm + +OS:Material:NoMass, + {068c936a-34c3-48e8-a44b-03d288e0b7e2}, !- Handle + CP02 CARPET PAD, !- Name + VeryRough, !- Roughness + 0.21648, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.8; !- Visible Absorptance + +OS:Material, + {84790b85-50db-4f8d-b82c-18ddeb5a58a7}, !- Handle + 100mm Normalweight concrete floor, !- Name + MediumSmooth, !- Roughness + 0.1016, !- Thickness {m} + 2.31, !- Conductivity {W/m-K} + 2322, !- Density {kg/m3} + 832; !- Specific Heat {J/kg-K} + +OS:Material:NoMass, + {2a3e0c2b-3d45-4845-a1d0-0d708671d65f}, !- Handle + Nonres_Floor_Insulation, !- Name + MediumSmooth, !- Roughness + 2.88291975297193, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:Construction, + {9a7d0cbb-460a-484a-86e2-b8900db9432f}, !- Handle + Floor Adiabatic construction, !- Name + , !- Surface Rendering Name + {068c936a-34c3-48e8-a44b-03d288e0b7e2}, !- Layer 1 + {84790b85-50db-4f8d-b82c-18ddeb5a58a7}, !- Layer 2 + {2a3e0c2b-3d45-4845-a1d0-0d708671d65f}; !- Layer 3 + +OS:Material, + {8ee49414-a4bc-49d8-9d55-f7088a195d1c}, !- Handle + G01 13mm gypsum board, !- Name + Smooth, !- Roughness + 0.0127, !- Thickness {m} + 0.16, !- Conductivity {W/m-K} + 800, !- Density {kg/m3} + 1090, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.5; !- Visible Absorptance + +OS:Construction, + {516ea637-b5bc-4c2d-a2be-aeff52a1505a}, !- Handle + Wall Adiabatic construction, !- Name + , !- Surface Rendering Name + {8ee49414-a4bc-49d8-9d55-f7088a195d1c}, !- Layer 1 + {8ee49414-a4bc-49d8-9d55-f7088a195d1c}; !- Layer 2 + +OS:Material, + {b2e0e17f-70de-4b4a-8667-5d9d1ae55e4f}, !- Handle + M10 200mm concrete block basement wall, !- Name + MediumRough, !- Roughness + 0.2032, !- Thickness {m} + 1.326, !- Conductivity {W/m-K} + 1842, !- Density {kg/m3} + 912; !- Specific Heat {J/kg-K} + +OS:Construction, + {81011cb2-2c32-4276-afcc-62156cdbf76a}, !- Handle + Basement Wall construction, !- Name + , !- Surface Rendering Name + {b2e0e17f-70de-4b4a-8667-5d9d1ae55e4f}; !- Layer 1 + +OS:Construction, + {b981cc99-f32e-49fc-9724-5c4d2a8fe191}, !- Handle + Basement Floor construction, !- Name + , !- Surface Rendering Name + {b2e0e17f-70de-4b4a-8667-5d9d1ae55e4f}, !- Layer 1 + {068c936a-34c3-48e8-a44b-03d288e0b7e2}; !- Layer 2 + +OS:DefaultConstructionSet, + {ef6356a1-8948-4234-8bf8-69a9c9dc8c24}, !- Handle + BTAP-Mass at hdd = 5000.0, !- Name + {61a31190-6f9d-4a24-bb0a-b5849713f6c2}, !- Default Exterior Surface Constructions Name + {ff372157-234d-4345-ba7b-a01a0144a24b}, !- Default Interior Surface Constructions Name + {df0969c5-d54c-4b85-ae85-2702c59efde2}, !- Default Ground Contact Surface Constructions Name + {2282980d-f2b0-48f9-88a3-d48761c1b4f6}, !- Default Exterior SubSurface Constructions Name + {d2d88173-8963-4d89-833b-fd7e8845e2b2}, !- Default Interior SubSurface Constructions Name + {0c3afc52-e166-44f8-a48c-4e081aaf39ac}, !- Interior Partition Construction Name + , !- Space Shading Construction Name + , !- Building Shading Construction Name + , !- Site Shading Construction Name + ; !- Adiabatic Surface Construction Name + +OS:DefaultSurfaceConstructions, + {ce1ce1d1-7abf-4529-ad36-9c232758f12d}, !- Handle + NECB2011 - FullSrvRest - WholeBuilding - NECB HDD Method at hdd = 5000.0, !- Name + {a15a049c-5710-4d9c-b140-e1138f04c3cc}, !- Floor Construction Name + {3e4e0de8-dc48-4b2f-b1b0-4d966cb7fe98}, !- Wall Construction Name + {5debd3d0-6778-4f80-a7c5-bbc056dce8bd}; !- Roof Ceiling Construction Name + +OS:DefaultSurfaceConstructions, + {ff372157-234d-4345-ba7b-a01a0144a24b}, !- Handle + Default Surface Constructions 2, !- Name + {f62c7229-3d7c-4a15-9fab-8c2bbc992b63}, !- Floor Construction Name + {aa3599a8-3a6c-4a6d-be08-911aeebd4cce}, !- Wall Construction Name + {69e81ca8-29d6-4e7d-8864-b072be9dbab4}; !- Roof Ceiling Construction Name + +OS:DefaultSurfaceConstructions, + {32d09c53-c530-4164-8d5e-75e459f35e6b}, !- Handle + NECB2011 - FullSrvRest - WholeBuilding - NECB HDD Method at hdd = 5000.0 1, !- Name + {56a43948-e678-4320-bce4-472b99639608}, !- Floor Construction Name + {8508483c-e3d3-4e9f-9822-700f6f28bc09}, !- Wall Construction Name + {d9fbc9bf-b362-489e-8441-7833031da7df}; !- Roof Ceiling Construction Name + +OS:DefaultSubSurfaceConstructions, + {2d6f73dc-99f0-4500-ac36-60d600b2d030}, !- Handle + NECB2011 - FullSrvRest - WholeBuilding - NECB HDD Method at hdd = 5000.0, !- Name + {5d372585-a4a9-4119-9375-8025cfbe4fd8}, !- Fixed Window Construction Name + {5d372585-a4a9-4119-9375-8025cfbe4fd8}, !- Operable Window Construction Name + {e52d26ff-b854-493c-8eea-cd1f7d7f0478}, !- Door Construction Name + {1b146c6d-fa46-4a0c-b89c-4b45585fa307}, !- Glass Door Construction Name + {0b6440c4-0a0d-4f9d-b7d9-02dc2a1f3e85}, !- Overhead Door Construction Name + {2ecca862-4148-484b-9384-709384df43a1}, !- Skylight Construction Name + {64ffc09e-058a-436a-8580-179b571dbb0e}, !- Tubular Daylight Dome Construction Name + {70f73c08-7d45-4122-b59f-d4433d3442ae}; !- Tubular Daylight Diffuser Construction Name + +OS:DefaultSubSurfaceConstructions, + {d2d88173-8963-4d89-833b-fd7e8845e2b2}, !- Handle + Default Sub Surface Constructions 2, !- Name + {1edfa97d-db5d-47e9-84bf-fa3962fa0a9f}, !- Fixed Window Construction Name + {1edfa97d-db5d-47e9-84bf-fa3962fa0a9f}, !- Operable Window Construction Name + {1f899a26-5c6c-467e-9c0f-6ff484534c9c}, !- Door Construction Name + , !- Glass Door Construction Name + , !- Overhead Door Construction Name + , !- Skylight Construction Name + , !- Tubular Daylight Dome Construction Name + ; !- Tubular Daylight Diffuser Construction Name + +OS:Construction, + {0c3afc52-e166-44f8-a48c-4e081aaf39ac}, !- Handle + BTAP-Int-Partition, !- Name + , !- Surface Rendering Name + {e2cb5f93-293f-4e04-a4cb-e1ba7f67cbf6}; !- Layer 1 + +OS:StandardsInformation:Construction, + {44468e2c-1071-4b3a-b069-f44da49f6d4b}, !- Handle + {0c3afc52-e166-44f8-a48c-4e081aaf39ac}, !- Construction Name + InteriorPartition, !- Intended Surface Type + ; !- Standards Construction Type + +OS:Construction, + {a15a049c-5710-4d9c-b140-e1138f04c3cc}, !- Handle + BTAP-Ext-Floor-Mass, !- Name + , !- Surface Rendering Name + {a4e6cff1-76a8-4326-a8bd-f452a82b3f32}, !- Layer 1 + {e3369030-7db5-426a-a75b-59b83568b7c1}, !- Layer 2 + {ba980602-8501-4aa1-bb10-3a903fa38237}; !- Layer 3 + +OS:StandardsInformation:Construction, + {7fa971f3-f4a6-4aeb-8399-e17cfb057b8f}, !- Handle + {a15a049c-5710-4d9c-b140-e1138f04c3cc}, !- Construction Name + ExteriorFloor, !- Intended Surface Type + Mass, !- Standards Construction Type + 0, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Construction, + {3e4e0de8-dc48-4b2f-b1b0-4d966cb7fe98}, !- Handle + BTAP-Ext-Wall-Mass, !- Name + , !- Surface Rendering Name + {057cf8b7-1a79-4159-98f9-dde00ac299ff}, !- Layer 1 + {a2169114-d4e0-488b-aa38-29c168bd4d96}, !- Layer 2 + {a4e6cff1-76a8-4326-a8bd-f452a82b3f32}, !- Layer 3 + {09f50994-a176-4c1a-ba61-ac7b1e48472f}; !- Layer 4 + +OS:StandardsInformation:Construction, + {c39419e5-218c-4e4e-a8e1-adc64ab4a9d0}, !- Handle + {3e4e0de8-dc48-4b2f-b1b0-4d966cb7fe98}, !- Construction Name + ExteriorWall, !- Intended Surface Type + Mass, !- Standards Construction Type + 2, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Construction, + {5debd3d0-6778-4f80-a7c5-bbc056dce8bd}, !- Handle + BTAP-Ext-Roof-Metal, !- Name + , !- Surface Rendering Name + {caadfcd7-8543-44b4-a5a5-98c4886b1a48}, !- Layer 1 + {a4e6cff1-76a8-4326-a8bd-f452a82b3f32}; !- Layer 2 + +OS:StandardsInformation:Construction, + {f5e6e340-a036-49f3-8d13-cb226fb9120b}, !- Handle + {5debd3d0-6778-4f80-a7c5-bbc056dce8bd}, !- Construction Name + ExteriorRoof, !- Intended Surface Type + Metal, !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Construction, + {f62c7229-3d7c-4a15-9fab-8c2bbc992b63}, !- Handle + BTAP-Int-Floor, !- Name + , !- Surface Rendering Name + {752c76f8-cbac-435b-b8f2-acd19dba9b37}, !- Layer 1 + {ba980602-8501-4aa1-bb10-3a903fa38237}; !- Layer 2 + +OS:StandardsInformation:Construction, + {d7620139-d183-42c4-884b-c1b0ed5b4228}, !- Handle + {f62c7229-3d7c-4a15-9fab-8c2bbc992b63}, !- Construction Name + InteriorFloor, !- Intended Surface Type + ; !- Standards Construction Type + +OS:Construction, + {aa3599a8-3a6c-4a6d-be08-911aeebd4cce}, !- Handle + BTAP-Int-Wall, !- Name + , !- Surface Rendering Name + {1f76ca51-0f94-4786-976d-0f871e3bd343}, !- Layer 1 + {1f76ca51-0f94-4786-976d-0f871e3bd343}; !- Layer 2 + +OS:StandardsInformation:Construction, + {aa16ba6d-f864-4fc2-a8c2-f46c34b87354}, !- Handle + {aa3599a8-3a6c-4a6d-be08-911aeebd4cce}, !- Construction Name + InteriorWall, !- Intended Surface Type + ; !- Standards Construction Type + +OS:Construction, + {69e81ca8-29d6-4e7d-8864-b072be9dbab4}, !- Handle + BTAP-Int-Ceiling, !- Name + , !- Surface Rendering Name + {ba980602-8501-4aa1-bb10-3a903fa38237}, !- Layer 1 + {752c76f8-cbac-435b-b8f2-acd19dba9b37}; !- Layer 2 + +OS:StandardsInformation:Construction, + {eea7b107-3b3f-462c-bb21-2806380c95f6}, !- Handle + {69e81ca8-29d6-4e7d-8864-b072be9dbab4}, !- Construction Name + InteriorCeiling, !- Intended Surface Type + ; !- Standards Construction Type + +OS:Construction, + {56a43948-e678-4320-bce4-472b99639608}, !- Handle + BTAP-Grnd-Floor-Mass, !- Name + , !- Surface Rendering Name + {bc34ba43-dd51-45e2-99e4-19ee8cae37df}, !- Layer 1 + {ba980602-8501-4aa1-bb10-3a903fa38237}; !- Layer 2 + +OS:StandardsInformation:Construction, + {87843d6c-0d7b-44aa-a0d8-de9716a8a9c5}, !- Handle + {56a43948-e678-4320-bce4-472b99639608}, !- Construction Name + GroundContactFloor, !- Intended Surface Type + Mass, !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Construction, + {8508483c-e3d3-4e9f-9822-700f6f28bc09}, !- Handle + BTAP-Grnd-Wall-Mass, !- Name + , !- Surface Rendering Name + {bc34ba43-dd51-45e2-99e4-19ee8cae37df}, !- Layer 1 + {ba980602-8501-4aa1-bb10-3a903fa38237}; !- Layer 2 + +OS:StandardsInformation:Construction, + {9cfc15d2-14f0-46e3-98cf-4ddc355bbf39}, !- Handle + {8508483c-e3d3-4e9f-9822-700f6f28bc09}, !- Construction Name + GroundContactWall, !- Intended Surface Type + Mass, !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Construction, + {d9fbc9bf-b362-489e-8441-7833031da7df}, !- Handle + BTAP-Grnd-Roof-Mass, !- Name + , !- Surface Rendering Name + {bc34ba43-dd51-45e2-99e4-19ee8cae37df}, !- Layer 1 + {ba980602-8501-4aa1-bb10-3a903fa38237}; !- Layer 2 + +OS:StandardsInformation:Construction, + {4e7432a7-6331-41ac-a4c1-672eb8b9de9d}, !- Handle + {d9fbc9bf-b362-489e-8441-7833031da7df}, !- Construction Name + GroundContactRoof, !- Intended Surface Type + Mass, !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Construction, + {5d372585-a4a9-4119-9375-8025cfbe4fd8}, !- Handle + BTAP-Ext-FixedWindow, !- Name + , !- Surface Rendering Name + {3fde24d3-804a-47f1-9bcf-c8bea7aa089d}; !- Layer 1 + +OS:StandardsInformation:Construction, + {4d4c7760-ecf6-4ad1-83fb-87a0340eec43}, !- Handle + {5d372585-a4a9-4119-9375-8025cfbe4fd8}, !- Construction Name + ExteriorWindow; !- Intended Surface Type + +OS:Construction, + {e52d26ff-b854-493c-8eea-cd1f7d7f0478}, !- Handle + BTAP-Ext-Door, !- Name + , !- Surface Rendering Name + {5ca752be-78e7-4265-b592-2a9eb728227a}, !- Layer 1 + {a4e6cff1-76a8-4326-a8bd-f452a82b3f32}; !- Layer 2 + +OS:StandardsInformation:Construction, + {91d326bf-e925-45af-bf1a-6278b6627c89}, !- Handle + {e52d26ff-b854-493c-8eea-cd1f7d7f0478}, !- Construction Name + ExteriorDoor, !- Intended Surface Type + , !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Construction, + {1b146c6d-fa46-4a0c-b89c-4b45585fa307}, !- Handle + BTAP-Ext-GlassDoors, !- Name + , !- Surface Rendering Name + {3fde24d3-804a-47f1-9bcf-c8bea7aa089d}; !- Layer 1 + +OS:StandardsInformation:Construction, + {6be86eb7-e1e2-4b00-8bc2-a1890b38c4a5}, !- Handle + {1b146c6d-fa46-4a0c-b89c-4b45585fa307}, !- Construction Name + GlassDoor; !- Intended Surface Type + +OS:Construction, + {0b6440c4-0a0d-4f9d-b7d9-02dc2a1f3e85}, !- Handle + BTAP-Ext-OverHeadDoor, !- Name + , !- Surface Rendering Name + {a4e6cff1-76a8-4326-a8bd-f452a82b3f32}; !- Layer 1 + +OS:StandardsInformation:Construction, + {106fb0be-89d3-4d01-8a3f-79763e3326b9}, !- Handle + {0b6440c4-0a0d-4f9d-b7d9-02dc2a1f3e85}, !- Construction Name + ExteriorDoor, !- Intended Surface Type + RollUp, !- Standards Construction Type + 0, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Construction, + {2ecca862-4148-484b-9384-709384df43a1}, !- Handle + BTAP-Ext-Skylights, !- Name + , !- Surface Rendering Name + {3fde24d3-804a-47f1-9bcf-c8bea7aa089d}; !- Layer 1 + +OS:StandardsInformation:Construction, + {6af99d3d-70b3-4d0f-9420-fda75b386c5a}, !- Handle + {2ecca862-4148-484b-9384-709384df43a1}, !- Construction Name + Skylight; !- Intended Surface Type + +OS:Construction, + {64ffc09e-058a-436a-8580-179b571dbb0e}, !- Handle + BTAP-Ext-DaylightDomes, !- Name + , !- Surface Rendering Name + {3fde24d3-804a-47f1-9bcf-c8bea7aa089d}; !- Layer 1 + +OS:StandardsInformation:Construction, + {ee573b34-d883-4f01-8065-b2f50a721e99}, !- Handle + {64ffc09e-058a-436a-8580-179b571dbb0e}, !- Construction Name + TubularDaylightDome; !- Intended Surface Type + +OS:Construction, + {70f73c08-7d45-4122-b59f-d4433d3442ae}, !- Handle + BTAP-Ext-DaylightDiffuser, !- Name + , !- Surface Rendering Name + {3fde24d3-804a-47f1-9bcf-c8bea7aa089d}; !- Layer 1 + +OS:StandardsInformation:Construction, + {8c7a3ac1-71a4-498c-bb93-9f438a67e700}, !- Handle + {70f73c08-7d45-4122-b59f-d4433d3442ae}, !- Construction Name + TubularDaylightDiffuser; !- Intended Surface Type + +OS:Construction, + {1edfa97d-db5d-47e9-84bf-fa3962fa0a9f}, !- Handle + BTAP-Int-Window, !- Name + , !- Surface Rendering Name + {3fde24d3-804a-47f1-9bcf-c8bea7aa089d}; !- Layer 1 + +OS:StandardsInformation:Construction, + {041603b9-abcd-48e7-8132-0a676e8c2617}, !- Handle + {1edfa97d-db5d-47e9-84bf-fa3962fa0a9f}, !- Construction Name + InteriorWindow, !- Intended Surface Type + ; !- Standards Construction Type + +OS:Construction, + {1f899a26-5c6c-467e-9c0f-6ff484534c9c}, !- Handle + BTAP-Int-Door, !- Name + , !- Surface Rendering Name + {e2cb5f93-293f-4e04-a4cb-e1ba7f67cbf6}; !- Layer 1 + +OS:StandardsInformation:Construction, + {355c8fc9-119e-4b63-92b7-6ce27e730186}, !- Handle + {1f899a26-5c6c-467e-9c0f-6ff484534c9c}, !- Construction Name + InteriorDoor, !- Intended Surface Type + ; !- Standards Construction Type + +OS:Material, + {e2cb5f93-293f-4e04-a4cb-e1ba7f67cbf6}, !- Handle + G05 25mm wood, !- Name + MediumSmooth, !- Roughness + 0.0254, !- Thickness {m} + 0.15, !- Conductivity {W/m-K} + 608, !- Density {kg/m3} + 1630, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.5, !- Solar Absorptance + 0.5; !- Visible Absorptance + +OS:StandardsInformation:Material, + {ca14a8c1-9c82-403f-8c09-6b1c7768eb07}, !- Handle + {e2cb5f93-293f-4e04-a4cb-e1ba7f67cbf6}; !- Material Name + +OS:Material:NoMass, + {a4e6cff1-76a8-4326-a8bd-f452a82b3f32}, !- Handle + Typical Insulation, !- Name + Smooth, !- Roughness + 0.101874652714525, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {0fa24f09-7adc-47a8-9816-f80ccd620391}, !- Handle + {a4e6cff1-76a8-4326-a8bd-f452a82b3f32}; !- Material Name + +OS:Material, + {e3369030-7db5-426a-a75b-59b83568b7c1}, !- Handle + 4 in. Normalweight Concrete Floor, !- Name + MediumRough, !- Roughness + 0.1016, !- Thickness {m} + 2.31, !- Conductivity {W/m-K} + 2321.99999999999, !- Density {kg/m3} + 831.999999999997, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {9ef003e2-016a-4421-bfd3-c4cd0c65f4bf}, !- Handle + {e3369030-7db5-426a-a75b-59b83568b7c1}; !- Material Name + +OS:Material:NoMass, + {ba980602-8501-4aa1-bb10-3a903fa38237}, !- Handle + Typical Carpet Pad, !- Name + Smooth, !- Roughness + 0.216479986995276, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.8; !- Visible Absorptance + +OS:StandardsInformation:Material, + {2ef63f7b-66ca-45b3-9795-75c76abff512}, !- Handle + {ba980602-8501-4aa1-bb10-3a903fa38237}; !- Material Name + +OS:Material, + {057cf8b7-1a79-4159-98f9-dde00ac299ff}, !- Handle + 1IN Stucco, !- Name + Smooth, !- Roughness + 0.0253, !- Thickness {m} + 0.691799999999999, !- Conductivity {W/m-K} + 1858, !- Density {kg/m3} + 836.999999999999, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.92; !- Visible Absorptance + +OS:StandardsInformation:Material, + {b3cdd6c3-4a04-473d-98c1-deef29780c92}, !- Handle + {057cf8b7-1a79-4159-98f9-dde00ac299ff}; !- Material Name + +OS:Material, + {a2169114-d4e0-488b-aa38-29c168bd4d96}, !- Handle + 8IN CONCRETE HW RefBldg, !- Name + Rough, !- Roughness + 0.2032, !- Thickness {m} + 1.311, !- Conductivity {W/m-K} + 2240, !- Density {kg/m3} + 836.800000000001, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {ee309b66-0fb3-4099-a251-39016df42c2c}, !- Handle + {a2169114-d4e0-488b-aa38-29c168bd4d96}; !- Material Name + +OS:Material, + {09f50994-a176-4c1a-ba61-ac7b1e48472f}, !- Handle + 1/2IN Gypsum, !- Name + Smooth, !- Roughness + 0.0127, !- Thickness {m} + 0.16, !- Conductivity {W/m-K} + 784.9, !- Density {kg/m3} + 830.000000000001, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.4, !- Solar Absorptance + 0.4; !- Visible Absorptance + +OS:StandardsInformation:Material, + {b4824db3-04cd-4148-a7f7-e344e0f05346}, !- Handle + {09f50994-a176-4c1a-ba61-ac7b1e48472f}; !- Material Name + +OS:Material, + {caadfcd7-8543-44b4-a5a5-98c4886b1a48}, !- Handle + Metal Roof Surface, !- Name + Smooth, !- Roughness + 0.000799999999999998, !- Thickness {m} + 45.2799999999999, !- Conductivity {W/m-K} + 7823.99999999999, !- Density {kg/m3} + 499.999999999996, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {df41369e-3a6b-4b67-ac3f-b27f8818caa3}, !- Handle + {caadfcd7-8543-44b4-a5a5-98c4886b1a48}; !- Material Name + +OS:Material, + {752c76f8-cbac-435b-b8f2-acd19dba9b37}, !- Handle + 100mm Normalweight concrete floor 1, !- Name + MediumSmooth, !- Roughness + 0.1016, !- Thickness {m} + 2.31, !- Conductivity {W/m-K} + 2322, !- Density {kg/m3} + 832; !- Specific Heat {J/kg-K} + +OS:StandardsInformation:Material, + {4e93babc-b98b-4737-81ef-3fa6337431db}, !- Handle + {752c76f8-cbac-435b-b8f2-acd19dba9b37}; !- Material Name + +OS:Material, + {1f76ca51-0f94-4786-976d-0f871e3bd343}, !- Handle + G01 13mm gypsum board 1, !- Name + Smooth, !- Roughness + 0.0127, !- Thickness {m} + 0.16, !- Conductivity {W/m-K} + 800, !- Density {kg/m3} + 1090, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.5; !- Visible Absorptance + +OS:StandardsInformation:Material, + {70f35797-587f-4bbd-9bec-b94ddb4c6538}, !- Handle + {1f76ca51-0f94-4786-976d-0f871e3bd343}; !- Material Name + +OS:Material, + {bc34ba43-dd51-45e2-99e4-19ee8cae37df}, !- Handle + 6 in. Normalweight Concrete Floor, !- Name + MediumRough, !- Roughness + 0.1524, !- Thickness {m} + 2.31, !- Conductivity {W/m-K} + 2321.99999999999, !- Density {kg/m3} + 831.999999999997, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {bb4e7e12-2d8f-4142-acae-c7f4f30e757c}, !- Handle + {bc34ba43-dd51-45e2-99e4-19ee8cae37df}; !- Material Name + +OS:WindowMaterial:SimpleGlazingSystem, + {3fde24d3-804a-47f1-9bcf-c8bea7aa089d}, !- Handle + SimpleGlazing, !- Name + 2.2, !- U-Factor {W/m2-K} + 0.6, !- Solar Heat Gain Coefficient + 0.21; !- Visible Transmittance + +OS:StandardsInformation:Material, + {a34f32f9-c380-432c-88a8-c67fda7cbc04}, !- Handle + {3fde24d3-804a-47f1-9bcf-c8bea7aa089d}; !- Material Name + +OS:Material, + {5ca752be-78e7-4265-b592-2a9eb728227a}, !- Handle + F08 Metal surface, !- Name + Smooth, !- Roughness + 0.0008, !- Thickness {m} + 45.2800000000001, !- Conductivity {W/m-K} + 7823.99999999999, !- Density {kg/m3} + 500, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {93331bdc-83e2-4a71-8248-c8c1d10a18e8}, !- Handle + {5ca752be-78e7-4265-b592-2a9eb728227a}; !- Material Name + +OS:DefaultSurfaceConstructions, + {61a31190-6f9d-4a24-bb0a-b5849713f6c2}, !- Handle + BTAP-Mass at hdd = 5000.0, !- Name + {c48b5fac-d7b5-4b26-8c69-0a44f3361aea}, !- Floor Construction Name + {8e93ac72-2942-4b5f-af50-967aaa67908f}, !- Wall Construction Name + {f9433964-d53a-48f2-8e3c-815f11d0e9dd}; !- Roof Ceiling Construction Name + +OS:Construction, + {c48b5fac-d7b5-4b26-8c69-0a44f3361aea}, !- Handle + BTAP-Ext-Floor-Mass:U-0.162, !- Name + , !- Surface Rendering Name + {db27699b-64b7-4a61-9bbe-d8ab0e928c85}, !- Layer 1 + {941d078f-d393-4b9c-860f-3d2fb873d1ad}, !- Layer 2 + {9a5a11db-c7af-4088-91b9-50be316e6984}; !- Layer 3 + +OS:StandardsInformation:Construction, + {6cb2c46f-5c5c-4b61-bcda-aeccf2ab0bb7}, !- Handle + {c48b5fac-d7b5-4b26-8c69-0a44f3361aea}, !- Construction Name + ExteriorFloor, !- Intended Surface Type + Mass, !- Standards Construction Type + 0, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Material:NoMass, + {db27699b-64b7-4a61-9bbe-d8ab0e928c85}, !- Handle + Typical Insulation 1, !- Name + Smooth, !- Roughness + 5.91237683519488, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {d2d9dd1b-5316-4559-b4ee-a0c4239b4f4e}, !- Handle + {db27699b-64b7-4a61-9bbe-d8ab0e928c85}; !- Material Name + +OS:Material, + {941d078f-d393-4b9c-860f-3d2fb873d1ad}, !- Handle + 4 in. Normalweight Concrete Floor 1, !- Name + MediumRough, !- Roughness + 0.1016, !- Thickness {m} + 2.31, !- Conductivity {W/m-K} + 2321.99999999999, !- Density {kg/m3} + 831.999999999997, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {578ef72e-069a-452e-b12d-37ccb596fc65}, !- Handle + {941d078f-d393-4b9c-860f-3d2fb873d1ad}; !- Material Name + +OS:Material:NoMass, + {9a5a11db-c7af-4088-91b9-50be316e6984}, !- Handle + Typical Carpet Pad 1, !- Name + Smooth, !- Roughness + 0.216479986995276, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.8; !- Visible Absorptance + +OS:StandardsInformation:Material, + {d038b3a2-cf87-4dcf-8fc2-13d5822207b4}, !- Handle + {9a5a11db-c7af-4088-91b9-50be316e6984}; !- Material Name + +OS:Construction, + {8e93ac72-2942-4b5f-af50-967aaa67908f}, !- Handle + BTAP-Ext-Wall-Mass:U-0.21, !- Name + , !- Surface Rendering Name + {222c70aa-5b94-4434-ac8f-19be1988d0b8}, !- Layer 1 + {f9cf47a0-d91c-451f-acc9-7f21de1171ff}, !- Layer 2 + {3af3e5f8-ddee-469f-9697-16acefe4cdce}, !- Layer 3 + {a9421efa-e65c-40af-b7e4-228ca00a9649}; !- Layer 4 + +OS:StandardsInformation:Construction, + {c9fb3643-fde5-4ac7-96ab-396d7339489f}, !- Handle + {8e93ac72-2942-4b5f-af50-967aaa67908f}, !- Construction Name + ExteriorWall, !- Intended Surface Type + Mass, !- Standards Construction Type + 2, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Material, + {222c70aa-5b94-4434-ac8f-19be1988d0b8}, !- Handle + 1IN Stucco 1, !- Name + Smooth, !- Roughness + 0.0253, !- Thickness {m} + 0.691799999999999, !- Conductivity {W/m-K} + 1858, !- Density {kg/m3} + 836.999999999999, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.92; !- Visible Absorptance + +OS:StandardsInformation:Material, + {6e19995b-bf89-4b24-89aa-5c5dccb8de59}, !- Handle + {222c70aa-5b94-4434-ac8f-19be1988d0b8}; !- Material Name + +OS:Material, + {f9cf47a0-d91c-451f-acc9-7f21de1171ff}, !- Handle + 8IN CONCRETE HW RefBldg 1, !- Name + Rough, !- Roughness + 0.2032, !- Thickness {m} + 1.311, !- Conductivity {W/m-K} + 2240, !- Density {kg/m3} + 836.800000000001, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {b35cc3c5-59e8-474f-9284-edd79c5a3835}, !- Handle + {f9cf47a0-d91c-451f-acc9-7f21de1171ff}; !- Material Name + +OS:Material:NoMass, + {3af3e5f8-ddee-469f-9697-16acefe4cdce}, !- Handle + Typical Insulation 2, !- Name + Smooth, !- Roughness + 4.49096231241638, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {77764f1a-3a06-458a-bef0-41b40e65c744}, !- Handle + {3af3e5f8-ddee-469f-9697-16acefe4cdce}; !- Material Name + +OS:Material, + {a9421efa-e65c-40af-b7e4-228ca00a9649}, !- Handle + 1/2IN Gypsum 1, !- Name + Smooth, !- Roughness + 0.0127, !- Thickness {m} + 0.16, !- Conductivity {W/m-K} + 784.9, !- Density {kg/m3} + 830.000000000001, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.4, !- Solar Absorptance + 0.4; !- Visible Absorptance + +OS:StandardsInformation:Material, + {d746c5e3-13e5-494d-8bdf-e104f001d8de}, !- Handle + {a9421efa-e65c-40af-b7e4-228ca00a9649}; !- Material Name + +OS:Construction, + {f9433964-d53a-48f2-8e3c-815f11d0e9dd}, !- Handle + BTAP-Ext-Roof-Metal:U-0.162, !- Name + , !- Surface Rendering Name + {a361c31d-7edb-4ba5-9d73-959e126d408b}, !- Layer 1 + {f623ee6f-205b-4bb7-bf6c-659501728729}; !- Layer 2 + +OS:StandardsInformation:Construction, + {c605212c-a711-4f27-afc5-0bae776869ed}, !- Handle + {f9433964-d53a-48f2-8e3c-815f11d0e9dd}, !- Construction Name + ExteriorRoof, !- Intended Surface Type + Metal, !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Material, + {a361c31d-7edb-4ba5-9d73-959e126d408b}, !- Handle + Metal Roof Surface 1, !- Name + Smooth, !- Roughness + 0.000799999999999998, !- Thickness {m} + 45.2799999999999, !- Conductivity {W/m-K} + 7823.99999999999, !- Density {kg/m3} + 499.999999999996, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {cd60643b-1988-4e2b-8203-542b7876a1c3}, !- Handle + {a361c31d-7edb-4ba5-9d73-959e126d408b}; !- Material Name + +OS:Material:NoMass, + {f623ee6f-205b-4bb7-bf6c-659501728729}, !- Handle + Typical Insulation 3, !- Name + Smooth, !- Roughness + 6.17282183832832, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {ee4a3ae3-f5b5-4a8d-8a76-345c375ffff5}, !- Handle + {f623ee6f-205b-4bb7-bf6c-659501728729}; !- Material Name + +OS:DefaultSurfaceConstructions, + {df0969c5-d54c-4b85-ae85-2702c59efde2}, !- Handle + BTAP-Mass at hdd = 5000.0 1, !- Name + {2ae9cb11-654c-4d2e-8f47-ef4844e4d583}, !- Floor Construction Name + {32bbd528-3189-4db7-840f-94ad38d000d3}, !- Wall Construction Name + {8b276cec-9bae-4018-b8a2-4a447d3ff90f}; !- Roof Ceiling Construction Name + +OS:Construction, + {2ae9cb11-654c-4d2e-8f47-ef4844e4d583}, !- Handle + BTAP-Grnd-Floor-Mass:U-0.757, !- Name + , !- Surface Rendering Name + {b17e33cb-feb1-423e-afe6-85c471c45438}, !- Layer 1 + {65d0d3fa-653e-4cae-af0f-688e5984628e}; !- Layer 2 + +OS:StandardsInformation:Construction, + {809cb716-07d6-4520-b577-08bacbbb4b1c}, !- Handle + {2ae9cb11-654c-4d2e-8f47-ef4844e4d583}, !- Construction Name + GroundContactFloor, !- Intended Surface Type + Mass, !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Material, + {b17e33cb-feb1-423e-afe6-85c471c45438}, !- Handle + 6 in. Normalweight Concrete Floor 1, !- Name + MediumRough, !- Roughness + 0.1524, !- Thickness {m} + 2.31, !- Conductivity {W/m-K} + 2321.99999999999, !- Density {kg/m3} + 831.999999999997, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {b6461ec9-f66f-4c3a-b8d2-82e9b238f641}, !- Handle + {b17e33cb-feb1-423e-afe6-85c471c45438}; !- Material Name + +OS:Material:NoMass, + {65d0d3fa-653e-4cae-af0f-688e5984628e}, !- Handle + Typical Carpet Pad 2, !- Name + Smooth, !- Roughness + 1.25502993703786, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.8; !- Visible Absorptance + +OS:StandardsInformation:Material, + {6bf3833e-61be-47d1-9fc0-2743a06364ac}, !- Handle + {65d0d3fa-653e-4cae-af0f-688e5984628e}; !- Material Name + +OS:Construction, + {32bbd528-3189-4db7-840f-94ad38d000d3}, !- Handle + BTAP-Grnd-Wall-Mass:U-0.284, !- Name + , !- Surface Rendering Name + {be74a77b-d668-4bdc-8fc8-8835faaf2bef}, !- Layer 1 + {4fbbd59c-deaa-4f45-ab3b-6bdbd06c2d7b}; !- Layer 2 + +OS:StandardsInformation:Construction, + {3eec8c1b-ad91-4f41-8760-9224c95c1607}, !- Handle + {32bbd528-3189-4db7-840f-94ad38d000d3}, !- Construction Name + GroundContactWall, !- Intended Surface Type + Mass, !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Material, + {be74a77b-d668-4bdc-8fc8-8835faaf2bef}, !- Handle + 6 in. Normalweight Concrete Floor 2, !- Name + MediumRough, !- Roughness + 0.1524, !- Thickness {m} + 2.31, !- Conductivity {W/m-K} + 2321.99999999999, !- Density {kg/m3} + 831.999999999997, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {d063081c-794a-44f6-9bd6-35f87493ef32}, !- Handle + {be74a77b-d668-4bdc-8fc8-8835faaf2bef}; !- Material Name + +OS:Material:NoMass, + {4fbbd59c-deaa-4f45-ab3b-6bdbd06c2d7b}, !- Handle + Typical Carpet Pad 3, !- Name + Smooth, !- Roughness + 3.45515273458935, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.8; !- Visible Absorptance + +OS:StandardsInformation:Material, + {7248fb92-42ef-402a-948d-aec39d88257c}, !- Handle + {4fbbd59c-deaa-4f45-ab3b-6bdbd06c2d7b}; !- Material Name + +OS:Construction, + {8b276cec-9bae-4018-b8a2-4a447d3ff90f}, !- Handle + BTAP-Grnd-Roof-Mass:U-0.284, !- Name + , !- Surface Rendering Name + {cb1255bd-ee04-4f2b-ba18-2777f87b896c}, !- Layer 1 + {1cb8b0a4-99e2-4c13-9ed3-4d41e371c67f}; !- Layer 2 + +OS:StandardsInformation:Construction, + {08d650a6-fbc7-4782-b2ad-4d88eb372166}, !- Handle + {8b276cec-9bae-4018-b8a2-4a447d3ff90f}, !- Construction Name + GroundContactRoof, !- Intended Surface Type + Mass, !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Material, + {cb1255bd-ee04-4f2b-ba18-2777f87b896c}, !- Handle + 6 in. Normalweight Concrete Floor 3, !- Name + MediumRough, !- Roughness + 0.1524, !- Thickness {m} + 2.31, !- Conductivity {W/m-K} + 2321.99999999999, !- Density {kg/m3} + 831.999999999997, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {8c63c3a2-4391-4d0a-b5b8-2dd7e58c220c}, !- Handle + {cb1255bd-ee04-4f2b-ba18-2777f87b896c}; !- Material Name + +OS:Material:NoMass, + {1cb8b0a4-99e2-4c13-9ed3-4d41e371c67f}, !- Handle + Typical Carpet Pad 4, !- Name + Smooth, !- Roughness + 3.45515273458935, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.8; !- Visible Absorptance + +OS:StandardsInformation:Material, + {336ac2a3-b3f6-4765-a7e0-4e9a6d86466c}, !- Handle + {1cb8b0a4-99e2-4c13-9ed3-4d41e371c67f}; !- Material Name + +OS:DefaultSubSurfaceConstructions, + {2282980d-f2b0-48f9-88a3-d48761c1b4f6}, !- Handle + BTAP-Mass at hdd = 5000.0, !- Name + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Fixed Window Construction Name + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Operable Window Construction Name + {bd7e529b-9dc1-4a32-b327-b7f4308c81ab}, !- Door Construction Name + {3050a508-ba9b-4ab4-bf02-88c2ecab1c28}, !- Glass Door Construction Name + {780bca99-2c92-49f6-b888-971fc087650a}, !- Overhead Door Construction Name + {c1fce275-3073-4194-85ae-8b52560d84a4}, !- Skylight Construction Name + {0cfb5bf0-a3a0-4524-a3cb-0f834b2200b8}, !- Tubular Daylight Dome Construction Name + {08f7c165-2727-466d-ab2a-16fe227774a5}; !- Tubular Daylight Diffuser Construction Name + +OS:WindowMaterial:SimpleGlazingSystem, + {0b2e73a1-ce49-460e-b705-4f05c21c8b19}, !- Handle + SimpleGlazing:U=0.220 SHGC=0.600, !- Name + 2.2, !- U-Factor {W/m2-K} + 0.6, !- Solar Heat Gain Coefficient + 0.21; !- Visible Transmittance + +OS:Construction, + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Handle + BTAP-Ext-FixedWindow:U=0.220 SHGC=0.600, !- Name + , !- Surface Rendering Name + {0b2e73a1-ce49-460e-b705-4f05c21c8b19}; !- Layer 1 + +OS:Construction, + {bd7e529b-9dc1-4a32-b327-b7f4308c81ab}, !- Handle + BTAP-Ext-Door:U-2.2, !- Name + , !- Surface Rendering Name + {a0bc4922-f71f-4eb7-8b42-d0e834c48478}, !- Layer 1 + {f8428113-9012-4ae3-b9e9-c3d111469768}; !- Layer 2 + +OS:StandardsInformation:Construction, + {52d690ec-74a5-405d-a396-2b9f0570c8ec}, !- Handle + {bd7e529b-9dc1-4a32-b327-b7f4308c81ab}, !- Construction Name + ExteriorDoor, !- Intended Surface Type + , !- Standards Construction Type + 1, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Material, + {a0bc4922-f71f-4eb7-8b42-d0e834c48478}, !- Handle + F08 Metal surface 1, !- Name + Smooth, !- Roughness + 0.0008, !- Thickness {m} + 45.2800000000001, !- Conductivity {W/m-K} + 7823.99999999999, !- Density {kg/m3} + 500, !- Specific Heat {J/kg-K} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {fa89da63-5908-431c-be76-bdf6b4967dd1}, !- Handle + {a0bc4922-f71f-4eb7-8b42-d0e834c48478}; !- Material Name + +OS:Material:NoMass, + {f8428113-9012-4ae3-b9e9-c3d111469768}, !- Handle + Typical Insulation 4, !- Name + Smooth, !- Roughness + 0.454527786700932, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {fe9a7364-ee55-434f-b1cc-dc5686a7bc20}, !- Handle + {f8428113-9012-4ae3-b9e9-c3d111469768}; !- Material Name + +OS:Construction, + {3050a508-ba9b-4ab4-bf02-88c2ecab1c28}, !- Handle + BTAP-Ext-GlassDoors:U=0.220 SHGC=0.600, !- Name + , !- Surface Rendering Name + {0b2e73a1-ce49-460e-b705-4f05c21c8b19}; !- Layer 1 + +OS:Construction, + {780bca99-2c92-49f6-b888-971fc087650a}, !- Handle + BTAP-Ext-OverHeadDoor:U-2.2, !- Name + , !- Surface Rendering Name + {785b727d-26f9-4dd7-a317-3084c316caf0}; !- Layer 1 + +OS:StandardsInformation:Construction, + {7fe747e9-80ac-44d9-bc3e-2506aaff531d}, !- Handle + {780bca99-2c92-49f6-b888-971fc087650a}, !- Construction Name + ExteriorDoor, !- Intended Surface Type + RollUp, !- Standards Construction Type + 0, !- Perturbable Layer + Insulation, !- Perturbable Layer Type + ; !- Other Perturbable Layer Type + +OS:Material:NoMass, + {785b727d-26f9-4dd7-a317-3084c316caf0}, !- Handle + Typical Insulation 5, !- Name + Smooth, !- Roughness + 0.454545454545455, !- Thermal Resistance {m2-K/W} + 0.9, !- Thermal Absorptance + 0.7, !- Solar Absorptance + 0.7; !- Visible Absorptance + +OS:StandardsInformation:Material, + {58bcd376-3b1a-408d-9d3c-61d5c40ef881}, !- Handle + {785b727d-26f9-4dd7-a317-3084c316caf0}; !- Material Name + +OS:Construction, + {c1fce275-3073-4194-85ae-8b52560d84a4}, !- Handle + BTAP-Ext-Skylights:U=0.220 SHGC=0.600, !- Name + , !- Surface Rendering Name + {0b2e73a1-ce49-460e-b705-4f05c21c8b19}; !- Layer 1 + +OS:Construction, + {0cfb5bf0-a3a0-4524-a3cb-0f834b2200b8}, !- Handle + BTAP-Ext-DaylightDomes:U=0.220 SHGC=0.600, !- Name + , !- Surface Rendering Name + {0b2e73a1-ce49-460e-b705-4f05c21c8b19}; !- Layer 1 + +OS:Construction, + {08f7c165-2727-466d-ab2a-16fe227774a5}, !- Handle + BTAP-Ext-DaylightDiffuser:U=0.220 SHGC=0.600, !- Name + , !- Surface Rendering Name + {0b2e73a1-ce49-460e-b705-4f05c21c8b19}; !- Layer 1 + +OS:ThermostatSetpoint:DualSetpoint, + {c7eb651a-ff34-44fe-9932-700abcfb0325}, !- Handle + Space Function Office - enclosed Thermostat 1, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:ThermostatSetpoint:DualSetpoint, + {fab3c7da-7908-4b56-b925-16e63f4dc808}, !- Handle + Space Function Warehouse - fine Thermostat 1, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:ThermostatSetpoint:DualSetpoint, + {f9d4b68e-2d7a-4fbe-a4f3-945dd661cb92}, !- Handle + Space Function Warehouse - med/blk Thermostat 1, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:SubSurface, + {44191d9c-3ccf-40b8-bdef-eaed24f7c4e5}, !- Handle + Bulk Storage Left Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {2eb36d53-8956-4573-9d42-f3de2486a693}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 0, 100.553694839222, 3.605877488203, !- X,Y,Z Vertex 1 {m} + 0, 100.553694839222, 0.762, !- X,Y,Z Vertex 2 {m} + 0, 30.5039135876431, 0.762, !- X,Y,Z Vertex 3 {m} + 0, 30.5039135876431, 3.605877488203; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {97ab9edc-a79a-4797-92e0-5a94cd80e204}, !- Handle + Bulk Storage Rear Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {b8b06532-b20c-4b27-b353-fb685ea15ba8}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 45.6923703814647, 100.579094839222, 3.60697784757277, !- X,Y,Z Vertex 1 {m} + 45.6923703814647, 100.579094839222, 0.762, !- X,Y,Z Vertex 2 {m} + 0.0254000000000048, 100.579094839222, 0.762, !- X,Y,Z Vertex 3 {m} + 0.0254000000000048, 100.579094839222, 3.60697784757277; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {466eb643-cd78-4bcb-8482-c2603c6a5308}, !- Handle + Bulk Storage Right Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {93a00761-ab33-4e9d-bff7-fed32e66feb1}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 45.7177703814647, 30.5039135876431, 3.605877488203, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 30.5039135876431, 0.762, !- X,Y,Z Vertex 2 {m} + 45.7177703814647, 100.553694839222, 0.762, !- X,Y,Z Vertex 3 {m} + 45.7177703814647, 100.553694839222, 3.605877488203; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {c03eecbf-e3f2-461b-ac54-f703a278ef5d}, !- Handle + Fine Storage Front Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {a50eff28-8688-422b-9443-0a4fe183df9f}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 25.9321365494966, 0, 3.61112240525708, !- X,Y,Z Vertex 1 {m} + 25.9321365494966, 0, 0.762, !- X,Y,Z Vertex 2 {m} + 45.6923703814647, 0, 0.762, !- X,Y,Z Vertex 3 {m} + 45.6923703814647, 0, 3.61112240525708; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {22604dcd-195d-4b42-8fa4-2d8ae26102d5}, !- Handle + Fine Storage Left Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {e7c4e556-9445-43b4-bfcc-f9fc21f24f21}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 0, 30.4531135876431, 3.61059931700919, !- X,Y,Z Vertex 1 {m} + 0, 30.4531135876431, 0.762, !- X,Y,Z Vertex 2 {m} + 0, 9.16895407629293, 0.762, !- X,Y,Z Vertex 3 {m} + 0, 9.16895407629293, 3.61059931700919; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {eb595d64-a34a-4cac-95f7-eeaed0c6bf37}, !- Handle + Fine Storage Office Front Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {5b1ce779-a299-4910-83a2-6fb6d1cee24f}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 0.0254, 0, 6.4526919105121, !- X,Y,Z Vertex 1 {m} + 0.0254, 0, 5.02899190227003, !- X,Y,Z Vertex 2 {m} + 25.8813365494966, 0, 5.02899190227003, !- X,Y,Z Vertex 3 {m} + 25.8813365494966, 0, 6.4526919105121; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {d631ad4d-b164-438a-a9ce-904ad7c8ffc3}, !- Handle + Fine Storage Office Left Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {145bfd04-ce48-4581-a2a9-e8970362044f}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 0, 9.11815407629293, 6.45783863023517, !- X,Y,Z Vertex 1 {m} + 0, 9.11815407629293, 5.02899190227003, !- X,Y,Z Vertex 2 {m} + 0, 0.0254000000000012, 5.02899190227003, !- X,Y,Z Vertex 3 {m} + 0, 0.0254000000000012, 6.45783863023517; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {98eb6bdf-fc78-475e-a534-74a789d32b9d}, !- Handle + Fine Storage Right Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {a0ba0fa9-aa51-4fbe-bdcc-bf0a22e397dd}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 45.7177703814647, 0.0254, 3.60856110679729, !- X,Y,Z Vertex 1 {m} + 45.7177703814647, 0.0254, 0.762, !- X,Y,Z Vertex 2 {m} + 45.7177703814647, 30.4531135876431, 0.762, !- X,Y,Z Vertex 3 {m} + 45.7177703814647, 30.4531135876431, 3.60856110679729; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {6ba40d4c-5378-48be-9576-c2392d308bc5}, !- Handle + Office Front Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {a722f50f-fda4-4b2c-843f-44ea72a832c9}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 0.0254, 0, 2.18570000824207, !- X,Y,Z Vertex 1 {m} + 0.0254, 0, 0.762, !- X,Y,Z Vertex 2 {m} + 25.8813365494966, 0, 0.762, !- X,Y,Z Vertex 3 {m} + 25.8813365494966, 0, 2.18570000824207; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {18c1613d-3050-43d6-87ab-08ae61e56757}, !- Handle + Office Left Wall_FixedWindow, !- Name + FixedWindow, !- Sub Surface Type + {1a8cd7c3-aa78-4353-8a3f-7f7eb8ca2468}, !- Construction Name + {af7ffab5-cb7d-4793-a68a-918ca67f7479}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + , !- Multiplier + , !- Number of Vertices + 0, 9.11815407629293, 2.19084672796514, !- X,Y,Z Vertex 1 {m} + 0, 9.11815407629293, 0.762, !- X,Y,Z Vertex 2 {m} + 0, 0.0254000000000012, 0.762, !- X,Y,Z Vertex 3 {m} + 0, 0.0254000000000012, 2.19084672796514; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {f1010649-a399-4a2f-85c0-11c2b3e74fa1}, !- Handle + Bulk Storage Roof_Skylight, !- Name + Skylight, !- Sub Surface Type + {c1fce275-3073-4194-85ae-8b52560d84a4}, !- Construction Name + {516ff702-eb03-4a25-9228-e1ad9dc5895c}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + 1, !- Multiplier + , !- Number of Vertices + 27.9702873083666, 57.6913209663936, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 27.9702873083666, 73.3662874604714, 8.53398380454007, !- X,Y,Z Vertex 2 {m} + 17.7474830730984, 73.3662874604714, 8.53398380454007, !- X,Y,Z Vertex 3 {m} + 17.7474830730984, 57.6913209663936, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:SubSurface, + {4fb80c5d-116a-4f29-91d7-d3c25ebc6985}, !- Handle + Fine Storage Roof_Skylight, !- Name + Skylight, !- Sub Surface Type + {c1fce275-3073-4194-85ae-8b52560d84a4}, !- Construction Name + {dcc10c35-212a-4ba7-8909-e38fa0c8d3e8}, !- Surface Name + , !- Outside Boundary Condition Object + , !- View Factor to Ground + , !- Frame and Divider Name + 1, !- Multiplier + , !- Number of Vertices + 27.9702873083666, 11.8316553820655, 8.53398380454007, !- X,Y,Z Vertex 1 {m} + 27.9702873083666, 18.6468582055775, 8.53398380454007, !- X,Y,Z Vertex 2 {m} + 17.7474830730984, 18.6468582055775, 8.53398380454007, !- X,Y,Z Vertex 3 {m} + 17.7474830730984, 11.8316553820655, 8.53398380454007; !- X,Y,Z Vertex 4 {m} + +OS:ThermostatSetpoint:DualSetpoint, + {0326d90b-48a9-4a8e-8244-66223ebb8486}, !- Handle + Space Function Office - enclosed Thermostat 2, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:ThermostatSetpoint:DualSetpoint, + {4b38530c-68e9-4d87-8be0-c9a6e49d1505}, !- Handle + Space Function Warehouse - fine Thermostat 2, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:ThermostatSetpoint:DualSetpoint, + {4b29b621-8fd2-4b9a-aae5-03855e342c06}, !- Handle + Space Function Warehouse - med/blk Thermostat 2, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:SimulationControl, + {4d69e532-393a-479e-a0ed-b280408d13d7}, !- Handle + , !- Do Zone Sizing Calculation + , !- Do System Sizing Calculation + , !- Do Plant Sizing Calculation + No, !- Run Simulation for Sizing Periods + Yes, !- Run Simulation for Weather File Run Periods + , !- Loads Convergence Tolerance Value {W} + , !- Temperature Convergence Tolerance Value {deltaC} + , !- Solar Distribution + , !- Maximum Number of Warmup Days + , !- Minimum Number of Warmup Days + No, !- Do HVAC Sizing Simulation for Sizing Periods + 1; !- Maximum Number of HVAC Sizing Simulation Passes + +OS:ThermalZone, + {6c1adbbd-b731-4330-93ba-8c172088a4d0}, !- Handle + ALL_ST=Office - enclosed_FL=Building Story 1_SCH=A, !- Name + , !- Multiplier + , !- Ceiling Height {m} + , !- Volume {m3} + , !- Floor Area {m2} + , !- Zone Inside Convection Algorithm + , !- Zone Outside Convection Algorithm + , !- Zone Conditioning Equipment List Name + {043b010d-5588-418b-8582-2b69ceae0f7b}, !- Zone Air Inlet Port List + {3e65b38a-1fcf-483f-b596-ce694bc66acf}, !- Zone Air Exhaust Port List + {2fd6e88e-ecbd-42a3-ae1a-1e08fd1148e9}, !- Zone Air Node Name + {7e9828c6-334e-4d61-9742-a9e98cd3207a}, !- Zone Return Air Port List + , !- Primary Daylighting Control Name + , !- Fraction of Zone Controlled by Primary Daylighting Control + , !- Secondary Daylighting Control Name + , !- Fraction of Zone Controlled by Secondary Daylighting Control + , !- Illuminance Map Name + {4004fcc0-5fbd-4309-a4d6-9c8a6955bedc}, !- Group Rendering Name + {272bf7c0-b97e-4726-95e2-1bea43db697c}, !- Thermostat Name + No; !- Use Ideal Air Loads + +OS:Node, + {1b60d939-40ab-409e-84e9-1e86e0b75628}, !- Handle + Node 1, !- Name + {2fd6e88e-ecbd-42a3-ae1a-1e08fd1148e9}, !- Inlet Port + ; !- Outlet Port + +OS:Connection, + {2fd6e88e-ecbd-42a3-ae1a-1e08fd1148e9}, !- Handle + {6c1adbbd-b731-4330-93ba-8c172088a4d0}, !- Source Object + 11, !- Outlet Port + {1b60d939-40ab-409e-84e9-1e86e0b75628}, !- Target Object + 2; !- Inlet Port + +OS:PortList, + {043b010d-5588-418b-8582-2b69ceae0f7b}, !- Handle + {6c1adbbd-b731-4330-93ba-8c172088a4d0}, !- HVAC Component + {ee006a1b-6a42-4a22-84bd-78b092707b54}; !- Port 1 + +OS:PortList, + {3e65b38a-1fcf-483f-b596-ce694bc66acf}, !- Handle + {6c1adbbd-b731-4330-93ba-8c172088a4d0}; !- HVAC Component + +OS:PortList, + {7e9828c6-334e-4d61-9742-a9e98cd3207a}, !- Handle + {6c1adbbd-b731-4330-93ba-8c172088a4d0}, !- HVAC Component + {e94f669d-b9ec-45c8-9ad9-92e72972dd81}; !- Port 1 + +OS:Sizing:Zone, + {616070bf-a3cd-4038-8451-123f43b075f7}, !- Handle + {6c1adbbd-b731-4330-93ba-8c172088a4d0}, !- Zone or ZoneList Name + TemperatureDifference, !- Zone Cooling Design Supply Air Temperature Input Method + 14, !- Zone Cooling Design Supply Air Temperature {C} + 11, !- Zone Cooling Design Supply Air Temperature Difference {deltaC} + TemperatureDifference, !- Zone Heating Design Supply Air Temperature Input Method + 40, !- Zone Heating Design Supply Air Temperature {C} + 21, !- Zone Heating Design Supply Air Temperature Difference {deltaC} + 0.0085, !- Zone Cooling Design Supply Air Humidity Ratio {kg-H2O/kg-air} + 0.008, !- Zone Heating Design Supply Air Humidity Ratio {kg-H2O/kg-air} + 1.3, !- Zone Heating Sizing Factor + 1.1, !- Zone Cooling Sizing Factor + DesignDay, !- Cooling Design Air Flow Method + , !- Cooling Design Air Flow Rate {m3/s} + , !- Cooling Minimum Air Flow per Zone Floor Area {m3/s-m2} + , !- Cooling Minimum Air Flow {m3/s} + , !- Cooling Minimum Air Flow Fraction + DesignDay, !- Heating Design Air Flow Method + , !- Heating Design Air Flow Rate {m3/s} + , !- Heating Maximum Air Flow per Zone Floor Area {m3/s-m2} + , !- Heating Maximum Air Flow {m3/s} + , !- Heating Maximum Air Flow Fraction + No, !- Account for Dedicated Outdoor Air System + NeutralSupplyAir, !- Dedicated Outdoor Air System Control Strategy + autosize, !- Dedicated Outdoor Air Low Setpoint Temperature for Design {C} + autosize; !- Dedicated Outdoor Air High Setpoint Temperature for Design {C} + +OS:ZoneHVAC:EquipmentList, + {4104870e-5494-4fde-a795-82d345ee2773}, !- Handle + Zone HVAC Equipment List 1, !- Name + {6c1adbbd-b731-4330-93ba-8c172088a4d0}, !- Thermal Zone + , !- Load Distribution Scheme + {7fa3ac7c-10ba-4d80-86ec-88df3a8a3394}, !- Zone Equipment 1 + 1, !- Zone Equipment Cooling Sequence 1 + 1, !- Zone Equipment Heating or No-Load Sequence 1 + , !- Zone Equipment Sequential Cooling Fraction Schedule Name 1 + , !- Zone Equipment Sequential Heating Fraction Schedule Name 1 + {8a2b8f1f-5928-43f8-81cf-965d7a1f20a5}, !- Zone Equipment 2 + 2, !- Zone Equipment Cooling Sequence 2 + 2, !- Zone Equipment Heating or No-Load Sequence 2 + , !- Zone Equipment Sequential Cooling Fraction Schedule Name 2 + ; !- Zone Equipment Sequential Heating Fraction Schedule Name 2 + +OS:ThermostatSetpoint:DualSetpoint, + {272bf7c0-b97e-4726-95e2-1bea43db697c}, !- Handle + Space Function Office - enclosed Thermostat 3, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:ThermalZone, + {60569c67-8392-4395-8052-94b9e792b96b}, !- Handle + ALL_ST=Warehouse - med/blk_FL=Building Story 1_SCH=A, !- Name + , !- Multiplier + , !- Ceiling Height {m} + , !- Volume {m3} + , !- Floor Area {m2} + , !- Zone Inside Convection Algorithm + , !- Zone Outside Convection Algorithm + , !- Zone Conditioning Equipment List Name + {38456173-bdea-4d6b-afc0-49715dc4e592}, !- Zone Air Inlet Port List + {146be730-f542-4d8e-bdb8-ef9b961a1794}, !- Zone Air Exhaust Port List + {7eb9e458-ce4c-4b2f-af12-40d57607b0b8}, !- Zone Air Node Name + {a07a6d4e-ec14-40d3-bae3-6d8a8ab33439}, !- Zone Return Air Port List + , !- Primary Daylighting Control Name + , !- Fraction of Zone Controlled by Primary Daylighting Control + , !- Secondary Daylighting Control Name + , !- Fraction of Zone Controlled by Secondary Daylighting Control + , !- Illuminance Map Name + {542774fd-eb95-42ad-a955-5bca8c42520b}, !- Group Rendering Name + {525daa43-0b14-4ab1-b46d-bbd05b8a03c8}, !- Thermostat Name + No; !- Use Ideal Air Loads + +OS:Node, + {9df9cc79-576d-43b6-9ece-46ea47f150d4}, !- Handle + Node 4, !- Name + {7eb9e458-ce4c-4b2f-af12-40d57607b0b8}, !- Inlet Port + ; !- Outlet Port + +OS:Connection, + {7eb9e458-ce4c-4b2f-af12-40d57607b0b8}, !- Handle + {60569c67-8392-4395-8052-94b9e792b96b}, !- Source Object + 11, !- Outlet Port + {9df9cc79-576d-43b6-9ece-46ea47f150d4}, !- Target Object + 2; !- Inlet Port + +OS:PortList, + {38456173-bdea-4d6b-afc0-49715dc4e592}, !- Handle + {60569c67-8392-4395-8052-94b9e792b96b}, !- HVAC Component + {ccbecfe1-9225-42fd-804b-5e4cfd257cfe}; !- Port 1 + +OS:PortList, + {146be730-f542-4d8e-bdb8-ef9b961a1794}, !- Handle + {60569c67-8392-4395-8052-94b9e792b96b}; !- HVAC Component + +OS:PortList, + {a07a6d4e-ec14-40d3-bae3-6d8a8ab33439}, !- Handle + {60569c67-8392-4395-8052-94b9e792b96b}, !- HVAC Component + {0d3b2994-170d-435e-876f-867975d5c4dc}; !- Port 1 + +OS:Sizing:Zone, + {89a31322-d068-44dc-ae4e-a44585f51b67}, !- Handle + {60569c67-8392-4395-8052-94b9e792b96b}, !- Zone or ZoneList Name + TemperatureDifference, !- Zone Cooling Design Supply Air Temperature Input Method + 14, !- Zone Cooling Design Supply Air Temperature {C} + 11, !- Zone Cooling Design Supply Air Temperature Difference {deltaC} + TemperatureDifference, !- Zone Heating Design Supply Air Temperature Input Method + 40, !- Zone Heating Design Supply Air Temperature {C} + 21, !- Zone Heating Design Supply Air Temperature Difference {deltaC} + 0.0085, !- Zone Cooling Design Supply Air Humidity Ratio {kg-H2O/kg-air} + 0.008, !- Zone Heating Design Supply Air Humidity Ratio {kg-H2O/kg-air} + 1.3, !- Zone Heating Sizing Factor + 1.1, !- Zone Cooling Sizing Factor + DesignDay, !- Cooling Design Air Flow Method + , !- Cooling Design Air Flow Rate {m3/s} + , !- Cooling Minimum Air Flow per Zone Floor Area {m3/s-m2} + , !- Cooling Minimum Air Flow {m3/s} + , !- Cooling Minimum Air Flow Fraction + DesignDay, !- Heating Design Air Flow Method + , !- Heating Design Air Flow Rate {m3/s} + , !- Heating Maximum Air Flow per Zone Floor Area {m3/s-m2} + , !- Heating Maximum Air Flow {m3/s} + , !- Heating Maximum Air Flow Fraction + No, !- Account for Dedicated Outdoor Air System + NeutralSupplyAir, !- Dedicated Outdoor Air System Control Strategy + autosize, !- Dedicated Outdoor Air Low Setpoint Temperature for Design {C} + autosize; !- Dedicated Outdoor Air High Setpoint Temperature for Design {C} + +OS:ZoneHVAC:EquipmentList, + {e136fa26-7816-4939-9186-db404f4093ca}, !- Handle + Zone HVAC Equipment List 2, !- Name + {60569c67-8392-4395-8052-94b9e792b96b}, !- Thermal Zone + , !- Load Distribution Scheme + {54d5c499-b97e-499d-ade6-7d0c6fbed4c6}, !- Zone Equipment 1 + 1, !- Zone Equipment Cooling Sequence 1 + 1, !- Zone Equipment Heating or No-Load Sequence 1 + , !- Zone Equipment Sequential Cooling Fraction Schedule Name 1 + , !- Zone Equipment Sequential Heating Fraction Schedule Name 1 + {e9513dd5-f7ca-42d5-b624-59ba27ca145f}, !- Zone Equipment 2 + 2, !- Zone Equipment Cooling Sequence 2 + 2, !- Zone Equipment Heating or No-Load Sequence 2 + , !- Zone Equipment Sequential Cooling Fraction Schedule Name 2 + ; !- Zone Equipment Sequential Heating Fraction Schedule Name 2 + +OS:ThermostatSetpoint:DualSetpoint, + {525daa43-0b14-4ab1-b46d-bbd05b8a03c8}, !- Handle + Space Function Warehouse - med/blk Thermostat 3, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:ThermalZone, + {d0cebe41-1ec4-4dd7-8f92-397f53b49203}, !- Handle + ALL_ST=Warehouse - fine_FL=Building Story 1_SCH=A, !- Name + , !- Multiplier + , !- Ceiling Height {m} + , !- Volume {m3} + , !- Floor Area {m2} + , !- Zone Inside Convection Algorithm + , !- Zone Outside Convection Algorithm + , !- Zone Conditioning Equipment List Name + {788c0b89-3f45-45b9-9296-81b4b51a52c4}, !- Zone Air Inlet Port List + {6a868a31-f374-4356-a23f-0ceadd799606}, !- Zone Air Exhaust Port List + {cfd698e0-17ff-4b13-942c-7f2d99257b26}, !- Zone Air Node Name + {90da99ca-3c8f-4e0e-a140-b94921826b94}, !- Zone Return Air Port List + , !- Primary Daylighting Control Name + , !- Fraction of Zone Controlled by Primary Daylighting Control + , !- Secondary Daylighting Control Name + , !- Fraction of Zone Controlled by Secondary Daylighting Control + , !- Illuminance Map Name + {806f38ad-3efd-4c9f-a57b-dc268c7803c7}, !- Group Rendering Name + {c95b44d6-d987-48cf-9509-7f7539583aa1}, !- Thermostat Name + No; !- Use Ideal Air Loads + +OS:Node, + {bd379b3d-518d-4b2e-ab04-3f9bbefd65cc}, !- Handle + Node 7, !- Name + {cfd698e0-17ff-4b13-942c-7f2d99257b26}, !- Inlet Port + ; !- Outlet Port + +OS:Connection, + {cfd698e0-17ff-4b13-942c-7f2d99257b26}, !- Handle + {d0cebe41-1ec4-4dd7-8f92-397f53b49203}, !- Source Object + 11, !- Outlet Port + {bd379b3d-518d-4b2e-ab04-3f9bbefd65cc}, !- Target Object + 2; !- Inlet Port + +OS:PortList, + {788c0b89-3f45-45b9-9296-81b4b51a52c4}, !- Handle + {d0cebe41-1ec4-4dd7-8f92-397f53b49203}, !- HVAC Component + {4771220b-498b-43c2-9092-4c9764e778cc}; !- Port 1 + +OS:PortList, + {6a868a31-f374-4356-a23f-0ceadd799606}, !- Handle + {d0cebe41-1ec4-4dd7-8f92-397f53b49203}; !- HVAC Component + +OS:PortList, + {90da99ca-3c8f-4e0e-a140-b94921826b94}, !- Handle + {d0cebe41-1ec4-4dd7-8f92-397f53b49203}, !- HVAC Component + {7cbf55ac-c92f-488f-a842-f86d1155d61e}; !- Port 1 + +OS:Sizing:Zone, + {a0148e65-d625-4e64-99ec-465eb57b5ae2}, !- Handle + {d0cebe41-1ec4-4dd7-8f92-397f53b49203}, !- Zone or ZoneList Name + TemperatureDifference, !- Zone Cooling Design Supply Air Temperature Input Method + 14, !- Zone Cooling Design Supply Air Temperature {C} + 11, !- Zone Cooling Design Supply Air Temperature Difference {deltaC} + TemperatureDifference, !- Zone Heating Design Supply Air Temperature Input Method + 40, !- Zone Heating Design Supply Air Temperature {C} + 21, !- Zone Heating Design Supply Air Temperature Difference {deltaC} + 0.0085, !- Zone Cooling Design Supply Air Humidity Ratio {kg-H2O/kg-air} + 0.008, !- Zone Heating Design Supply Air Humidity Ratio {kg-H2O/kg-air} + 1.3, !- Zone Heating Sizing Factor + 1.1, !- Zone Cooling Sizing Factor + DesignDay, !- Cooling Design Air Flow Method + , !- Cooling Design Air Flow Rate {m3/s} + , !- Cooling Minimum Air Flow per Zone Floor Area {m3/s-m2} + , !- Cooling Minimum Air Flow {m3/s} + , !- Cooling Minimum Air Flow Fraction + DesignDay, !- Heating Design Air Flow Method + , !- Heating Design Air Flow Rate {m3/s} + , !- Heating Maximum Air Flow per Zone Floor Area {m3/s-m2} + , !- Heating Maximum Air Flow {m3/s} + , !- Heating Maximum Air Flow Fraction + No, !- Account for Dedicated Outdoor Air System + NeutralSupplyAir, !- Dedicated Outdoor Air System Control Strategy + autosize, !- Dedicated Outdoor Air Low Setpoint Temperature for Design {C} + autosize; !- Dedicated Outdoor Air High Setpoint Temperature for Design {C} + +OS:ZoneHVAC:EquipmentList, + {1053c3c5-c80e-4df5-a880-8a8fc7fdd392}, !- Handle + Zone HVAC Equipment List 3, !- Name + {d0cebe41-1ec4-4dd7-8f92-397f53b49203}, !- Thermal Zone + , !- Load Distribution Scheme + {7fc13487-fb0f-4ae3-b528-a54fe34b0774}, !- Zone Equipment 1 + 1, !- Zone Equipment Cooling Sequence 1 + 1, !- Zone Equipment Heating or No-Load Sequence 1 + , !- Zone Equipment Sequential Cooling Fraction Schedule Name 1 + , !- Zone Equipment Sequential Heating Fraction Schedule Name 1 + {2f8f1143-8fa6-4274-8658-c0d05cbe24bf}, !- Zone Equipment 2 + 2, !- Zone Equipment Cooling Sequence 2 + 2, !- Zone Equipment Heating or No-Load Sequence 2 + , !- Zone Equipment Sequential Cooling Fraction Schedule Name 2 + ; !- Zone Equipment Sequential Heating Fraction Schedule Name 2 + +OS:ThermostatSetpoint:DualSetpoint, + {c95b44d6-d987-48cf-9509-7f7539583aa1}, !- Handle + Space Function Warehouse - fine Thermostat 3, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Heating Setpoint Temperature Schedule Name + {464561eb-f631-4a8d-a753-4d87291d0357}; !- Cooling Setpoint Temperature Schedule Name + +OS:Rendering:Color, + {4004fcc0-5fbd-4309-a4d6-9c8a6955bedc}, !- Handle + ALL_ST=Office - enclosed_FL=Building Story 1_SCH=A, !- Name + 47, !- Rendering Red Value + 211, !- Rendering Green Value + 38; !- Rendering Blue Value + +OS:Rendering:Color, + {806f38ad-3efd-4c9f-a57b-dc268c7803c7}, !- Handle + ALL_ST=Warehouse - fine_FL=Building Story 1_SCH=A, !- Name + 53, !- Rendering Red Value + 204, !- Rendering Green Value + 116; !- Rendering Blue Value + +OS:Rendering:Color, + {542774fd-eb95-42ad-a955-5bca8c42520b}, !- Handle + ALL_ST=Warehouse - med/blk_FL=Building Story 1_SCH=A, !- Name + 152, !- Rendering Red Value + 249, !- Rendering Green Value + 143; !- Rendering Blue Value + +OS:Rendering:Color, + {e9352c49-8076-44de-a25e-5c9129534bc3}, !- Handle + Space Function Office - enclosed 2, !- Name + 177, !- Rendering Red Value + 23, !- Rendering Green Value + 233; !- Rendering Blue Value + +OS:Rendering:Color, + {ca6ff41b-13d3-433f-982a-441b87254e54}, !- Handle + Space Function Warehouse - fine 2, !- Name + 154, !- Rendering Red Value + 30, !- Rendering Green Value + 171; !- Rendering Blue Value + +OS:Rendering:Color, + {b30e9dd9-9195-42cf-a37e-7037e2856ce8}, !- Handle + Space Function Warehouse - med/blk 2, !- Name + 158, !- Rendering Red Value + 236, !- Rendering Green Value + 124; !- Rendering Blue Value + +OS:Foundation:Kiva, + {b5fc88e0-f5c3-4584-8ef5-78c180b10c07}, !- Handle + Bldg Kiva Foundation, !- Name + , !- Initial Indoor Air Temperature {C} + , !- Interior Horizontal Insulation Material Name + , !- Interior Horizontal Insulation Depth {m} + , !- Interior Horizontal Insulation Width {m} + , !- Interior Vertical Insulation Material Name + , !- Interior Vertical Insulation Depth {m} + , !- Exterior Horizontal Insulation Material Name + , !- Exterior Horizontal Insulation Depth {m} + , !- Exterior Horizontal Insulation Width {m} + , !- Exterior Vertical Insulation Material Name + , !- Exterior Vertical Insulation Depth {m} + 0, !- Wall Height Above Grade {m} + 0, !- Wall Depth Below Slab {m} + , !- Footing Wall Construction Name + , !- Footing Material Name + ; !- Footing Depth {m} + +OS:Material, + {8ce01102-daf8-46c5-a5b4-3af94feb8951}, !- Handle + Expanded Polystyrene, !- Name + MediumSmooth, !- Roughness + 0.0363958681740979, !- Thickness {m} + 0.029, !- Conductivity {W/m-K} + 29, !- Density {kg/m3} + 1210; !- Specific Heat {J/kg-K} + +OS:Construction, + {91f0c0a2-5b5c-4175-b0e3-98454b378893}, !- Handle + BTAP-Grnd-Floor-Mass:U-0.757_std, !- Name + , !- Surface Rendering Name + {b17e33cb-feb1-423e-afe6-85c471c45438}, !- Layer 1 + {8ce01102-daf8-46c5-a5b4-3af94feb8951}; !- Layer 2 + +OS:SurfaceProperty:ExposedFoundationPerimeter, + {8dcb810f-6b6b-41ff-bc9a-6243fd4550a5}, !- Handle + {a966bae9-9301-4492-ae85-a3416cb9da09}, !- Surface Name + TotalExposedPerimeter, !- Exposed Perimeter Calculation Method + 35.0502906257895; !- Total Exposed Perimeter {m} + +OS:SurfaceProperty:ExposedFoundationPerimeter, + {6f5e8aea-358d-41ed-890a-c8d48188e4f3}, !- Handle + {eb38baf8-4819-4f38-99d7-de17082804a6}, !- Surface Name + TotalExposedPerimeter, !- Exposed Perimeter Calculation Method + 71.6245069309614; !- Total Exposed Perimeter {m} + +OS:SurfaceProperty:ExposedFoundationPerimeter, + {8d4de424-9d25-4bb4-adf4-ba2dffb1a9d6}, !- Handle + {e86312f3-df9c-4a72-8bf5-276fd9968053}, !- Surface Name + TotalExposedPerimeter, !- Exposed Perimeter Calculation Method + 185.918932884622; !- Total Exposed Perimeter {m} + +OS:Foundation:Kiva:Settings, + {ee945c02-446a-4ecf-ade7-654d5e218c6c}, !- Handle + , !- Soil Conductivity {W/m-K} + , !- Soil Density {kg/m3} + , !- Soil Specific Heat {J/kg-K} + , !- Ground Solar Absorptivity {dimensionless} + , !- Ground Thermal Absorptivity {dimensionless} + , !- Ground Surface Roughness {m} + , !- Far-Field Width {m} + , !- Deep-Ground Boundary Condition + , !- Deep-Ground Depth {m} + , !- Minimum Cell Dimension {m} + , !- Maximum Cell Growth Coefficient {dimensionless} + ; !- Simulation Timestep + +OS:AirLoopHVAC, + {7be47e75-8502-45f4-80c5-952fc53814d6}, !- Handle + sys_3|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none|, !- Name + , !- Controller List Name + {48f0fd3e-6142-4549-bc10-d55e48d7d8c5}, !- Availability Schedule + {f01466e8-2e74-41af-b8f3-76ebf449713a}, !- Availability Manager List Name + autosize, !- Design Supply Air Flow Rate {m3/s} + 1, !- Design Return Air Flow Fraction of Supply Air Flow + , !- Branch List Name + , !- Connector List Name + {b4000635-bd64-4c99-8035-2b79c60a1471}, !- Supply Side Inlet Node Name + {26cd4ff9-15c7-476e-b959-fb8802957aa3}, !- Demand Side Outlet Node Name + {5d70625c-b478-403e-af8c-847090b7e010}, !- Demand Side Inlet Node A + {03612c98-ebba-4929-b26c-c69859bd3fa9}, !- Supply Side Outlet Node A + , !- Demand Side Inlet Node B + , !- Supply Side Outlet Node B + , !- Return Air Bypass Flow Temperature Setpoint Schedule Name + {37b83718-3a20-4382-8326-80da5fa5b280}, !- Demand Mixer Name + {87bd367d-c71e-4ec5-ac75-e623e93d98a8}, !- Demand Splitter A Name + , !- Demand Splitter B Name + ; !- Supply Splitter Name + +OS:Node, + {99cc0038-2011-4622-af06-c1806afd56c9}, !- Handle + Node 2, !- Name + {b4000635-bd64-4c99-8035-2b79c60a1471}, !- Inlet Port + {861d5ee7-27a4-48f0-9941-d65deb96fcd5}; !- Outlet Port + +OS:Node, + {2f9d7abf-cfe9-470a-b9cc-7523ef0757c5}, !- Handle + Node 3, !- Name + {e41691a6-7d23-4753-87ef-daf9cd7ff445}, !- Inlet Port + {03612c98-ebba-4929-b26c-c69859bd3fa9}; !- Outlet Port + +OS:Connection, + {b4000635-bd64-4c99-8035-2b79c60a1471}, !- Handle + {7be47e75-8502-45f4-80c5-952fc53814d6}, !- Source Object + 9, !- Outlet Port + {99cc0038-2011-4622-af06-c1806afd56c9}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {03612c98-ebba-4929-b26c-c69859bd3fa9}, !- Handle + {2f9d7abf-cfe9-470a-b9cc-7523ef0757c5}, !- Source Object + 3, !- Outlet Port + {7be47e75-8502-45f4-80c5-952fc53814d6}, !- Target Object + 12; !- Inlet Port + +OS:Node, + {a5c39915-4857-4722-a61a-fe044301fafb}, !- Handle + Node 5, !- Name + {5d70625c-b478-403e-af8c-847090b7e010}, !- Inlet Port + {f8593d43-4fff-4fb4-bad2-ac9cbc33e51f}; !- Outlet Port + +OS:Node, + {80607256-ea86-4e09-a5ba-19f2f1a702b5}, !- Handle + Node 6, !- Name + {2dfc8888-9c5a-4830-bcb0-eae984bfe518}, !- Inlet Port + {26cd4ff9-15c7-476e-b959-fb8802957aa3}; !- Outlet Port + +OS:Node, + {f2ded789-bda1-4b05-a52c-1efedc741805}, !- Handle + Node 8, !- Name + {d6324333-af32-4f3f-8e26-7bd7b7a69f3f}, !- Inlet Port + {ee006a1b-6a42-4a22-84bd-78b092707b54}; !- Outlet Port + +OS:Connection, + {5d70625c-b478-403e-af8c-847090b7e010}, !- Handle + {7be47e75-8502-45f4-80c5-952fc53814d6}, !- Source Object + 11, !- Outlet Port + {a5c39915-4857-4722-a61a-fe044301fafb}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {26cd4ff9-15c7-476e-b959-fb8802957aa3}, !- Handle + {80607256-ea86-4e09-a5ba-19f2f1a702b5}, !- Source Object + 3, !- Outlet Port + {7be47e75-8502-45f4-80c5-952fc53814d6}, !- Target Object + 10; !- Inlet Port + +OS:AirLoopHVAC:ZoneSplitter, + {87bd367d-c71e-4ec5-ac75-e623e93d98a8}, !- Handle + Air Loop HVAC Zone Splitter 1, !- Name + {f8593d43-4fff-4fb4-bad2-ac9cbc33e51f}, !- Inlet Node Name + {72820161-e5fc-45e5-9cb2-f0168b38007e}; !- Outlet Node Name 1 + +OS:AirLoopHVAC:ZoneMixer, + {37b83718-3a20-4382-8326-80da5fa5b280}, !- Handle + Air Loop HVAC Zone Mixer 1, !- Name + {2dfc8888-9c5a-4830-bcb0-eae984bfe518}, !- Outlet Node Name + {036d52d7-9b57-4620-ab5d-cbc5070badc5}; !- Inlet Node Name 1 + +OS:Connection, + {f8593d43-4fff-4fb4-bad2-ac9cbc33e51f}, !- Handle + {a5c39915-4857-4722-a61a-fe044301fafb}, !- Source Object + 3, !- Outlet Port + {87bd367d-c71e-4ec5-ac75-e623e93d98a8}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {2dfc8888-9c5a-4830-bcb0-eae984bfe518}, !- Handle + {37b83718-3a20-4382-8326-80da5fa5b280}, !- Source Object + 2, !- Outlet Port + {80607256-ea86-4e09-a5ba-19f2f1a702b5}, !- Target Object + 2; !- Inlet Port + +OS:Sizing:System, + {062716ec-21bb-44a2-a959-a606feb58e08}, !- Handle + {7be47e75-8502-45f4-80c5-952fc53814d6}, !- AirLoop Name + Sensible, !- Type of Load to Size On + Autosize, !- Design Outdoor Air Flow Rate {m3/s} + 1, !- Central Heating Maximum System Air Flow Ratio + 7, !- Preheat Design Temperature {C} + 0.008, !- Preheat Design Humidity Ratio {kg-H2O/kg-Air} + 13, !- Precool Design Temperature {C} + 0.008, !- Precool Design Humidity Ratio {kg-H2O/kg-Air} + 13, !- Central Cooling Design Supply Air Temperature {C} + 43, !- Central Heating Design Supply Air Temperature {C} + NonCoincident, !- Sizing Option + No, !- 100% Outdoor Air in Cooling + No, !- 100% Outdoor Air in Heating + 0.0085, !- Central Cooling Design Supply Air Humidity Ratio {kg-H2O/kg-Air} + 0.008, !- Central Heating Design Supply Air Humidity Ratio {kg-H2O/kg-Air} + DesignDay, !- Cooling Design Air Flow Method + 0, !- Cooling Design Air Flow Rate {m3/s} + DesignDay, !- Heating Design Air Flow Method + 0, !- Heating Design Air Flow Rate {m3/s} + ZoneSum, !- System Outdoor Air Method + 1, !- Zone Maximum Outdoor Air Fraction {dimensionless} + 0.0099676501, !- Cooling Supply Air Flow Rate Per Floor Area {m3/s-m2} + 1, !- Cooling Fraction of Autosized Cooling Supply Air Flow Rate + 3.9475456e-05, !- Cooling Supply Air Flow Rate Per Unit Cooling Capacity {m3/s-W} + 0.0099676501, !- Heating Supply Air Flow Rate Per Floor Area {m3/s-m2} + 1, !- Heating Fraction of Autosized Heating Supply Air Flow Rate + 1, !- Heating Fraction of Autosized Cooling Supply Air Flow Rate + 3.1588213e-05, !- Heating Supply Air Flow Rate Per Unit Heating Capacity {m3/s-W} + CoolingDesignCapacity, !- Cooling Design Capacity Method + autosize, !- Cooling Design Capacity {W} + 234.7, !- Cooling Design Capacity Per Floor Area {W/m2} + 1, !- Fraction of Autosized Cooling Design Capacity + HeatingDesignCapacity, !- Heating Design Capacity Method + autosize, !- Heating Design Capacity {W} + 157, !- Heating Design Capacity Per Floor Area {W/m2} + 1, !- Fraction of Autosized Heating Design Capacity + OnOff; !- Central Cooling Capacity Control Method + +OS:AvailabilityManagerAssignmentList, + {f01466e8-2e74-41af-b8f3-76ebf449713a}, !- Handle + Air Loop HVAC 1 AvailabilityManagerAssignmentList, !- Name + {39e4c427-b554-4bd9-b3d2-3cbb05c9d92c}; !- Availability Manager Name 1 + +OS:Fan:ConstantVolume, + {d8588b85-a11b-4d98-881b-c5263c336e08}, !- Handle + Fan Constant Volume 1, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + 0.39975, !- Fan Total Efficiency + 640, !- Pressure Rise {Pa} + AutoSize, !- Maximum Flow Rate {m3/s} + 0.615, !- Motor Efficiency + , !- Motor In Airstream Fraction + {c6aa7562-8af6-47ce-b859-76da9e21254c}, !- Air Inlet Node Name + {e41691a6-7d23-4753-87ef-daf9cd7ff445}, !- Air Outlet Node Name + ; !- End-Use Subcategory + +OS:Coil:Cooling:DX:SingleSpeed, + {22ea4965-1a39-45f6-863c-07179d725fd8}, !- Handle + CoilCoolingDXSingleSpeed_dx 49kBtu/hr 14.0SEER, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + autosize, !- Rated Total Cooling Capacity {W} + autosize, !- Rated Sensible Heat Ratio + 4.11713235489972, !- Rated COP {W/W} + autosize, !- Rated Air Flow Rate {m3/s} + 773.3, !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + {89607d0c-5c46-41a0-8c72-a7de6c24781d}, !- Air Inlet Node Name + {b0bbe561-0a74-40cd-b8ed-4574958b27ec}, !- Air Outlet Node Name + {929218f9-da77-4b47-9e6c-bd3b29a57431}, !- Total Cooling Capacity Function of Temperature Curve Name + {899b0ad4-b535-4c55-9247-ab9c5ad0bd61}, !- Total Cooling Capacity Function of Flow Fraction Curve Name + {e48f8ca2-64f8-435d-adb8-a86c3a81d988}, !- Energy Input Ratio Function of Temperature Curve Name + {4e181a91-d4a4-4fea-8f42-cbc11ac7dfe5}, !- Energy Input Ratio Function of Flow Fraction Curve Name + {d09eedfa-c075-4850-996a-c51a707c3fd5}, !- Part Load Fraction Correlation Curve Name + -25, !- Minimum Outdoor Dry-Bulb Temperature for Compressor Operation {C} + , !- Nominal Time for Condensate Removal to Begin {s} + , !- Ratio of Initial Moisture Evaporation Rate and Steady State Latent Capacity {dimensionless} + , !- Maximum Cycling Rate {cycles/hr} + , !- Latent Capacity Time Constant {s} + , !- Condenser Air Inlet Node Name + AirCooled, !- Condenser Type + 0, !- Evaporative Condenser Effectiveness {dimensionless} + Autosize, !- Evaporative Condenser Air Flow Rate {m3/s} + Autosize, !- Evaporative Condenser Pump Rated Power Consumption {W} + 0, !- Crankcase Heater Capacity {W} + 0, !- Maximum Outdoor Dry-Bulb Temperature for Crankcase Heater Operation {C} + , !- Supply Water Storage Tank Name + , !- Condensate Collection Water Storage Tank Name + 0, !- Basin Heater Capacity {W/K} + 10, !- Basin Heater Setpoint Temperature {C} + ; !- Basin Heater Operating Schedule Name + +OS:Curve:Biquadratic, + {7db0d2da-02c9-4464-b400-ed155eedfce6}, !- Handle + Curve Biquadratic 1, !- Name + 0.942587793, !- Coefficient1 Constant + 0.009543347, !- Coefficient2 x + 0.00068377, !- Coefficient3 x**2 + -0.011042676, !- Coefficient4 y + 5.249e-06, !- Coefficient5 y**2 + -9.72e-06, !- Coefficient6 x*y + 17, !- Minimum Value of x + 22, !- Maximum Value of x + 13, !- Minimum Value of y + 46; !- Maximum Value of y + +OS:Curve:Quadratic, + {93457c55-77af-4468-9c8f-95c23256a6ef}, !- Handle + Curve Quadratic 1, !- Name + 0.8, !- Coefficient1 Constant + 0.2, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0.5, !- Minimum Value of x + 1.5; !- Maximum Value of x + +OS:Curve:Biquadratic, + {81eb32f9-e7b5-4db4-bf20-c3c7697018ed}, !- Handle + Curve Biquadratic 2, !- Name + 0.342414409, !- Coefficient1 Constant + 0.034885008, !- Coefficient2 x + -0.0006237, !- Coefficient3 x**2 + 0.004977216, !- Coefficient4 y + 0.000437951, !- Coefficient5 y**2 + -0.000728028, !- Coefficient6 x*y + 17, !- Minimum Value of x + 22, !- Maximum Value of x + 13, !- Minimum Value of y + 46; !- Maximum Value of y + +OS:Curve:Quadratic, + {7ebb50f0-0760-45cc-94cd-34924802ef58}, !- Handle + Curve Quadratic 2, !- Name + 1.1552, !- Coefficient1 Constant + -0.1808, !- Coefficient2 x + 0.0256, !- Coefficient3 x**2 + 0.5, !- Minimum Value of x + 1.5; !- Maximum Value of x + +OS:Curve:Quadratic, + {c9ba4bb0-0d85-4bb5-ba11-2a2e10f6a96d}, !- Handle + Curve Quadratic 3, !- Name + 0.85, !- Coefficient1 Constant + 0.15, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Coil:Heating:Electric, + {8359741d-1900-4609-99d0-8e4ef667784b}, !- Handle + Coil Heating Electric 1, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + , !- Efficiency + , !- Nominal Capacity {W} + {74239fdb-3730-419c-80c7-ecba129395ee}, !- Air Inlet Node Name + {efee4a96-51e8-4752-9f73-a289540172ca}; !- Air Outlet Node Name + +OS:Controller:OutdoorAir, + {8dec321f-2329-4b33-b35f-1693b66f0cc3}, !- Handle + Controller Outdoor Air 1, !- Name + , !- Relief Air Outlet Node Name + , !- Return Air Node Name + , !- Mixed Air Node Name + , !- Actuator Node Name + autosize, !- Minimum Outdoor Air Flow Rate {m3/s} + Autosize, !- Maximum Outdoor Air Flow Rate {m3/s} + NoEconomizer, !- Economizer Control Type + ModulateFlow, !- Economizer Control Action Type + 28, !- Economizer Maximum Limit Dry-Bulb Temperature {C} + 64000, !- Economizer Maximum Limit Enthalpy {J/kg} + , !- Economizer Maximum Limit Dewpoint Temperature {C} + , !- Electronic Enthalpy Limit Curve Name + -100, !- Economizer Minimum Limit Dry-Bulb Temperature {C} + NoLockout, !- Lockout Type + FixedMinimum, !- Minimum Limit Type + {48f0fd3e-6142-4549-bc10-d55e48d7d8c5}, !- Minimum Outdoor Air Schedule Name + , !- Minimum Fraction of Outdoor Air Schedule Name + , !- Maximum Fraction of Outdoor Air Schedule Name + {f01b651c-4f67-4eb0-bf26-6a6c5e94ef7e}, !- Controller Mechanical Ventilation + , !- Time of Day Economizer Control Schedule Name + No, !- High Humidity Control + , !- Humidistat Control Zone Name + , !- High Humidity Outdoor Air Flow Ratio + , !- Control High Indoor Humidity Based on Outdoor Humidity Ratio + BypassWhenWithinEconomizerLimits; !- Heat Recovery Bypass Control Type + +OS:Controller:MechanicalVentilation, + {f01b651c-4f67-4eb0-bf26-6a6c5e94ef7e}, !- Handle + Controller Mechanical Ventilation 1, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule + , !- Demand Controlled Ventilation + ZoneSum; !- System Outdoor Air Method + +OS:AirLoopHVAC:OutdoorAirSystem, + {1552a4e2-3c7f-4c06-ac91-87fa24cac550}, !- Handle + Air Loop HVAC Outdoor Air System 1, !- Name + {8dec321f-2329-4b33-b35f-1693b66f0cc3}, !- Controller Name + , !- Outdoor Air Equipment List Name + , !- Availability Manager List Name + {bde2c184-e6cd-4207-a47a-358823702a7c}, !- Mixed Air Node Name + {d83f991b-4583-46fe-97ce-c4bca1d840f6}, !- Outdoor Air Stream Node Name + {b61487cb-c8b9-498a-bc81-f79d27c2140c}, !- Relief Air Stream Node Name + {861d5ee7-27a4-48f0-9941-d65deb96fcd5}; !- Return Air Stream Node Name + +OS:Node, + {c4f2e8cd-6692-47a9-83cc-0c2867847984}, !- Handle + Node 9, !- Name + , !- Inlet Port + {d83f991b-4583-46fe-97ce-c4bca1d840f6}; !- Outlet Port + +OS:Connection, + {d83f991b-4583-46fe-97ce-c4bca1d840f6}, !- Handle + {c4f2e8cd-6692-47a9-83cc-0c2867847984}, !- Source Object + 3, !- Outlet Port + {1552a4e2-3c7f-4c06-ac91-87fa24cac550}, !- Target Object + 6; !- Inlet Port + +OS:Node, + {a0ccd26f-90a9-4686-9a10-b3bafe8ed0fc}, !- Handle + Node 10, !- Name + {b61487cb-c8b9-498a-bc81-f79d27c2140c}, !- Inlet Port + ; !- Outlet Port + +OS:Connection, + {b61487cb-c8b9-498a-bc81-f79d27c2140c}, !- Handle + {1552a4e2-3c7f-4c06-ac91-87fa24cac550}, !- Source Object + 7, !- Outlet Port + {a0ccd26f-90a9-4686-9a10-b3bafe8ed0fc}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {e41691a6-7d23-4753-87ef-daf9cd7ff445}, !- Handle + {d8588b85-a11b-4d98-881b-c5263c336e08}, !- Source Object + 9, !- Outlet Port + {2f9d7abf-cfe9-470a-b9cc-7523ef0757c5}, !- Target Object + 2; !- Inlet Port + +OS:Node, + {0f95f389-f2af-4199-9040-c2e5d60f56cc}, !- Handle + Node 11, !- Name + {efee4a96-51e8-4752-9f73-a289540172ca}, !- Inlet Port + {c6aa7562-8af6-47ce-b859-76da9e21254c}; !- Outlet Port + +OS:Connection, + {efee4a96-51e8-4752-9f73-a289540172ca}, !- Handle + {8359741d-1900-4609-99d0-8e4ef667784b}, !- Source Object + 6, !- Outlet Port + {0f95f389-f2af-4199-9040-c2e5d60f56cc}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {c6aa7562-8af6-47ce-b859-76da9e21254c}, !- Handle + {0f95f389-f2af-4199-9040-c2e5d60f56cc}, !- Source Object + 3, !- Outlet Port + {d8588b85-a11b-4d98-881b-c5263c336e08}, !- Target Object + 8; !- Inlet Port + +OS:Node, + {8b8e7120-8f02-4616-971f-fb5510d86a79}, !- Handle + Node 12, !- Name + {b0bbe561-0a74-40cd-b8ed-4574958b27ec}, !- Inlet Port + {74239fdb-3730-419c-80c7-ecba129395ee}; !- Outlet Port + +OS:Connection, + {b0bbe561-0a74-40cd-b8ed-4574958b27ec}, !- Handle + {22ea4965-1a39-45f6-863c-07179d725fd8}, !- Source Object + 9, !- Outlet Port + {8b8e7120-8f02-4616-971f-fb5510d86a79}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {74239fdb-3730-419c-80c7-ecba129395ee}, !- Handle + {8b8e7120-8f02-4616-971f-fb5510d86a79}, !- Source Object + 3, !- Outlet Port + {8359741d-1900-4609-99d0-8e4ef667784b}, !- Target Object + 5; !- Inlet Port + +OS:Node, + {6d6607da-43ff-4d1f-a918-a2b100b6e5d1}, !- Handle + Node 13, !- Name + {bde2c184-e6cd-4207-a47a-358823702a7c}, !- Inlet Port + {89607d0c-5c46-41a0-8c72-a7de6c24781d}; !- Outlet Port + +OS:Connection, + {861d5ee7-27a4-48f0-9941-d65deb96fcd5}, !- Handle + {99cc0038-2011-4622-af06-c1806afd56c9}, !- Source Object + 3, !- Outlet Port + {1552a4e2-3c7f-4c06-ac91-87fa24cac550}, !- Target Object + 8; !- Inlet Port + +OS:Connection, + {bde2c184-e6cd-4207-a47a-358823702a7c}, !- Handle + {1552a4e2-3c7f-4c06-ac91-87fa24cac550}, !- Source Object + 5, !- Outlet Port + {6d6607da-43ff-4d1f-a918-a2b100b6e5d1}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {89607d0c-5c46-41a0-8c72-a7de6c24781d}, !- Handle + {6d6607da-43ff-4d1f-a918-a2b100b6e5d1}, !- Source Object + 3, !- Outlet Port + {22ea4965-1a39-45f6-863c-07179d725fd8}, !- Target Object + 8; !- Inlet Port + +OS:SetpointManager:SingleZone:Reheat, + {e8f8027f-9877-4eb7-89f8-13747402ec33}, !- Handle + Setpoint Manager Single Zone Reheat 1, !- Name + 13, !- Minimum Supply Air Temperature {C} + 43, !- Maximum Supply Air Temperature {C} + {6c1adbbd-b731-4330-93ba-8c172088a4d0}, !- Control Zone Name + {2f9d7abf-cfe9-470a-b9cc-7523ef0757c5}; !- Setpoint Node or NodeList Name + +OS:ZoneHVAC:Baseboard:Convective:Electric, + {7fa3ac7c-10ba-4d80-86ec-88df3a8a3394}, !- Handle + Zone HVAC Baseboard Convective Electric 1, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule + autosize, !- Nominal Capacity {W} + 1; !- Efficiency + +OS:AirTerminal:SingleDuct:ConstantVolume:NoReheat, + {8a2b8f1f-5928-43f8-81cf-965d7a1f20a5}, !- Handle + Air Terminal Single Duct Constant Volume No Reheat 1, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + {784e151f-f4d9-4f5e-a11a-5f9b0a58e3fe}, !- Air Inlet Node Name + {d6324333-af32-4f3f-8e26-7bd7b7a69f3f}, !- Air Outlet Node Name + AutoSize; !- Maximum Air Flow Rate {m3/s} + +OS:Node, + {ad5339b2-12db-42db-95ec-f60a20072557}, !- Handle + Node 14, !- Name + {e94f669d-b9ec-45c8-9ad9-92e72972dd81}, !- Inlet Port + {036d52d7-9b57-4620-ab5d-cbc5070badc5}; !- Outlet Port + +OS:Connection, + {ee006a1b-6a42-4a22-84bd-78b092707b54}, !- Handle + {f2ded789-bda1-4b05-a52c-1efedc741805}, !- Source Object + 3, !- Outlet Port + {043b010d-5588-418b-8582-2b69ceae0f7b}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {e94f669d-b9ec-45c8-9ad9-92e72972dd81}, !- Handle + {7e9828c6-334e-4d61-9742-a9e98cd3207a}, !- Source Object + 2, !- Outlet Port + {ad5339b2-12db-42db-95ec-f60a20072557}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {036d52d7-9b57-4620-ab5d-cbc5070badc5}, !- Handle + {ad5339b2-12db-42db-95ec-f60a20072557}, !- Source Object + 3, !- Outlet Port + {37b83718-3a20-4382-8326-80da5fa5b280}, !- Target Object + 3; !- Inlet Port + +OS:Node, + {06937d39-5305-4d10-8fe0-339a78cbce8d}, !- Handle + Node 15, !- Name + {72820161-e5fc-45e5-9cb2-f0168b38007e}, !- Inlet Port + {784e151f-f4d9-4f5e-a11a-5f9b0a58e3fe}; !- Outlet Port + +OS:Connection, + {72820161-e5fc-45e5-9cb2-f0168b38007e}, !- Handle + {87bd367d-c71e-4ec5-ac75-e623e93d98a8}, !- Source Object + 3, !- Outlet Port + {06937d39-5305-4d10-8fe0-339a78cbce8d}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {784e151f-f4d9-4f5e-a11a-5f9b0a58e3fe}, !- Handle + {06937d39-5305-4d10-8fe0-339a78cbce8d}, !- Source Object + 3, !- Outlet Port + {8a2b8f1f-5928-43f8-81cf-965d7a1f20a5}, !- Target Object + 3; !- Inlet Port + +OS:Connection, + {d6324333-af32-4f3f-8e26-7bd7b7a69f3f}, !- Handle + {8a2b8f1f-5928-43f8-81cf-965d7a1f20a5}, !- Source Object + 4, !- Outlet Port + {f2ded789-bda1-4b05-a52c-1efedc741805}, !- Target Object + 2; !- Inlet Port + +OS:AirLoopHVAC, + {37176662-1444-42f0-b684-54eb4352df41}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none|, !- Name + , !- Controller List Name + {bf1f02ca-a131-45e6-b117-87cb43be5a00}, !- Availability Schedule + {33e16875-2c96-4d0f-a53b-38731571606b}, !- Availability Manager List Name + autosize, !- Design Supply Air Flow Rate {m3/s} + 1, !- Design Return Air Flow Fraction of Supply Air Flow + , !- Branch List Name + , !- Connector List Name + {62958948-c333-465d-8968-73e6b05403c2}, !- Supply Side Inlet Node Name + {688dd6be-10d4-4656-a20e-18b287473f65}, !- Demand Side Outlet Node Name + {7d43ae2b-def3-4f94-9252-05fc5ba30292}, !- Demand Side Inlet Node A + {7694758f-99f8-436b-a770-ffe044354689}, !- Supply Side Outlet Node A + , !- Demand Side Inlet Node B + , !- Supply Side Outlet Node B + , !- Return Air Bypass Flow Temperature Setpoint Schedule Name + {d7fb239b-234c-42aa-9154-cc9986f81790}, !- Demand Mixer Name + {1974de95-9304-4814-b522-a357481d46f0}, !- Demand Splitter A Name + , !- Demand Splitter B Name + ; !- Supply Splitter Name + +OS:Node, + {ea73a792-1ee9-488c-a673-3b3fc631f367}, !- Handle + Node 16, !- Name + {62958948-c333-465d-8968-73e6b05403c2}, !- Inlet Port + {33d24ea1-60a9-410b-88dd-24c4e3913c4d}; !- Outlet Port + +OS:Node, + {38afabf7-5368-4472-8ea6-73cefeaa30f1}, !- Handle + Node 17, !- Name + {e68dac31-04ff-4caf-9e79-0a996af8da4d}, !- Inlet Port + {7694758f-99f8-436b-a770-ffe044354689}; !- Outlet Port + +OS:Connection, + {62958948-c333-465d-8968-73e6b05403c2}, !- Handle + {37176662-1444-42f0-b684-54eb4352df41}, !- Source Object + 9, !- Outlet Port + {ea73a792-1ee9-488c-a673-3b3fc631f367}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {7694758f-99f8-436b-a770-ffe044354689}, !- Handle + {38afabf7-5368-4472-8ea6-73cefeaa30f1}, !- Source Object + 3, !- Outlet Port + {37176662-1444-42f0-b684-54eb4352df41}, !- Target Object + 12; !- Inlet Port + +OS:Node, + {b0fbaa85-d497-458e-8643-18d3219021f4}, !- Handle + Node 18, !- Name + {7d43ae2b-def3-4f94-9252-05fc5ba30292}, !- Inlet Port + {7599698d-1434-44df-b524-439b5c9db438}; !- Outlet Port + +OS:Node, + {6ad80dda-8ea4-43ae-a7f2-0f2108b74999}, !- Handle + Node 19, !- Name + {bb974d95-f5cf-4fde-b9a6-ad8b957d422f}, !- Inlet Port + {688dd6be-10d4-4656-a20e-18b287473f65}; !- Outlet Port + +OS:Node, + {7005c274-7c3e-45e6-b84a-1bb9c1605840}, !- Handle + Node 20, !- Name + {e581d669-2138-47ff-814b-5a9c59c70b21}, !- Inlet Port + {ccbecfe1-9225-42fd-804b-5e4cfd257cfe}; !- Outlet Port + +OS:Connection, + {7d43ae2b-def3-4f94-9252-05fc5ba30292}, !- Handle + {37176662-1444-42f0-b684-54eb4352df41}, !- Source Object + 11, !- Outlet Port + {b0fbaa85-d497-458e-8643-18d3219021f4}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {688dd6be-10d4-4656-a20e-18b287473f65}, !- Handle + {6ad80dda-8ea4-43ae-a7f2-0f2108b74999}, !- Source Object + 3, !- Outlet Port + {37176662-1444-42f0-b684-54eb4352df41}, !- Target Object + 10; !- Inlet Port + +OS:AirLoopHVAC:ZoneSplitter, + {1974de95-9304-4814-b522-a357481d46f0}, !- Handle + Air Loop HVAC Zone Splitter 2, !- Name + {7599698d-1434-44df-b524-439b5c9db438}, !- Inlet Node Name + {166e5364-2426-4fd4-be94-7abc5e6a6247}; !- Outlet Node Name 1 + +OS:AirLoopHVAC:ZoneMixer, + {d7fb239b-234c-42aa-9154-cc9986f81790}, !- Handle + Air Loop HVAC Zone Mixer 2, !- Name + {bb974d95-f5cf-4fde-b9a6-ad8b957d422f}, !- Outlet Node Name + {5c4070f0-0df7-4377-b255-c3999570abda}; !- Inlet Node Name 1 + +OS:Connection, + {7599698d-1434-44df-b524-439b5c9db438}, !- Handle + {b0fbaa85-d497-458e-8643-18d3219021f4}, !- Source Object + 3, !- Outlet Port + {1974de95-9304-4814-b522-a357481d46f0}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {bb974d95-f5cf-4fde-b9a6-ad8b957d422f}, !- Handle + {d7fb239b-234c-42aa-9154-cc9986f81790}, !- Source Object + 2, !- Outlet Port + {6ad80dda-8ea4-43ae-a7f2-0f2108b74999}, !- Target Object + 2; !- Inlet Port + +OS:Sizing:System, + {a08282b5-41e9-4a7e-96a4-55bc2adeb7e5}, !- Handle + {37176662-1444-42f0-b684-54eb4352df41}, !- AirLoop Name + Sensible, !- Type of Load to Size On + Autosize, !- Design Outdoor Air Flow Rate {m3/s} + 1, !- Central Heating Maximum System Air Flow Ratio + 7, !- Preheat Design Temperature {C} + 0.008, !- Preheat Design Humidity Ratio {kg-H2O/kg-Air} + 13, !- Precool Design Temperature {C} + 0.008, !- Precool Design Humidity Ratio {kg-H2O/kg-Air} + 13, !- Central Cooling Design Supply Air Temperature {C} + 43, !- Central Heating Design Supply Air Temperature {C} + NonCoincident, !- Sizing Option + No, !- 100% Outdoor Air in Cooling + No, !- 100% Outdoor Air in Heating + 0.0085, !- Central Cooling Design Supply Air Humidity Ratio {kg-H2O/kg-Air} + 0.008, !- Central Heating Design Supply Air Humidity Ratio {kg-H2O/kg-Air} + DesignDay, !- Cooling Design Air Flow Method + 0, !- Cooling Design Air Flow Rate {m3/s} + DesignDay, !- Heating Design Air Flow Method + 0, !- Heating Design Air Flow Rate {m3/s} + ZoneSum, !- System Outdoor Air Method + 1, !- Zone Maximum Outdoor Air Fraction {dimensionless} + 0.0099676501, !- Cooling Supply Air Flow Rate Per Floor Area {m3/s-m2} + 1, !- Cooling Fraction of Autosized Cooling Supply Air Flow Rate + 3.9475456e-05, !- Cooling Supply Air Flow Rate Per Unit Cooling Capacity {m3/s-W} + 0.0099676501, !- Heating Supply Air Flow Rate Per Floor Area {m3/s-m2} + 1, !- Heating Fraction of Autosized Heating Supply Air Flow Rate + 1, !- Heating Fraction of Autosized Cooling Supply Air Flow Rate + 3.1588213e-05, !- Heating Supply Air Flow Rate Per Unit Heating Capacity {m3/s-W} + CoolingDesignCapacity, !- Cooling Design Capacity Method + autosize, !- Cooling Design Capacity {W} + 234.7, !- Cooling Design Capacity Per Floor Area {W/m2} + 1, !- Fraction of Autosized Cooling Design Capacity + HeatingDesignCapacity, !- Heating Design Capacity Method + autosize, !- Heating Design Capacity {W} + 157, !- Heating Design Capacity Per Floor Area {W/m2} + 1, !- Fraction of Autosized Heating Design Capacity + OnOff; !- Central Cooling Capacity Control Method + +OS:AvailabilityManagerAssignmentList, + {33e16875-2c96-4d0f-a53b-38731571606b}, !- Handle + Air Loop HVAC 1 AvailabilityManagerAssignmentList 1, !- Name + {e88b0e59-2631-474e-a89e-528a33404f7d}; !- Availability Manager Name 1 + +OS:Fan:ConstantVolume, + {f41f5049-75b9-40c6-b964-ca14f6a19053}, !- Handle + Fan Constant Volume 2, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + 0.39975, !- Fan Total Efficiency + 640, !- Pressure Rise {Pa} + AutoSize, !- Maximum Flow Rate {m3/s} + 0.615, !- Motor Efficiency + , !- Motor In Airstream Fraction + {144f59e4-9417-4ad9-b4d5-4e9dd4bdaf94}, !- Air Inlet Node Name + {e68dac31-04ff-4caf-9e79-0a996af8da4d}, !- Air Outlet Node Name + ; !- End-Use Subcategory + +OS:Curve:Biquadratic, + {e8bb46e3-b23b-4f23-9cd0-0905c32fcf1f}, !- Handle + Curve Biquadratic 3, !- Name + 0.867905, !- Coefficient1 Constant + 0.0142459, !- Coefficient2 x + 0.000554364, !- Coefficient3 x**2 + -0.00755748, !- Coefficient4 y + 3.3048e-05, !- Coefficient5 y**2 + -0.000191808, !- Coefficient6 x*y + 13, !- Minimum Value of x + 24, !- Maximum Value of x + 24, !- Minimum Value of y + 46; !- Maximum Value of y + +OS:Curve:Quadratic, + {584adeb2-bec4-4ee2-83f5-ad3f95a407fd}, !- Handle + Curve Quadratic 4, !- Name + 1, !- Coefficient1 Constant + 0, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Curve:Biquadratic, + {544ac360-3d07-4997-8fb7-bf48215914c3}, !- Handle + Curve Biquadratic 4, !- Name + 0.116936, !- Coefficient1 Constant + 0.0284933, !- Coefficient2 x + -0.000411156, !- Coefficient3 x**2 + 0.0214108, !- Coefficient4 y + 0.000161028, !- Coefficient5 y**2 + -0.000679104, !- Coefficient6 x*y + 13, !- Minimum Value of x + 24, !- Maximum Value of x + 24, !- Minimum Value of y + 46; !- Maximum Value of y + +OS:Curve:Quadratic, + {636b469f-5715-4955-a8cd-b4dfa711ac64}, !- Handle + Curve Quadratic 5, !- Name + 1, !- Coefficient1 Constant + 0, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Curve:Cubic, + {10849b16-b2e8-45ab-a374-7456db8b31dd}, !- Handle + Curve Cubic 1, !- Name + 0.0277, !- Coefficient1 Constant + 4.9151, !- Coefficient2 x + -8.184, !- Coefficient3 x**2 + 4.2702, !- Coefficient4 x**3 + 0.7, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Coil:Cooling:DX:SingleSpeed, + {5974c2a8-360e-4be9-92a3-1f00b7c35cd2}, !- Handle + CoilCoolingDXSingleSpeed_dx 1 461kBtu/hr 8.39EER, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + autosize, !- Rated Total Cooling Capacity {W} + autosize, !- Rated Sensible Heat Ratio + 2.92982713155582, !- Rated COP {W/W} + autosize, !- Rated Air Flow Rate {m3/s} + 773.3, !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + {1b7105b4-c8ca-41a3-bda5-aa5c760bb29a}, !- Air Inlet Node Name + {1a7e9268-1bcd-4fbd-8125-e18a2bf4dead}, !- Air Outlet Node Name + {929218f9-da77-4b47-9e6c-bd3b29a57431}, !- Total Cooling Capacity Function of Temperature Curve Name + {899b0ad4-b535-4c55-9247-ab9c5ad0bd61}, !- Total Cooling Capacity Function of Flow Fraction Curve Name + {e48f8ca2-64f8-435d-adb8-a86c3a81d988}, !- Energy Input Ratio Function of Temperature Curve Name + {4e181a91-d4a4-4fea-8f42-cbc11ac7dfe5}, !- Energy Input Ratio Function of Flow Fraction Curve Name + {d09eedfa-c075-4850-996a-c51a707c3fd5}, !- Part Load Fraction Correlation Curve Name + -25, !- Minimum Outdoor Dry-Bulb Temperature for Compressor Operation {C} + , !- Nominal Time for Condensate Removal to Begin {s} + , !- Ratio of Initial Moisture Evaporation Rate and Steady State Latent Capacity {dimensionless} + , !- Maximum Cycling Rate {cycles/hr} + , !- Latent Capacity Time Constant {s} + , !- Condenser Air Inlet Node Name + AirCooled, !- Condenser Type + 0, !- Evaporative Condenser Effectiveness {dimensionless} + Autosize, !- Evaporative Condenser Air Flow Rate {m3/s} + Autosize, !- Evaporative Condenser Pump Rated Power Consumption {W} + 0, !- Crankcase Heater Capacity {W} + 0, !- Maximum Outdoor Dry-Bulb Temperature for Crankcase Heater Operation {C} + , !- Supply Water Storage Tank Name + , !- Condensate Collection Water Storage Tank Name + 0, !- Basin Heater Capacity {W/K} + 10, !- Basin Heater Setpoint Temperature {C} + ; !- Basin Heater Operating Schedule Name + +OS:Coil:Heating:Electric, + {87671eb2-9032-423a-9b19-2e4541764420}, !- Handle + Coil Heating Electric 2, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + , !- Efficiency + , !- Nominal Capacity {W} + {473ec29e-ddcc-4117-80d9-3a949f8e8e2c}, !- Air Inlet Node Name + {60c1647b-4cd2-48c0-a628-ddb7f4a250a6}; !- Air Outlet Node Name + +OS:Controller:OutdoorAir, + {2614cc2c-75e3-4bf1-8e92-23429cad15ed}, !- Handle + Controller Outdoor Air 2, !- Name + , !- Relief Air Outlet Node Name + , !- Return Air Node Name + , !- Mixed Air Node Name + , !- Actuator Node Name + autosize, !- Minimum Outdoor Air Flow Rate {m3/s} + Autosize, !- Maximum Outdoor Air Flow Rate {m3/s} + DifferentialEnthalpy, !- Economizer Control Type + ModulateFlow, !- Economizer Control Action Type + , !- Economizer Maximum Limit Dry-Bulb Temperature {C} + , !- Economizer Maximum Limit Enthalpy {J/kg} + , !- Economizer Maximum Limit Dewpoint Temperature {C} + , !- Electronic Enthalpy Limit Curve Name + , !- Economizer Minimum Limit Dry-Bulb Temperature {C} + NoLockout, !- Lockout Type + FixedMinimum, !- Minimum Limit Type + {bf1f02ca-a131-45e6-b117-87cb43be5a00}, !- Minimum Outdoor Air Schedule Name + , !- Minimum Fraction of Outdoor Air Schedule Name + , !- Maximum Fraction of Outdoor Air Schedule Name + {2bae44a0-b73d-47fd-9b0d-b759f1ebc093}, !- Controller Mechanical Ventilation + , !- Time of Day Economizer Control Schedule Name + No, !- High Humidity Control + , !- Humidistat Control Zone Name + , !- High Humidity Outdoor Air Flow Ratio + , !- Control High Indoor Humidity Based on Outdoor Humidity Ratio + BypassWhenWithinEconomizerLimits; !- Heat Recovery Bypass Control Type + +OS:Controller:MechanicalVentilation, + {2bae44a0-b73d-47fd-9b0d-b759f1ebc093}, !- Handle + Controller Mechanical Ventilation 2, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule + , !- Demand Controlled Ventilation + ZoneSum; !- System Outdoor Air Method + +OS:AirLoopHVAC:OutdoorAirSystem, + {3f6f11b7-1e08-4bb9-ac80-7e0d11cd2cbe}, !- Handle + Air Loop HVAC Outdoor Air System 2, !- Name + {2614cc2c-75e3-4bf1-8e92-23429cad15ed}, !- Controller Name + , !- Outdoor Air Equipment List Name + , !- Availability Manager List Name + {257357e0-eebf-4954-ae24-b2a8793a2084}, !- Mixed Air Node Name + {d281622a-16b4-4577-a7e7-79b58f8777dd}, !- Outdoor Air Stream Node Name + {53bcf979-453f-4cd7-8e13-e926e0ab33e5}, !- Relief Air Stream Node Name + {33d24ea1-60a9-410b-88dd-24c4e3913c4d}; !- Return Air Stream Node Name + +OS:Node, + {d400ab03-6d7f-407b-b8ae-af46be0927c1}, !- Handle + Node 21, !- Name + , !- Inlet Port + {d281622a-16b4-4577-a7e7-79b58f8777dd}; !- Outlet Port + +OS:Connection, + {d281622a-16b4-4577-a7e7-79b58f8777dd}, !- Handle + {d400ab03-6d7f-407b-b8ae-af46be0927c1}, !- Source Object + 3, !- Outlet Port + {3f6f11b7-1e08-4bb9-ac80-7e0d11cd2cbe}, !- Target Object + 6; !- Inlet Port + +OS:Node, + {abcb01be-029c-4adc-80a1-082db192046c}, !- Handle + Node 22, !- Name + {53bcf979-453f-4cd7-8e13-e926e0ab33e5}, !- Inlet Port + ; !- Outlet Port + +OS:Connection, + {53bcf979-453f-4cd7-8e13-e926e0ab33e5}, !- Handle + {3f6f11b7-1e08-4bb9-ac80-7e0d11cd2cbe}, !- Source Object + 7, !- Outlet Port + {abcb01be-029c-4adc-80a1-082db192046c}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {e68dac31-04ff-4caf-9e79-0a996af8da4d}, !- Handle + {f41f5049-75b9-40c6-b964-ca14f6a19053}, !- Source Object + 9, !- Outlet Port + {38afabf7-5368-4472-8ea6-73cefeaa30f1}, !- Target Object + 2; !- Inlet Port + +OS:Node, + {30531044-05c9-4bc1-bb8a-1aadb1af1b38}, !- Handle + Node 23, !- Name + {60c1647b-4cd2-48c0-a628-ddb7f4a250a6}, !- Inlet Port + {144f59e4-9417-4ad9-b4d5-4e9dd4bdaf94}; !- Outlet Port + +OS:Connection, + {60c1647b-4cd2-48c0-a628-ddb7f4a250a6}, !- Handle + {87671eb2-9032-423a-9b19-2e4541764420}, !- Source Object + 6, !- Outlet Port + {30531044-05c9-4bc1-bb8a-1aadb1af1b38}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {144f59e4-9417-4ad9-b4d5-4e9dd4bdaf94}, !- Handle + {30531044-05c9-4bc1-bb8a-1aadb1af1b38}, !- Source Object + 3, !- Outlet Port + {f41f5049-75b9-40c6-b964-ca14f6a19053}, !- Target Object + 8; !- Inlet Port + +OS:Node, + {1814f431-3584-49df-ba52-38f3ad02411d}, !- Handle + Node 24, !- Name + {1a7e9268-1bcd-4fbd-8125-e18a2bf4dead}, !- Inlet Port + {473ec29e-ddcc-4117-80d9-3a949f8e8e2c}; !- Outlet Port + +OS:Connection, + {1a7e9268-1bcd-4fbd-8125-e18a2bf4dead}, !- Handle + {5974c2a8-360e-4be9-92a3-1f00b7c35cd2}, !- Source Object + 9, !- Outlet Port + {1814f431-3584-49df-ba52-38f3ad02411d}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {473ec29e-ddcc-4117-80d9-3a949f8e8e2c}, !- Handle + {1814f431-3584-49df-ba52-38f3ad02411d}, !- Source Object + 3, !- Outlet Port + {87671eb2-9032-423a-9b19-2e4541764420}, !- Target Object + 5; !- Inlet Port + +OS:Node, + {51dcb280-93a0-4a3c-8032-9b7342a7acaa}, !- Handle + Node 25, !- Name + {257357e0-eebf-4954-ae24-b2a8793a2084}, !- Inlet Port + {1b7105b4-c8ca-41a3-bda5-aa5c760bb29a}; !- Outlet Port + +OS:Connection, + {33d24ea1-60a9-410b-88dd-24c4e3913c4d}, !- Handle + {ea73a792-1ee9-488c-a673-3b3fc631f367}, !- Source Object + 3, !- Outlet Port + {3f6f11b7-1e08-4bb9-ac80-7e0d11cd2cbe}, !- Target Object + 8; !- Inlet Port + +OS:Connection, + {257357e0-eebf-4954-ae24-b2a8793a2084}, !- Handle + {3f6f11b7-1e08-4bb9-ac80-7e0d11cd2cbe}, !- Source Object + 5, !- Outlet Port + {51dcb280-93a0-4a3c-8032-9b7342a7acaa}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {1b7105b4-c8ca-41a3-bda5-aa5c760bb29a}, !- Handle + {51dcb280-93a0-4a3c-8032-9b7342a7acaa}, !- Source Object + 3, !- Outlet Port + {5974c2a8-360e-4be9-92a3-1f00b7c35cd2}, !- Target Object + 8; !- Inlet Port + +OS:SetpointManager:SingleZone:Reheat, + {6ad36808-574b-4748-8dd0-65de73d0acea}, !- Handle + Setpoint Manager Single Zone Reheat 2, !- Name + 13, !- Minimum Supply Air Temperature {C} + 43, !- Maximum Supply Air Temperature {C} + {60569c67-8392-4395-8052-94b9e792b96b}, !- Control Zone Name + {38afabf7-5368-4472-8ea6-73cefeaa30f1}; !- Setpoint Node or NodeList Name + +OS:ZoneHVAC:Baseboard:Convective:Electric, + {54d5c499-b97e-499d-ade6-7d0c6fbed4c6}, !- Handle + Zone HVAC Baseboard Convective Electric 2, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule + autosize, !- Nominal Capacity {W} + 1; !- Efficiency + +OS:AirTerminal:SingleDuct:ConstantVolume:NoReheat, + {e9513dd5-f7ca-42d5-b624-59ba27ca145f}, !- Handle + Air Terminal Single Duct Constant Volume No Reheat 2, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + {c303da6d-467c-4b0b-827e-290cc6f7ce1a}, !- Air Inlet Node Name + {e581d669-2138-47ff-814b-5a9c59c70b21}, !- Air Outlet Node Name + AutoSize; !- Maximum Air Flow Rate {m3/s} + +OS:Node, + {a4a9b308-17fb-4c0c-92c1-13baf4679c3c}, !- Handle + Node 26, !- Name + {0d3b2994-170d-435e-876f-867975d5c4dc}, !- Inlet Port + {5c4070f0-0df7-4377-b255-c3999570abda}; !- Outlet Port + +OS:Connection, + {ccbecfe1-9225-42fd-804b-5e4cfd257cfe}, !- Handle + {7005c274-7c3e-45e6-b84a-1bb9c1605840}, !- Source Object + 3, !- Outlet Port + {38456173-bdea-4d6b-afc0-49715dc4e592}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {0d3b2994-170d-435e-876f-867975d5c4dc}, !- Handle + {a07a6d4e-ec14-40d3-bae3-6d8a8ab33439}, !- Source Object + 2, !- Outlet Port + {a4a9b308-17fb-4c0c-92c1-13baf4679c3c}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {5c4070f0-0df7-4377-b255-c3999570abda}, !- Handle + {a4a9b308-17fb-4c0c-92c1-13baf4679c3c}, !- Source Object + 3, !- Outlet Port + {d7fb239b-234c-42aa-9154-cc9986f81790}, !- Target Object + 3; !- Inlet Port + +OS:Node, + {4f24af95-f54f-4358-ad8b-1e7040112e63}, !- Handle + Node 27, !- Name + {166e5364-2426-4fd4-be94-7abc5e6a6247}, !- Inlet Port + {c303da6d-467c-4b0b-827e-290cc6f7ce1a}; !- Outlet Port + +OS:Connection, + {166e5364-2426-4fd4-be94-7abc5e6a6247}, !- Handle + {1974de95-9304-4814-b522-a357481d46f0}, !- Source Object + 3, !- Outlet Port + {4f24af95-f54f-4358-ad8b-1e7040112e63}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {c303da6d-467c-4b0b-827e-290cc6f7ce1a}, !- Handle + {4f24af95-f54f-4358-ad8b-1e7040112e63}, !- Source Object + 3, !- Outlet Port + {e9513dd5-f7ca-42d5-b624-59ba27ca145f}, !- Target Object + 3; !- Inlet Port + +OS:Connection, + {e581d669-2138-47ff-814b-5a9c59c70b21}, !- Handle + {e9513dd5-f7ca-42d5-b624-59ba27ca145f}, !- Source Object + 4, !- Outlet Port + {7005c274-7c3e-45e6-b84a-1bb9c1605840}, !- Target Object + 2; !- Inlet Port + +OS:AirLoopHVAC, + {26e1b82f-020a-45b3-8a26-e6692696d930}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| 1, !- Name + , !- Controller List Name + {a935fa5d-cac9-42c2-b5bb-d0f987c5f51f}, !- Availability Schedule + {7f24e034-36d5-416d-8407-f5f89036c9bc}, !- Availability Manager List Name + autosize, !- Design Supply Air Flow Rate {m3/s} + 1, !- Design Return Air Flow Fraction of Supply Air Flow + , !- Branch List Name + , !- Connector List Name + {681f9dab-6a0c-423a-b646-531adcb5ba59}, !- Supply Side Inlet Node Name + {052f479e-f947-4a36-b6d3-1fe16b7a7d15}, !- Demand Side Outlet Node Name + {a7a5e352-337a-43a9-aad5-2759eff4dd1d}, !- Demand Side Inlet Node A + {3a93a0a2-0509-4d44-b31c-0dbfd2044b6b}, !- Supply Side Outlet Node A + , !- Demand Side Inlet Node B + , !- Supply Side Outlet Node B + , !- Return Air Bypass Flow Temperature Setpoint Schedule Name + {6e80478d-a51f-494d-b89a-ae2b94da2962}, !- Demand Mixer Name + {9766af25-a9ba-4dc2-a339-c0650ca72bb4}, !- Demand Splitter A Name + , !- Demand Splitter B Name + ; !- Supply Splitter Name + +OS:Node, + {ac5a0f22-fab8-4547-9293-c7449ba526c4}, !- Handle + Node 28, !- Name + {681f9dab-6a0c-423a-b646-531adcb5ba59}, !- Inlet Port + {5c4b1fa8-0204-45ea-be09-03d25a4df629}; !- Outlet Port + +OS:Node, + {19939f15-d5dd-4ffc-97ea-e1c131d77ca3}, !- Handle + Node 29, !- Name + {30667c89-a419-462d-bf50-727b3ecc06b3}, !- Inlet Port + {3a93a0a2-0509-4d44-b31c-0dbfd2044b6b}; !- Outlet Port + +OS:Connection, + {681f9dab-6a0c-423a-b646-531adcb5ba59}, !- Handle + {26e1b82f-020a-45b3-8a26-e6692696d930}, !- Source Object + 9, !- Outlet Port + {ac5a0f22-fab8-4547-9293-c7449ba526c4}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {3a93a0a2-0509-4d44-b31c-0dbfd2044b6b}, !- Handle + {19939f15-d5dd-4ffc-97ea-e1c131d77ca3}, !- Source Object + 3, !- Outlet Port + {26e1b82f-020a-45b3-8a26-e6692696d930}, !- Target Object + 12; !- Inlet Port + +OS:Node, + {0ea76b65-878c-400c-9d20-fdb1f1e37c86}, !- Handle + Node 30, !- Name + {a7a5e352-337a-43a9-aad5-2759eff4dd1d}, !- Inlet Port + {a8a03ff6-5a55-4f37-b382-bf3e1dc46946}; !- Outlet Port + +OS:Node, + {bdecb080-6394-4eb9-b1d9-d70bc21d8a1c}, !- Handle + Node 31, !- Name + {ce0a2755-f2e2-466f-98e1-5bfb0a019f26}, !- Inlet Port + {052f479e-f947-4a36-b6d3-1fe16b7a7d15}; !- Outlet Port + +OS:Node, + {b1ee426e-b424-42ea-bbd5-5622b11559c2}, !- Handle + Node 32, !- Name + {48a090d4-f740-46fe-8242-5fa0b4fef610}, !- Inlet Port + {4771220b-498b-43c2-9092-4c9764e778cc}; !- Outlet Port + +OS:Connection, + {a7a5e352-337a-43a9-aad5-2759eff4dd1d}, !- Handle + {26e1b82f-020a-45b3-8a26-e6692696d930}, !- Source Object + 11, !- Outlet Port + {0ea76b65-878c-400c-9d20-fdb1f1e37c86}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {052f479e-f947-4a36-b6d3-1fe16b7a7d15}, !- Handle + {bdecb080-6394-4eb9-b1d9-d70bc21d8a1c}, !- Source Object + 3, !- Outlet Port + {26e1b82f-020a-45b3-8a26-e6692696d930}, !- Target Object + 10; !- Inlet Port + +OS:AirLoopHVAC:ZoneSplitter, + {9766af25-a9ba-4dc2-a339-c0650ca72bb4}, !- Handle + Air Loop HVAC Zone Splitter 3, !- Name + {a8a03ff6-5a55-4f37-b382-bf3e1dc46946}, !- Inlet Node Name + {f96420c7-f80c-4fd2-a133-24af36fcd4eb}; !- Outlet Node Name 1 + +OS:AirLoopHVAC:ZoneMixer, + {6e80478d-a51f-494d-b89a-ae2b94da2962}, !- Handle + Air Loop HVAC Zone Mixer 3, !- Name + {ce0a2755-f2e2-466f-98e1-5bfb0a019f26}, !- Outlet Node Name + {9a16df7b-caf3-4f57-8e77-e5396603cf6c}; !- Inlet Node Name 1 + +OS:Connection, + {a8a03ff6-5a55-4f37-b382-bf3e1dc46946}, !- Handle + {0ea76b65-878c-400c-9d20-fdb1f1e37c86}, !- Source Object + 3, !- Outlet Port + {9766af25-a9ba-4dc2-a339-c0650ca72bb4}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {ce0a2755-f2e2-466f-98e1-5bfb0a019f26}, !- Handle + {6e80478d-a51f-494d-b89a-ae2b94da2962}, !- Source Object + 2, !- Outlet Port + {bdecb080-6394-4eb9-b1d9-d70bc21d8a1c}, !- Target Object + 2; !- Inlet Port + +OS:Sizing:System, + {15921abe-d218-4b0b-8b8f-6dc762d2feb9}, !- Handle + {26e1b82f-020a-45b3-8a26-e6692696d930}, !- AirLoop Name + Sensible, !- Type of Load to Size On + Autosize, !- Design Outdoor Air Flow Rate {m3/s} + 1, !- Central Heating Maximum System Air Flow Ratio + 7, !- Preheat Design Temperature {C} + 0.008, !- Preheat Design Humidity Ratio {kg-H2O/kg-Air} + 13, !- Precool Design Temperature {C} + 0.008, !- Precool Design Humidity Ratio {kg-H2O/kg-Air} + 13, !- Central Cooling Design Supply Air Temperature {C} + 43, !- Central Heating Design Supply Air Temperature {C} + NonCoincident, !- Sizing Option + No, !- 100% Outdoor Air in Cooling + No, !- 100% Outdoor Air in Heating + 0.0085, !- Central Cooling Design Supply Air Humidity Ratio {kg-H2O/kg-Air} + 0.008, !- Central Heating Design Supply Air Humidity Ratio {kg-H2O/kg-Air} + DesignDay, !- Cooling Design Air Flow Method + 0, !- Cooling Design Air Flow Rate {m3/s} + DesignDay, !- Heating Design Air Flow Method + 0, !- Heating Design Air Flow Rate {m3/s} + ZoneSum, !- System Outdoor Air Method + 1, !- Zone Maximum Outdoor Air Fraction {dimensionless} + 0.0099676501, !- Cooling Supply Air Flow Rate Per Floor Area {m3/s-m2} + 1, !- Cooling Fraction of Autosized Cooling Supply Air Flow Rate + 3.9475456e-05, !- Cooling Supply Air Flow Rate Per Unit Cooling Capacity {m3/s-W} + 0.0099676501, !- Heating Supply Air Flow Rate Per Floor Area {m3/s-m2} + 1, !- Heating Fraction of Autosized Heating Supply Air Flow Rate + 1, !- Heating Fraction of Autosized Cooling Supply Air Flow Rate + 3.1588213e-05, !- Heating Supply Air Flow Rate Per Unit Heating Capacity {m3/s-W} + CoolingDesignCapacity, !- Cooling Design Capacity Method + autosize, !- Cooling Design Capacity {W} + 234.7, !- Cooling Design Capacity Per Floor Area {W/m2} + 1, !- Fraction of Autosized Cooling Design Capacity + HeatingDesignCapacity, !- Heating Design Capacity Method + autosize, !- Heating Design Capacity {W} + 157, !- Heating Design Capacity Per Floor Area {W/m2} + 1, !- Fraction of Autosized Heating Design Capacity + OnOff; !- Central Cooling Capacity Control Method + +OS:AvailabilityManagerAssignmentList, + {7f24e034-36d5-416d-8407-f5f89036c9bc}, !- Handle + Air Loop HVAC 1 AvailabilityManagerAssignmentList 2, !- Name + {3b9c4512-03cf-495c-8a48-ecba3eda1f7c}; !- Availability Manager Name 1 + +OS:Fan:ConstantVolume, + {58af866d-b578-47cd-b392-5f2586e65aa6}, !- Handle + Fan Constant Volume 3, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + 0.39975, !- Fan Total Efficiency + 640, !- Pressure Rise {Pa} + AutoSize, !- Maximum Flow Rate {m3/s} + 0.615, !- Motor Efficiency + , !- Motor In Airstream Fraction + {d3d9ad0d-40a4-469d-a46f-7b83866c5687}, !- Air Inlet Node Name + {30667c89-a419-462d-bf50-727b3ecc06b3}, !- Air Outlet Node Name + ; !- End-Use Subcategory + +OS:Curve:Biquadratic, + {c222aedf-0d89-4b0c-b02b-27994b9b0ba8}, !- Handle + Curve Biquadratic 5, !- Name + 0.867905, !- Coefficient1 Constant + 0.0142459, !- Coefficient2 x + 0.000554364, !- Coefficient3 x**2 + -0.00755748, !- Coefficient4 y + 3.3048e-05, !- Coefficient5 y**2 + -0.000191808, !- Coefficient6 x*y + 13, !- Minimum Value of x + 24, !- Maximum Value of x + 24, !- Minimum Value of y + 46; !- Maximum Value of y + +OS:Curve:Quadratic, + {b9b2686e-e008-42a2-b1d4-6c64cc68e164}, !- Handle + Curve Quadratic 6, !- Name + 1, !- Coefficient1 Constant + 0, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Curve:Biquadratic, + {ffc78e23-b1af-414a-8919-631c32aa541e}, !- Handle + Curve Biquadratic 6, !- Name + 0.116936, !- Coefficient1 Constant + 0.0284933, !- Coefficient2 x + -0.000411156, !- Coefficient3 x**2 + 0.0214108, !- Coefficient4 y + 0.000161028, !- Coefficient5 y**2 + -0.000679104, !- Coefficient6 x*y + 13, !- Minimum Value of x + 24, !- Maximum Value of x + 24, !- Minimum Value of y + 46; !- Maximum Value of y + +OS:Curve:Quadratic, + {69978a0f-d131-4fa1-ab7d-4eab3a13e2bb}, !- Handle + Curve Quadratic 7, !- Name + 1, !- Coefficient1 Constant + 0, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Curve:Cubic, + {184c6066-7cad-4fb5-82d3-8f938d5cf322}, !- Handle + Curve Cubic 2, !- Name + 0.0277, !- Coefficient1 Constant + 4.9151, !- Coefficient2 x + -8.184, !- Coefficient3 x**2 + 4.2702, !- Coefficient4 x**3 + 0.7, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Coil:Cooling:DX:SingleSpeed, + {d2f6c1aa-aa8a-419f-918b-a9ca10f768b7}, !- Handle + CoilCoolingDXSingleSpeed_dx 2 286kBtu/hr 8.39EER, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + autosize, !- Rated Total Cooling Capacity {W} + autosize, !- Rated Sensible Heat Ratio + 2.92982713155582, !- Rated COP {W/W} + autosize, !- Rated Air Flow Rate {m3/s} + 773.3, !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + {9faa61f7-782c-454c-908d-d470c539c3dd}, !- Air Inlet Node Name + {f71d8215-1965-4f75-b431-ebf67912463d}, !- Air Outlet Node Name + {929218f9-da77-4b47-9e6c-bd3b29a57431}, !- Total Cooling Capacity Function of Temperature Curve Name + {899b0ad4-b535-4c55-9247-ab9c5ad0bd61}, !- Total Cooling Capacity Function of Flow Fraction Curve Name + {e48f8ca2-64f8-435d-adb8-a86c3a81d988}, !- Energy Input Ratio Function of Temperature Curve Name + {4e181a91-d4a4-4fea-8f42-cbc11ac7dfe5}, !- Energy Input Ratio Function of Flow Fraction Curve Name + {d09eedfa-c075-4850-996a-c51a707c3fd5}, !- Part Load Fraction Correlation Curve Name + -25, !- Minimum Outdoor Dry-Bulb Temperature for Compressor Operation {C} + , !- Nominal Time for Condensate Removal to Begin {s} + , !- Ratio of Initial Moisture Evaporation Rate and Steady State Latent Capacity {dimensionless} + , !- Maximum Cycling Rate {cycles/hr} + , !- Latent Capacity Time Constant {s} + , !- Condenser Air Inlet Node Name + AirCooled, !- Condenser Type + 0, !- Evaporative Condenser Effectiveness {dimensionless} + Autosize, !- Evaporative Condenser Air Flow Rate {m3/s} + Autosize, !- Evaporative Condenser Pump Rated Power Consumption {W} + 0, !- Crankcase Heater Capacity {W} + 0, !- Maximum Outdoor Dry-Bulb Temperature for Crankcase Heater Operation {C} + , !- Supply Water Storage Tank Name + , !- Condensate Collection Water Storage Tank Name + 0, !- Basin Heater Capacity {W/K} + 10, !- Basin Heater Setpoint Temperature {C} + ; !- Basin Heater Operating Schedule Name + +OS:Coil:Heating:Electric, + {7e7d458a-7a83-4e42-ad3f-3875413fd25e}, !- Handle + Coil Heating Electric 3, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + , !- Efficiency + , !- Nominal Capacity {W} + {67cb63a6-254e-4226-a731-85d0961bda43}, !- Air Inlet Node Name + {e966d1ba-b353-4168-8bea-a9085220d23a}; !- Air Outlet Node Name + +OS:Controller:OutdoorAir, + {2fa35449-8b9b-4bfa-98c1-aeb251cd9e20}, !- Handle + Controller Outdoor Air 3, !- Name + , !- Relief Air Outlet Node Name + , !- Return Air Node Name + , !- Mixed Air Node Name + , !- Actuator Node Name + autosize, !- Minimum Outdoor Air Flow Rate {m3/s} + Autosize, !- Maximum Outdoor Air Flow Rate {m3/s} + DifferentialEnthalpy, !- Economizer Control Type + ModulateFlow, !- Economizer Control Action Type + , !- Economizer Maximum Limit Dry-Bulb Temperature {C} + , !- Economizer Maximum Limit Enthalpy {J/kg} + , !- Economizer Maximum Limit Dewpoint Temperature {C} + , !- Electronic Enthalpy Limit Curve Name + , !- Economizer Minimum Limit Dry-Bulb Temperature {C} + NoLockout, !- Lockout Type + FixedMinimum, !- Minimum Limit Type + {a935fa5d-cac9-42c2-b5bb-d0f987c5f51f}, !- Minimum Outdoor Air Schedule Name + , !- Minimum Fraction of Outdoor Air Schedule Name + , !- Maximum Fraction of Outdoor Air Schedule Name + {aad927f3-ff6e-448e-a21d-a80b3de4a266}, !- Controller Mechanical Ventilation + , !- Time of Day Economizer Control Schedule Name + No, !- High Humidity Control + , !- Humidistat Control Zone Name + , !- High Humidity Outdoor Air Flow Ratio + , !- Control High Indoor Humidity Based on Outdoor Humidity Ratio + BypassWhenWithinEconomizerLimits; !- Heat Recovery Bypass Control Type + +OS:Controller:MechanicalVentilation, + {aad927f3-ff6e-448e-a21d-a80b3de4a266}, !- Handle + Controller Mechanical Ventilation 3, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule + , !- Demand Controlled Ventilation + ZoneSum; !- System Outdoor Air Method + +OS:AirLoopHVAC:OutdoorAirSystem, + {4b24d1ea-41c8-4d3c-935c-59dfb50dfb99}, !- Handle + Air Loop HVAC Outdoor Air System 3, !- Name + {2fa35449-8b9b-4bfa-98c1-aeb251cd9e20}, !- Controller Name + , !- Outdoor Air Equipment List Name + , !- Availability Manager List Name + {9f5dca82-b104-4375-ad07-66e55bf97145}, !- Mixed Air Node Name + {5b7fd87e-05e3-42a5-a2f1-cfa84ea725c5}, !- Outdoor Air Stream Node Name + {0b248052-6ef8-43cf-a579-e735ff27be4f}, !- Relief Air Stream Node Name + {5c4b1fa8-0204-45ea-be09-03d25a4df629}; !- Return Air Stream Node Name + +OS:Node, + {bd26b05b-6ace-4320-b979-277f3960d8f2}, !- Handle + Node 33, !- Name + , !- Inlet Port + {5b7fd87e-05e3-42a5-a2f1-cfa84ea725c5}; !- Outlet Port + +OS:Connection, + {5b7fd87e-05e3-42a5-a2f1-cfa84ea725c5}, !- Handle + {bd26b05b-6ace-4320-b979-277f3960d8f2}, !- Source Object + 3, !- Outlet Port + {4b24d1ea-41c8-4d3c-935c-59dfb50dfb99}, !- Target Object + 6; !- Inlet Port + +OS:Node, + {74ff67d5-4267-4382-bd00-885ffdff6238}, !- Handle + Node 34, !- Name + {0b248052-6ef8-43cf-a579-e735ff27be4f}, !- Inlet Port + ; !- Outlet Port + +OS:Connection, + {0b248052-6ef8-43cf-a579-e735ff27be4f}, !- Handle + {4b24d1ea-41c8-4d3c-935c-59dfb50dfb99}, !- Source Object + 7, !- Outlet Port + {74ff67d5-4267-4382-bd00-885ffdff6238}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {30667c89-a419-462d-bf50-727b3ecc06b3}, !- Handle + {58af866d-b578-47cd-b392-5f2586e65aa6}, !- Source Object + 9, !- Outlet Port + {19939f15-d5dd-4ffc-97ea-e1c131d77ca3}, !- Target Object + 2; !- Inlet Port + +OS:Node, + {75247c1e-bcda-4bbc-8ccc-fb79f33ecf0e}, !- Handle + Node 35, !- Name + {e966d1ba-b353-4168-8bea-a9085220d23a}, !- Inlet Port + {d3d9ad0d-40a4-469d-a46f-7b83866c5687}; !- Outlet Port + +OS:Connection, + {e966d1ba-b353-4168-8bea-a9085220d23a}, !- Handle + {7e7d458a-7a83-4e42-ad3f-3875413fd25e}, !- Source Object + 6, !- Outlet Port + {75247c1e-bcda-4bbc-8ccc-fb79f33ecf0e}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {d3d9ad0d-40a4-469d-a46f-7b83866c5687}, !- Handle + {75247c1e-bcda-4bbc-8ccc-fb79f33ecf0e}, !- Source Object + 3, !- Outlet Port + {58af866d-b578-47cd-b392-5f2586e65aa6}, !- Target Object + 8; !- Inlet Port + +OS:Node, + {65f8427a-da0a-4aec-8f82-935d711c00ca}, !- Handle + Node 36, !- Name + {f71d8215-1965-4f75-b431-ebf67912463d}, !- Inlet Port + {67cb63a6-254e-4226-a731-85d0961bda43}; !- Outlet Port + +OS:Connection, + {f71d8215-1965-4f75-b431-ebf67912463d}, !- Handle + {d2f6c1aa-aa8a-419f-918b-a9ca10f768b7}, !- Source Object + 9, !- Outlet Port + {65f8427a-da0a-4aec-8f82-935d711c00ca}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {67cb63a6-254e-4226-a731-85d0961bda43}, !- Handle + {65f8427a-da0a-4aec-8f82-935d711c00ca}, !- Source Object + 3, !- Outlet Port + {7e7d458a-7a83-4e42-ad3f-3875413fd25e}, !- Target Object + 5; !- Inlet Port + +OS:Node, + {7a1fb99b-0653-464b-9778-a20e1261d1e8}, !- Handle + Node 37, !- Name + {9f5dca82-b104-4375-ad07-66e55bf97145}, !- Inlet Port + {9faa61f7-782c-454c-908d-d470c539c3dd}; !- Outlet Port + +OS:Connection, + {5c4b1fa8-0204-45ea-be09-03d25a4df629}, !- Handle + {ac5a0f22-fab8-4547-9293-c7449ba526c4}, !- Source Object + 3, !- Outlet Port + {4b24d1ea-41c8-4d3c-935c-59dfb50dfb99}, !- Target Object + 8; !- Inlet Port + +OS:Connection, + {9f5dca82-b104-4375-ad07-66e55bf97145}, !- Handle + {4b24d1ea-41c8-4d3c-935c-59dfb50dfb99}, !- Source Object + 5, !- Outlet Port + {7a1fb99b-0653-464b-9778-a20e1261d1e8}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {9faa61f7-782c-454c-908d-d470c539c3dd}, !- Handle + {7a1fb99b-0653-464b-9778-a20e1261d1e8}, !- Source Object + 3, !- Outlet Port + {d2f6c1aa-aa8a-419f-918b-a9ca10f768b7}, !- Target Object + 8; !- Inlet Port + +OS:SetpointManager:SingleZone:Reheat, + {72c3d931-acdb-4f7f-9398-4d9f84e6c120}, !- Handle + Setpoint Manager Single Zone Reheat 3, !- Name + 13, !- Minimum Supply Air Temperature {C} + 43, !- Maximum Supply Air Temperature {C} + {d0cebe41-1ec4-4dd7-8f92-397f53b49203}, !- Control Zone Name + {19939f15-d5dd-4ffc-97ea-e1c131d77ca3}; !- Setpoint Node or NodeList Name + +OS:ZoneHVAC:Baseboard:Convective:Electric, + {7fc13487-fb0f-4ae3-b528-a54fe34b0774}, !- Handle + Zone HVAC Baseboard Convective Electric 3, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule + autosize, !- Nominal Capacity {W} + 1; !- Efficiency + +OS:AirTerminal:SingleDuct:ConstantVolume:NoReheat, + {2f8f1143-8fa6-4274-8658-c0d05cbe24bf}, !- Handle + Air Terminal Single Duct Constant Volume No Reheat 3, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Availability Schedule Name + {20d66a40-1a6f-4d75-bc10-8b74a2a36d04}, !- Air Inlet Node Name + {48a090d4-f740-46fe-8242-5fa0b4fef610}, !- Air Outlet Node Name + AutoSize; !- Maximum Air Flow Rate {m3/s} + +OS:Node, + {65341163-5704-4e12-b65d-211af83e5a62}, !- Handle + Node 38, !- Name + {7cbf55ac-c92f-488f-a842-f86d1155d61e}, !- Inlet Port + {9a16df7b-caf3-4f57-8e77-e5396603cf6c}; !- Outlet Port + +OS:Connection, + {4771220b-498b-43c2-9092-4c9764e778cc}, !- Handle + {b1ee426e-b424-42ea-bbd5-5622b11559c2}, !- Source Object + 3, !- Outlet Port + {788c0b89-3f45-45b9-9296-81b4b51a52c4}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {7cbf55ac-c92f-488f-a842-f86d1155d61e}, !- Handle + {90da99ca-3c8f-4e0e-a140-b94921826b94}, !- Source Object + 2, !- Outlet Port + {65341163-5704-4e12-b65d-211af83e5a62}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {9a16df7b-caf3-4f57-8e77-e5396603cf6c}, !- Handle + {65341163-5704-4e12-b65d-211af83e5a62}, !- Source Object + 3, !- Outlet Port + {6e80478d-a51f-494d-b89a-ae2b94da2962}, !- Target Object + 3; !- Inlet Port + +OS:Node, + {ab9a4158-3a65-4c8f-9403-39961afc9b5f}, !- Handle + Node 39, !- Name + {f96420c7-f80c-4fd2-a133-24af36fcd4eb}, !- Inlet Port + {20d66a40-1a6f-4d75-bc10-8b74a2a36d04}; !- Outlet Port + +OS:Connection, + {f96420c7-f80c-4fd2-a133-24af36fcd4eb}, !- Handle + {9766af25-a9ba-4dc2-a339-c0650ca72bb4}, !- Source Object + 3, !- Outlet Port + {ab9a4158-3a65-4c8f-9403-39961afc9b5f}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {20d66a40-1a6f-4d75-bc10-8b74a2a36d04}, !- Handle + {ab9a4158-3a65-4c8f-9403-39961afc9b5f}, !- Source Object + 3, !- Outlet Port + {2f8f1143-8fa6-4274-8658-c0d05cbe24bf}, !- Target Object + 3; !- Inlet Port + +OS:Connection, + {48a090d4-f740-46fe-8242-5fa0b4fef610}, !- Handle + {2f8f1143-8fa6-4274-8658-c0d05cbe24bf}, !- Source Object + 4, !- Outlet Port + {b1ee426e-b424-42ea-bbd5-5622b11559c2}, !- Target Object + 2; !- Inlet Port + +OS:PlantLoop, + {472f4f79-624c-4318-b471-45e1f8e5fa82}, !- Handle + Main Service Water Loop, !- Name + , !- Fluid Type + 0, !- Glycol Concentration + , !- User Defined Fluid Type + , !- Plant Equipment Operation Heating Load + , !- Plant Equipment Operation Cooling Load + , !- Primary Plant Equipment Operation Scheme + {312b91f5-4988-4380-bf42-53472f483776}, !- Loop Temperature Setpoint Node Name + 60, !- Maximum Loop Temperature {C} + 10, !- Minimum Loop Temperature {C} + , !- Maximum Loop Flow Rate {m3/s} + , !- Minimum Loop Flow Rate {m3/s} + Autocalculate, !- Plant Loop Volume {m3} + {8a9cb5e3-9b1b-4a5d-aa1e-e078f65fd5ab}, !- Plant Side Inlet Node Name + {373045e7-525d-44a5-82a6-480350933f1e}, !- Plant Side Outlet Node Name + , !- Plant Side Branch List Name + {5dc2e495-c1fd-4213-b11a-38b52293c2b4}, !- Demand Side Inlet Node Name + {04e76864-4069-4047-aa86-d9cda30fbeca}, !- Demand Side Outlet Node Name + , !- Demand Side Branch List Name + , !- Demand Side Connector List Name + Optimal, !- Load Distribution Scheme + {b5e96dac-08a1-414e-859f-0aeb3ef7c479}, !- Availability Manager List Name + , !- Plant Loop Demand Calculation Scheme + , !- Common Pipe Simulation + , !- Pressure Simulation Type + , !- Plant Equipment Operation Heating Load Schedule + , !- Plant Equipment Operation Cooling Load Schedule + , !- Primary Plant Equipment Operation Scheme Schedule + , !- Component Setpoint Operation Scheme Schedule + {2abc158b-9ccf-4480-acfa-088f4fd6ed33}, !- Demand Mixer Name + {1cbf3689-9a0a-4401-816c-b9cd532b2f23}, !- Demand Splitter Name + {a63bbd64-3a70-40ce-9057-9eade43cbb4c}, !- Supply Mixer Name + {94c49223-c3b4-47a6-a2da-5df2165f4676}; !- Supply Splitter Name + +OS:Node, + {bc7799f7-4337-4443-8820-5e1d44151dd1}, !- Handle + Node 40, !- Name + {8a9cb5e3-9b1b-4a5d-aa1e-e078f65fd5ab}, !- Inlet Port + {9bb3979e-26e4-45eb-bcd7-6f9675a85281}; !- Outlet Port + +OS:Node, + {312b91f5-4988-4380-bf42-53472f483776}, !- Handle + Node 41, !- Name + {c3a1d573-99a8-41bd-931d-fcb2ba4c5001}, !- Inlet Port + {373045e7-525d-44a5-82a6-480350933f1e}; !- Outlet Port + +OS:Node, + {8e9c605c-c1b3-4883-a243-cec2ae444eec}, !- Handle + Node 42, !- Name + {a943c2fb-728e-4dff-8886-691f86374741}, !- Inlet Port + {bc983309-9a13-4e6c-96df-d032ed99e843}; !- Outlet Port + +OS:Connector:Mixer, + {a63bbd64-3a70-40ce-9057-9eade43cbb4c}, !- Handle + Connector Mixer 1, !- Name + {428e5d17-be19-4ba3-bfea-feecc8e4524d}, !- Outlet Branch Name + {9ae5345b-a46f-4095-899d-42b8341027b8}, !- Inlet Branch Name 1 + {9d1d63d1-2730-4340-89c8-25efb5d6bb95}; !- Inlet Branch Name 2 + +OS:Connector:Splitter, + {94c49223-c3b4-47a6-a2da-5df2165f4676}, !- Handle + Connector Splitter 1, !- Name + {4520adb5-63b9-41f1-9ce7-5481d15751bd}, !- Inlet Branch Name + {a943c2fb-728e-4dff-8886-691f86374741}, !- Outlet Branch Name 1 + {98ce9039-6658-496d-b4c5-4b44e9344a92}; !- Outlet Branch Name 2 + +OS:Connection, + {8a9cb5e3-9b1b-4a5d-aa1e-e078f65fd5ab}, !- Handle + {472f4f79-624c-4318-b471-45e1f8e5fa82}, !- Source Object + 14, !- Outlet Port + {bc7799f7-4337-4443-8820-5e1d44151dd1}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {a943c2fb-728e-4dff-8886-691f86374741}, !- Handle + {94c49223-c3b4-47a6-a2da-5df2165f4676}, !- Source Object + 3, !- Outlet Port + {8e9c605c-c1b3-4883-a243-cec2ae444eec}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {373045e7-525d-44a5-82a6-480350933f1e}, !- Handle + {312b91f5-4988-4380-bf42-53472f483776}, !- Source Object + 3, !- Outlet Port + {472f4f79-624c-4318-b471-45e1f8e5fa82}, !- Target Object + 15; !- Inlet Port + +OS:Node, + {c328fc24-35a9-4a6a-9da2-2ec8082cfe8d}, !- Handle + Node 43, !- Name + {5dc2e495-c1fd-4213-b11a-38b52293c2b4}, !- Inlet Port + {8841b045-7f9b-47e3-bbba-d3594276ed3e}; !- Outlet Port + +OS:Node, + {2ecfc202-130b-449e-9c68-a73d69451c04}, !- Handle + Node 44, !- Name + {fc3a7f56-1a2e-4309-b6b1-aba9df2cc307}, !- Inlet Port + {04e76864-4069-4047-aa86-d9cda30fbeca}; !- Outlet Port + +OS:Node, + {67a6c054-4175-4fd0-8638-7de704a3eaf0}, !- Handle + Node 45, !- Name + {e657be29-9d9b-410b-961a-40da74eca5b4}, !- Inlet Port + {6ee0b4c1-945d-4d45-ab63-4a72941af000}; !- Outlet Port + +OS:Connector:Mixer, + {2abc158b-9ccf-4480-acfa-088f4fd6ed33}, !- Handle + Connector Mixer 2, !- Name + {b3a9cb4d-5930-4866-a71f-4870b8edf018}, !- Outlet Branch Name + {dfbdbdb9-1e82-4234-913c-ea87f9f875bf}, !- Inlet Branch Name 1 + {a5d8f544-aaf8-475a-9c40-ad394a012014}, !- Inlet Branch Name 2 + {da654eb8-7498-4a03-87fb-4e8898622e64}, !- Inlet Branch Name 3 + {5666fa05-fd75-45ed-b4d4-8b5d6eea0ce7}; !- Inlet Branch Name 4 + +OS:Connector:Splitter, + {1cbf3689-9a0a-4401-816c-b9cd532b2f23}, !- Handle + Connector Splitter 2, !- Name + {8841b045-7f9b-47e3-bbba-d3594276ed3e}, !- Inlet Branch Name + {e657be29-9d9b-410b-961a-40da74eca5b4}, !- Outlet Branch Name 1 + {1344096d-be88-49c0-9e9b-255afa0c1391}, !- Outlet Branch Name 2 + {93589422-d1f8-4277-879e-56de51fdb42d}, !- Outlet Branch Name 3 + {7e487df5-261a-43bb-b3cc-bd36706fb84e}; !- Outlet Branch Name 4 + +OS:Connection, + {5dc2e495-c1fd-4213-b11a-38b52293c2b4}, !- Handle + {472f4f79-624c-4318-b471-45e1f8e5fa82}, !- Source Object + 17, !- Outlet Port + {c328fc24-35a9-4a6a-9da2-2ec8082cfe8d}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {8841b045-7f9b-47e3-bbba-d3594276ed3e}, !- Handle + {c328fc24-35a9-4a6a-9da2-2ec8082cfe8d}, !- Source Object + 3, !- Outlet Port + {1cbf3689-9a0a-4401-816c-b9cd532b2f23}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {e657be29-9d9b-410b-961a-40da74eca5b4}, !- Handle + {1cbf3689-9a0a-4401-816c-b9cd532b2f23}, !- Source Object + 3, !- Outlet Port + {67a6c054-4175-4fd0-8638-7de704a3eaf0}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {04e76864-4069-4047-aa86-d9cda30fbeca}, !- Handle + {2ecfc202-130b-449e-9c68-a73d69451c04}, !- Source Object + 3, !- Outlet Port + {472f4f79-624c-4318-b471-45e1f8e5fa82}, !- Target Object + 18; !- Inlet Port + +OS:Sizing:Plant, + {9cb0ce63-d9cb-4845-a12b-d37487277d92}, !- Handle + {472f4f79-624c-4318-b471-45e1f8e5fa82}, !- Plant or Condenser Loop Name + Heating, !- Loop Type + 60, !- Design Loop Exit Temperature {C} + 5, !- Loop Design Temperature Difference {deltaC} + NonCoincident, !- Sizing Option + 1, !- Zone Timesteps in Averaging Window + None; !- Coincident Sizing Factor Mode + +OS:AvailabilityManagerAssignmentList, + {b5e96dac-08a1-414e-859f-0aeb3ef7c479}, !- Handle + Plant Loop 1 AvailabilityManagerAssignmentList; !- Name + +OS:ScheduleTypeLimits, + {97367fda-80d1-4945-9e89-6689116a5c91}, !- Handle + Temperature Schedule Type Limits, !- Name + 0, !- Lower Limit Value + 100, !- Upper Limit Value + Continuous, !- Numeric Type + Temperature; !- Unit Type + +OS:Schedule:Ruleset, + {23a7bcc6-2918-4b8b-8b40-8204f15dc50b}, !- Handle + Service Water Loop Temp - 140F, !- Name + {97367fda-80d1-4945-9e89-6689116a5c91}, !- Schedule Type Limits Name + {da369f25-74a8-4829-add0-8e64c47a84f3}; !- Default Day Schedule Name + +OS:Schedule:Day, + {da369f25-74a8-4829-add0-8e64c47a84f3}, !- Handle + Service Water Loop Temp - 140F Default, !- Name + {97367fda-80d1-4945-9e89-6689116a5c91}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 60; !- Value Until Time 1 + +OS:SetpointManager:Scheduled, + {81aee33d-1d58-4675-a569-a8cbc1e4a6e7}, !- Handle + Service hot water setpoint manager, !- Name + Temperature, !- Control Variable + {23a7bcc6-2918-4b8b-8b40-8204f15dc50b}, !- Schedule Name + {312b91f5-4988-4380-bf42-53472f483776}; !- Setpoint Node or NodeList Name + +OS:Pump:ConstantSpeed, + {a4ce4ec3-9b38-40e3-a913-596b2d849949}, !- Handle + Main Service Water Loop Circulator Pump, !- Name + {9bb3979e-26e4-45eb-bcd7-6f9675a85281}, !- Inlet Node Name + {3ab960b3-3967-42b9-9822-781fe35cec43}, !- Outlet Node Name + autosize, !- Rated Flow Rate {m3/s} + 5452.20885045363, !- Rated Pump Head {Pa} + autosize, !- Rated Power Consumption {W} + 0.7, !- Motor Efficiency + 0, !- Fraction of Motor Inefficiencies to Fluid Stream + Intermittent, !- Pump Control Type + , !- Pump Flow Rate Schedule + , !- Pump Curve + , !- Impeller Diameter {m} + , !- Rotational Speed {rev/min} + , !- Zone + , !- Skin Loss Radiative Fraction + PowerPerFlowPerPressure, !- Design Power Sizing Method + 348701.1, !- Design Electric Power per Unit Flow Rate {W/(m3/s)} + 1.282051282, !- Design Shaft Power per Unit Flow Rate per Unit Head {W-s/m3-Pa} + General; !- End-Use Subcategory + +OS:Node, + {ac85a420-495f-451a-b388-4e2c538a0d65}, !- Handle + Node 46, !- Name + {3ab960b3-3967-42b9-9822-781fe35cec43}, !- Inlet Port + {4520adb5-63b9-41f1-9ce7-5481d15751bd}; !- Outlet Port + +OS:Connection, + {9bb3979e-26e4-45eb-bcd7-6f9675a85281}, !- Handle + {bc7799f7-4337-4443-8820-5e1d44151dd1}, !- Source Object + 3, !- Outlet Port + {a4ce4ec3-9b38-40e3-a913-596b2d849949}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {3ab960b3-3967-42b9-9822-781fe35cec43}, !- Handle + {a4ce4ec3-9b38-40e3-a913-596b2d849949}, !- Source Object + 3, !- Outlet Port + {ac85a420-495f-451a-b388-4e2c538a0d65}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {4520adb5-63b9-41f1-9ce7-5481d15751bd}, !- Handle + {ac85a420-495f-451a-b388-4e2c538a0d65}, !- Source Object + 3, !- Outlet Port + {94c49223-c3b4-47a6-a2da-5df2165f4676}, !- Target Object + 2; !- Inlet Port + +OS:ScheduleTypeLimits, + {197a388b-f54b-4c81-858f-e186b7c5aecc}, !- Handle + Temperature Schedule Type Limits 1, !- Name + 0, !- Lower Limit Value + 100, !- Upper Limit Value + Continuous, !- Numeric Type + Temperature; !- Unit Type + +OS:WaterHeater:Mixed, + {b803e992-5ddb-4ffa-b816-2f5a8d5c7597}, !- Handle + 28gal Electricity Water Heater - 19kBtu/hr 1 Therm Eff, !- Name + 0.105773176025519, !- Tank Volume {m3} + {23a7bcc6-2918-4b8b-8b40-8204f15dc50b}, !- Setpoint Temperature Schedule Name + 2, !- Deadband Temperature Difference {deltaC} + 60, !- Maximum Temperature Limit {C} + Cycle, !- Heater Control Type + 5526.64844733339, !- Heater Maximum Capacity {W} + , !- Heater Minimum Capacity {W} + , !- Heater Ignition Minimum Flow Rate {m3/s} + , !- Heater Ignition Delay {s} + Electricity, !- Heater Fuel Type + 1, !- Heater Thermal Efficiency + , !- Part Load Factor Curve Name + 21.6672081859205, !- Off Cycle Parasitic Fuel Consumption Rate {W} + Electricity, !- Off Cycle Parasitic Fuel Type + 0.8, !- Off Cycle Parasitic Heat Fraction to Tank + 21.6672081859205, !- On Cycle Parasitic Fuel Consumption Rate {W} + Electricity, !- On Cycle Parasitic Fuel Type + 0, !- On Cycle Parasitic Heat Fraction to Tank + Schedule, !- Ambient Temperature Indicator + {a8a42771-203d-4de8-961c-df0333d45299}, !- Ambient Temperature Schedule Name + , !- Ambient Temperature Thermal Zone Name + , !- Ambient Temperature Outdoor Air Node Name + 1.57254776241695, !- Off Cycle Loss Coefficient to Ambient Temperature {W/K} + , !- Off Cycle Loss Fraction to Thermal Zone + 1.57254776241695, !- On Cycle Loss Coefficient to Ambient Temperature {W/K} + , !- On Cycle Loss Fraction to Thermal Zone + , !- Peak Use Flow Rate {m3/s} + , !- Use Flow Rate Fraction Schedule Name + , !- Cold Water Supply Temperature Schedule Name + {bc983309-9a13-4e6c-96df-d032ed99e843}, !- Use Side Inlet Node Name + {5a30077e-7a6f-4338-969a-4e232501a43c}, !- Use Side Outlet Node Name + 1, !- Use Side Effectiveness + , !- Source Side Inlet Node Name + , !- Source Side Outlet Node Name + 1, !- Source Side Effectiveness + autosize, !- Use Side Design Flow Rate {m3/s} + autosize, !- Source Side Design Flow Rate {m3/s} + 1.5, !- Indirect Water Heating Recovery Time {hr} + IndirectHeatPrimarySetpoint, !- Source Side Flow Control Mode + , !- Indirect Alternate Setpoint Temperature Schedule Name + General; !- End-Use Subcategory + +OS:Schedule:Ruleset, + {924996d9-2841-4916-ab16-53a66ca02a67}, !- Handle + Schedule Ruleset 1, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + {cd293252-e443-483b-8383-2762c88924a3}; !- Default Day Schedule Name + +OS:Schedule:Day, + {cd293252-e443-483b-8383-2762c88924a3}, !- Handle + Schedule Day 3, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 22; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {04312de4-4681-48fe-902f-5d8684bcea5d}, !- Handle + Schedule Ruleset 2, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + {61d1cb3b-a35c-4a25-9a69-2fc591a5df3a}; !- Default Day Schedule Name + +OS:Schedule:Day, + {61d1cb3b-a35c-4a25-9a69-2fc591a5df3a}, !- Handle + Schedule Day 4, !- Name + {e12d4be5-1748-48a8-9d46-f43b012405de}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 60; !- Value Until Time 1 + +OS:WaterHeater:Sizing, + {58232101-61d1-402b-bf54-ae0fdf927c48}, !- Handle + {b803e992-5ddb-4ffa-b816-2f5a8d5c7597}, !- WaterHeater Name + PeakDraw, !- Design Mode + 0.538503, !- Time Storage Can Meet Peak Draw {hr} + 0, !- Time for Tank Recovery {hr} + 1; !- Nominal Tank Volume for Autosizing Plant Connections {m3} + +OS:Schedule:Ruleset, + {a8a42771-203d-4de8-961c-df0333d45299}, !- Handle + Water Heater Ambient Temp Schedule - 70.0f, !- Name + {197a388b-f54b-4c81-858f-e186b7c5aecc}, !- Schedule Type Limits Name + {c0ee1f72-ba15-44de-9a24-a5cd1340c9d6}; !- Default Day Schedule Name + +OS:Schedule:Day, + {c0ee1f72-ba15-44de-9a24-a5cd1340c9d6}, !- Handle + Water Heater Ambient Temp Schedule - 70.0f Default, !- Name + {197a388b-f54b-4c81-858f-e186b7c5aecc}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 21.1111111111111; !- Value Until Time 1 + +OS:Node, + {33845817-5747-4d70-ab06-5a97d7bb22c2}, !- Handle + Node 47, !- Name + {5a30077e-7a6f-4338-969a-4e232501a43c}, !- Inlet Port + {9ae5345b-a46f-4095-899d-42b8341027b8}; !- Outlet Port + +OS:Connection, + {bc983309-9a13-4e6c-96df-d032ed99e843}, !- Handle + {8e9c605c-c1b3-4883-a243-cec2ae444eec}, !- Source Object + 3, !- Outlet Port + {b803e992-5ddb-4ffa-b816-2f5a8d5c7597}, !- Target Object + 31; !- Inlet Port + +OS:Connection, + {5a30077e-7a6f-4338-969a-4e232501a43c}, !- Handle + {b803e992-5ddb-4ffa-b816-2f5a8d5c7597}, !- Source Object + 32, !- Outlet Port + {33845817-5747-4d70-ab06-5a97d7bb22c2}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {9ae5345b-a46f-4095-899d-42b8341027b8}, !- Handle + {33845817-5747-4d70-ab06-5a97d7bb22c2}, !- Source Object + 3, !- Outlet Port + {a63bbd64-3a70-40ce-9057-9eade43cbb4c}, !- Target Object + 3; !- Inlet Port + +OS:Pipe:Adiabatic, + {d9e2ce71-ee87-4312-b82a-20a8430a3baf}, !- Handle + Pipe Adiabatic 1, !- Name + {4becde1b-7ae9-4662-b618-10548164b905}, !- Inlet Node Name + {cc71ac68-1b93-4d0f-a8ef-602dab0ae483}; !- Outlet Node Name + +OS:Node, + {a80bcb85-3211-497f-9d40-ff0df2e29438}, !- Handle + Node 48, !- Name + {98ce9039-6658-496d-b4c5-4b44e9344a92}, !- Inlet Port + {4becde1b-7ae9-4662-b618-10548164b905}; !- Outlet Port + +OS:Connection, + {98ce9039-6658-496d-b4c5-4b44e9344a92}, !- Handle + {94c49223-c3b4-47a6-a2da-5df2165f4676}, !- Source Object + 4, !- Outlet Port + {a80bcb85-3211-497f-9d40-ff0df2e29438}, !- Target Object + 2; !- Inlet Port + +OS:Node, + {d6d865f6-a814-4915-bc55-2f7e20622b9d}, !- Handle + Node 49, !- Name + {cc71ac68-1b93-4d0f-a8ef-602dab0ae483}, !- Inlet Port + {9d1d63d1-2730-4340-89c8-25efb5d6bb95}; !- Outlet Port + +OS:Connection, + {4becde1b-7ae9-4662-b618-10548164b905}, !- Handle + {a80bcb85-3211-497f-9d40-ff0df2e29438}, !- Source Object + 3, !- Outlet Port + {d9e2ce71-ee87-4312-b82a-20a8430a3baf}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {cc71ac68-1b93-4d0f-a8ef-602dab0ae483}, !- Handle + {d9e2ce71-ee87-4312-b82a-20a8430a3baf}, !- Source Object + 3, !- Outlet Port + {d6d865f6-a814-4915-bc55-2f7e20622b9d}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {9d1d63d1-2730-4340-89c8-25efb5d6bb95}, !- Handle + {d6d865f6-a814-4915-bc55-2f7e20622b9d}, !- Source Object + 3, !- Outlet Port + {a63bbd64-3a70-40ce-9057-9eade43cbb4c}, !- Target Object + 4; !- Inlet Port + +OS:Pipe:Adiabatic, + {3d1c354e-01b2-4844-b38b-6ddaef9af829}, !- Handle + Pipe Adiabatic 2, !- Name + {6ee0b4c1-945d-4d45-ab63-4a72941af000}, !- Inlet Node Name + {2554d1a0-aaa1-4d02-ad5f-02b76983778e}; !- Outlet Node Name + +OS:Node, + {2620778c-7235-48e9-abb3-8e48cfda50c6}, !- Handle + Node 50, !- Name + {2554d1a0-aaa1-4d02-ad5f-02b76983778e}, !- Inlet Port + {dfbdbdb9-1e82-4234-913c-ea87f9f875bf}; !- Outlet Port + +OS:Connection, + {6ee0b4c1-945d-4d45-ab63-4a72941af000}, !- Handle + {67a6c054-4175-4fd0-8638-7de704a3eaf0}, !- Source Object + 3, !- Outlet Port + {3d1c354e-01b2-4844-b38b-6ddaef9af829}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {2554d1a0-aaa1-4d02-ad5f-02b76983778e}, !- Handle + {3d1c354e-01b2-4844-b38b-6ddaef9af829}, !- Source Object + 3, !- Outlet Port + {2620778c-7235-48e9-abb3-8e48cfda50c6}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {dfbdbdb9-1e82-4234-913c-ea87f9f875bf}, !- Handle + {2620778c-7235-48e9-abb3-8e48cfda50c6}, !- Source Object + 3, !- Outlet Port + {2abc158b-9ccf-4480-acfa-088f4fd6ed33}, !- Target Object + 3; !- Inlet Port + +OS:Pipe:Adiabatic, + {9c1dac13-a2e7-493a-a801-66db4a8bcfa5}, !- Handle + Pipe Adiabatic 3, !- Name + {7bde0a47-fda0-49a5-8c95-2f4b2e5674e0}, !- Inlet Node Name + {c3a1d573-99a8-41bd-931d-fcb2ba4c5001}; !- Outlet Node Name + +OS:Node, + {1cc01aa0-8dbc-4d11-9f33-9cedf7a7a2e2}, !- Handle + Node 51, !- Name + {428e5d17-be19-4ba3-bfea-feecc8e4524d}, !- Inlet Port + {7bde0a47-fda0-49a5-8c95-2f4b2e5674e0}; !- Outlet Port + +OS:Connection, + {428e5d17-be19-4ba3-bfea-feecc8e4524d}, !- Handle + {a63bbd64-3a70-40ce-9057-9eade43cbb4c}, !- Source Object + 2, !- Outlet Port + {1cc01aa0-8dbc-4d11-9f33-9cedf7a7a2e2}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {7bde0a47-fda0-49a5-8c95-2f4b2e5674e0}, !- Handle + {1cc01aa0-8dbc-4d11-9f33-9cedf7a7a2e2}, !- Source Object + 3, !- Outlet Port + {9c1dac13-a2e7-493a-a801-66db4a8bcfa5}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {c3a1d573-99a8-41bd-931d-fcb2ba4c5001}, !- Handle + {9c1dac13-a2e7-493a-a801-66db4a8bcfa5}, !- Source Object + 3, !- Outlet Port + {312b91f5-4988-4380-bf42-53472f483776}, !- Target Object + 2; !- Inlet Port + +OS:Pipe:Adiabatic, + {9e181288-c86f-4fe8-b6e7-fbb41d62aa99}, !- Handle + Pipe Adiabatic 4, !- Name + {9d4cbc69-8b84-4ba9-8c4f-eb80153b5a79}, !- Inlet Node Name + {fc3a7f56-1a2e-4309-b6b1-aba9df2cc307}; !- Outlet Node Name + +OS:Node, + {fef9dfef-250d-4d86-9d17-2c708227643c}, !- Handle + Node 52, !- Name + {b3a9cb4d-5930-4866-a71f-4870b8edf018}, !- Inlet Port + {9d4cbc69-8b84-4ba9-8c4f-eb80153b5a79}; !- Outlet Port + +OS:Connection, + {b3a9cb4d-5930-4866-a71f-4870b8edf018}, !- Handle + {2abc158b-9ccf-4480-acfa-088f4fd6ed33}, !- Source Object + 2, !- Outlet Port + {fef9dfef-250d-4d86-9d17-2c708227643c}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {9d4cbc69-8b84-4ba9-8c4f-eb80153b5a79}, !- Handle + {fef9dfef-250d-4d86-9d17-2c708227643c}, !- Source Object + 3, !- Outlet Port + {9e181288-c86f-4fe8-b6e7-fbb41d62aa99}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {fc3a7f56-1a2e-4309-b6b1-aba9df2cc307}, !- Handle + {9e181288-c86f-4fe8-b6e7-fbb41d62aa99}, !- Source Object + 3, !- Outlet Port + {2ecfc202-130b-449e-9c68-a73d69451c04}, !- Target Object + 2; !- Inlet Port + +OS:WaterUse:Connections, + {e664687a-30c9-45c9-97cf-09fc49c1e5f9}, !- Handle + Water Use Connections 1, !- Name + {d6b380b7-f06f-4927-b17a-bdf4bcd5127e}, !- Inlet Node Name + {14bc7965-d0db-4f49-bc2b-7ab8d4123223}, !- Outlet Node Name + , !- Supply Water Storage Tank Name + , !- Reclamation Water Storage Tank Name + , !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + None, !- Drain Water Heat Exchanger Type + Plant, !- Drain Water Heat Exchanger Destination + , !- Drain Water Heat Exchanger U-Factor Times Area {W/K} + {45d571ce-b03c-4ebb-a5e3-616470bdb5f3}; !- Water Use Equipment Name 1 + +OS:WaterUse:Equipment:Definition, + {a2766800-0f38-4c74-8691-6b13bc420555}, !- Handle + Zone1 office Service Water Use Def 0.09gal/min, !- Name + , !- End-Use Subcategory + 5.73409412398431e-06, !- Peak Flow Rate {m3/s} + {b10dfdc7-5516-44ce-b8d6-02022f0ed62b}, !- Target Temperature Schedule Name + {3fef956a-4e57-40b5-8cc4-b4f7d55a4f3d}, !- Sensible Fraction Schedule Name + {f98060af-46bf-4164-9bf9-11937167abae}; !- Latent Fraction Schedule Name + +OS:Schedule:Ruleset, + {3fef956a-4e57-40b5-8cc4-b4f7d55a4f3d}, !- Handle + Schedule Ruleset 3, !- Name + , !- Schedule Type Limits Name + {289947ba-1122-46ee-8a5e-56a9813e4742}; !- Default Day Schedule Name + +OS:Schedule:Day, + {289947ba-1122-46ee-8a5e-56a9813e4742}, !- Handle + Schedule Day 5, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.2; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {f98060af-46bf-4164-9bf9-11937167abae}, !- Handle + Schedule Ruleset 4, !- Name + , !- Schedule Type Limits Name + {decb6503-4c58-4555-b185-a98ab3098dff}; !- Default Day Schedule Name + +OS:Schedule:Day, + {decb6503-4c58-4555-b185-a98ab3098dff}, !- Handle + Schedule Day 6, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.05; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {b10dfdc7-5516-44ce-b8d6-02022f0ed62b}, !- Handle + Schedule Ruleset 5, !- Name + , !- Schedule Type Limits Name + {c664aa03-39ff-4922-ad87-b82507afd13a}; !- Default Day Schedule Name + +OS:Schedule:Day, + {c664aa03-39ff-4922-ad87-b82507afd13a}, !- Handle + Schedule Day 7, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 60; !- Value Until Time 1 + +OS:WaterUse:Equipment, + {45d571ce-b03c-4ebb-a5e3-616470bdb5f3}, !- Handle + Zone1 office Service Water Use 0.09gal/min, !- Name + {a2766800-0f38-4c74-8691-6b13bc420555}, !- Water Use Equipment Definition Name + {12c3d4a0-20ec-4e1f-8040-e70cdfba4a69}, !- Space Name + {a6ac21e9-5670-4b9f-a31b-383b6b401f2f}; !- Flow Rate Fraction Schedule Name + +OS:Schedule:Ruleset, + {a6ac21e9-5670-4b9f-a31b-383b6b401f2f}, !- Handle + NECB-A-Service Water Heating, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + {12701f25-95e4-471e-85e6-830f46bf10a1}; !- Default Day Schedule Name + +OS:Schedule:Day, + {12701f25-95e4-471e-85e6-830f46bf10a1}, !- Handle + NECB-A-Service Water Heating Default, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 7, !- Hour 1 + 0, !- Minute 1 + 0.05, !- Value Until Time 1 + 8, !- Hour 2 + 0, !- Minute 2 + 0.1, !- Value Until Time 2 + 10, !- Hour 3 + 0, !- Minute 3 + 0.5, !- Value Until Time 3 + 16, !- Hour 4 + 0, !- Minute 4 + 0.9, !- Value Until Time 4 + 17, !- Hour 5 + 0, !- Minute 5 + 0.7, !- Value Until Time 5 + 18, !- Hour 6 + 0, !- Minute 6 + 0.5, !- Value Until Time 6 + 19, !- Hour 7 + 0, !- Minute 7 + 0.3, !- Value Until Time 7 + 22, !- Hour 8 + 0, !- Minute 8 + 0.2, !- Value Until Time 8 + 24, !- Hour 9 + 0, !- Minute 9 + 0.05; !- Value Until Time 9 + +OS:Schedule:Rule, + {d9792c64-38f6-48b5-befe-aecb5f46bf17}, !- Handle + Schedule Rule 17, !- Name + {a6ac21e9-5670-4b9f-a31b-383b6b401f2f}, !- Schedule Ruleset Name + 2, !- Rule Order + {50c3ab5c-b6f6-49be-93df-eebfabba6c43}, !- Day Schedule Name + , !- Apply Sunday + Yes, !- Apply Monday + Yes, !- Apply Tuesday + Yes, !- Apply Wednesday + Yes, !- Apply Thursday + Yes, !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {50c3ab5c-b6f6-49be-93df-eebfabba6c43}, !- Handle + NECB-A-Service Water Heating Default|Wkdy Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 7, !- Hour 1 + 0, !- Minute 1 + 0.05, !- Value Until Time 1 + 8, !- Hour 2 + 0, !- Minute 2 + 0.1, !- Value Until Time 2 + 10, !- Hour 3 + 0, !- Minute 3 + 0.5, !- Value Until Time 3 + 16, !- Hour 4 + 0, !- Minute 4 + 0.9, !- Value Until Time 4 + 17, !- Hour 5 + 0, !- Minute 5 + 0.7, !- Value Until Time 5 + 18, !- Hour 6 + 0, !- Minute 6 + 0.5, !- Value Until Time 6 + 19, !- Hour 7 + 0, !- Minute 7 + 0.3, !- Value Until Time 7 + 22, !- Hour 8 + 0, !- Minute 8 + 0.2, !- Value Until Time 8 + 24, !- Hour 9 + 0, !- Minute 9 + 0.05; !- Value Until Time 9 + +OS:Schedule:Rule, + {dbc44e9a-4421-415a-ad17-5907561f528e}, !- Handle + Schedule Rule 18, !- Name + {a6ac21e9-5670-4b9f-a31b-383b6b401f2f}, !- Schedule Ruleset Name + 1, !- Rule Order + {f96fa142-43e5-486a-b067-f91c493ba558}, !- Day Schedule Name + , !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + Yes, !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {f96fa142-43e5-486a-b067-f91c493ba558}, !- Handle + NECB-A-Service Water Heating Sat Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.05; !- Value Until Time 1 + +OS:Schedule:Rule, + {ffa27cd1-685c-47e7-b4f8-f1b560050462}, !- Handle + Schedule Rule 19, !- Name + {a6ac21e9-5670-4b9f-a31b-383b6b401f2f}, !- Schedule Ruleset Name + 0, !- Rule Order + {d2573d88-8742-4ad2-97b9-5f250d000ea3}, !- Day Schedule Name + Yes, !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + , !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {d2573d88-8742-4ad2-97b9-5f250d000ea3}, !- Handle + NECB-A-Service Water Heating Sun|Hol Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.05; !- Value Until Time 1 + +OS:Node, + {ed323b20-04cf-4319-b095-4f71155ef091}, !- Handle + Node 53, !- Name + {1344096d-be88-49c0-9e9b-255afa0c1391}, !- Inlet Port + {d6b380b7-f06f-4927-b17a-bdf4bcd5127e}; !- Outlet Port + +OS:Connection, + {1344096d-be88-49c0-9e9b-255afa0c1391}, !- Handle + {1cbf3689-9a0a-4401-816c-b9cd532b2f23}, !- Source Object + 4, !- Outlet Port + {ed323b20-04cf-4319-b095-4f71155ef091}, !- Target Object + 2; !- Inlet Port + +OS:Node, + {a0f9ca88-25b0-4e59-a3e4-b43aba0bff41}, !- Handle + Node 54, !- Name + {14bc7965-d0db-4f49-bc2b-7ab8d4123223}, !- Inlet Port + {a5d8f544-aaf8-475a-9c40-ad394a012014}; !- Outlet Port + +OS:Connection, + {d6b380b7-f06f-4927-b17a-bdf4bcd5127e}, !- Handle + {ed323b20-04cf-4319-b095-4f71155ef091}, !- Source Object + 3, !- Outlet Port + {e664687a-30c9-45c9-97cf-09fc49c1e5f9}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {14bc7965-d0db-4f49-bc2b-7ab8d4123223}, !- Handle + {e664687a-30c9-45c9-97cf-09fc49c1e5f9}, !- Source Object + 3, !- Outlet Port + {a0f9ca88-25b0-4e59-a3e4-b43aba0bff41}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {a5d8f544-aaf8-475a-9c40-ad394a012014}, !- Handle + {a0f9ca88-25b0-4e59-a3e4-b43aba0bff41}, !- Source Object + 3, !- Outlet Port + {2abc158b-9ccf-4480-acfa-088f4fd6ed33}, !- Target Object + 4; !- Inlet Port + +OS:WaterUse:Connections, + {722d19c4-9d7a-4b51-b434-0c32ddebbcb6}, !- Handle + Water Use Connections 2, !- Name + {0a810edf-8336-4a00-b8c7-1517b33ecaf3}, !- Inlet Node Name + {bb4465df-d0af-4bf7-aef2-d30660038cbc}, !- Outlet Node Name + , !- Supply Water Storage Tank Name + , !- Reclamation Water Storage Tank Name + , !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + None, !- Drain Water Heat Exchanger Type + Plant, !- Drain Water Heat Exchanger Destination + , !- Drain Water Heat Exchanger U-Factor Times Area {W/K} + {798e1b89-28ec-4c65-bb76-00c1c431565c}; !- Water Use Equipment Name 1 + +OS:WaterUse:Equipment:Definition, + {5b58a932-4078-4641-8287-48bdafd3ffa4}, !- Handle + Zone2 fine storage Service Water Use Def 0.15gal/min, !- Name + , !- End-Use Subcategory + 9.75642040105023e-06, !- Peak Flow Rate {m3/s} + {e7891429-12cb-4a93-b940-ef93234e8e24}, !- Target Temperature Schedule Name + {6f12b0ec-6e7d-4eaa-8319-901e32bff40b}, !- Sensible Fraction Schedule Name + {2742c7b8-4e4f-41ed-a55c-0bcc18eebcae}; !- Latent Fraction Schedule Name + +OS:Schedule:Ruleset, + {6f12b0ec-6e7d-4eaa-8319-901e32bff40b}, !- Handle + Schedule Ruleset 6, !- Name + , !- Schedule Type Limits Name + {b04ba4a5-e1b7-455b-ae86-bc4cf1b384f1}; !- Default Day Schedule Name + +OS:Schedule:Day, + {b04ba4a5-e1b7-455b-ae86-bc4cf1b384f1}, !- Handle + Schedule Day 8, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.2; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {2742c7b8-4e4f-41ed-a55c-0bcc18eebcae}, !- Handle + Schedule Ruleset 7, !- Name + , !- Schedule Type Limits Name + {f52cbd08-1393-410f-9bb5-935442a7923b}; !- Default Day Schedule Name + +OS:Schedule:Day, + {f52cbd08-1393-410f-9bb5-935442a7923b}, !- Handle + Schedule Day 9, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.05; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {e7891429-12cb-4a93-b940-ef93234e8e24}, !- Handle + Schedule Ruleset 8, !- Name + , !- Schedule Type Limits Name + {d5b0a110-d648-4def-82aa-76c2e6d650f3}; !- Default Day Schedule Name + +OS:Schedule:Day, + {d5b0a110-d648-4def-82aa-76c2e6d650f3}, !- Handle + Schedule Day 10, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 60; !- Value Until Time 1 + +OS:WaterUse:Equipment, + {798e1b89-28ec-4c65-bb76-00c1c431565c}, !- Handle + Zone2 fine storage Service Water Use 0.15gal/min, !- Name + {5b58a932-4078-4641-8287-48bdafd3ffa4}, !- Water Use Equipment Definition Name + {cdd6a95f-f907-4c0e-817d-962525d358d0}, !- Space Name + {a6ac21e9-5670-4b9f-a31b-383b6b401f2f}; !- Flow Rate Fraction Schedule Name + +OS:Node, + {cc046b1d-ab3f-4f88-aba3-448f691acdac}, !- Handle + Node 55, !- Name + {93589422-d1f8-4277-879e-56de51fdb42d}, !- Inlet Port + {0a810edf-8336-4a00-b8c7-1517b33ecaf3}; !- Outlet Port + +OS:Connection, + {93589422-d1f8-4277-879e-56de51fdb42d}, !- Handle + {1cbf3689-9a0a-4401-816c-b9cd532b2f23}, !- Source Object + 5, !- Outlet Port + {cc046b1d-ab3f-4f88-aba3-448f691acdac}, !- Target Object + 2; !- Inlet Port + +OS:Node, + {2c3e58ba-8d81-4e18-9be4-47a9d2ec2082}, !- Handle + Node 56, !- Name + {bb4465df-d0af-4bf7-aef2-d30660038cbc}, !- Inlet Port + {da654eb8-7498-4a03-87fb-4e8898622e64}; !- Outlet Port + +OS:Connection, + {0a810edf-8336-4a00-b8c7-1517b33ecaf3}, !- Handle + {cc046b1d-ab3f-4f88-aba3-448f691acdac}, !- Source Object + 3, !- Outlet Port + {722d19c4-9d7a-4b51-b434-0c32ddebbcb6}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {bb4465df-d0af-4bf7-aef2-d30660038cbc}, !- Handle + {722d19c4-9d7a-4b51-b434-0c32ddebbcb6}, !- Source Object + 3, !- Outlet Port + {2c3e58ba-8d81-4e18-9be4-47a9d2ec2082}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {da654eb8-7498-4a03-87fb-4e8898622e64}, !- Handle + {2c3e58ba-8d81-4e18-9be4-47a9d2ec2082}, !- Source Object + 3, !- Outlet Port + {2abc158b-9ccf-4480-acfa-088f4fd6ed33}, !- Target Object + 5; !- Inlet Port + +OS:WaterUse:Connections, + {e69e6177-4479-42e9-8039-5700c4f58aca}, !- Handle + Water Use Connections 3, !- Name + {30b5cc8a-b73c-42d7-b329-eff758f7a299}, !- Inlet Node Name + {2142d871-e175-4d3d-87c4-9868e4af69e6}, !- Outlet Node Name + , !- Supply Water Storage Tank Name + , !- Reclamation Water Storage Tank Name + , !- Hot Water Supply Temperature Schedule Name + , !- Cold Water Supply Temperature Schedule Name + None, !- Drain Water Heat Exchanger Type + Plant, !- Drain Water Heat Exchanger Destination + , !- Drain Water Heat Exchanger U-Factor Times Area {W/K} + {0c10a6e2-1a4a-4990-a5db-e7bf6d547886}; !- Water Use Equipment Name 1 + +OS:WaterUse:Equipment:Definition, + {1c403fa0-71a8-40ec-841d-c3de47cab1ef}, !- Handle + Zone3 bulk storage Service Water Use Def 0.18gal/min, !- Name + , !- End-Use Subcategory + 1.12198834612077e-05, !- Peak Flow Rate {m3/s} + {e176ad35-07b5-42c6-8490-1a2439df728f}, !- Target Temperature Schedule Name + {ba10f122-db37-4ace-b8d3-cfa472825a4b}, !- Sensible Fraction Schedule Name + {09ce2f1b-8ccd-4d45-aed3-d5773165483c}; !- Latent Fraction Schedule Name + +OS:Schedule:Ruleset, + {ba10f122-db37-4ace-b8d3-cfa472825a4b}, !- Handle + Schedule Ruleset 9, !- Name + , !- Schedule Type Limits Name + {4431de9e-8d44-490b-8e5b-e6bea43b9748}; !- Default Day Schedule Name + +OS:Schedule:Day, + {4431de9e-8d44-490b-8e5b-e6bea43b9748}, !- Handle + Schedule Day 11, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.2; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {09ce2f1b-8ccd-4d45-aed3-d5773165483c}, !- Handle + Schedule Ruleset 10, !- Name + , !- Schedule Type Limits Name + {c8a45ca8-8242-4399-818a-659fad0fdb11}; !- Default Day Schedule Name + +OS:Schedule:Day, + {c8a45ca8-8242-4399-818a-659fad0fdb11}, !- Handle + Schedule Day 12, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0.05; !- Value Until Time 1 + +OS:Schedule:Ruleset, + {e176ad35-07b5-42c6-8490-1a2439df728f}, !- Handle + Schedule Ruleset 11, !- Name + , !- Schedule Type Limits Name + {80f9fe5e-2e01-4464-8b4d-67e7791150cd}; !- Default Day Schedule Name + +OS:Schedule:Day, + {80f9fe5e-2e01-4464-8b4d-67e7791150cd}, !- Handle + Schedule Day 13, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 60; !- Value Until Time 1 + +OS:WaterUse:Equipment, + {0c10a6e2-1a4a-4990-a5db-e7bf6d547886}, !- Handle + Zone3 bulk storage Service Water Use 0.18gal/min, !- Name + {1c403fa0-71a8-40ec-841d-c3de47cab1ef}, !- Water Use Equipment Definition Name + {39655c19-15b3-4081-92c2-4613ae84d8e6}, !- Space Name + {a6ac21e9-5670-4b9f-a31b-383b6b401f2f}; !- Flow Rate Fraction Schedule Name + +OS:Node, + {36afeab9-03cf-487a-a860-24460f3601c4}, !- Handle + Node 57, !- Name + {7e487df5-261a-43bb-b3cc-bd36706fb84e}, !- Inlet Port + {30b5cc8a-b73c-42d7-b329-eff758f7a299}; !- Outlet Port + +OS:Connection, + {7e487df5-261a-43bb-b3cc-bd36706fb84e}, !- Handle + {1cbf3689-9a0a-4401-816c-b9cd532b2f23}, !- Source Object + 6, !- Outlet Port + {36afeab9-03cf-487a-a860-24460f3601c4}, !- Target Object + 2; !- Inlet Port + +OS:Node, + {8af68e8c-cc51-424b-a382-b318e012cc31}, !- Handle + Node 58, !- Name + {2142d871-e175-4d3d-87c4-9868e4af69e6}, !- Inlet Port + {5666fa05-fd75-45ed-b4d4-8b5d6eea0ce7}; !- Outlet Port + +OS:Connection, + {30b5cc8a-b73c-42d7-b329-eff758f7a299}, !- Handle + {36afeab9-03cf-487a-a860-24460f3601c4}, !- Source Object + 3, !- Outlet Port + {e69e6177-4479-42e9-8039-5700c4f58aca}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {2142d871-e175-4d3d-87c4-9868e4af69e6}, !- Handle + {e69e6177-4479-42e9-8039-5700c4f58aca}, !- Source Object + 3, !- Outlet Port + {8af68e8c-cc51-424b-a382-b318e012cc31}, !- Target Object + 2; !- Inlet Port + +OS:Connection, + {5666fa05-fd75-45ed-b4d4-8b5d6eea0ce7}, !- Handle + {8af68e8c-cc51-424b-a382-b318e012cc31}, !- Source Object + 3, !- Outlet Port + {2abc158b-9ccf-4480-acfa-088f4fd6ed33}, !- Target Object + 6; !- Inlet Port + +OS:Sizing:Parameters, + {a63713bf-b995-4910-a6c6-92d32ffa0f38}, !- Handle + 1.3, !- Heating Sizing Factor + 1.1; !- Cooling Sizing Factor + +OS:OutputControl:ReportingTolerances, + {a9fb0ce2-a1aa-4157-a8cc-f1839f2df136}, !- Handle + 1, !- Tolerance for Time Heating Setpoint Not Met {deltaC} + 1; !- Tolerance for Time Cooling Setpoint Not Met {deltaC} + +OS:Schedule:Ruleset, + {d8db0aef-5b0a-4c5a-82d9-4fc022bea810}, !- Handle + Economizer Max OA Fraction 100 pct, !- Name + , !- Schedule Type Limits Name + {c5318059-6cb8-48ca-8576-2461fac420be}; !- Default Day Schedule Name + +OS:Schedule:Day, + {c5318059-6cb8-48ca-8576-2461fac420be}, !- Handle + Economizer Max OA Fraction 100 pct Default, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 1; !- Value Until Time 1 + +OS:AvailabilityManager:NightCycle, + {39e4c427-b554-4bd9-b3d2-3cbb05c9d92c}, !- Handle + Availability Manager Night Cycle 1, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Applicability Schedule + , !- Fan Schedule + CycleOnAny, !- Control Type + 1, !- Thermostat Tolerance {deltaC} + , !- Cycling Run Time Control Type + 3600, !- Cycling Run Time {s} + {cb21daed-4d44-4b41-bf2d-94a732476e5b}, !- Control Zone or Zone List Name + {854fa78a-5434-4fd8-9a23-4a0f83942186}, !- Cooling Control Zone or Zone List Name + {6fb55cbb-35bc-4743-bd28-1c484db5f127}, !- Heating Control Zone or Zone List Name + {19d7d986-e128-4ae4-9cd4-303841d2eea6}; !- Heating Zone Fans Only Zone or Zone List Name + +OS:ModelObjectList, + {cb21daed-4d44-4b41-bf2d-94a732476e5b}, !- Handle + Availability Manager Night Cycle 1 Control Zone List; !- Name + +OS:ModelObjectList, + {854fa78a-5434-4fd8-9a23-4a0f83942186}, !- Handle + Availability Manager Night Cycle 1 Cooling Control Zone List; !- Name + +OS:ModelObjectList, + {6fb55cbb-35bc-4743-bd28-1c484db5f127}, !- Handle + Availability Manager Night Cycle 1 Heating Control Zone List; !- Name + +OS:ModelObjectList, + {19d7d986-e128-4ae4-9cd4-303841d2eea6}, !- Handle + Availability Manager Night Cycle 1 Heating Zone Fans Only Zone List; !- Name + +OS:Schedule:Ruleset, + {48f0fd3e-6142-4549-bc10-d55e48d7d8c5}, !- Handle + sys_3|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + {34032079-484d-4fa1-8799-00bac7b80f42}, !- Default Day Schedule Name + {df83cb92-c449-4b8b-a33b-10440cecf786}, !- Summer Design Day Schedule Name + {13462341-5f88-4c50-863f-ada4e10e7ab6}; !- Winter Design Day Schedule Name + +OS:Schedule:Day, + {34032079-484d-4fa1-8799-00bac7b80f42}, !- Handle + sys_3|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Default, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 8, !- Hour 1 + 0, !- Minute 1 + 0, !- Value Until Time 1 + 19, !- Hour 2 + 0, !- Minute 2 + 1, !- Value Until Time 2 + 24, !- Hour 3 + 0, !- Minute 3 + 0; !- Value Until Time 3 + +OS:AdditionalProperties, + {80f7355c-8196-43a2-8aa7-69ae8be2e5d4}, !- Handle + {48f0fd3e-6142-4549-bc10-d55e48d7d8c5}, !- Object Name + max_occ_in_spaces, !- Feature Name 1 + Double, !- Feature Data Type 1 + 11.856343523309617, !- Feature Value 1 + number_of_spaces_included, !- Feature Name 2 + Integer, !- Feature Data Type 2 + 1, !- Feature Value 2 + date_parent_object_last_edited, !- Feature Name 3 + String, !- Feature Data Type 3 + 2023-02-20 23:53:44 UTC, !- Feature Value 3 + date_parent_object_created, !- Feature Name 4 + String, !- Feature Data Type 4 + 2023-02-20 23:53:44 UTC; !- Feature Value 4 + +OS:Schedule:Day, + {c51843b7-4f5c-452f-b639-ca6338a18ee7}, !- Handle + Schedule Day 14, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Day, + {13462341-5f88-4c50-863f-ada4e10e7ab6}, !- Handle + sys_3|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Winter Design Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 1; !- Value Until Time 1 + +OS:Schedule:Day, + {23babeb4-e947-49d7-9c69-c22db0acac06}, !- Handle + Schedule Day 15, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Day, + {df83cb92-c449-4b8b-a33b-10440cecf786}, !- Handle + sys_3|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Summer Design Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 1; !- Value Until Time 1 + +OS:Schedule:Rule, + {3b1248cd-156c-4c2b-bdc1-09fb9c36a832}, !- Handle + sys_3|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Sunday Rule, !- Name + {48f0fd3e-6142-4549-bc10-d55e48d7d8c5}, !- Schedule Ruleset Name + 0, !- Rule Order + {e18c81bc-967b-41ad-bc6b-bdb806072f9a}, !- Day Schedule Name + Yes, !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + Yes, !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {e18c81bc-967b-41ad-bc6b-bdb806072f9a}, !- Handle + sys_3|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Sunday, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:AvailabilityManager:NightCycle, + {e88b0e59-2631-474e-a89e-528a33404f7d}, !- Handle + Availability Manager Night Cycle 2, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Applicability Schedule + , !- Fan Schedule + CycleOnAny, !- Control Type + 1, !- Thermostat Tolerance {deltaC} + , !- Cycling Run Time Control Type + 3600, !- Cycling Run Time {s} + {f2c08a7b-3dcc-4a97-8ea8-a1afd7c1e241}, !- Control Zone or Zone List Name + {b2c7361c-4235-4680-8d5a-cf6ea3af403d}, !- Cooling Control Zone or Zone List Name + {7a8c2d70-268d-4093-99f2-c99446e74270}, !- Heating Control Zone or Zone List Name + {2666179a-a76c-4df4-925a-8ab141fe06c8}; !- Heating Zone Fans Only Zone or Zone List Name + +OS:ModelObjectList, + {f2c08a7b-3dcc-4a97-8ea8-a1afd7c1e241}, !- Handle + Availability Manager Night Cycle 2 Control Zone List; !- Name + +OS:ModelObjectList, + {b2c7361c-4235-4680-8d5a-cf6ea3af403d}, !- Handle + Availability Manager Night Cycle 2 Cooling Control Zone List; !- Name + +OS:ModelObjectList, + {7a8c2d70-268d-4093-99f2-c99446e74270}, !- Handle + Availability Manager Night Cycle 2 Heating Control Zone List; !- Name + +OS:ModelObjectList, + {2666179a-a76c-4df4-925a-8ab141fe06c8}, !- Handle + Availability Manager Night Cycle 2 Heating Zone Fans Only Zone List; !- Name + +OS:Schedule:Ruleset, + {bf1f02ca-a131-45e6-b117-87cb43be5a00}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + {372faa1e-0dc9-47cb-b9fc-b28333770919}, !- Default Day Schedule Name + {b98a8f01-708c-4116-854b-17adf8081e5a}, !- Summer Design Day Schedule Name + {de786604-c7f8-420f-80a8-faa2957b3fee}; !- Winter Design Day Schedule Name + +OS:Schedule:Day, + {372faa1e-0dc9-47cb-b9fc-b28333770919}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Default, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 8, !- Hour 1 + 0, !- Minute 1 + 0, !- Value Until Time 1 + 19, !- Hour 2 + 0, !- Minute 2 + 1, !- Value Until Time 2 + 24, !- Hour 3 + 0, !- Minute 3 + 0; !- Value Until Time 3 + +OS:AdditionalProperties, + {a4a04b30-2a18-41b3-adac-f122fcc6f22c}, !- Handle + {bf1f02ca-a131-45e6-b117-87cb43be5a00}, !- Object Name + max_occ_in_spaces, !- Feature Name 1 + Double, !- Feature Data Type 1 + 32.081870710131746, !- Feature Value 1 + number_of_spaces_included, !- Feature Name 2 + Integer, !- Feature Data Type 2 + 1, !- Feature Value 2 + date_parent_object_last_edited, !- Feature Name 3 + String, !- Feature Data Type 3 + 2023-02-20 23:53:44 UTC, !- Feature Value 3 + date_parent_object_created, !- Feature Name 4 + String, !- Feature Data Type 4 + 2023-02-20 23:53:44 UTC; !- Feature Value 4 + +OS:Schedule:Day, + {ca52dcfd-109b-4d31-98ad-d6d1b6ec27c8}, !- Handle + Schedule Day 16, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Day, + {de786604-c7f8-420f-80a8-faa2957b3fee}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Winter Design Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 1; !- Value Until Time 1 + +OS:Schedule:Day, + {10a47ed9-6a3a-4488-b042-f0242a404412}, !- Handle + Schedule Day 17, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Day, + {b98a8f01-708c-4116-854b-17adf8081e5a}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Summer Design Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 1; !- Value Until Time 1 + +OS:Schedule:Rule, + {0c55526b-c6df-4b70-8a07-ada49183d11a}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Sunday Rule, !- Name + {bf1f02ca-a131-45e6-b117-87cb43be5a00}, !- Schedule Ruleset Name + 0, !- Rule Order + {05d6c7c5-89b3-4105-be48-f119d170455b}, !- Day Schedule Name + Yes, !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + Yes, !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {05d6c7c5-89b3-4105-be48-f119d170455b}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| Occ Sch Sunday, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:EnergyManagementSystem:Sensor, + {b57003b4-3809-4ed9-bc60-61f85b697cb2}, !- Handle + OAT, !- Name + Environment, !- Output Variable or Output Meter Index Key Name + Site Outdoor Air Drybulb Temperature; !- Output Variable or Output Meter Name + +OS:EnergyManagementSystem:Actuator, + {47436e7a-fd7e-4b37-837c-6c7683c866c4}, !- Handle + sys4mixedshrnonescdxshcessfcvzhbezcnonesrfnoneHtgSch0, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Actuated Component Name + Schedule:Year, !- Actuated Component Type + Schedule Value; !- Actuated Component Control Type + +OS:EnergyManagementSystem:Actuator, + {39017975-782c-480b-9d2b-0bd83bd423c8}, !- Handle + sys4mixedshrnonescdxshcessfcvzhbezcnonesrfnoneClgSch0, !- Name + {464561eb-f631-4a8d-a753-4d87291d0357}, !- Actuated Component Name + Schedule:Year, !- Actuated Component Type + Schedule Value; !- Actuated Component Control Type + +OS:EnergyManagementSystem:Program, + {7d504894-8b0b-4474-986f-44b99782960c}, !- Handle + sys4mixedshrnonescdxshcessfcvzhbezcnonesrfnoneOptimumStartProg0, !- Name + IF DaylightSavings==0 && DayOfWeek>1 && Hour==5 && {b57003b4-3809-4ed9-bc60-61f85b697cb2}<23.9 && {b57003b4-3809-4ed9-bc60-61f85b697cb2}>1.7, !- Program Line 1 + SET {39017975-782c-480b-9d2b-0bd83bd423c8} = 29.4, !- Program Line 2 + SET {47436e7a-fd7e-4b37-837c-6c7683c866c4} = 15.6, !- Program Line 3 + ELSEIF DaylightSavings==0 && DayOfWeek==1 && Hour==7 && {b57003b4-3809-4ed9-bc60-61f85b697cb2}<23.9 && {b57003b4-3809-4ed9-bc60-61f85b697cb2}>1.7, !- Program Line 4 + SET {39017975-782c-480b-9d2b-0bd83bd423c8} = 29.4, !- Program Line 5 + SET {47436e7a-fd7e-4b37-837c-6c7683c866c4} = 15.6, !- Program Line 6 + ELSEIF DaylightSavings==1 && DayOfWeek>1 && Hour==4 && {b57003b4-3809-4ed9-bc60-61f85b697cb2}<23.9 && {b57003b4-3809-4ed9-bc60-61f85b697cb2}>1.7, !- Program Line 7 + SET {39017975-782c-480b-9d2b-0bd83bd423c8} = 29.4, !- Program Line 8 + SET {47436e7a-fd7e-4b37-837c-6c7683c866c4} = 15.6, !- Program Line 9 + ELSEIF DaylightSavings==1 && DayOfWeek==1 && Hour==6 && {b57003b4-3809-4ed9-bc60-61f85b697cb2}<23.9 && {b57003b4-3809-4ed9-bc60-61f85b697cb2}>1.7, !- Program Line 10 + SET {39017975-782c-480b-9d2b-0bd83bd423c8} = 29.4, !- Program Line 11 + SET {47436e7a-fd7e-4b37-837c-6c7683c866c4} = 15.6, !- Program Line 12 + ELSE, !- Program Line 13 + SET {39017975-782c-480b-9d2b-0bd83bd423c8} = NULL, !- Program Line 14 + SET {47436e7a-fd7e-4b37-837c-6c7683c866c4} = NULL, !- Program Line 15 + ENDIF; !- Program Line 16 + +OS:EnergyManagementSystem:ProgramCallingManager, + {202058fb-c306-490b-86f4-13c305fae0cf}, !- Handle + sys4mixedshrnonescdxshcessfcvzhbezcnonesrfnoneOptimumStartCallingManager0, !- Name + BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point + {7d504894-8b0b-4474-986f-44b99782960c}; !- Program Name 1 + +OS:AvailabilityManager:NightCycle, + {3b9c4512-03cf-495c-8a48-ecba3eda1f7c}, !- Handle + Availability Manager Night Cycle 3, !- Name + {aa8c2e64-442d-49a3-9e96-c03cffcd5806}, !- Applicability Schedule + , !- Fan Schedule + CycleOnAny, !- Control Type + 1, !- Thermostat Tolerance {deltaC} + , !- Cycling Run Time Control Type + 3600, !- Cycling Run Time {s} + {0b4384b2-a604-46c0-b3d6-809842b211d2}, !- Control Zone or Zone List Name + {6061520d-778d-41c1-b5a2-f9d925efee38}, !- Cooling Control Zone or Zone List Name + {607a7146-995c-42f0-9d97-ecf9ac76573b}, !- Heating Control Zone or Zone List Name + {887a9772-57fd-4ece-b648-5dcb3bdb726e}; !- Heating Zone Fans Only Zone or Zone List Name + +OS:ModelObjectList, + {0b4384b2-a604-46c0-b3d6-809842b211d2}, !- Handle + Availability Manager Night Cycle 3 Control Zone List; !- Name + +OS:ModelObjectList, + {6061520d-778d-41c1-b5a2-f9d925efee38}, !- Handle + Availability Manager Night Cycle 3 Cooling Control Zone List; !- Name + +OS:ModelObjectList, + {607a7146-995c-42f0-9d97-ecf9ac76573b}, !- Handle + Availability Manager Night Cycle 3 Heating Control Zone List; !- Name + +OS:ModelObjectList, + {887a9772-57fd-4ece-b648-5dcb3bdb726e}, !- Handle + Availability Manager Night Cycle 3 Heating Zone Fans Only Zone List; !- Name + +OS:Schedule:Ruleset, + {a935fa5d-cac9-42c2-b5bb-d0f987c5f51f}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| 1 Occ Sch, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + {61570052-3c7f-4cae-b37a-2b1c0befc3b8}, !- Default Day Schedule Name + {b46bc234-5987-47da-9525-0e86fc9dbc8d}, !- Summer Design Day Schedule Name + {e32a6c8f-57c9-483d-a005-62d60cb9ba7f}; !- Winter Design Day Schedule Name + +OS:Schedule:Day, + {61570052-3c7f-4cae-b37a-2b1c0befc3b8}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| 1 Occ Sch Default, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 8, !- Hour 1 + 0, !- Minute 1 + 0, !- Value Until Time 1 + 19, !- Hour 2 + 0, !- Minute 2 + 1, !- Value Until Time 2 + 24, !- Hour 3 + 0, !- Minute 3 + 0; !- Value Until Time 3 + +OS:AdditionalProperties, + {74de0c19-26de-49be-a7bf-5a56b086aeb5}, !- Handle + {a935fa5d-cac9-42c2-b5bb-d0f987c5f51f}, !- Object Name + max_occ_in_spaces, !- Feature Name 1 + Double, !- Feature Data Type 1 + 27.897278878375673, !- Feature Value 1 + number_of_spaces_included, !- Feature Name 2 + Integer, !- Feature Data Type 2 + 1, !- Feature Value 2 + date_parent_object_last_edited, !- Feature Name 3 + String, !- Feature Data Type 3 + 2023-02-20 23:53:44 UTC, !- Feature Value 3 + date_parent_object_created, !- Feature Name 4 + String, !- Feature Data Type 4 + 2023-02-20 23:53:44 UTC; !- Feature Value 4 + +OS:Schedule:Day, + {f6d2d108-1220-4881-bd56-f9807678296b}, !- Handle + Schedule Day 18, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Day, + {e32a6c8f-57c9-483d-a005-62d60cb9ba7f}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| 1 Occ Sch Winter Design Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 1; !- Value Until Time 1 + +OS:Schedule:Day, + {19098a10-8a06-4fc9-a1ac-64627baa1c89}, !- Handle + Schedule Day 19, !- Name + , !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:Schedule:Day, + {b46bc234-5987-47da-9525-0e86fc9dbc8d}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| 1 Occ Sch Summer Design Day, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 1; !- Value Until Time 1 + +OS:Schedule:Rule, + {84256b36-f86c-4c43-bcc3-278891fc6e0e}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| 1 Occ Sch Sunday Rule, !- Name + {a935fa5d-cac9-42c2-b5bb-d0f987c5f51f}, !- Schedule Ruleset Name + 0, !- Rule Order + {76376aec-14e7-4caf-ac52-2bb2bc90418c}, !- Day Schedule Name + Yes, !- Apply Sunday + , !- Apply Monday + , !- Apply Tuesday + , !- Apply Wednesday + , !- Apply Thursday + , !- Apply Friday + Yes, !- Apply Saturday + DateRange, !- Date Specification Type + 1, !- Start Month + 1, !- Start Day + 12, !- End Month + 31; !- End Day + +OS:Schedule:Day, + {76376aec-14e7-4caf-ac52-2bb2bc90418c}, !- Handle + sys_4|mixed|shr>none|sc>dx|sh>c-e|ssf>cv|zh>b-e|zc>none|srf>none| 1 Occ Sch Sunday, !- Name + {1bceaaf3-a1cb-4c22-866e-7cba8d9a374a}, !- Schedule Type Limits Name + , !- Interpolate to Timestep + 24, !- Hour 1 + 0, !- Minute 1 + 0; !- Value Until Time 1 + +OS:EnergyManagementSystem:Sensor, + {e1e9618f-91ff-4b37-b9c4-f71ea9a5714e}, !- Handle + OAT_1, !- Name + Environment, !- Output Variable or Output Meter Index Key Name + Site Outdoor Air Drybulb Temperature; !- Output Variable or Output Meter Name + +OS:EnergyManagementSystem:Actuator, + {d7b0ced4-7eb0-43c4-8acf-b80577ffdb3a}, !- Handle + sys4mixedshrnonescdxshcessfcvzhbezcnonesrfnone1HtgSch0, !- Name + {0c7d39a2-b5a5-468c-b728-b3328f59a977}, !- Actuated Component Name + Schedule:Year, !- Actuated Component Type + Schedule Value; !- Actuated Component Control Type + +OS:EnergyManagementSystem:Actuator, + {352ce7da-4349-4849-84b6-ad12a09f8955}, !- Handle + sys4mixedshrnonescdxshcessfcvzhbezcnonesrfnone1ClgSch0, !- Name + {464561eb-f631-4a8d-a753-4d87291d0357}, !- Actuated Component Name + Schedule:Year, !- Actuated Component Type + Schedule Value; !- Actuated Component Control Type + +OS:EnergyManagementSystem:Program, + {35052eb0-32ef-4e7d-a6db-198abfdef675}, !- Handle + sys4mixedshrnonescdxshcessfcvzhbezcnonesrfnone1OptimumStartProg0, !- Name + IF DaylightSavings==0 && DayOfWeek>1 && Hour==5 && {e1e9618f-91ff-4b37-b9c4-f71ea9a5714e}<23.9 && {e1e9618f-91ff-4b37-b9c4-f71ea9a5714e}>1.7, !- Program Line 1 + SET {352ce7da-4349-4849-84b6-ad12a09f8955} = 29.4, !- Program Line 2 + SET {d7b0ced4-7eb0-43c4-8acf-b80577ffdb3a} = 15.6, !- Program Line 3 + ELSEIF DaylightSavings==0 && DayOfWeek==1 && Hour==7 && {e1e9618f-91ff-4b37-b9c4-f71ea9a5714e}<23.9 && {e1e9618f-91ff-4b37-b9c4-f71ea9a5714e}>1.7, !- Program Line 4 + SET {352ce7da-4349-4849-84b6-ad12a09f8955} = 29.4, !- Program Line 5 + SET {d7b0ced4-7eb0-43c4-8acf-b80577ffdb3a} = 15.6, !- Program Line 6 + ELSEIF DaylightSavings==1 && DayOfWeek>1 && Hour==4 && {e1e9618f-91ff-4b37-b9c4-f71ea9a5714e}<23.9 && {e1e9618f-91ff-4b37-b9c4-f71ea9a5714e}>1.7, !- Program Line 7 + SET {352ce7da-4349-4849-84b6-ad12a09f8955} = 29.4, !- Program Line 8 + SET {d7b0ced4-7eb0-43c4-8acf-b80577ffdb3a} = 15.6, !- Program Line 9 + ELSEIF DaylightSavings==1 && DayOfWeek==1 && Hour==6 && {e1e9618f-91ff-4b37-b9c4-f71ea9a5714e}<23.9 && {e1e9618f-91ff-4b37-b9c4-f71ea9a5714e}>1.7, !- Program Line 10 + SET {352ce7da-4349-4849-84b6-ad12a09f8955} = 29.4, !- Program Line 11 + SET {d7b0ced4-7eb0-43c4-8acf-b80577ffdb3a} = 15.6, !- Program Line 12 + ELSE, !- Program Line 13 + SET {352ce7da-4349-4849-84b6-ad12a09f8955} = NULL, !- Program Line 14 + SET {d7b0ced4-7eb0-43c4-8acf-b80577ffdb3a} = NULL, !- Program Line 15 + ENDIF; !- Program Line 16 + +OS:EnergyManagementSystem:ProgramCallingManager, + {2a391945-389b-4ce8-b897-ecae1480b59f}, !- Handle + sys4mixedshrnonescdxshcessfcvzhbezcnonesrfnone1OptimumStartCallingManager0, !- Name + BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point + {35052eb0-32ef-4e7d-a6db-198abfdef675}; !- Program Name 1 + +OS:Curve:Biquadratic, + {929218f9-da77-4b47-9e6c-bd3b29a57431}, !- Handle + DXCOOL-NECB2011-REF-CAPFT, !- Name + 0.867905, !- Coefficient1 Constant + 0.0142459, !- Coefficient2 x + 0.00055436, !- Coefficient3 x**2 + -0.0075575, !- Coefficient4 y + 3.3e-05, !- Coefficient5 y**2 + -0.0001918, !- Coefficient6 x*y + 13, !- Minimum Value of x + 24, !- Maximum Value of x + 24, !- Minimum Value of y + 46; !- Maximum Value of y + +OS:Curve:Quadratic, + {899b0ad4-b535-4c55-9247-ab9c5ad0bd61}, !- Handle + DXCOOL-NECB2011-REF-CAPFFLOW, !- Name + 0.8, !- Coefficient1 Constant + 0.2, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0.5, !- Minimum Value of x + 1.5; !- Maximum Value of x + +OS:Curve:Biquadratic, + {e48f8ca2-64f8-435d-adb8-a86c3a81d988}, !- Handle + DXCOOL-NECB2011-REF-COOLEIRFT, !- Name + 0.1141714, !- Coefficient1 Constant + 0.02818224, !- Coefficient2 x + -0.0004199, !- Coefficient3 x**2 + 0.02141082, !- Coefficient4 y + 0.000161028, !- Coefficient5 y**2 + -0.000679104, !- Coefficient6 x*y + 13, !- Minimum Value of x + 24, !- Maximum Value of x + 24, !- Minimum Value of y + 46; !- Maximum Value of y + +OS:Curve:Quadratic, + {4e181a91-d4a4-4fea-8f42-cbc11ac7dfe5}, !- Handle + DXCOOL-NECB2011-REF-COOLEIRFFLOW, !- Name + 1.1552, !- Coefficient1 Constant + -0.1808, !- Coefficient2 x + 0.0256, !- Coefficient3 x**2 + 0.5, !- Minimum Value of x + 1.5; !- Maximum Value of x + +OS:Curve:Cubic, + {d09eedfa-c075-4850-996a-c51a707c3fd5}, !- Handle + DXCOOL-NECB2011-REF-COOLPLFFPLR, !- Name + 0.0277, !- Coefficient1 Constant + 4.9151, !- Coefficient2 x + -8.184, !- Coefficient3 x**2 + 4.2702, !- Coefficient4 x**3 + 0.7, !- Minimum Value of x + 1; !- Maximum Value of x + From 33ecd0f48ee3fb85946757cc9e7744938b9ebc10 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 22 Mar 2023 09:40:03 -0700 Subject: [PATCH 02/40] Add test for issue. --- src/model/test/Space_GTest.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index 302ee331921..307465c0e42 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3226,4 +3226,15 @@ TEST_F(ModelFixture, Space_Polyhedron_Volume) { EXPECT_EQ(volume, s.volume()); } -//# endif // SURFACESHATTERING +TEST_F(ModelFixture, Issue_4837) { + + osversion::VersionTranslator translator; + openstudio::path modelPath = resourcesPath() / toPath("model/test_file.osm"); + model::OptionalModel model = translator.loadModel(modelPath); + EXPECT_TRUE(model); + + boost::optional space = model->getConcreteModelObjectByName("Zone1 Office"); + ASSERT_TRUE(space); + + EXPECT_DOUBLE_EQ(1011.0, space->volume()); +} From 1e82fae436ecd04fa94569d7f099b886711a4a56 Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 22 Mar 2023 09:40:15 -0700 Subject: [PATCH 03/40] Formatting. --- src/model/test/Space_GTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index 307465c0e42..6792707b432 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3235,6 +3235,6 @@ TEST_F(ModelFixture, Issue_4837) { boost::optional space = model->getConcreteModelObjectByName("Zone1 Office"); ASSERT_TRUE(space); - + EXPECT_DOUBLE_EQ(1011.0, space->volume()); } From b79debce5de9fa16ad29f0dfe8cec07f9ef6baab Mon Sep 17 00:00:00 2001 From: Joe Robertson Date: Wed, 22 Mar 2023 10:57:26 -0700 Subject: [PATCH 04/40] Improve new test. --- src/model/test/Space_GTest.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index 6792707b432..95f6299a96b 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3233,8 +3233,18 @@ TEST_F(ModelFixture, Issue_4837) { model::OptionalModel model = translator.loadModel(modelPath); EXPECT_TRUE(model); - boost::optional space = model->getConcreteModelObjectByName("Zone1 Office"); - ASSERT_TRUE(space); + boost::optional space1 = model->getConcreteModelObjectByName("Zone1 Office"); + ASSERT_TRUE(space1); + EXPECT_TRUE(space1->isEnclosedVolume()); + EXPECT_DOUBLE_EQ(1011.0, space1->volume()); - EXPECT_DOUBLE_EQ(1011.0, space->volume()); + boost::optional space2 = model->getConcreteModelObjectByName("Zone2 Fine Storage"); + ASSERT_TRUE(space2); + EXPECT_TRUE(space2->isEnclosedVolume()); + EXPECT_DOUBLE_EQ(10876.0, space2->volume()); + + boost::optional space3 = model->getConcreteModelObjectByName("Zone3 Bulk Storage"); + ASSERT_TRUE(space3); + EXPECT_TRUE(space3->isEnclosedVolume()); + EXPECT_DOUBLE_EQ(27338.0, space3->volume()); } From efc58cd5e3dd5f64701702af49932cf95d9ff6a8 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 24 Mar 2023 15:19:24 +0100 Subject: [PATCH 05/40] Make Polyhedron::edgesNotTwoForEnclosedVolumeTest a member function --- src/utilities/geometry/Polyhedron.cpp | 10 +++++----- src/utilities/geometry/Polyhedron.hpp | 2 +- src/utilities/geometry/Test/Polyhedron_GTest.cpp | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index 5853c8882ff..cb59e9365af 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -119,14 +119,14 @@ std::vector Polyhedron::uniqueVertices() const { return uniqVertices; } -std::vector Polyhedron::edgesNotTwoForEnclosedVolumeTest(const Polyhedron& volumePoly) { +std::vector Polyhedron::edgesNotTwoForEnclosedVolumeTest() const { std::vector uniqueSurface3dEdges; - uniqueSurface3dEdges.reserve(volumePoly.numVertices()); + uniqueSurface3dEdges.reserve(numVertices()); // construct list of unique edges int surfNum = 0; - for (const auto& surface : volumePoly.m_surfaces) { + for (const auto& surface : m_surfaces) { LOG(Debug, "Surface: " << surface.name); const auto& vertices = surface.vertices; for (auto it = vertices.begin(); it != vertices.end(); ++it) { @@ -222,7 +222,7 @@ VolumeEnclosedReturnType Polyhedron::isEnclosedVolume() const { VolumeEnclosedReturnType result; - std::vector edgeNot2orig = edgesNotTwoForEnclosedVolumeTest(*this); + std::vector edgeNot2orig = this->edgesNotTwoForEnclosedVolumeTest(); // if all edges had two counts then it is fully enclosed if (edgeNot2orig.empty()) { result.isEnclosedVolume = true; @@ -232,7 +232,7 @@ VolumeEnclosedReturnType Polyhedron::isEnclosedVolume() const { // consistent with the number of edges found that didn't have a count of two Polyhedron updatedZonePoly = updateZonePolygonsForMissingColinearPoints(); // this is done after initial test since it is computationally intensive. - std::vector edgeNot2again = edgesNotTwoForEnclosedVolumeTest(updatedZonePoly); + std::vector edgeNot2again = updatedZonePoly.edgesNotTwoForEnclosedVolumeTest(); if (edgeNot2again.empty()) { result.isEnclosedVolume = true; return result; diff --git a/src/utilities/geometry/Polyhedron.hpp b/src/utilities/geometry/Polyhedron.hpp index 76a95a44354..a7688f9959c 100644 --- a/src/utilities/geometry/Polyhedron.hpp +++ b/src/utilities/geometry/Polyhedron.hpp @@ -109,7 +109,7 @@ class UTILITIES_API Polyhedron // Maybe unused std::vector uniqueVertices() const; - static std::vector edgesNotTwoForEnclosedVolumeTest(const Polyhedron& volumePoly); + std::vector edgesNotTwoForEnclosedVolumeTest() const; Polyhedron updateZonePolygonsForMissingColinearPoints() const; diff --git a/src/utilities/geometry/Test/Polyhedron_GTest.cpp b/src/utilities/geometry/Test/Polyhedron_GTest.cpp index 09c607c1d8b..92347af9422 100644 --- a/src/utilities/geometry/Test/Polyhedron_GTest.cpp +++ b/src/utilities/geometry/Test/Polyhedron_GTest.cpp @@ -78,14 +78,14 @@ TEST_F(GeometryFixture, Polyhedron_Enclosed) { auto uniqVertices = zonePoly.uniqueVertices(); EXPECT_EQ(10, uniqVertices.size()); - std::vector edgeNot2orig = Polyhedron::edgesNotTwoForEnclosedVolumeTest(zonePoly); + std::vector edgeNot2orig = zonePoly.edgesNotTwoForEnclosedVolumeTest(); EXPECT_EQ(6, edgeNot2orig.size()); auto updatedZonePoly = zonePoly.updateZonePolygonsForMissingColinearPoints(); // We expect the two points from the split south walls to have been added to the roof and floor EXPECT_EQ(30, updatedZonePoly.numVertices()); - std::vector edgeNot2again = Polyhedron::edgesNotTwoForEnclosedVolumeTest(updatedZonePoly); + std::vector edgeNot2again = updatedZonePoly.edgesNotTwoForEnclosedVolumeTest(); EXPECT_TRUE(edgeNot2again.empty()); } From 2b9dfbe7af13f1af1c73bc4e534d85ad8c8bb4d7 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 24 Mar 2023 15:20:25 +0100 Subject: [PATCH 06/40] Try to detect Surfaces in a Space that may be reversed. --- src/model/Space.cpp | 147 ++++++++++++++++++++++++++++++++------- src/model/Space.hpp | 9 +++ src/model/Space_Impl.hpp | 9 +++ 3 files changed, 141 insertions(+), 24 deletions(-) diff --git a/src/model/Space.cpp b/src/model/Space.cpp index 63559f5902a..ebe527ed5f0 100644 --- a/src/model/Space.cpp +++ b/src/model/Space.cpp @@ -152,6 +152,9 @@ #include #include +#include + +#include namespace openstudio { namespace model { @@ -918,25 +921,95 @@ namespace model { return result; } + std::vector Space_Impl::findSurfacesWithIncorrectOrientation() const { + std::vector result; + + auto surfaces = this->surfaces(); + for (const auto& surface : surfaces) { + + auto normal = surface.outwardNormal(); + auto this_pt = surface.vertices()[0]; + bool found = false; + for (const auto& anotherSurface : surfaces) { + if (surface == anotherSurface) { + continue; + } + for (const auto& another_pt : anotherSurface.vertices()) { + const Vector3d v1 = this_pt - another_pt; + auto thisdot = normal.dot(v1); + if (std::abs(thisdot) > 0.001) { + found = true; + if (thisdot < 0.0) { + result.push_back(surface); + } + break; + } + } + if (found) { + break; + } + } + + if (!found) { + LOG(Error, "Could not find any dot product that isn't zero for Surface " << surface.nameString()); + } + } + + return result; + } + + bool Space_Impl::areAllSurfacesCorrectlyOriented() const { + auto surfaces = findSurfacesWithIncorrectOrientation(); + for (const auto& surface : surfaces) { + LOG(Error, "In Space " << nameString() << ", Surface " << surface.nameString() << " has an outward normal pointing in the wrong direction."); + } + + return surfaces.empty(); + } + + bool Space_Impl::fixSurfacesWithIncorrectOrientation() { + + auto surfaces = findSurfacesWithIncorrectOrientation(); + if (surfaces.empty()) { + return false; + } + + for (auto& surface : surfaces) { + auto vertices = surface.vertices(); + + LOG(Error, "In Space " << nameString() << ", Surface " << surface.nameString() + << " has an outward normal pointing in the wrong direction. Flipping it."); + std::reverse(vertices.begin(), vertices.end()); + surface.setVertices(openstudio::reorderULC(vertices)); + } + return true; + } + double Space_Impl::volume() const { boost::optional value = getDouble(OS_SpaceFields::Volume, true); if (value) { return value.get(); } - auto volumePoly = this->polyhedron(); + if (areAllSurfacesCorrectlyOriented()) { - auto [isVolEnclosed, edgesNot2] = volumePoly.isEnclosedVolume(); - if (isVolEnclosed) { - return volumePoly.calcPolyhedronVolume(); - } + auto volumePoly = this->polyhedron(); - LOG(Warn, briefDescription() << " is not enclosed, there are " << edgesNot2.size() - << " edges that aren't used exactly twice. Volume calculation will be potentially inaccurate"); + auto [isVolEnclosed, edgesNot2] = volumePoly.isEnclosedVolume(); + if (isVolEnclosed) { + return volumePoly.calcPolyhedronVolume(); + } - double result = 0; + LOG(Warn, briefDescription() << " is not enclosed, there are " << edgesNot2.size() + << " edges that aren't used exactly twice. " + "Falling back to ceilingHeight * floorArea. Volume calculation will be potentially inaccurate."); + + } else { + LOG(Warn, briefDescription() << " has some Surfaces with incorrection orientation. Call Space::fixSurfacesWithIncorrectOrientation(). " + "Falling back to ceilingHeight * floorArea. Volume calculation will be potentially inaccurate."); + } - result = this->ceilingHeight() * this->floorArea(); + const double result = this->ceilingHeight() * this->floorArea(); return result; } @@ -2907,7 +2980,14 @@ namespace model { } } - boost::optional outwardNormal = getOutwardNormal(floorPrint); + // Enforce the same z + std::vector reorderedFloorPrint; + reorderedFloorPrint.reserve(floorPrint.size()); + std::transform(floorPrint.cbegin(), floorPrint.cend(), std::back_inserter(reorderedFloorPrint), [&z](const auto& pt) { + return Point3d{pt.x(), pt.y(), z}; + }); + + boost::optional outwardNormal = getOutwardNormal(reorderedFloorPrint); if (!outwardNormal) { LOG(Error, "Cannot compute outwardNormal for floorPrint."); return boost::none; @@ -2918,36 +2998,43 @@ namespace model { return boost::none; } + reorderedFloorPrint = openstudio::reorderULC(reorderedFloorPrint); + // we are good to go, create the space Space space(model); // create the floor - std::vector points; - for (const auto& elem : floorPrint) { - points.push_back(Point3d(elem.x(), elem.y(), z)); - } - Surface floor(points, model); + Surface floor(reorderedFloorPrint, model); + floor.setName(fmt::format("{} Floor", space.nameString())); floor.setSpace(space); + double zCeiling = z + floorHeight; + std::vector points; + points.reserve(4); // create each wall for (unsigned i = 1; i <= numPoints; ++i) { + // Counter clockwise, Upper Left Corner convention points = { - {floorPrint[i % numPoints].x(), floorPrint[i % numPoints].y(), z + floorHeight}, - {floorPrint[i % numPoints].x(), floorPrint[i % numPoints].y(), z}, - {floorPrint[i - 1].x(), floorPrint[i - 1].y(), z}, - {floorPrint[i - 1].x(), floorPrint[i - 1].y(), z + floorHeight}, + {reorderedFloorPrint[i - 1].x(), reorderedFloorPrint[i - 1].y(), zCeiling}, // Upper Left Corner + {reorderedFloorPrint[i % numPoints].x(), reorderedFloorPrint[i % numPoints].y(), zCeiling}, // Upper Right Corner + {reorderedFloorPrint[i % numPoints].x(), reorderedFloorPrint[i % numPoints].y(), z}, // Lower Right Corner + {reorderedFloorPrint[i - 1].x(), reorderedFloorPrint[i - 1].y(), z}, // Lower Left Corner }; Surface wall(points, model); + wall.setName(fmt::format("{} Wall", space.nameString())); + wall.setSpace(space); } // create the roofCeiling - points.clear(); - for (auto rit = floorPrint.rbegin(), ritend = floorPrint.rend(); rit != ritend; ++rit) { - points.push_back(Point3d(rit->x(), rit->y(), z + floorHeight)); - } - Surface roofCeiling(points, model); + std::vector ceilingPoints; + ceilingPoints.reserve(reorderedFloorPrint.size()); + std::transform(reorderedFloorPrint.crbegin(), reorderedFloorPrint.crend(), std::back_inserter(ceilingPoints), [zCeiling](const auto& pt) { + return Point3d{pt.x(), pt.y(), zCeiling}; + }); + Surface roofCeiling(ceilingPoints, model); + roofCeiling.setName(fmt::format("{} RoofCeiling", space.nameString())); roofCeiling.setSpace(space); return space; @@ -3470,6 +3557,18 @@ namespace model { return getImpl()->exhaustZoneMixing(); } + std::vector Space::findSurfacesWithIncorrectOrientation() const { + return getImpl()->findSurfacesWithIncorrectOrientation(); + } + + bool Space::areAllSurfacesCorrectlyOriented() const { + return getImpl()->areAllSurfacesCorrectlyOriented(); + } + + bool Space::fixSurfacesWithIncorrectOrientation() { + return getImpl()->fixSurfacesWithIncorrectOrientation(); + } + /// @cond Space::Space(std::shared_ptr impl) : PlanarSurfaceGroup(std::move(impl)) {} /// @endcond diff --git a/src/model/Space.hpp b/src/model/Space.hpp index 344d376d0e9..6a9ac14c952 100644 --- a/src/model/Space.hpp +++ b/src/model/Space.hpp @@ -640,6 +640,15 @@ namespace model { /** Returns all ZoneMixing objects which exhaust air from this space */ std::vector exhaustZoneMixing() const; + // Find all surfaces where the outwardNormal does not point towards the outside of the Space + std::vector findSurfacesWithIncorrectOrientation() const; + + // Checks the outwardNormal of every surface points towards the outside of the Space + bool areAllSurfacesCorrectlyOriented() const; + + // Returns true if the orientation of any surface has been changed + bool fixSurfacesWithIncorrectOrientation(); + //@} protected: /// @cond diff --git a/src/model/Space_Impl.hpp b/src/model/Space_Impl.hpp index b2f936584ed..576747378a7 100644 --- a/src/model/Space_Impl.hpp +++ b/src/model/Space_Impl.hpp @@ -508,6 +508,15 @@ namespace model { Polyhedron polyhedron() const; bool isEnclosedVolume() const; + // Find all surfaces where the outwardNormal does not point towards the outside of the Space + std::vector findSurfacesWithIncorrectOrientation() const; + + // Checks the outwardNormal of every surface points towards the outside of the Space + bool areAllSurfacesCorrectlyOriented() const; + + // Returns true if the orientation of any surface has been changed + bool fixSurfacesWithIncorrectOrientation(); + std::vector zoneMixing() const; std::vector supplyZoneMixing() const; std::vector exhaustZoneMixing() const; From b3e8e954cfa7b1c70cbe02a4edc631051ea8c0d5 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 24 Mar 2023 15:20:36 +0100 Subject: [PATCH 07/40] Rename test file and update Gtest --- resources/CMakeLists.txt | 2 +- .../{test_file.osm => 4837_SpaceVolume.osm} | 0 src/model/test/Space_GTest.cpp | 72 ++++++++++++++----- 3 files changed, 56 insertions(+), 18 deletions(-) rename resources/model/{test_file.osm => 4837_SpaceVolume.osm} (100%) diff --git a/resources/CMakeLists.txt b/resources/CMakeLists.txt index 5257587a9ae..9c47de51d50 100644 --- a/resources/CMakeLists.txt +++ b/resources/CMakeLists.txt @@ -174,7 +174,7 @@ set(model_resources_src model/ParkUnder_Retail_Office_C2.osm model/ASHRAECourthouse.osm model/A205ExampleChiller.RS0001.a205.cbor - model/test_file.osm + model/4837_SpaceVolume.osm ) diff --git a/resources/model/test_file.osm b/resources/model/4837_SpaceVolume.osm similarity index 100% rename from resources/model/test_file.osm rename to resources/model/4837_SpaceVolume.osm diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index 95f6299a96b..d40644d0e91 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3227,24 +3227,62 @@ TEST_F(ModelFixture, Space_Polyhedron_Volume) { } TEST_F(ModelFixture, Issue_4837) { - osversion::VersionTranslator translator; - openstudio::path modelPath = resourcesPath() / toPath("model/test_file.osm"); - model::OptionalModel model = translator.loadModel(modelPath); - EXPECT_TRUE(model); - - boost::optional space1 = model->getConcreteModelObjectByName("Zone1 Office"); - ASSERT_TRUE(space1); - EXPECT_TRUE(space1->isEnclosedVolume()); - EXPECT_DOUBLE_EQ(1011.0, space1->volume()); + openstudio::path modelPath = resourcesPath() / toPath("model/4837_SpaceVolume.osm"); + model::OptionalModel model_ = translator.loadModel(modelPath); + ASSERT_TRUE(model_); + Model model = model_.get(); + + { + auto space = model.getConcreteModelObjectByName("Zone1 Office").get(); + EXPECT_TRUE(space.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space.isEnclosedVolume()); + EXPECT_NEAR(1010.76, space.volume(), 0.1); + } - boost::optional space2 = model->getConcreteModelObjectByName("Zone2 Fine Storage"); - ASSERT_TRUE(space2); - EXPECT_TRUE(space2->isEnclosedVolume()); - EXPECT_DOUBLE_EQ(10876.0, space2->volume()); + { + auto surface = model.getConcreteModelObjectByName("Bulk Storage Front Wall Reversed").get(); + auto vertices = surface.vertices(); + auto outNormal = surface.outwardNormal(); + EXPECT_EQ(openstudio::Vector3d(0, -1, 0), outNormal); + + auto space = model.getConcreteModelObjectByName("Zone2 Fine Storage").get(); + auto wrongOrientations = space.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(1, wrongOrientations.size()); + EXPECT_EQ("Bulk Storage Front Wall Reversed", wrongOrientations.front().nameString()); + EXPECT_FALSE(space.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space.fixSurfacesWithIncorrectOrientation()); + EXPECT_TRUE(space.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space.isEnclosedVolume()); + EXPECT_NEAR(11554.41, space.volume(), 0.1); + + auto newVertices = surface.vertices(); + EXPECT_NE(vertices, newVertices); + auto newOutNormal = surface.outwardNormal(); + EXPECT_NE(outNormal, newOutNormal); + EXPECT_EQ(openstudio::Vector3d(0, 1, 0), newOutNormal); + } - boost::optional space3 = model->getConcreteModelObjectByName("Zone3 Bulk Storage"); - ASSERT_TRUE(space3); - EXPECT_TRUE(space3->isEnclosedVolume()); - EXPECT_DOUBLE_EQ(27338.0, space3->volume()); + { + auto surface = model.getConcreteModelObjectByName("Bulk Storage Front Wall").get(); + auto vertices = surface.vertices(); + auto outNormal = surface.outwardNormal(); + EXPECT_EQ(openstudio::Vector3d(0, 1, 0), outNormal); + + auto space = model.getConcreteModelObjectByName("Zone3 Bulk Storage").get(); + EXPECT_FALSE(space.areAllSurfacesCorrectlyOriented()); + auto wrongOrientations = space.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(1, wrongOrientations.size()); + EXPECT_EQ(surface.nameString(), wrongOrientations.front().nameString()); + EXPECT_TRUE(space.fixSurfacesWithIncorrectOrientation()); + EXPECT_TRUE(space.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space.isEnclosedVolume()); + EXPECT_NEAR(27350.0, space.volume(), 0.1); + + auto newVertices = surface.vertices(); + EXPECT_NE(vertices, newVertices); + auto newOutNormal = surface.outwardNormal(); + EXPECT_NE(outNormal, newOutNormal); + EXPECT_EQ(openstudio::Vector3d(0, -1, 0), newOutNormal); + } } From 03656a3e17326d542e2cac00856079ec09830424 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 24 Mar 2023 15:20:53 +0100 Subject: [PATCH 08/40] Create a more simple test --- src/model/test/Space_GTest.cpp | 70 ++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index d40644d0e91..1a43054970b 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3286,3 +3286,73 @@ TEST_F(ModelFixture, Issue_4837) { EXPECT_EQ(openstudio::Vector3d(0, -1, 0), newOutNormal); } } + +TEST_F(ModelFixture, Space_4837_SpaceVolume) { + + Model m; + + constexpr double width = 10.0; + constexpr double height = 3.6; + constexpr double spaceFloorArea = width * width; + constexpr double spaceVolume = spaceFloorArea * height; + + // y (=North) + // ▲ + // │ + // 10o────────o + // │ │ + // │ │ + // │ Space 1│ + // │ │ + // o────────o───► x + // 0 10 + + // Counterclockwise points, Upper Left Corner convention + std::vector floorPointsSpace1{ + {width, width, 0.0}, + {width, 0.0, 0.0}, + {0.0, 0.0, 0.0}, + {0.0, width, 0.0}, + }; + + auto space1 = Space::fromFloorPrint(floorPointsSpace1, height, m).get(); + EXPECT_TRUE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space1.isEnclosedVolume()); + EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); + + // Grab a wall, flip it so it's outward normal points towards the space and not outside + auto surfaces = space1.surfaces(); + auto it = std::find_if(surfaces.begin(), surfaces.end(), [](auto& sf) { return sf.surfaceType() == "Wall"; }); + ASSERT_TRUE(it != surfaces.end()); + auto sfName = it->nameString(); + auto vertices = it->vertices(); + std::reverse(vertices.begin(), vertices.end()); + it->setVertices(vertices); + auto wrongOrientations = space1.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(1, wrongOrientations.size()); + EXPECT_EQ(sfName, wrongOrientations.front().nameString()); + EXPECT_FALSE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space1.isEnclosedVolume()); + EXPECT_EQ(spaceVolume, space1.volume()); // It falls back to the floor * ceilingHeight and since this is a box, it works... + EXPECT_TRUE(space1.fixSurfacesWithIncorrectOrientation()); + EXPECT_TRUE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space1.isEnclosedVolume()); + EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); + + // Flip everything + for (auto& sf : surfaces) { + auto vertices = sf.vertices(); + std::reverse(vertices.begin(), vertices.end()); + sf.setVertices(vertices); + } + + wrongOrientations = space1.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(6, wrongOrientations.size()); + EXPECT_FALSE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space1.isEnclosedVolume()); + EXPECT_EQ(spaceVolume, space1.volume()); + EXPECT_TRUE(space1.fixSurfacesWithIncorrectOrientation()); + EXPECT_TRUE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space1.isEnclosedVolume()); + EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); +} From 8bdf15a5ea2154f98e4c295850335769453bb787 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 24 Mar 2023 15:56:55 +0100 Subject: [PATCH 09/40] Create a second test like in the supplied file, where one space is non convex. --- src/model/test/Space_GTest.cpp | 66 ++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index 1a43054970b..60316b6f700 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3356,3 +3356,69 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume) { EXPECT_TRUE(space1.isEnclosedVolume()); EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); } + +TEST_F(ModelFixture, Space_4837_SpaceVolume_NonConvex) { + + Model m; + + // y (=North) + // ▲ + // │ building height = 2m + // 10├────────┼────────┼ + // │ │ + // │ | │ + // │ z=0 z=1 │ + // │ | │ + // └────────┴────────┴───► x + // 0 10 20 + + constexpr double width = 10.0; + constexpr double heightPart1 = 2.0; + constexpr double heightPart2 = 1.0; + constexpr double spaceFloorAreaEach = width * width; + constexpr double spaceVolumePart1 = (spaceFloorAreaEach * heightPart1); + constexpr double spaceVolumePart2 = (spaceFloorAreaEach * heightPart2); + constexpr double spaceVolume = spaceVolumePart1 + spaceVolumePart2; + + auto makeFloor = [](double min_x, double max_x, double min_y, double max_y, double z) { + // Counterclockwise points, Upper Left Corner convention, except here we want to create a floor + // so outward normal must be pointing DOWN, so clockwise order + return std::vector{ + Point3d(max_x, max_y, z), + Point3d(max_x, min_y, z), + Point3d(min_x, min_y, z), + Point3d(min_x, max_y, z), + }; + }; + + auto floorSurface1Points = makeFloor(0.0, width, 0.0, width, 0.0); + auto space1 = Space::fromFloorPrint(floorSurface1Points, heightPart1, m).get(); + EXPECT_EQ(spaceFloorAreaEach, space1.floorArea()); + EXPECT_EQ(spaceVolumePart1, space1.volume()); + EXPECT_TRUE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space1.isEnclosedVolume()); + + auto floorSurface2Points = makeFloor(width, 2 * width, 0.0, width, 1.0); + auto space2 = Space::fromFloorPrint(floorSurface2Points, heightPart2, m).get(); + EXPECT_EQ(spaceFloorAreaEach, space2.floorArea()); + EXPECT_EQ(spaceVolumePart2, space2.volume()); + EXPECT_TRUE(space2.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space2.isEnclosedVolume()); + + EXPECT_EQ(12, m.getConcreteModelObjects().size()); + space1.intersectSurfaces(space2); + EXPECT_EQ(13, m.getConcreteModelObjects().size()); + space1.matchSurfaces(space2); + EXPECT_EQ(13, m.getConcreteModelObjects().size()); + + ThermalZone z(m); + space1.setThermalZone(z); + space2.setThermalZone(z); + auto mergedSpace = z.combineSpaces().get(); + EXPECT_EQ(11, m.getConcreteModelObjects().size()); + + EXPECT_TRUE(mergedSpace.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(mergedSpace.isEnclosedVolume()); + EXPECT_EQ(2 * spaceFloorAreaEach, mergedSpace.floorArea()); + EXPECT_EQ(spaceVolume, mergedSpace.volume()); +} From e8ab8db57cf8289d62ee43ccde1684d6d89a4bc4 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Sat, 25 Mar 2023 11:40:19 +0100 Subject: [PATCH 10/40] Add an option to automatically name the Space + surface in Space::fromFloorPrint --- src/model/Space.cpp | 18 +++++++++++++----- src/model/Space.hpp | 3 ++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/model/Space.cpp b/src/model/Space.cpp index ebe527ed5f0..dbcdd0f7113 100644 --- a/src/model/Space.cpp +++ b/src/model/Space.cpp @@ -2957,7 +2957,8 @@ namespace model { return result; } - boost::optional Space::fromFloorPrint(const std::vector& floorPrint, double floorHeight, Model& model) { + boost::optional Space::fromFloorPrint(const std::vector& floorPrint, double floorHeight, Model& model, + const std::string& spaceName) { // check floor height if (floorHeight <= 0) { LOG(Error, "Cannot create a space with floorHeight " << floorHeight << "."); @@ -2998,14 +2999,17 @@ namespace model { return boost::none; } - reorderedFloorPrint = openstudio::reorderULC(reorderedFloorPrint); + // reorderedFloorPrint = openstudio::reorderULC(reorderedFloorPrint); // we are good to go, create the space Space space(model); // create the floor Surface floor(reorderedFloorPrint, model); - floor.setName(fmt::format("{} Floor", space.nameString())); + if (!spaceName.empty()) { + space.setName(spaceName); + floor.setName(fmt::format("{} Floor", space.nameString())); + } floor.setSpace(space); double zCeiling = z + floorHeight; @@ -3022,7 +3026,9 @@ namespace model { }; Surface wall(points, model); - wall.setName(fmt::format("{} Wall", space.nameString())); + if (!spaceName.empty()) { + wall.setName(fmt::format("{} Wall {}", space.nameString(), i)); + } wall.setSpace(space); } @@ -3034,7 +3040,9 @@ namespace model { return Point3d{pt.x(), pt.y(), zCeiling}; }); Surface roofCeiling(ceilingPoints, model); - roofCeiling.setName(fmt::format("{} RoofCeiling", space.nameString())); + if (!spaceName.empty()) { + roofCeiling.setName(fmt::format("{} RoofCeiling", space.nameString())); + } roofCeiling.setSpace(space); return space; diff --git a/src/model/Space.hpp b/src/model/Space.hpp index 6a9ac14c952..4e349568d23 100644 --- a/src/model/Space.hpp +++ b/src/model/Space.hpp @@ -103,7 +103,8 @@ namespace model { static IddObjectType iddObjectType(); /// Create a space from a floor print and extrude distance. - static boost::optional fromFloorPrint(const std::vector& floorPrint, double floorHeight, Model& model); + static boost::optional fromFloorPrint(const std::vector& floorPrint, double floorHeight, Model& model, + const std::string& spaceName = ""); /** @name Getters */ //@{ From c05b99ba1d35f586d709a5166840d108f3b269dd Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Sat, 25 Mar 2023 11:40:33 +0100 Subject: [PATCH 11/40] Failed raycasting try 1 --- src/model/Space.cpp | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/src/model/Space.cpp b/src/model/Space.cpp index dbcdd0f7113..6069272b785 100644 --- a/src/model/Space.cpp +++ b/src/model/Space.cpp @@ -927,31 +927,34 @@ namespace model { auto surfaces = this->surfaces(); for (const auto& surface : surfaces) { - auto normal = surface.outwardNormal(); - auto this_pt = surface.vertices()[0]; + auto outwardNormal = surface.outwardNormal(); + auto inwardNormal = outwardNormal.reverseVector(); + auto centroid = surface.centroid(); bool found = false; for (const auto& anotherSurface : surfaces) { if (surface == anotherSurface) { continue; } - for (const auto& another_pt : anotherSurface.vertices()) { - const Vector3d v1 = this_pt - another_pt; - auto thisdot = normal.dot(v1); - if (std::abs(thisdot) > 0.001) { - found = true; - if (thisdot < 0.0) { - result.push_back(surface); - } - break; - } + auto anotherPlane = anotherSurface.plane(); + // If this isn't orthogonal + if (std::abs(anotherPlane.outwardNormal().dot(outwardNormal)) < 0.001) { + LOG(Debug, "Surface " << surface.nameString() << " is orthogonal to " << anotherSurface.nameString()); + continue; } - if (found) { + auto projectedCentroid = anotherPlane.project(centroid); + auto v = (centroid - projectedCentroid); + if (!v.normalize()) { + LOG(Debug, "Surface " << surface.nameString() << " is on the same plane as " << anotherSurface.nameString()); + continue; + } + if (std::abs(outwardNormal.dot(v) - 1) < 0.001) { + LOG(Debug, "Surface " << surface.nameString() << " raycasts to " << anotherSurface.nameString()); + found = true; break; } } - if (!found) { - LOG(Error, "Could not find any dot product that isn't zero for Surface " << surface.nameString()); + result.push_back(surface); } } From 426eefa099c2d60f6e6bb680360fb662b274c24b Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Sat, 25 Mar 2023 11:56:13 +0100 Subject: [PATCH 12/40] Raycasting that works. Left both the inward/outward conventions for testing. Will adjust --- src/model/Space.cpp | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/src/model/Space.cpp b/src/model/Space.cpp index 6069272b785..394ac58743c 100644 --- a/src/model/Space.cpp +++ b/src/model/Space.cpp @@ -924,33 +924,50 @@ namespace model { std::vector Space_Impl::findSurfacesWithIncorrectOrientation() const { std::vector result; + const Point3d p0{}; + auto surfaces = this->surfaces(); for (const auto& surface : surfaces) { auto outwardNormal = surface.outwardNormal(); + auto surfacePoint = surface.centroid(); auto inwardNormal = outwardNormal.reverseVector(); - auto centroid = surface.centroid(); bool found = false; for (const auto& anotherSurface : surfaces) { if (surface == anotherSurface) { continue; } auto anotherPlane = anotherSurface.plane(); + const double vd = anotherPlane.outwardNormal().dot(outwardNormal); + + auto reversedPlane = anotherPlane.reversePlane(); + const double vd2 = reversedPlane.outwardNormal().dot(inwardNormal); + + OS_ASSERT(vd == vd2); + // If this isn't orthogonal - if (std::abs(anotherPlane.outwardNormal().dot(outwardNormal)) < 0.001) { + if (std::abs(vd) < 0.001) { LOG(Debug, "Surface " << surface.nameString() << " is orthogonal to " << anotherSurface.nameString()); continue; } - auto projectedCentroid = anotherPlane.project(centroid); - auto v = (centroid - projectedCentroid); - if (!v.normalize()) { - LOG(Debug, "Surface " << surface.nameString() << " is on the same plane as " << anotherSurface.nameString()); - continue; + if (vd > 0) { + LOG(Debug, "Surfaces '" << surface.nameString() << "' and '" << anotherSurface.nameString() + << "' are seemingly pointing in the opposite outward direction, which is good"); + } else { + LOG(Debug, "Surfaces '" << surface.nameString() << "' and '" << anotherSurface.nameString() + << "' are seemingly pointing in the same outward direction, potentially one is in the wrong direction."); } - if (std::abs(outwardNormal.dot(v) - 1) < 0.001) { - LOG(Debug, "Surface " << surface.nameString() << " raycasts to " << anotherSurface.nameString()); + + const double v0 = anotherPlane.outwardNormal().dot(surfacePoint - p0) + anotherPlane.d(); + const double v02 = reversedPlane.outwardNormal().reverseVector().dot(surfacePoint - p0) - reversedPlane.d(); + OS_ASSERT(v0 == v02); + const double t = v0 / vd; + if (t > 0.0) { + LOG(Debug, "Surface '" << surface.nameString() << "' raycasts to " << anotherSurface.nameString()); found = true; break; + } else { + LOG(Debug, "Surface '" << surface.nameString() << "' does not raycast to " << anotherSurface.nameString()); } } if (!found) { @@ -964,7 +981,8 @@ namespace model { bool Space_Impl::areAllSurfacesCorrectlyOriented() const { auto surfaces = findSurfacesWithIncorrectOrientation(); for (const auto& surface : surfaces) { - LOG(Error, "In Space " << nameString() << ", Surface " << surface.nameString() << " has an outward normal pointing in the wrong direction."); + LOG(Error, + "In Space '" << nameString() << "', Surface '" << surface.nameString() << "' has an outward normal pointing in the wrong direction."); } return surfaces.empty(); @@ -980,8 +998,8 @@ namespace model { for (auto& surface : surfaces) { auto vertices = surface.vertices(); - LOG(Error, "In Space " << nameString() << ", Surface " << surface.nameString() - << " has an outward normal pointing in the wrong direction. Flipping it."); + LOG(Error, "In Space '" << nameString() << "', Surface '" << surface.nameString() + << "' has an outward normal pointing in the wrong direction. Flipping it."); std::reverse(vertices.begin(), vertices.end()); surface.setVertices(openstudio::reorderULC(vertices)); } From 94c9e849118240beb4f926cb3fa4ed2cb5e0e84a Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 10:22:31 +0200 Subject: [PATCH 13/40] I got Pwned by this 10 year old comment quite bad. Plane equation used is actually ax+by+cz+d = 0. The ray tracing was spitting wrong results and I couldn't understand why because my math was good. Turns out the equation in this comment was wrong. I had to redo all calcs manually to figure it out. --- src/utilities/geometry/Plane.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utilities/geometry/Plane.hpp b/src/utilities/geometry/Plane.hpp index bf81da5e388..14e0ede90c2 100644 --- a/src/utilities/geometry/Plane.hpp +++ b/src/utilities/geometry/Plane.hpp @@ -44,7 +44,7 @@ class Point3d; class Vector3d; /** Plane defines an infinite plane in 3D space. The equation of a plane is - * a*x + b*y + c*z = d, any point that satisfies this equation is on the plane. + * a*x + b*y + c*z + d = 0, any point that satisfies this equation is on the plane. */ class UTILITIES_API Plane { From 80458683ddc1d887d417f6acfbe817d4a91f59da Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 10:40:43 +0200 Subject: [PATCH 14/40] Add a convenience function Plane::anyPointOnPlane --- src/utilities/geometry/Plane.cpp | 16 ++++++++++++++++ src/utilities/geometry/Plane.hpp | 3 +++ 2 files changed, 19 insertions(+) diff --git a/src/utilities/geometry/Plane.cpp b/src/utilities/geometry/Plane.cpp index 382c8459821..2d25947c256 100644 --- a/src/utilities/geometry/Plane.cpp +++ b/src/utilities/geometry/Plane.cpp @@ -341,6 +341,22 @@ double Plane::d() const { return m_d; } +Point3d Plane::anyPointOnPlane() const { + + if (std::abs(m_d) < 0.0001) { + return Point3d(0.0, 0.0, 0.0); + } + // a*x + b*y + c*z + d = 0, any point that satisfies this equation is on the plane. + if (std::abs(m_a) > 0.0) { + return Point3d(-m_d / m_a, 0.0, 0.0); + } + if (std::abs(m_b) > 0.0) { + return Point3d(0.0, -m_d / m_b, 0.0); + } + + return Point3d(0.0, 0.0, -m_d / m_c); +} + std::ostream& operator<<(std::ostream& os, const Plane& plane) { os << "[" << plane.a() << ", " << plane.b() << ", " << plane.c() << ", " << plane.d() << "]"; return os; diff --git a/src/utilities/geometry/Plane.hpp b/src/utilities/geometry/Plane.hpp index 14e0ede90c2..052abfe5d87 100644 --- a/src/utilities/geometry/Plane.hpp +++ b/src/utilities/geometry/Plane.hpp @@ -102,6 +102,9 @@ class UTILITIES_API Plane /// coefficient d double d() const; + // Returns any Point3d that's on this plane + Point3d anyPointOnPlane() const; + private: // construct with coefficients Plane(double a, double b, double c, double d); From ab91ea25fc81429227f76e1e12b5b09f1348db0b Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 10:47:04 +0200 Subject: [PATCH 15/40] Create a Plane::rayIntersection method --- src/utilities/geometry/Plane.cpp | 47 ++++++++++++++++++++++++++++++++ src/utilities/geometry/Plane.hpp | 4 +++ 2 files changed, 51 insertions(+) diff --git a/src/utilities/geometry/Plane.cpp b/src/utilities/geometry/Plane.cpp index 2d25947c256..508f9613964 100644 --- a/src/utilities/geometry/Plane.cpp +++ b/src/utilities/geometry/Plane.cpp @@ -357,7 +357,54 @@ Point3d Plane::anyPointOnPlane() const { return Point3d(0.0, 0.0, -m_d / m_c); } +boost::optional Plane::rayIntersection(const Point3d& rayOrigin, const Vector3d& rayDirection, bool enforceDirectionOfPlane) const { + + // Any point on plane p = (x, y, z): + // a*x + b*y +c*z + d = 0 + // <=> Pn · p + d = 0, where Pn is the plane outwardNormal (1) + // + // Any point on a ray, given it's origin r0 (X0, Y0, Z0) and the direction rD (Xd, Yd, Zd), satisfies this equation + // r(t) = r0 + t * rD, **with t > 0** (2) + // (t > 0 because, directed ray, otherwise, it's a line) + // + // If there is an intersection, then this equation must be satisfied: + // Pn · r(t) + d = 0 + // <=> Pn · R0 + t * (Pn·Rd) + d = 0 + // <=> t = -((Pn · R0) + d) / (Pn · Rd), **With t > 0** + + const Point3d p0{}; + + auto thisOutwardNormal = outwardNormal(); + + double vd = thisOutwardNormal.dot(rayDirection); + + if (std::abs(vd) < 0.001) { + LOG(Debug, "Plane is orthogonal to Ray, no intersection possible"); + return {}; + } + if (vd > 0) { + if (enforceDirectionOfPlane) { + LOG(Debug, "Plane normal and ray are poiting in the same direction..."); + return {}; + } else { + LOG(Trace, "Plane normal and ray are poiting in the same direction..."); + } + } else { + LOG(Trace, "Plane normal and ray are poiting in the opposite direction..."); + } + + const double v0 = -(thisOutwardNormal.dot(rayOrigin - p0) + m_d); + const double t = v0 / vd; + LOG(Trace, "vd=" << vd << ", v0=" << v0 << ", t=" << t); + if (t > 0.0) { + return rayOrigin + t * rayDirection; + } + + return {}; +} + std::ostream& operator<<(std::ostream& os, const Plane& plane) { + // os << fmt::format("Plane: {:g}x {:+g}y {:+g}z {:+g} = 0", plane.a(), plane.b(), plane.c(), plane.d()); os << "[" << plane.a() << ", " << plane.b() << ", " << plane.c() << ", " << plane.d() << "]"; return os; } diff --git a/src/utilities/geometry/Plane.hpp b/src/utilities/geometry/Plane.hpp index 052abfe5d87..93882276287 100644 --- a/src/utilities/geometry/Plane.hpp +++ b/src/utilities/geometry/Plane.hpp @@ -105,6 +105,10 @@ class UTILITIES_API Plane // Returns any Point3d that's on this plane Point3d anyPointOnPlane() const; + /** Project a directed ray towards a plane and returns the intersection point if any. The RayDirection should be shooting TOWARDS the plane + * If enforceDirectionOfPlane is true, the ray direction and the plane outward normal must be facing each other */ + boost::optional rayIntersection(const Point3d& rayOrigin, const Vector3d& rayDirection, bool enforceDirectionOfPlane = false) const; + private: // construct with coefficients Plane(double a, double b, double c, double d); From 4d8070af8e3f8f38d84beaf551e037ffa340ec6e Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 10:47:13 +0200 Subject: [PATCH 16/40] Test the rayIntersection method --- src/utilities/geometry/Test/Plane_GTest.cpp | 224 ++++++++++++++++++++ 1 file changed, 224 insertions(+) diff --git a/src/utilities/geometry/Test/Plane_GTest.cpp b/src/utilities/geometry/Test/Plane_GTest.cpp index f33952b28ff..03d5399769c 100644 --- a/src/utilities/geometry/Test/Plane_GTest.cpp +++ b/src/utilities/geometry/Test/Plane_GTest.cpp @@ -725,3 +725,227 @@ TEST_F(GeometryFixture, Plane_ProblemSurface2) { EXPECT_TRUE(plane2->equal(*plane)); } } + +TEST_F(GeometryFixture, Plane_RayIntersection) { + + // This is a 30x10x0.3 base, with a rectangle triangle on top of 30x10x10 + // ▲ z + // │ + // x├─ 10.3 + // x │ + // x │ + // x │ + // x │ + // x │ + // x │ + // x ├─ 0.3 + // │ │ + // ◄────┼──────────────┼─ + // y 10.0 0.0 + + // Putting extra vertices here on purpose to show that the Space::volume was miscalculating due to averaging foor and ceiling heights + std::vector roof{ + {+30.0, +0.0, +10.3}, // + {+30.0, +10.0, +0.3}, // + {+0.0, +10.0, +0.3}, // + {+0.0, +0.0, +10.3}, // + {+10.0, +0.0, +10.3}, // + {+20.0, +0.0, +10.3}, + }; + + std::vector east{ + {+30.0, +0.0, +10.3}, + {+30.0, +0.0, +0.0}, + {+30.0, +10.0, +0.0}, + {+30.0, +10.0, +0.3}, + }; + + std::vector north{ + {+30.0, +10.0, +0.3}, + {+30.0, +10.0, +0.0}, + {+0.0, +10.0, +0.0}, + {+0.0, +10.0, +0.3}, + }; + + std::vector west{ + {+0.0, +10.0, +0.3}, + {+0.0, +10.0, +0.0}, + {+0.0, +0.0, +0.0}, + {+0.0, +0.0, +10.3}, + }; + + std::vector south1{ + {+0.0, +0.0, +10.3}, + {+0.0, +0.0, +0.0}, + {+15.0, +0.0, +0.0}, + {+15.0, +0.0, +10.3}, + }; + + std::vector south2{ + {+15.0, +0.0, +10.3}, + {+15.0, +0.0, +0.0}, + {+30.0, +0.0, +0.0}, + {+30.0, +0.0, +10.3}, + }; + + // Clockwise because normal is pointing down + std::vector floor{ + {+0.0, +0.0, +0.0}, + {+0.0, +10.0, +0.0}, + {+30.0, +10.0, +0.0}, + {+30.0, +0.0, +0.0}, + }; + + Plane floorPlane(floor); + EXPECT_DOUBLE_EQ(0.0, floorPlane.a()); + EXPECT_DOUBLE_EQ(0.0, floorPlane.b()); + EXPECT_DOUBLE_EQ(-1.0, floorPlane.c()); + EXPECT_DOUBLE_EQ(0.0, floorPlane.d()); + + Plane roofPlane(roof); + Vector3d roofNormal(0, 1, 1); + ASSERT_TRUE(roofNormal.normalize()); + EXPECT_DOUBLE_EQ(0.0, roofPlane.a()); + EXPECT_DOUBLE_EQ(roofNormal.y(), roofPlane.b()); + EXPECT_DOUBLE_EQ(roofNormal.z(), roofPlane.c()); + EXPECT_DOUBLE_EQ(-roofNormal.y() * 10.3, roofPlane.d()); + EXPECT_DOUBLE_EQ(-7.2831998462214402, roofPlane.d()); + + Plane south1Plane(south1); + EXPECT_DOUBLE_EQ(0.0, south1Plane.a()); + EXPECT_DOUBLE_EQ(-1.0, south1Plane.b()); + EXPECT_DOUBLE_EQ(0.0, south1Plane.c()); + EXPECT_DOUBLE_EQ(0.0, south1Plane.d()); + + Plane south2Plane(south2); + EXPECT_DOUBLE_EQ(0.0, south2Plane.a()); + EXPECT_DOUBLE_EQ(-1.0, south2Plane.b()); + EXPECT_DOUBLE_EQ(0.0, south2Plane.c()); + EXPECT_DOUBLE_EQ(0.0, south2Plane.d()); + + Plane northPlane(north); + EXPECT_DOUBLE_EQ(0.0, northPlane.a()); + EXPECT_DOUBLE_EQ(1.0, northPlane.b()); + EXPECT_DOUBLE_EQ(0.0, northPlane.c()); + EXPECT_DOUBLE_EQ(-10.0, northPlane.d()); + + Plane westPlane(west); + EXPECT_DOUBLE_EQ(-1.0, westPlane.a()); + EXPECT_DOUBLE_EQ(0.0, westPlane.b()); + EXPECT_DOUBLE_EQ(0.0, westPlane.c()); + EXPECT_DOUBLE_EQ(0.0, westPlane.d()); + + Plane eastPlane(east); + EXPECT_DOUBLE_EQ(1.0, eastPlane.a()); + EXPECT_DOUBLE_EQ(0.0, eastPlane.b()); + EXPECT_DOUBLE_EQ(0.0, eastPlane.c()); + EXPECT_DOUBLE_EQ(-30.0, eastPlane.d()); + + for (const auto& plane : {floorPlane, roofPlane, south1Plane, south2Plane, northPlane, westPlane, eastPlane}) { + const Point3d p = plane.anyPointOnPlane(); + EXPECT_TRUE(plane.pointOnPlane(p)); + } + + // Floor shoots to Roof (only) + { + Point3d r0(5.0, 5.0, 0.0); + EXPECT_TRUE(floorPlane.pointOnPlane(r0)); + Vector3d rD = floorPlane.outwardNormal().reverseVector(); + EXPECT_TRUE(vectorEqual(Vector3d(0.0, 0.0, 1.0), rD)); + + EXPECT_FALSE(south1Plane.rayIntersection(r0, rD)); + EXPECT_FALSE(south2Plane.rayIntersection(r0, rD)); + EXPECT_FALSE(northPlane.rayIntersection(r0, rD)); + EXPECT_FALSE(eastPlane.rayIntersection(r0, rD)); + EXPECT_FALSE(westPlane.rayIntersection(r0, rD)); + + { + boost::optional intersection_ = roofPlane.rayIntersection(r0, rD); + ASSERT_TRUE(intersection_); + EXPECT_TRUE(pointEqual({5.0, 5.0, 5.3}, intersection_.get())); + EXPECT_TRUE(roofPlane.pointOnPlane(intersection_.get())); + } + + // Reverse shoots nowhere + EXPECT_FALSE(south1Plane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(south2Plane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(northPlane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(westPlane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(eastPlane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(roofPlane.rayIntersection(r0, rD.reverseVector())); + } + + // Roof shoots to floor and the south walls + // it shouldn't shoot to the north wall because even though they aren't orthogonal, we should expect (t < 0) + { + Point3d r0(5.0, 5.0, 5.3); + EXPECT_TRUE(roofPlane.pointOnPlane(r0)); + Vector3d rD = roofPlane.outwardNormal().reverseVector(); + EXPECT_TRUE(vectorEqual(Vector3d(0.0, -0.707107, -0.707107), rD)); + + EXPECT_FALSE(northPlane.rayIntersection(r0, rD)); + EXPECT_FALSE(eastPlane.rayIntersection(r0, rD)); + EXPECT_FALSE(westPlane.rayIntersection(r0, rD)); + + { + boost::optional intersection_ = floorPlane.rayIntersection(r0, rD); + ASSERT_TRUE(intersection_); + EXPECT_TRUE(pointEqual({5.0, -0.3, 0.0}, intersection_.get())); + EXPECT_TRUE(floorPlane.pointOnPlane(intersection_.get())); + } + + { + boost::optional intersection_ = south1Plane.rayIntersection(r0, rD); + ASSERT_TRUE(intersection_); + EXPECT_TRUE(pointEqual({5.0, 0.0, 0.3}, intersection_.get())) << intersection_.get(); + EXPECT_TRUE(south1Plane.pointOnPlane(intersection_.get())); + } + { + boost::optional intersection_ = south2Plane.rayIntersection(r0, rD); + ASSERT_TRUE(intersection_); + EXPECT_TRUE(pointEqual({5.0, 0.0, 0.3}, intersection_.get())) << intersection_.get(); + EXPECT_TRUE(south2Plane.pointOnPlane(intersection_.get())); + } + + // Reverse shoots to the north plane... + EXPECT_FALSE(south1Plane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(south2Plane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(westPlane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(eastPlane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(floorPlane.rayIntersection(r0, rD.reverseVector())); + + { + boost::optional intersection_ = northPlane.rayIntersection(r0, rD.reverseVector()); + ASSERT_TRUE(intersection_); + EXPECT_TRUE(pointEqual({5.0, 10.0, 10.3}, intersection_.get())) << intersection_.get(); + EXPECT_TRUE(northPlane.pointOnPlane(intersection_.get())); + } + } + + // East wall shoots to West wall (only) + { + Point3d r0(30.0, 5.0, 5.0); + EXPECT_TRUE(eastPlane.pointOnPlane(r0)); + Vector3d rD = eastPlane.outwardNormal().reverseVector(); + EXPECT_FALSE(south1Plane.rayIntersection(r0, rD)); + EXPECT_FALSE(south2Plane.rayIntersection(r0, rD)); + EXPECT_FALSE(northPlane.rayIntersection(r0, rD)); + EXPECT_FALSE(floorPlane.rayIntersection(r0, rD)); + EXPECT_FALSE(roofPlane.rayIntersection(r0, rD)); + + { + boost::optional intersection_ = westPlane.rayIntersection(r0, rD); + ASSERT_TRUE(intersection_); + EXPECT_TRUE(pointEqual({0.0, 5.0, 5.0}, intersection_.get())); + EXPECT_TRUE(westPlane.pointOnPlane(intersection_.get())); + } + + // Reverse shoots nowhere + EXPECT_FALSE(south1Plane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(south2Plane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(northPlane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(westPlane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(floorPlane.rayIntersection(r0, rD.reverseVector())); + EXPECT_FALSE(roofPlane.rayIntersection(r0, rD.reverseVector())); + } +} From 172211b039f73cb9ed68d60bf34d62ff02112fb4 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 11:27:03 +0200 Subject: [PATCH 17/40] Adust SpaceGtest --- src/model/Space.cpp | 10 +++++----- src/model/test/Space_GTest.cpp | 24 ++++++++++++++++++++---- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/model/Space.cpp b/src/model/Space.cpp index 394ac58743c..3394d0aa5fc 100644 --- a/src/model/Space.cpp +++ b/src/model/Space.cpp @@ -930,8 +930,9 @@ namespace model { for (const auto& surface : surfaces) { auto outwardNormal = surface.outwardNormal(); - auto surfacePoint = surface.centroid(); auto inwardNormal = outwardNormal.reverseVector(); + + auto surfacePoint = surface.centroid(); bool found = false; for (const auto& anotherSurface : surfaces) { if (surface == anotherSurface) { @@ -942,7 +943,6 @@ namespace model { auto reversedPlane = anotherPlane.reversePlane(); const double vd2 = reversedPlane.outwardNormal().dot(inwardNormal); - OS_ASSERT(vd == vd2); // If this isn't orthogonal @@ -950,16 +950,16 @@ namespace model { LOG(Debug, "Surface " << surface.nameString() << " is orthogonal to " << anotherSurface.nameString()); continue; } - if (vd > 0) { + if (vd < 0) { LOG(Debug, "Surfaces '" << surface.nameString() << "' and '" << anotherSurface.nameString() - << "' are seemingly pointing in the opposite outward direction, which is good"); + << "' are seemingly pointing in the opposite outward direction, which is a good sign."); } else { LOG(Debug, "Surfaces '" << surface.nameString() << "' and '" << anotherSurface.nameString() << "' are seemingly pointing in the same outward direction, potentially one is in the wrong direction."); } const double v0 = anotherPlane.outwardNormal().dot(surfacePoint - p0) + anotherPlane.d(); - const double v02 = reversedPlane.outwardNormal().reverseVector().dot(surfacePoint - p0) - reversedPlane.d(); + const double v02 = -(reversedPlane.outwardNormal().dot(surfacePoint - p0) + reversedPlane.d()); OS_ASSERT(v0 == v02); const double t = v0 / vd; if (t > 0.0) { diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index 60316b6f700..113b9c5d419 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -74,7 +74,14 @@ #include "../../osversion/VersionTranslator.hpp" #include "../../utilities/geometry/Intersection.hpp" +#include #include +#include +#include +#include + +#include +#include using namespace openstudio; using namespace openstudio::model; @@ -3179,7 +3186,7 @@ TEST_F(ModelFixture, Space_Polyhedron_Volume) { // This is a 30x10x0.3 base, with a rectangle triangle on top of 30x10x10 // ▲ z // │ - // x├─ 10.0 + // x├─ 10.3 // x │ // x │ // x │ @@ -3195,7 +3202,7 @@ TEST_F(ModelFixture, Space_Polyhedron_Volume) { south2.setName("1-SOUTH-2"); south2.setSpace(s); - // Putting extra vertices here on purpose to show that the Space::volume will miscalculate due to averaging foor and ceiling heights + // Putting extra vertices here on purpose to show that the Space::volume was miscalculating due to averaging foor and ceiling heights Surface roof({{+30.0, +0.0, +10.3}, {+30.0, +10.0, +0.3}, {+0.0, +10.0, +0.3}, {+0.0, +0.0, +10.3}, {+10.0, +0.0, +10.3}, {+20.0, +0.0, +10.3}}, m); roof.setName("ROOF"); roof.setSpace(s); @@ -3220,9 +3227,18 @@ TEST_F(ModelFixture, Space_Polyhedron_Volume) { floor.setName("FLOOR"); floor.setSpace(s); + auto wrongOrientations = s.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(0, wrongOrientations.size()) << [&wrongOrientations]() { + std::vector surfaceNames; + surfaceNames.reserve(wrongOrientations.size()); + std::transform(wrongOrientations.cbegin(), wrongOrientations.cend(), std::back_inserter(surfaceNames), + [](const auto& sf) { return sf.nameString(); }); + return fmt::format("surfaceNames={}", surfaceNames); + }(); + EXPECT_TRUE(s.areAllSurfacesCorrectlyOriented()); EXPECT_TRUE(s.isEnclosedVolume()); - double volume = 30.0 * 10.0 * 0.3 + 30.0 * 10.0 * 10.0 / 2.0; + constexpr double volume = (30.0 * 10.0 * 0.3) + (30.0 * 10.0 * 10.0) / 2.0; EXPECT_EQ(volume, s.volume()); } @@ -3254,7 +3270,7 @@ TEST_F(ModelFixture, Issue_4837) { EXPECT_TRUE(space.fixSurfacesWithIncorrectOrientation()); EXPECT_TRUE(space.areAllSurfacesCorrectlyOriented()); EXPECT_TRUE(space.isEnclosedVolume()); - EXPECT_NEAR(11554.41, space.volume(), 0.1); + EXPECT_NEAR(10880.57, space.volume(), 0.1); auto newVertices = surface.vertices(); EXPECT_NE(vertices, newVertices); From f63237b16a968be0e774e18bf640b23be5a94150 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 11:11:25 +0200 Subject: [PATCH 18/40] Add a reverseEqual method for Surface3dEdge... A potential application is checking that each edge is used exactly twice and in reversed order, otherwise a face is reversed --- src/utilities/geometry/Polyhedron.cpp | 4 ++++ src/utilities/geometry/Polyhedron.hpp | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index cb59e9365af..8d95d6ddcd2 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -58,6 +58,10 @@ bool Surface3dEdge::operator!=(const Surface3dEdge& other) const { return !(*this == other); } +bool Surface3dEdge::reverseEqual(const Surface3dEdge& other) const { + return isAlmostEqual3dPt(m_start, other.m_end) && isAlmostEqual3dPt(m_end, other.m_start); +} + Point3d Surface3dEdge::start() const { return m_start; } diff --git a/src/utilities/geometry/Polyhedron.hpp b/src/utilities/geometry/Polyhedron.hpp index a7688f9959c..932c450caf9 100644 --- a/src/utilities/geometry/Polyhedron.hpp +++ b/src/utilities/geometry/Polyhedron.hpp @@ -64,6 +64,9 @@ class UTILITIES_API Surface3dEdge /// check equality: this uses a tolerance bool operator==(const Surface3dEdge& other) const; + // Asserts that isAlmostEqual3dPt(start, other.end) && isAlmostEqual3dPt(end, other.start) + bool reverseEqual(const Surface3dEdge& other) const; + /// check inequality bool operator!=(const Surface3dEdge& other) const; From 41a8251860c43324bcac02bd05d4c059f59e4974 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 11:12:30 +0200 Subject: [PATCH 19/40] Const-correctness in Geometry.cpp (+ a std::rotate) --- src/utilities/geometry/Geometry.cpp | 156 ++++++++++++++-------------- 1 file changed, 77 insertions(+), 79 deletions(-) diff --git a/src/utilities/geometry/Geometry.cpp b/src/utilities/geometry/Geometry.cpp index f3cdabfb5f5..c096cb28b53 100644 --- a/src/utilities/geometry/Geometry.cpp +++ b/src/utilities/geometry/Geometry.cpp @@ -65,12 +65,12 @@ boost::optional getArea(const Point3dVector& points) { // magnitude is twice the area OptionalVector3d getNewellVector(const Point3dVector& points) { OptionalVector3d result; - size_t N = points.size(); + const size_t N = points.size(); if (N >= 3) { Vector3d vec; for (unsigned i = 1; i < N - 1; ++i) { - Vector3d v1 = points[i] - points[0]; - Vector3d v2 = points[i + 1] - points[0]; + const Vector3d v1 = points[i] - points[0]; + const Vector3d v2 = points[i + 1] - points[0]; vec += v1.cross(v2); } result = vec; @@ -95,18 +95,18 @@ OptionalPoint3d getCentroid(const Point3dVector& points) { if (points.size() >= 3) { // convert to face coordinates - Transformation alignFace = Transformation::alignFace(points); + const Transformation alignFace = Transformation::alignFace(points); Point3dVector surfacePoints = alignFace.inverse() * points; - size_t N = surfacePoints.size(); + const size_t N = surfacePoints.size(); double A = 0; double cx = 0; double cy = 0; for (size_t i = 0; i < N; ++i) { - double x1; - double x2; - double y1; - double y2; + double x1 = 0.0; + double x2 = 0.0; + double y1 = 0.0; + double y2 = 0.0; if (i == N - 1) { x1 = surfacePoints[i].x(); x2 = surfacePoints[0].x(); @@ -119,7 +119,7 @@ OptionalPoint3d getCentroid(const Point3dVector& points) { y2 = surfacePoints[i + 1].y(); } - double dA = (x1 * y2 - x2 * y1); + const double dA = (x1 * y2 - x2 * y1); A += 0.5 * dA; cx += (x1 + x2) * dA; cy += (y1 + y2) * dA; @@ -127,7 +127,7 @@ OptionalPoint3d getCentroid(const Point3dVector& points) { if (A > 0) { // centroid in face coordinates - Point3d surfaceCentroid(cx / (6.0 * A), cy / (6.0 * A), 0.0); + const Point3d surfaceCentroid(cx / (6.0 * A), cy / (6.0 * A), 0.0); // centroid result = alignFace * surfaceCentroid; @@ -138,20 +138,20 @@ OptionalPoint3d getCentroid(const Point3dVector& points) { /// reorder points to upper-left-corner convention Point3dVector reorderULC(const Point3dVector& points) { - size_t N = points.size(); + const size_t N = points.size(); if (N < 3) { return {}; } // transformation to align face - Transformation t = Transformation::alignFace(points); + const Transformation t = Transformation::alignFace(points); Point3dVector facePoints = t.inverse() * points; // find ulc index in face coordinates double maxY = std::numeric_limits::min(); double minX = std::numeric_limits::max(); - unsigned ulcIndex = 0; - for (unsigned i = 0; i < N; ++i) { + size_t ulcIndex = 0; + for (size_t i = 0; i < N; ++i) { OS_ASSERT(std::abs(facePoints[i].z()) < 0.001); if ((maxY < facePoints[i].y()) || ((maxY < facePoints[i].y() + 0.00001) && (minX > facePoints[i].x()))) { ulcIndex = i; @@ -166,21 +166,19 @@ Point3dVector reorderULC(const Point3dVector& points) { } // create result - Point3dVector result; - std::copy(points.begin() + ulcIndex, points.end(), std::back_inserter(result)); - std::copy(points.begin(), points.begin() + ulcIndex, std::back_inserter(result)); - OS_ASSERT(result.size() == N); + Point3dVector result = points; + std::rotate(result.begin(), std::next(result.begin(), ulcIndex), result.end()); return result; } std::vector removeCollinear(const Point3dVector& points, double tol) { - Transformation t = Transformation::alignFace(points); + const Transformation t = Transformation::alignFace(points); std::vector result = t * simplify(t.inverse() * points, true, tol); return result; } std::vector removeCollinearLegacy(const Point3dVector& points, double tol) { - size_t N = points.size(); + const size_t N = points.size(); if (N < 3) { return points; } @@ -190,7 +188,7 @@ std::vector removeCollinearLegacy(const Point3dVector& points, double t result.push_back(lastPoint); for (unsigned i = 1; i < N; ++i) { - Point3d currentPoint = points[i]; + const Point3d& currentPoint = points[i]; Point3d nextPoint = points[0]; if (i < N - 1) { nextPoint = points[i + 1]; @@ -203,14 +201,14 @@ std::vector removeCollinearLegacy(const Point3dVector& points, double t if (a.normalize()) { if (b.normalize()) { - Vector3d c = a.cross(b); + const Vector3d c = a.cross(b); if (c.length() >= tol) { // cross product is significant result.push_back(currentPoint); lastPoint = currentPoint; } else { // see if dot product is near -1 - double d = a.dot(b); + const double d = a.dot(b); if (d <= -1.0 + tol) { // this is a line reversal result.push_back(currentPoint); @@ -227,13 +225,13 @@ std::vector removeCollinearLegacy(const Point3dVector& points, double t bool resizeBegin = true; while (resizeBegin) { resizeBegin = false; - unsigned newN = iEnd - iBegin; + const unsigned newN = iEnd - iBegin; if (newN > 3) { Vector3d a = (result[iBegin] - result[iEnd - 1]); Vector3d b = (result[iBegin + 1] - result[iBegin]); if (a.normalize()) { if (b.normalize()) { - double d = a.dot(b); + const double d = a.dot(b); if (d >= 1.0 - tol) { iBegin++; resizeBegin = true; @@ -252,13 +250,13 @@ std::vector removeCollinearLegacy(const Point3dVector& points, double t bool resizeEnd = true; while (resizeEnd) { resizeEnd = false; - unsigned newN = iEnd - iBegin; + const unsigned newN = iEnd - iBegin; if (newN > 3) { Vector3d a = (result[iEnd - 1] - result[iEnd - 2]); Vector3d b = (result[iBegin] - result[iEnd - 1]); if (a.normalize()) { if (b.normalize()) { - double d = a.dot(b); + const double d = a.dot(b); if (d >= 1.0 - tol) { iEnd--; resizeEnd = true; @@ -279,10 +277,10 @@ std::vector removeCollinearLegacy(const Point3dVector& points, double t } double getDistanceSquared(const Point3d& point1, const Point3d& point2) { - double dx = point1.x() - point2.x(); - double dy = point1.y() - point2.y(); - double dz = point1.z() - point2.z(); - double result = dx * dx + dy * dy + dz * dz; + const double dx = point1.x() - point2.x(); + const double dy = point1.y() - point2.y(); + const double dz = point1.z() - point2.z(); + const double result = dx * dx + dy * dy + dz * dz; return result; } @@ -336,27 +334,27 @@ double getDistancePointToTriangle(const Point3d& point, const std::vector 1.0 - 1.0E-12) { // triangle is collinear return 0; } - double a = E0.dot(E0); - double c = E1.dot(E1); - double d = E0.dot(BminusP); - double e = E1.dot(BminusP); - // double f = BminusP.dot(BminusP); // unused + const double a = E0.dot(E0); + const double c = E1.dot(E1); + const double d = E0.dot(BminusP); + const double e = E1.dot(BminusP); + // const double f = BminusP.dot(BminusP); // unused - double det = a * c - b * b; - double s = b * e - c * d; - double t = b * d - a * e; + const double det = a * c - b * b; + const double s = b * e - c * d; + const double t = b * d - a * e; Point3d closestPoint; @@ -380,7 +378,7 @@ double getDistancePointToTriangle(const Point3d& point, const std::vector> computeTriangulation(const Point3dVector& vert } // if holes have been triangulated, rejoin them here before subtraction - std::vector> newHoles = joinAll(holes, tol); + const std::vector> newHoles = joinAll(holes, tol); std::vector allPoints; @@ -495,8 +493,8 @@ std::vector> computeTriangulation(const Point3dVector& vert if (!polyPartitionHoles) { // use boost to do all the intersections - std::vector> allFaces = subtract(vertices, newHoles, tol); - std::vector> noHoles; + const std::vector> allFaces = subtract(vertices, newHoles, tol); + const std::vector> noHoles; for (const std::vector& face : allFaces) { std::vector> temp = computeTriangulation(face, noHoles); result.insert(result.end(), temp.begin(), temp.end()); @@ -510,17 +508,17 @@ std::vector> computeTriangulation(const Point3dVector& vert TPPLPoly outerPoly; // must be counter-clockwise, input vertices are clockwise outerPoly.Init(vertices.size()); outerPoly.SetHole(false); - size_t n = vertices.size(); + const size_t n = vertices.size(); for (size_t i = 0; i < n; ++i) { // should all have zero z coordinate now - double z = vertices[n - i - 1].z(); + const double z = vertices[n - i - 1].z(); if (std::abs(z) > tol) { LOG_FREE(Error, "utilities.geometry.computeTriangulation", "All points must be on z = 0 plane for triangulation methods"); return result; } - Point3d point = getCombinedPoint(vertices[n - i - 1], allPoints, tol); + const Point3d point = getCombinedPoint(vertices[n - i - 1], allPoints, tol); outerPoly[i].x = point.x(); outerPoly[i].y = point.y(); } @@ -541,13 +539,13 @@ std::vector> computeTriangulation(const Point3dVector& vert for (unsigned i = 0; i < holeVertices.size(); ++i) { // should all have zero z coordinate now - double z = holeVertices[i].z(); + const double z = holeVertices[i].z(); if (std::abs(z) > tol) { LOG_FREE(Error, "utilities.geometry.computeTriangulation", "All points must be on z = 0 plane for triangulation methods"); return result; } - Point3d point = getCombinedPoint(holeVertices[i], allPoints, tol); + const Point3d point = getCombinedPoint(holeVertices[i], allPoints, tol); innerPoly[i].x = point.x(); innerPoly[i].y = point.y(); } @@ -581,8 +579,8 @@ std::vector> computeTriangulation(const Point3dVector& vert std::vector triangle; for (long i = 0; i < it->GetNumPoints(); ++i) { - TPPLPoint point = it->GetPoint(i); - triangle.push_back(Point3d(point.x, point.y, 0)); + const TPPLPoint point = it->GetPoint(i); + triangle.emplace_back(point.x, point.y, 0); } //std::cout << triangle << '\n'; result.push_back(triangle); @@ -614,7 +612,7 @@ bool applyViewAndDaylightingGlassRatios(double viewGlassToWallRatio, double dayl Point3dVector& daylightingVertices, Point3dVector& exteriorShadingVertices, Point3dVector& interiorShelfVertices) { // check inputs for reasonableness - double totalWWR = viewGlassToWallRatio + daylightingGlassToWallRatio; + const double totalWWR = viewGlassToWallRatio + daylightingGlassToWallRatio; if (totalWWR == 0) { // requesting no glass? remove existing windows? return false; @@ -627,18 +625,18 @@ bool applyViewAndDaylightingGlassRatios(double viewGlassToWallRatio, double dayl return false; } - Transformation transformation = Transformation::alignFace(surfaceVertices); - Point3dVector faceVertices = transformation.inverse() * surfaceVertices; + const Transformation transformation = Transformation::alignFace(surfaceVertices); + const Point3dVector faceVertices = transformation.inverse() * surfaceVertices; if (faceVertices.empty()) { return false; } - bool doViewGlass = (viewGlassToWallRatio > 0); - bool doDaylightGlass = (daylightingGlassToWallRatio > 0); - bool doExteriorShading = (doViewGlass && (exteriorShadingProjectionFactor > 0)); - bool doInteriorShelf = (doDaylightGlass && (interiorShelfProjectionFactor > 0)); - bool doViewAndDaylightGlass = (doViewGlass && doDaylightGlass); + const bool doViewGlass = (viewGlassToWallRatio > 0); + const bool doDaylightGlass = (daylightingGlassToWallRatio > 0); + const bool doExteriorShading = (doViewGlass && (exteriorShadingProjectionFactor > 0)); + const bool doInteriorShelf = (doDaylightGlass && (interiorShelfProjectionFactor > 0)); + const bool doViewAndDaylightGlass = (doViewGlass && doDaylightGlass); // ignore these user arguments? if (!doViewGlass) { @@ -663,19 +661,19 @@ bool applyViewAndDaylightingGlassRatios(double viewGlassToWallRatio, double dayl return false; } - double oneInch = 0.0254; + constexpr double oneInch = 0.0254; // DLM: preserve a 1" gap between window and edge to keep SketchUp happy - double minGlassToEdgeDistance = oneInch; + constexpr double minGlassToEdgeDistance = oneInch; double minViewToDaylightDistance = 0; if (doViewAndDaylightGlass) { minViewToDaylightDistance = oneInch; } // wall parameters - double wallWidth = xmax - xmin; - double wallHeight = ymax - ymin; - double wallArea = wallWidth * wallHeight; + const double wallWidth = xmax - xmin; + const double wallHeight = ymax - ymin; + const double wallArea = wallWidth * wallHeight; if (wallWidth < 2 * minGlassToEdgeDistance) { LOG_FREE(Warn, "utilities.geometry.applyViewAndDaylightingGlassRatios", @@ -695,11 +693,11 @@ bool applyViewAndDaylightingGlassRatios(double viewGlassToWallRatio, double dayl return false; } - double maxWindowArea = wallArea - 2 * wallHeight * minGlassToEdgeDistance - - (wallWidth - 2 * minGlassToEdgeDistance) * (2 * minGlassToEdgeDistance + minViewToDaylightDistance); - double requestedViewArea = viewGlassToWallRatio * wallArea; - double requestedDaylightingArea = daylightingGlassToWallRatio * wallArea; - double requestedTotalWindowArea = totalWWR * wallArea; + const double maxWindowArea = wallArea - 2 * wallHeight * minGlassToEdgeDistance + - (wallWidth - 2 * minGlassToEdgeDistance) * (2 * minGlassToEdgeDistance + minViewToDaylightDistance); + const double requestedViewArea = viewGlassToWallRatio * wallArea; + const double requestedDaylightingArea = daylightingGlassToWallRatio * wallArea; + const double requestedTotalWindowArea = totalWWR * wallArea; if (requestedTotalWindowArea > maxWindowArea) { LOG_FREE( @@ -724,9 +722,9 @@ bool applyViewAndDaylightingGlassRatios(double viewGlassToWallRatio, double dayl double daylightingMinY = 0; // initial free parameters - double viewWidthInset = minGlassToEdgeDistance; + const double viewWidthInset = minGlassToEdgeDistance; double viewSillHeight = std::max(desiredViewGlassSillHeight, minGlassToEdgeDistance); - double daylightingWidthInset = minGlassToEdgeDistance; + const double daylightingWidthInset = minGlassToEdgeDistance; double daylightingHeaderHeight = std::max(desiredDaylightingGlassHeaderHeight, minGlassToEdgeDistance); bool converged = false; @@ -875,7 +873,7 @@ bool isPointOnLineBetweenPoints(const Point3d& start, const Point3d& end, const // The tolerance has to be low enough. Take for eg a plenum that has an edge that's 30meters long, you risk adding point from the floor to // the roof, cf E+ #7383 // compute the shortest distance from the point to the line first to avoid false positive - double distance = getDistancePointToLineSegment(test, {start, end}); + const double distance = getDistancePointToLineSegment(test, {start, end}); if (distance < tol) { // getDistancePointToLineSegment always positive, it's calculated as norml_L2 return (std::abs((getDistance(start, end) - (getDistance(start, test) + getDistance(test, end)))) < tol); } From 565bea0567882199b86a0e2b4376fdb10130d27f Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 16:22:35 +0200 Subject: [PATCH 20/40] Move semantics + const correctness in geometry folder --- src/utilities/geometry/BoundingBox.cpp | 2 - src/utilities/geometry/BoundingBox.hpp | 2 +- src/utilities/geometry/EulerAngles.cpp | 3 - src/utilities/geometry/EulerAngles.hpp | 8 +- src/utilities/geometry/Plane.cpp | 119 ++++++++++------------ src/utilities/geometry/Plane.hpp | 12 ++- src/utilities/geometry/Point3d.cpp | 3 - src/utilities/geometry/Point3d.hpp | 8 +- src/utilities/geometry/PointLatLon.cpp | 87 ++++++++++------ src/utilities/geometry/PointLatLon.hpp | 11 +- src/utilities/geometry/Polygon3d.cpp | 2 - src/utilities/geometry/Polygon3d.hpp | 9 +- src/utilities/geometry/Transformation.cpp | 3 - src/utilities/geometry/Transformation.hpp | 8 +- src/utilities/geometry/Vector3d.cpp | 3 - src/utilities/geometry/Vector3d.hpp | 8 +- 16 files changed, 155 insertions(+), 133 deletions(-) diff --git a/src/utilities/geometry/BoundingBox.cpp b/src/utilities/geometry/BoundingBox.cpp index 3aa14a65d84..416ab58f765 100644 --- a/src/utilities/geometry/BoundingBox.cpp +++ b/src/utilities/geometry/BoundingBox.cpp @@ -33,8 +33,6 @@ namespace openstudio { -BoundingBox::BoundingBox() = default; - void BoundingBox::add(const BoundingBox& other) { this->addPoints(other.corners()); } diff --git a/src/utilities/geometry/BoundingBox.hpp b/src/utilities/geometry/BoundingBox.hpp index 2ba921a72b1..28bc9f7ecb5 100644 --- a/src/utilities/geometry/BoundingBox.hpp +++ b/src/utilities/geometry/BoundingBox.hpp @@ -49,7 +49,7 @@ class UTILITIES_API BoundingBox { public: /// default constructor creates empty BoundingBox, will not intersect with anything - BoundingBox(); + BoundingBox() = default; /// add another BoundingBox void add(const BoundingBox& other); diff --git a/src/utilities/geometry/EulerAngles.cpp b/src/utilities/geometry/EulerAngles.cpp index b5f7e59942a..e6bc58d6fb9 100644 --- a/src/utilities/geometry/EulerAngles.cpp +++ b/src/utilities/geometry/EulerAngles.cpp @@ -41,9 +41,6 @@ EulerAngles::EulerAngles(double psi, double theta, double phi) : m_storage(3) { m_storage[2] = phi; } -/// copy constructor -EulerAngles::EulerAngles(const EulerAngles& other) = default; - /// get psi double EulerAngles::psi() const { return m_storage[0]; diff --git a/src/utilities/geometry/EulerAngles.hpp b/src/utilities/geometry/EulerAngles.hpp index 26f22242343..dbadb4a3480 100644 --- a/src/utilities/geometry/EulerAngles.hpp +++ b/src/utilities/geometry/EulerAngles.hpp @@ -54,8 +54,12 @@ class UTILITIES_API EulerAngles /// constructor with psi, theta, phi EulerAngles(double psi, double theta, double phi); - /// copy constructor - EulerAngles(const EulerAngles& other); + // Copy and move operators are implicitly declared (Rule of 1) + // EulerAngles(const EulerAngles& other) = default; + // EulerAngles(EulerAngles&& other) = default; + // EulerAngles& operator=(const EulerAngles&) = default; + // EulerAngles& operator=(EulerAngles&&) = default; + // ~EulerAngles() noexcept = default; /// get psi double psi() const; diff --git a/src/utilities/geometry/Plane.cpp b/src/utilities/geometry/Plane.cpp index 508f9613964..1a9205d3716 100644 --- a/src/utilities/geometry/Plane.cpp +++ b/src/utilities/geometry/Plane.cpp @@ -42,13 +42,6 @@ namespace openstudio { -Plane::Plane(const Plane& other) : m_a(other.a()), m_b(other.b()), m_c(other.c()), m_d(other.d()) { - // test that normal has length 1 - double length = m_a * m_a + m_b * m_b + m_c * m_c; - double tol = 0.0001; - OS_ASSERT(std::fabs(1.0 - length) < tol); -} - Plane::Plane(const Point3d& point, const Vector3d& outwardNormal) { Vector3d thisNormal(outwardNormal); if (!thisNormal.normalize()) { @@ -62,21 +55,21 @@ Plane::Plane(const Point3d& point, const Vector3d& outwardNormal) { } double det3x3(const Matrix& m) { - double det = m(0, 0) * m(1, 1) * m(2, 2) + m(0, 1) * m(1, 2) * m(2, 0) + m(0, 2) * m(1, 0) * m(2, 1) - m(0, 2) * m(1, 1) * m(2, 0) - - m(0, 1) * m(1, 0) * m(2, 2) - m(0, 0) * m(1, 2) * m(2, 1); + const double det = m(0, 0) * m(1, 1) * m(2, 2) + m(0, 1) * m(1, 2) * m(2, 0) + m(0, 2) * m(1, 0) * m(2, 1) - m(0, 2) * m(1, 1) * m(2, 0) + - m(0, 1) * m(1, 0) * m(2, 2) - m(0, 0) * m(1, 2) * m(2, 1); return det; } Plane::Plane(const std::vector& points) : m_a(0.0), m_b(0.0), m_c(0.0), m_d(0.0) { - size_t N = points.size(); + const size_t N = points.size(); if (N < 3) { LOG_AND_THROW("Cannot compute plane with fewer than three points"); } else if (N == 3) { // duplicates code in point and normal ctor, points[1] is the point and (a x b) is the normal - Point3d point = points[1]; - Vector3d a = points[1] - points[0]; - Vector3d b = points[2] - points[1]; + const Point3d& point = points[1]; + const Vector3d a = points[1] - points[0]; + const Vector3d b = points[2] - points[1]; Vector3d thisNormal = a.cross(b); if (!thisNormal.normalize()) { @@ -91,8 +84,8 @@ Plane::Plane(const std::vector& points) : m_a(0.0), m_b(0.0), m_c(0.0), } else { bool foundSolution = false; - double tol = 1e-8; // 0.0001 was too big for the determinant tolerance, 1e-12 was too small - double maxDet = tol; + // 0.0001 was too big for the determinant tolerance, 1e-12 was too small + double maxDet = 1e-8; // solve the equation ax+by+cz+d=0 in a few different ways, keep the best one @@ -111,17 +104,17 @@ Plane::Plane(const std::vector& points) : m_a(0.0), m_b(0.0), m_c(0.0), b[i] = -(points[i].z() - points[0].z()); } - Matrix AtA = prod(At, A); - double det = det3x3(AtA); // always positive for A'*A + const Matrix AtA = prod(At, A); + const double det = det3x3(AtA); // always positive for A'*A if (det > maxDet) { Matrix AtAInv(3, 3); - bool test = invert(AtA, AtAInv); + const bool test = invert(AtA, AtAInv); if (test) { maxDet = det; Vector x = prod(prod(AtAInv, At), b); - double a_c = x[0]; - double b_c = x[1]; - double d_c = x[2]; + const double a_c = x[0]; + const double b_c = x[1]; + const double d_c = x[2]; // a = a_c*c // b = b_c*c @@ -153,17 +146,17 @@ Plane::Plane(const std::vector& points) : m_a(0.0), m_b(0.0), m_c(0.0), b[i] = -(points[i].y() - points[0].y()); } - Matrix AtA = prod(At, A); - double det = det3x3(AtA); // always positive for A'*A + const Matrix AtA = prod(At, A); + const double det = det3x3(AtA); // always positive for A'*A if (det > maxDet) { Matrix AtAInv(3, 3); - bool test = invert(AtA, AtAInv); + const bool test = invert(AtA, AtAInv); if (test) { maxDet = det; Vector x = prod(prod(AtAInv, At), b); - double a_b = x[0]; - double c_b = x[1]; - double d_b = x[2]; + const double a_b = x[0]; + const double c_b = x[1]; + const double d_b = x[2]; // a = a_b*b // c = c_b*b @@ -195,16 +188,16 @@ Plane::Plane(const std::vector& points) : m_a(0.0), m_b(0.0), m_c(0.0), b[i] = -(points[i].x() - points[0].x()); } - Matrix AtA = prod(At, A); - double det = det3x3(AtA); // always positive for A'*A + const Matrix AtA = prod(At, A); + const double det = det3x3(AtA); // always positive for A'*A if (det > maxDet) { Matrix AtAInv(3, 3); - bool test = invert(AtA, AtAInv); + const bool test = invert(AtA, AtAInv); if (test) { Vector x = prod(prod(AtAInv, At), b); - double b_a = x[0]; - double c_a = x[1]; - double d_a = x[2]; + const double b_a = x[0]; + const double c_a = x[1]; + const double d_a = x[2]; // b = b_a*a // c = c_a*a @@ -232,7 +225,7 @@ Plane::Plane(const std::vector& points) : m_a(0.0), m_b(0.0), m_c(0.0), // this corresponds to the other solution to the sqrt boost::optional outwardNormal = getOutwardNormal(points); if (outwardNormal) { - double thisDot = m_a * outwardNormal.get().x() + m_b * outwardNormal.get().y() + m_c * outwardNormal.get().z(); + const double thisDot = m_a * outwardNormal.get().x() + m_b * outwardNormal.get().y() + m_c * outwardNormal.get().z(); if (thisDot < 0) { m_a = -m_a; m_b = -m_b; @@ -242,16 +235,16 @@ Plane::Plane(const std::vector& points) : m_a(0.0), m_b(0.0), m_c(0.0), } // test that normal has length 1 - double length = m_a * m_a + m_b * m_b + m_c * m_c; - tol = 0.0001; + const double length = m_a * m_a + m_b * m_b + m_c * m_c; + constexpr double tol = 0.0001; OS_ASSERT(std::fabs(1.0 - length) <= tol); } } Plane::Plane(double a, double b, double c, double d) : m_a(a), m_b(b), m_c(c), m_d(d) { // test that normal has length 1 - double length = m_a * m_a + m_b * m_b + m_c * m_c; - double tol = 0.0001; + const double length = m_a * m_a + m_b * m_b + m_c * m_c; + constexpr double tol = 0.0001; OS_ASSERT(std::fabs(1.0 - length) <= tol); } @@ -261,26 +254,26 @@ Vector3d Plane::outwardNormal() const { bool Plane::parallel(const Plane& other, double tol) const { // dot product of outward normals should be 1 or negative 1 - double thisDot = (m_a * other.a() + m_b * other.b() + m_c * other.c()); - bool result = (std::fabs(thisDot) >= 1.0 - tol); + const double thisDot = (m_a * other.a() + m_b * other.b() + m_c * other.c()); + const bool result = (std::fabs(thisDot) >= 1.0 - tol); return result; } // is this plane equal to the other plane // true if dot product of outward normals is >= (1-tol) and abs(d1-d2) <= tol bool Plane::equal(const Plane& other, double tol) const { - double thisDot = (m_a * other.a() + m_b * other.b() + m_c * other.c()); - double dist = m_d - other.d(); - bool result = (thisDot >= 1 - tol) && (std::fabs(dist) <= tol); + const double thisDot = (m_a * other.a() + m_b * other.b() + m_c * other.c()); + const double dist = m_d - other.d(); + const bool result = (thisDot >= 1 - tol) && (std::fabs(dist) <= tol); return result; } // is this plane reverse equal to the other plane // true if dot product of outward normals is <= (-1+tol) and abs(d1+d2) <= tol bool Plane::reverseEqual(const Plane& other, double tol) const { - double thisDot = (m_a * other.a() + m_b * other.b() + m_c * other.c()); - double dist = m_d + other.d(); - bool result = (thisDot <= -1 + tol) && (std::fabs(dist) <= tol); + const double thisDot = (m_a * other.a() + m_b * other.b() + m_c * other.c()); + const double dist = m_d + other.d(); + const bool result = (thisDot <= -1 + tol) && (std::fabs(dist) <= tol); return result; } @@ -290,17 +283,17 @@ Plane Plane::reversePlane() const { Point3d Plane::project(const Point3d& point) const { // http://www.9math.com/book/projection-point-plane - double u = point.x(); - double v = point.y(); - double w = point.z(); + const double u = point.x(); + const double v = point.y(); + const double w = point.z(); - double num = m_a * u + m_b * v + m_c * w + m_d; - double den = m_a * m_a + m_b * m_b + m_c * m_c; // this should always be 1.0 - double ratio = num / den; + const double num = m_a * u + m_b * v + m_c * w + m_d; + const double den = m_a * m_a + m_b * m_b + m_c * m_c; // this should always be 1.0 + const double ratio = num / den; - double x = u - m_a * ratio; - double y = v - m_b * ratio; - double z = w - m_c * ratio; + const double x = u - m_a * ratio; + const double y = v - m_b * ratio; + const double z = w - m_c * ratio; return {x, y, z}; } @@ -316,11 +309,11 @@ std::vector Plane::project(const std::vector& points) const { bool Plane::pointOnPlane(const Point3d& point, double tol) const { // project point to plane - Point3d projected = project(point); + const Point3d projected = project(point); // get distance - Vector3d diff = point - projected; - double dist = diff.length(); + const Vector3d diff = point - projected; + const double dist = diff.length(); return (dist <= tol); } @@ -344,17 +337,17 @@ double Plane::d() const { Point3d Plane::anyPointOnPlane() const { if (std::abs(m_d) < 0.0001) { - return Point3d(0.0, 0.0, 0.0); + return {0.0, 0.0, 0.0}; } // a*x + b*y + c*z + d = 0, any point that satisfies this equation is on the plane. if (std::abs(m_a) > 0.0) { - return Point3d(-m_d / m_a, 0.0, 0.0); + return {-m_d / m_a, 0.0, 0.0}; } if (std::abs(m_b) > 0.0) { - return Point3d(0.0, -m_d / m_b, 0.0); + return {0.0, -m_d / m_b, 0.0}; } - return Point3d(0.0, 0.0, -m_d / m_c); + return {0.0, 0.0, -m_d / m_c}; } boost::optional Plane::rayIntersection(const Point3d& rayOrigin, const Vector3d& rayDirection, bool enforceDirectionOfPlane) const { @@ -376,7 +369,7 @@ boost::optional Plane::rayIntersection(const Point3d& rayOrigin, const auto thisOutwardNormal = outwardNormal(); - double vd = thisOutwardNormal.dot(rayDirection); + const double vd = thisOutwardNormal.dot(rayDirection); if (std::abs(vd) < 0.001) { LOG(Debug, "Plane is orthogonal to Ray, no intersection possible"); diff --git a/src/utilities/geometry/Plane.hpp b/src/utilities/geometry/Plane.hpp index 93882276287..ba8b594371f 100644 --- a/src/utilities/geometry/Plane.hpp +++ b/src/utilities/geometry/Plane.hpp @@ -49,9 +49,6 @@ class Vector3d; class UTILITIES_API Plane { public: - /// copy constructor - Plane(const Plane& other); - /// construct with point and outward normal, throws openstudio::Exception if outwardNormal has 0 length. Plane(const Point3d& point, const Vector3d& outwardNormal); @@ -60,8 +57,13 @@ class UTILITIES_API Plane /// throws openstudio::Exception if cannot compute plane for these points. Plane(const std::vector& points); - /// virtual destructor - virtual ~Plane() = default; + // Copy and move operators are implicitly declared (Rule of 1) + // There's no need to check if the length of the normal is zero since we never allow another plane to not satisfy this condition + // Plane(const Plane& other) = default; + // Plane(Plane&& other) = default; + // Plane& operator=(const Plane&) = default; + // Plane& operator=(Plane&&) = default; + // ~Plane() noexcept = default; /// get the outward normal of this plane Vector3d outwardNormal() const; diff --git a/src/utilities/geometry/Point3d.cpp b/src/utilities/geometry/Point3d.cpp index 36bf11ec1c4..6e991e0f75b 100644 --- a/src/utilities/geometry/Point3d.cpp +++ b/src/utilities/geometry/Point3d.cpp @@ -42,9 +42,6 @@ Point3d::Point3d(double x, double y, double z) : m_storage(3) { m_storage[2] = z; } -/// copy constructor -Point3d::Point3d(const Point3d& other) = default; - /// get x double Point3d::x() const { return m_storage[0]; diff --git a/src/utilities/geometry/Point3d.hpp b/src/utilities/geometry/Point3d.hpp index a641b580342..29d4a5ca0bd 100644 --- a/src/utilities/geometry/Point3d.hpp +++ b/src/utilities/geometry/Point3d.hpp @@ -51,8 +51,12 @@ class UTILITIES_API Point3d /// constructor with x, y, z Point3d(double x, double y, double z); - /// copy constructor - Point3d(const Point3d& other); + // Copy and move operators are implicitly declared + // Point3d(const Point3d& other) = default; + // Point3d(Point3d&& other) = default; + // Point3d& operator=(const Point3d&) = default; + // Point3d& operator=(Point3d&&) = default; + // ~Point3d() noexcept = default; /// get x double x() const; diff --git a/src/utilities/geometry/PointLatLon.cpp b/src/utilities/geometry/PointLatLon.cpp index 90968d6632a..44d582ac92f 100644 --- a/src/utilities/geometry/PointLatLon.cpp +++ b/src/utilities/geometry/PointLatLon.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace openstudio { @@ -51,7 +52,29 @@ PointLatLon::PointLatLon(const PointLatLon& other) : m_storage(other.m_storage) m_localCartesianConverter.reset(); } -PointLatLon::~PointLatLon() = default; +PointLatLon::PointLatLon(PointLatLon&& other) noexcept : m_storage(std::move(other.m_storage)) { + m_localCartesianConverter.reset(); +} + +PointLatLon& PointLatLon::operator=(const openstudio::PointLatLon& other) { + if (this == &other) { + return *this; + } + m_storage = other.m_storage; + m_localCartesianConverter.reset(); + return *this; +} + +PointLatLon& PointLatLon::operator=(PointLatLon&& other) noexcept { + if (this == &other) { + return *this; + } + m_storage = std::move(other.m_storage); + m_localCartesianConverter.reset(); + return *this; +} + +PointLatLon::~PointLatLon() noexcept = default; /// get lat double PointLatLon::lat() const { @@ -68,19 +91,13 @@ double PointLatLon::height() const { return m_storage[2]; } -PointLatLon& PointLatLon::operator=(const openstudio::PointLatLon& other) { - m_storage = other.m_storage; - m_localCartesianConverter.reset(); - return *this; -} - /// check equality bool PointLatLon::operator==(const PointLatLon& other) const { return (m_storage == other.m_storage); } double PointLatLon::operator-(const PointLatLon& other) const { - double s12; + double s12 = 0.0; const GeographicLib::Geodesic& geod = GeographicLib::Geodesic::WGS84(); geod.Inverse(lat(), lon(), other.lat(), other.lon(), s12); return s12; @@ -88,15 +105,16 @@ double PointLatLon::operator-(const PointLatLon& other) const { Point3d PointLatLon::toLocalCartesian(const PointLatLon& point) const { initLocalCartesianConverter(); - double x; - double y; - double z; + double x = 0.0; + double y = 0.0; + double z = 0.0; m_localCartesianConverter->Forward(point.lat(), point.lon(), point.height(), x, y, z); return {x, y, z}; } std::vector PointLatLon::toLocalCartesian(const std::vector& points) const { std::vector result; + result.reserve(points.size()); for (const auto& point : points) { result.push_back(toLocalCartesian(point)); } @@ -105,15 +123,16 @@ std::vector PointLatLon::toLocalCartesian(const std::vectorReverse(point.x(), point.y(), point.z(), lat, lon, h); return {lat, lon, h}; } std::vector PointLatLon::fromLocalCartesian(const std::vector& points) const { std::vector result; + result.reserve(points.size()); for (const auto& point : points) { result.push_back(fromLocalCartesian(point)); } @@ -125,18 +144,19 @@ int PointLatLon::utmZone() const { } Point3d PointLatLon::toUTM(const PointLatLon& point) const { - int zone; - bool northp; - double x; - double y; - double gamma; - double k; + int zone = 0; + bool northp = false; + double x = 0.0; + double y = 0.0; + double gamma = 0.0; + double k = 0.0; GeographicLib::UTMUPS::Forward(point.lat(), point.lon(), zone, northp, x, y, gamma, k, utmZone()); return {x, y, point.height()}; } std::vector PointLatLon::toUTM(const std::vector& points) const { std::vector result; + result.reserve(points.size()); for (const auto& point : points) { result.push_back(toUTM(point)); } @@ -144,26 +164,27 @@ std::vector PointLatLon::toUTM(const std::vector& points) } PointLatLon PointLatLon::fromUTM(const Point3d& point) const { - int zone; - bool northp; + int zone = 0; + bool northp = false; { - double x; - double y; - double gamma; - double k; + double x = 0.0; + double y = 0.0; + double gamma = 0.0; + double k = 0.0; GeographicLib::UTMUPS::Forward(lat(), lon(), zone, northp, x, y, gamma, k); } - double lat; - double lon; - double gamma; - double k; + double lat = 0.0; + double lon = 0.0; + double gamma = 0.0; + double k = 0.0; GeographicLib::UTMUPS::Reverse(zone, northp, point.x(), point.y(), lat, lon, gamma, k); return {lat, lon, point.z()}; } std::vector PointLatLon::fromUTM(const std::vector& points) const { std::vector result; + result.reserve(points.size()); for (const auto& point : points) { result.push_back(fromUTM(point)); } @@ -172,7 +193,7 @@ std::vector PointLatLon::fromUTM(const std::vector& points void PointLatLon::initLocalCartesianConverter() const { if (!m_localCartesianConverter) { - m_localCartesianConverter = std::unique_ptr(new GeographicLib::LocalCartesian(lat(), lon(), height())); + m_localCartesianConverter = std::make_unique(lat(), lon(), height()); } } @@ -196,8 +217,8 @@ std::ostream& operator<<(std::ostream& os, const std::vector& point } double getDistanceLatLon(double lat1, double lon1, double lat2, double lon2) { - PointLatLon p1(lat1, lon1); - PointLatLon p2(lat2, lon2); + const PointLatLon p1(lat1, lon1); + const PointLatLon p2(lat2, lon2); return (p1 - p2); } diff --git a/src/utilities/geometry/PointLatLon.hpp b/src/utilities/geometry/PointLatLon.hpp index e65ab96bcb9..3d3f714cee7 100644 --- a/src/utilities/geometry/PointLatLon.hpp +++ b/src/utilities/geometry/PointLatLon.hpp @@ -63,11 +63,12 @@ class UTILITIES_API PointLatLon /// constructor with lat, lon, and height PointLatLon(double lat, double lon, double height = 0); - /// copy constructor + // Rule of 5/6 because the assignment operators need to reset the LocalCartesian converter and the LocalCartesian converter has a deleted copy PointLatLon(const PointLatLon& other); - - /// destructor - ~PointLatLon(); + PointLatLon(PointLatLon&& other) noexcept; + PointLatLon& operator=(const PointLatLon& other); + PointLatLon& operator=(PointLatLon&& other) noexcept; + ~PointLatLon() noexcept; /// get lat double lat() const; @@ -78,8 +79,6 @@ class UTILITIES_API PointLatLon /// get height double height() const; - PointLatLon& operator=(const openstudio::PointLatLon& other); - /// check equality bool operator==(const PointLatLon& other) const; diff --git a/src/utilities/geometry/Polygon3d.cpp b/src/utilities/geometry/Polygon3d.cpp index c5118f35de2..b860f807c6f 100644 --- a/src/utilities/geometry/Polygon3d.cpp +++ b/src/utilities/geometry/Polygon3d.cpp @@ -35,8 +35,6 @@ namespace openstudio { -Polygon3d::Polygon3d() = default; - Polygon3d::Polygon3d(const Point3dVector& outerPath) { for (const auto& p : outerPath) { m_outerPath.emplace_back(p); diff --git a/src/utilities/geometry/Polygon3d.hpp b/src/utilities/geometry/Polygon3d.hpp index 124c498df79..4e86f17c2a2 100644 --- a/src/utilities/geometry/Polygon3d.hpp +++ b/src/utilities/geometry/Polygon3d.hpp @@ -43,7 +43,7 @@ class UTILITIES_API Polygon3d { public: // Constructs an empty polygon - Polygon3d(); + Polygon3d() = default; // Construct a polygon with an outer path Polygon3d(const Point3dVector& outerPath); @@ -51,6 +51,13 @@ class UTILITIES_API Polygon3d // Constructs a polygon with an outer path and one or more inner paths Polygon3d(const Point3dVector& outerPath, const Point3dVectorVector& innerPaths); + // Copy and move operators are implicitly declared (Rule of 1) + // Polygon3d(const Polygon3d& other) = default; + // Polygon3d(Polygon3d&& other) = default; + // Polygon3d& operator=(const Polygon3d&) = default; + // Polygon3d& operator=(Polygon3d&&) = default; + // ~Polygon3d() noexcept = default; + // Assigns an outer path for the polygon void setOuterPath(const Point3dVector& outerPath); diff --git a/src/utilities/geometry/Transformation.cpp b/src/utilities/geometry/Transformation.cpp index b47238ef905..567368cb637 100644 --- a/src/utilities/geometry/Transformation.cpp +++ b/src/utilities/geometry/Transformation.cpp @@ -50,9 +50,6 @@ namespace openstudio { /// default constructor creates identity transformation Transformation::Transformation() : m_storage(identity_matrix(4)) {} -/// copy constructor -Transformation::Transformation(const Transformation& other) = default; - /// constructor from storage, asserts matrix is 4x4 Transformation::Transformation(const Matrix& matrix) : m_storage(matrix) { OS_ASSERT(matrix.size1() == 4); diff --git a/src/utilities/geometry/Transformation.hpp b/src/utilities/geometry/Transformation.hpp index ceb833cd874..ebb2a0b0cb3 100644 --- a/src/utilities/geometry/Transformation.hpp +++ b/src/utilities/geometry/Transformation.hpp @@ -59,8 +59,12 @@ class UTILITIES_API Transformation /// constructor from storage, asserts vector is size 16 Transformation(const Vector& vector); - /// copy constructor - Transformation(const Transformation& other); + // Copy and move operators are implicitly declared (Rule of 1) + // Transformation(const Transformation& other) = default; + // Transformation(Transformation&& other) = default; + // Transformation& operator=(const Transformation&) = default; + // Transformation& operator=(Transformation&&) = default; + // ~Transformation() noexcept = default; /// rotation about origin defined by axis and angle (radians) static Transformation rotation(const Vector3d& axis, double radians); diff --git a/src/utilities/geometry/Vector3d.cpp b/src/utilities/geometry/Vector3d.cpp index 98638de09e1..64e62bf4e2d 100644 --- a/src/utilities/geometry/Vector3d.cpp +++ b/src/utilities/geometry/Vector3d.cpp @@ -41,9 +41,6 @@ Vector3d::Vector3d(double x, double y, double z) : m_storage(3) { m_storage[2] = z; } -/// copy constructor -Vector3d::Vector3d(const Vector3d& other) = default; - /// get x double Vector3d::x() const { return m_storage[0]; diff --git a/src/utilities/geometry/Vector3d.hpp b/src/utilities/geometry/Vector3d.hpp index d644f239a08..4bc39db4d67 100644 --- a/src/utilities/geometry/Vector3d.hpp +++ b/src/utilities/geometry/Vector3d.hpp @@ -48,8 +48,12 @@ class UTILITIES_API Vector3d /// constructor with x, y, z Vector3d(double x, double y, double z); - /// copy constructor - Vector3d(const Vector3d& other); + // Copy and move operators are implicitly declared (Rule of 1) + // Vector3d(const Vector3d& other) = default; + // Vector3d(Vector3d&& other) = default; + // Vector3d& operator=(const Vector3d&) = default; + // Vector3d& operator=(Vector3d&&) = default; + // ~Vector3d() noexcept = default; /// get x double x() const; From 515f5d82be461ef7c0c59398f879808d334d78b3 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 16:24:25 +0200 Subject: [PATCH 21/40] `#define BOOST_UBLAS_MOVE_SEMANTICS` cf https://www.boost.org/doc/libs/1_79_0/libs/numeric/ublas/doc/options.html --- src/utilities/data/Vector.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utilities/data/Vector.hpp b/src/utilities/data/Vector.hpp index 8f4a1f0c3c2..ef887cdd764 100644 --- a/src/utilities/data/Vector.hpp +++ b/src/utilities/data/Vector.hpp @@ -32,6 +32,8 @@ #include "../UtilitiesAPI.hpp" +#define BOOST_UBLAS_MOVE_SEMANTICS + #include #include From 57d18b21d0c40d0405e1bbcaaabdb26ca1fd18b0 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 16:26:08 +0200 Subject: [PATCH 22/40] Add a failing test for finding incorrectly oriented surfaces in a H-shaped building --- src/model/test/Space_GTest.cpp | 73 ++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 3 deletions(-) diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index 113b9c5d419..81502aa66e7 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -64,11 +64,13 @@ #include "../../utilities/core/UUID.hpp" +#include "../../utilities/geometry/BoundingBox.hpp" +#include "../../utilities/geometry/Geometry.hpp" #include "../../utilities/geometry/Point3d.hpp" -#include "../../utilities/geometry/Vector3d.hpp" +#include "../../utilities/geometry/Polyhedron.hpp" #include "../../utilities/geometry/Transformation.hpp" -#include "../../utilities/geometry/Geometry.hpp" -#include "../../utilities/geometry/BoundingBox.hpp" +#include "../../utilities/geometry/Vector3d.hpp" + #include "../../utilities/idf/WorkspaceObjectWatcher.hpp" #include "../../utilities/core/Compare.hpp" #include "../../osversion/VersionTranslator.hpp" @@ -3438,3 +3440,68 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_NonConvex) { EXPECT_EQ(2 * spaceFloorAreaEach, mergedSpace.floorArea()); EXPECT_EQ(spaceVolume, mergedSpace.volume()); } + +TEST_F(ModelFixture, Space_4837_SpaceVolume_Hshaped) { + + Model m; + + // ▲ y (=North) + // │ (5) (8) building height = 2m + //15 o────o o────o (1) + // │(4) │ │ │ + // │ │<---│----│---- Space1 Wall 5 + //10 │ o────o │<---- Space1 Wall 1 + // │ (6) (7) │ + // │ │ + // │(3) │ (2) + // o──────────────o───► x + // 0 5 10 15 + + constexpr double height = 2.0; + + constexpr double width = 15.0; + constexpr double spaceFloorAreaOri = width * width; + + constexpr double widthRemoved = 5.0; + constexpr double spaceFloorAreaRemoved = widthRemoved * widthRemoved; + + constexpr double spaceFloorArea = spaceFloorAreaOri - spaceFloorAreaRemoved; + constexpr double spaceVolume = spaceFloorArea * height; + + EXPECT_EQ(200.0, spaceFloorArea); + EXPECT_EQ(400.0, spaceVolume); + + std::vector floorPoints{ + {15.0, 15.0, 0.0}, // + {15.0, 0.00, 0.0}, // + {0.00, 0.00, 0.0}, // + {0.00, 15.0, 0.0}, // + {5.00, 15.0, 0.0}, // + {5.00, 10.0, 0.0}, // + {10.0, 10.0, 0.0}, // + {10.0, 15.0, 0.0}, // + }; + auto space = Space::fromFloorPrint(floorPoints, 2.0, m, "Space1").get(); + EXPECT_TRUE(space.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space.isEnclosedVolume()); + EXPECT_DOUBLE_EQ(spaceVolume, space.volume()); + + auto surfaces = space.surfaces(); + const std::string sfName = "Space1 Wall 5"; + + auto it = std::find_if(surfaces.begin(), surfaces.end(), [&sfName](const Surface& s) { return s.nameString() == sfName; }); + ASSERT_TRUE(it != surfaces.end()) << [&surfaces]() { + std::vector surfaceNames; + surfaceNames.reserve(surfaces.size()); + std::transform(surfaces.cbegin(), surfaces.cend(), std::back_inserter(surfaceNames), [](const auto& sf) { return sf.nameString(); }); + return fmt::format("surfaceNames={}", surfaceNames); + }(); + auto vertices = it->vertices(); + std::reverse(vertices.begin(), vertices.end()); + it->setVertices(vertices); + + { + auto wrongOrientations = space.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(1, wrongOrientations.size()); + } +} From 35f110d54efe5608b8a58cef1d111c8abc03840c Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 16:28:08 +0200 Subject: [PATCH 23/40] Implemented Polyhedron checking the surfaces edges are in reversed order. --- src/model/test/Space_GTest.cpp | 15 ++++ src/utilities/geometry/Polyhedron.cpp | 112 +++++++++++++++++++++++--- src/utilities/geometry/Polyhedron.hpp | 17 +++- 3 files changed, 132 insertions(+), 12 deletions(-) diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index 81502aa66e7..e1d7cb1f460 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3504,4 +3504,19 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_Hshaped) { auto wrongOrientations = space.findSurfacesWithIncorrectOrientation(); EXPECT_EQ(1, wrongOrientations.size()); } + + // Use the Polyhedron method of checking the surface edges (ensuring they are in REVERSE order) + { + std::vector wrongOrientations = space.polyhedron().findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(1, wrongOrientations.size()); + EXPECT_EQ(sfName, wrongOrientations.front().name); + } + + EXPECT_FALSE(space.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space.isEnclosedVolume()); + EXPECT_EQ(spaceVolume, space.volume()); // It falls back to the floor * ceilingHeight and since this is a box, it works... + EXPECT_TRUE(space.fixSurfacesWithIncorrectOrientation()); + EXPECT_TRUE(space.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space.isEnclosedVolume()); + EXPECT_DOUBLE_EQ(spaceVolume, space.volume()); } diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index 8d95d6ddcd2..63caf66d147 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -37,6 +37,7 @@ #include #include +#include #include #include @@ -77,10 +78,18 @@ size_t Surface3dEdge::firstSurfNum() const { return m_firstSurfNum; } -std::vector Surface3dEdge::allSurfaces() const { +const std::vector& Surface3dEdge::allSurfaces() const { return m_allSurfaces; } +void Surface3dEdge::markConflictedOrientation() { + m_conflictedOrientation = true; +} + +bool Surface3dEdge::hasConflictedOrientation() const { + return m_conflictedOrientation; +} + void Surface3dEdge::appendSurface(Surface3d surface) { m_allSurfaces.emplace_back(std::move(surface)); } @@ -95,7 +104,22 @@ std::ostream& operator<<(std::ostream& os, const Surface3dEdge& edge) { return os; } -Surface3d::Surface3d(std::vector t_vertices, std::string t_name) : vertices(std::move(t_vertices)), name(std::move(t_name)) {} +Surface3d::Surface3d(std::vector t_vertices, std::string t_name) : vertices(std::move(t_vertices)), name(std::move(t_name)) { + for (auto it = vertices.begin(); it != vertices.end(); ++it) { + + auto itnext = std::next(it); + if (itnext == std::end(vertices)) { + itnext = std::begin(vertices); + } + + // Don't care about surfNum + edges.emplace_back(*it, *itnext, *this, 0); + } +} + +bool Surface3d::operator<(const Surface3d& rhs) const { + return this->name < rhs.name; +} Polyhedron::Polyhedron(std::vector surfaces) : m_surfaces(std::move(surfaces)){}; @@ -123,7 +147,7 @@ std::vector Polyhedron::uniqueVertices() const { return uniqVertices; } -std::vector Polyhedron::edgesNotTwoForEnclosedVolumeTest() const { +std::vector Polyhedron::edgesMatches() const { std::vector uniqueSurface3dEdges; uniqueSurface3dEdges.reserve(numVertices()); @@ -146,6 +170,10 @@ std::vector Polyhedron::edgesNotTwoForEnclosedVolumeTest() const } else { LOG(Debug, " FOUND: " << thisSurface3dEdge); itFound->appendSurface(surface); + if (!itFound->reverseEqual(thisSurface3dEdge)) { + LOG(Debug, " Edges are not in reverse orientation for " << thisSurface3dEdge); + itFound->markConflictedOrientation(); + } } } ++surfNum; @@ -154,6 +182,14 @@ std::vector Polyhedron::edgesNotTwoForEnclosedVolumeTest() const for (auto& edge : uniqueSurface3dEdges) { LOG(Debug, edge); } + + return uniqueSurface3dEdges; +} + +std::vector Polyhedron::edgesNotTwoForEnclosedVolumeTest() const { + + std::vector uniqueSurface3dEdges = edgesMatches(); + // All edges for an enclosed polyhedron should be shared by two (and only two) sides. // So if the count is not two for all edges, the polyhedron is not enclosed, so erase all that are 2 uniqueSurface3dEdges.erase( @@ -167,7 +203,7 @@ Polyhedron Polyhedron::updateZonePolygonsForMissingColinearPoints() const { // Make a copy, we don't want to mutate in place Polyhedron updZonePoly(*this); - std::vector uniqVertices = uniqueVertices(); + const std::vector uniqVertices = uniqueVertices(); for (auto& surface : updZonePoly.m_surfaces) { // for (int iterationLimiter = 0; iterationLimiter < 20; ++iterationLimiter) { // could probably be while loop but want to make sure it does not get stuck @@ -226,7 +262,7 @@ VolumeEnclosedReturnType Polyhedron::isEnclosedVolume() const { VolumeEnclosedReturnType result; - std::vector edgeNot2orig = this->edgesNotTwoForEnclosedVolumeTest(); + const std::vector edgeNot2orig = this->edgesNotTwoForEnclosedVolumeTest(); // if all edges had two counts then it is fully enclosed if (edgeNot2orig.empty()) { result.isEnclosedVolume = true; @@ -234,9 +270,9 @@ VolumeEnclosedReturnType Polyhedron::isEnclosedVolume() const { } else { // if the count is three or greater it is likely that a vertex that is colinear was counted on the faces on one edge and not // on the "other side" of the edge Go through all the points looking for the number that are colinear and see if that is // consistent with the number of edges found that didn't have a count of two - Polyhedron updatedZonePoly = + const Polyhedron updatedZonePoly = updateZonePolygonsForMissingColinearPoints(); // this is done after initial test since it is computationally intensive. - std::vector edgeNot2again = updatedZonePoly.edgesNotTwoForEnclosedVolumeTest(); + const std::vector edgeNot2again = updatedZonePoly.edgesNotTwoForEnclosedVolumeTest(); if (edgeNot2again.empty()) { result.isEnclosedVolume = true; return result; @@ -249,6 +285,61 @@ VolumeEnclosedReturnType Polyhedron::isEnclosedVolume() const { } } +std::vector Polyhedron::findSurfacesWithIncorrectOrientation() const { + + std::vector uniqueSurface3dEdges = edgesMatches(); + + if (std::any_of(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), [](const auto& edge) { return edge.count() != 2; })) { + const Polyhedron updatedZonePoly = + updateZonePolygonsForMissingColinearPoints(); // this is done after initial test since it is computationally intensive. + uniqueSurface3dEdges = updatedZonePoly.edgesMatches(); + + if (std::any_of(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), [](const auto& edge) { return edge.count() != 2; })) { + LOG(Warn, "Can't lookup surfaces with incorrect orientations for a non-enclosed Polyhedron"); + return {}; + } + } + + // Remove non-conflicted edges + uniqueSurface3dEdges.erase( + std::remove_if(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), [](const auto& edge) { return !edge.hasConflictedOrientation(); }), + uniqueSurface3dEdges.end()); + if (uniqueSurface3dEdges.empty()) { + return {}; + } + + std::set conflictedSurfaces; + std::set> conflictedSurfacePairs; + for (auto& edge : uniqueSurface3dEdges) { + const auto& surfaces = edge.allSurfaces(); + const auto& sf1 = surfaces.front(); + const auto& sf2 = surfaces.back(); + if (sf1 < sf2) { + conflictedSurfacePairs.emplace(sf1, sf2); + } else { + conflictedSurfacePairs.emplace(sf2, sf1); + } + } + + for (const auto& [sf1, sf2] : conflictedSurfacePairs) { + // Count number of conflicted edges... + auto c1 = std::accumulate(sf1.edges.cbegin(), sf1.edges.cend(), 0, [&uniqueSurface3dEdges](int count, const auto& edge) { + return count + std::count(uniqueSurface3dEdges.cbegin(), uniqueSurface3dEdges.cend(), edge); + }); + auto c2 = std::accumulate(sf2.edges.cbegin(), sf2.edges.cend(), 0, [&uniqueSurface3dEdges](int count, const auto& edge) { + return count + std::count(uniqueSurface3dEdges.cbegin(), uniqueSurface3dEdges.cend(), edge); + }); + LOG(Debug, sf1.name << " has " << c1 << " conflicted edges out of " << sf1.edges.size()); + LOG(Debug, sf2.name << " has " << c2 << " conflicted edges out of " << sf2.edges.size()); + if (c1 > c2) { + conflictedSurfaces.insert(sf1); + } else { + conflictedSurfaces.insert(sf2); + } + } + return {conflictedSurfaces.begin(), conflictedSurfaces.end()}; +} + // boost::optional Polyhedron::calculatedVolume() const { // auto [isVolEnclosed, edgesNot2] = isEnclosedVolume(); // if (isVolEnclosed) { @@ -259,15 +350,16 @@ VolumeEnclosedReturnType Polyhedron::isEnclosedVolume() const { double Polyhedron::calcPolyhedronVolume() const { + const Point3d p0{}; double volume = 0.0; for (const auto& surface : m_surfaces) { const std::vector& vertices = surface.vertices; - Vector3d p3FaceOrigin = vertices[1] - Point3d{}; + const Vector3d p3FaceOrigin = vertices[1] - p0; boost::optional newellAreaVector = getNewellVector(vertices); if (!newellAreaVector) { LOG_AND_THROW("Cannot compute newellAreaVector"); } - double pyramidVolume = newellAreaVector->dot(p3FaceOrigin); + const double pyramidVolume = newellAreaVector->dot(p3FaceOrigin); volume += pyramidVolume; } // for (int NFace = 1; NFace <= Poly.NumSurfaceFaces; ++NFace) { @@ -282,7 +374,7 @@ double Polyhedron::calcDivergenceTheoremVolume() const { double volume = 0.0; for (const auto& surface : m_surfaces) { const std::vector& vertices = surface.vertices; - Plane plane(vertices); + const Plane plane(vertices); boost::optional area = getArea(vertices); if (!area) { LOG_AND_THROW("Cannot compute area for " << surface.name); diff --git a/src/utilities/geometry/Polyhedron.hpp b/src/utilities/geometry/Polyhedron.hpp index 932c450caf9..2c46b040b55 100644 --- a/src/utilities/geometry/Polyhedron.hpp +++ b/src/utilities/geometry/Polyhedron.hpp @@ -43,6 +43,8 @@ namespace model { class ThermalZone; } // namespace model +class Surface3dEdge; + // A thin wrapper to improve reporting, by attaching a name to the vertices class UTILITIES_API Surface3d { @@ -51,6 +53,10 @@ class UTILITIES_API Surface3d Surface3d(std::vector t_vertices, std::string t_name = "None"); std::vector vertices; std::string name; + std::vector edges; + // std::vector conflictedOrientation; + + bool operator<(const Surface3d& rhs) const; }; class UTILITIES_API Surface3dEdge @@ -78,12 +84,16 @@ class UTILITIES_API Surface3dEdge // Checks whether a Point: is not almost equal to the start and end points, and that isPointOnLineBetweenPoints(start, end, testVertex) is true bool containsPoint(const Point3d& testVertex); - std::vector allSurfaces() const; + const std::vector& allSurfaces() const; + + void markConflictedOrientation(); + bool hasConflictedOrientation() const; private: Point3d m_start; Point3d m_end; size_t m_firstSurfNum; + bool m_conflictedOrientation = false; std::vector m_allSurfaces; }; @@ -109,11 +119,12 @@ class UTILITIES_API Polyhedron // This is done by checking that every edge is used exactly TWICE. VolumeEnclosedReturnType isEnclosedVolume() const; - // Maybe unused std::vector uniqueVertices() const; std::vector edgesNotTwoForEnclosedVolumeTest() const; + std::vector edgesMatches() const; + Polyhedron updateZonePolygonsForMissingColinearPoints() const; size_t numVertices() const; @@ -128,6 +139,8 @@ class UTILITIES_API Polyhedron // Polyhedron MUST be enclosed double calcDivergenceTheoremVolume() const; + std::vector findSurfacesWithIncorrectOrientation() const; + private: REGISTER_LOGGER("utilities.Polyhedron"); From 1c18477025f15f24334cc97c2a3bfbcc93370604 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 27 Mar 2023 16:34:49 +0200 Subject: [PATCH 24/40] WIP --- src/utilities/geometry/Polyhedron.cpp | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index 63caf66d147..0a96fbc8655 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -105,6 +105,8 @@ std::ostream& operator<<(std::ostream& os, const Surface3dEdge& edge) { } Surface3d::Surface3d(std::vector t_vertices, std::string t_name) : vertices(std::move(t_vertices)), name(std::move(t_name)) { + int surfNum = 0; + for (auto it = vertices.begin(); it != vertices.end(); ++it) { auto itnext = std::next(it); @@ -112,8 +114,7 @@ Surface3d::Surface3d(std::vector t_vertices, std::string t_name) : vert itnext = std::begin(vertices); } - // Don't care about surfNum - edges.emplace_back(*it, *itnext, *this, 0); + edges.emplace_back(*it, *itnext, *this, surfNum++); } } @@ -153,20 +154,13 @@ std::vector Polyhedron::edgesMatches() const { uniqueSurface3dEdges.reserve(numVertices()); // construct list of unique edges - int surfNum = 0; for (const auto& surface : m_surfaces) { LOG(Debug, "Surface: " << surface.name); - const auto& vertices = surface.vertices; - for (auto it = vertices.begin(); it != vertices.end(); ++it) { - auto itnext = std::next(it); - if (itnext == std::end(vertices)) { - itnext = std::begin(vertices); - } - Surface3dEdge thisSurface3dEdge(*it, *itnext, surface, surfNum); + for (const Surface3dEdge& thisSurface3dEdge : surface.edges) { auto itFound = std::find(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), thisSurface3dEdge); if (itFound == uniqueSurface3dEdges.end()) { LOG(Debug, "NOT FOUND: " << thisSurface3dEdge); - uniqueSurface3dEdges.emplace_back(std::move(thisSurface3dEdge)); + uniqueSurface3dEdges.push_back(thisSurface3dEdge); } else { LOG(Debug, " FOUND: " << thisSurface3dEdge); itFound->appendSurface(surface); @@ -176,7 +170,6 @@ std::vector Polyhedron::edgesMatches() const { } } } - ++surfNum; } for (auto& edge : uniqueSurface3dEdges) { @@ -211,6 +204,7 @@ Polyhedron Polyhedron::updateZonePolygonsForMissingColinearPoints() const { bool insertedVertext = true; while (insertedVertext) { insertedVertext = false; + // TODO: loop on edges and insert edge too auto& vertices = surface.vertices; for (auto it = vertices.begin(); it != vertices.end(); ++it) { From f1e437c6ea3529d80e7e8b7f019c6bb48b8cdebe Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 28 Mar 2023 16:30:21 +0200 Subject: [PATCH 25/40] Refactor Polyhedron and child classes to use state to avoid computing the same stuff over and over again and clean up the API. Catch the case where it's also completely inside out --- src/model/Space.cpp | 67 ++- src/model/Space_Impl.hpp | 3 + src/utilities/geometry/Geometry.i | 13 +- src/utilities/geometry/Polyhedron.cpp | 391 +++++++++++------- src/utilities/geometry/Polyhedron.hpp | 113 +++-- .../geometry/Test/Polyhedron_GTest.cpp | 89 ++-- 6 files changed, 423 insertions(+), 253 deletions(-) diff --git a/src/model/Space.cpp b/src/model/Space.cpp index 3394d0aa5fc..d687ecef18d 100644 --- a/src/model/Space.cpp +++ b/src/model/Space.cpp @@ -853,19 +853,22 @@ namespace model { } Polyhedron Space_Impl::polyhedron() const { + auto sfs = surfaces(); std::vector surface3ds; - for (auto& surface : surfaces()) { - surface3ds.emplace_back(surface.vertices(), surface.nameString()); + surface3ds.reserve(sfs.size()); + for (size_t surfNum = 0; auto& surface : sfs) { + surface3ds.emplace_back(surface.vertices(), surface.nameString(), surfNum++); } return {surface3ds}; } bool Space_Impl::isEnclosedVolume() const { auto volumePoly = this->polyhedron(); - auto [isVolEnclosed, edgesNot2] = volumePoly.isEnclosedVolume(); + auto isVolEnclosed = volumePoly.isEnclosedVolume(); if (!isVolEnclosed) { + const auto edgesNot2 = volumePoly.edgesNotTwo(); LOG(Warn, briefDescription() << " is not enclosed, there are " << edgesNot2.size() << " edges that aren't used exactly twice"); - for (const Surface3dEdge& edge : edgesNot2) { + for (const auto& edge : edgesNot2) { LOG(Debug, edge); } } @@ -921,7 +924,7 @@ namespace model { return result; } - std::vector Space_Impl::findSurfacesWithIncorrectOrientation() const { + std::vector Space_Impl::findSurfacesWithIncorrectOrientationRaycasting() const { std::vector result; const Point3d p0{}; @@ -978,6 +981,33 @@ namespace model { return result; } + std::vector Space_Impl::findSurfacesWithIncorrectOrientationPolyhedron(const Polyhedron& volumePoly) const { + auto sf3ds = volumePoly.findSurfacesWithIncorrectOrientation(); + if (sf3ds.empty()) { + return {}; + } + std::vector sfNames; + sfNames.reserve(sf3ds.size()); + std::transform(sf3ds.cbegin(), sf3ds.cend(), std::back_inserter(sfNames), [](const auto& sf3d) { return sf3d.name; }); + std::vector surfaces = this->surfaces(); + surfaces.erase(std::remove_if(surfaces.begin(), surfaces.end(), + [&sfNames](const auto& surface) { + return std::find(sfNames.cbegin(), sfNames.cend(), surface.nameString()) == sfNames.cend(); + }), + surfaces.end()); + return surfaces; + } + + std::vector Space_Impl::findSurfacesWithIncorrectOrientation() const { + auto volumePoly = this->polyhedron(); + if (volumePoly.isEnclosedVolume()) { + return findSurfacesWithIncorrectOrientationPolyhedron(volumePoly); + } + LOG(Warn, "Can't lookup surfaces with incorrect orientations for a non-enclosed Polyhedron, falling back to the Raycasting method. " + "This will produce false-negatives for non-convex spaces such as H-shaped spaces."); + return findSurfacesWithIncorrectOrientationRaycasting(); + } + bool Space_Impl::areAllSurfacesCorrectlyOriented() const { auto surfaces = findSurfacesWithIncorrectOrientation(); for (const auto& surface : surfaces) { @@ -1012,21 +1042,22 @@ namespace model { return value.get(); } - if (areAllSurfacesCorrectlyOriented()) { - - auto volumePoly = this->polyhedron(); + auto volumePoly = this->polyhedron(); - auto [isVolEnclosed, edgesNot2] = volumePoly.isEnclosedVolume(); - if (isVolEnclosed) { - return volumePoly.calcPolyhedronVolume(); + if (volumePoly.isEnclosedVolume()) { + if (volumePoly.isCompletelyInsideOut()) { + const double volume = volumePoly.polyhedronVolume(); + LOG(Error, briefDescription() << " has all of its Surfaces that are inside-out. Call Space::fixSurfacesWithIncorrectOrientation()."); + return -volume; + } else if (!volumePoly.hasAnySurfaceWithIncorrectOrientation()) { + return volumePoly.polyhedronVolume(); + } else { + LOG(Warn, briefDescription() << " has some Surfaces with incorrection orientation. Call Space::fixSurfacesWithIncorrectOrientation(). " + "Falling back to ceilingHeight * floorArea. Volume calculation will be potentially inaccurate."); } - - LOG(Warn, briefDescription() << " is not enclosed, there are " << edgesNot2.size() - << " edges that aren't used exactly twice. " - "Falling back to ceilingHeight * floorArea. Volume calculation will be potentially inaccurate."); - } else { - LOG(Warn, briefDescription() << " has some Surfaces with incorrection orientation. Call Space::fixSurfacesWithIncorrectOrientation(). " + LOG(Warn, briefDescription() << " is not enclosed, there are " << volumePoly.edgesNotTwo().size() + << " edges that aren't used exactly twice. " "Falling back to ceilingHeight * floorArea. Volume calculation will be potentially inaccurate."); } @@ -1081,7 +1112,7 @@ namespace model { double Space_Impl::numberOfPeople() const { double result = 0.0; - double area = floorArea(); + const double area = floorArea(); for (const People& person : this->people()) { result += person.getNumberOfPeople(area); diff --git a/src/model/Space_Impl.hpp b/src/model/Space_Impl.hpp index 576747378a7..2eb5bb84a9c 100644 --- a/src/model/Space_Impl.hpp +++ b/src/model/Space_Impl.hpp @@ -511,6 +511,9 @@ namespace model { // Find all surfaces where the outwardNormal does not point towards the outside of the Space std::vector findSurfacesWithIncorrectOrientation() const; + std::vector findSurfacesWithIncorrectOrientationRaycasting() const; + std::vector findSurfacesWithIncorrectOrientationPolyhedron(const Polyhedron& volumePoly) const; + // Checks the outwardNormal of every surface points towards the outside of the Space bool areAllSurfacesCorrectlyOriented() const; diff --git a/src/utilities/geometry/Geometry.i b/src/utilities/geometry/Geometry.i index 25217dd3d90..bf0b7c01e97 100644 --- a/src/utilities/geometry/Geometry.i +++ b/src/utilities/geometry/Geometry.i @@ -55,7 +55,6 @@ %template(OptionalFloorplanJS) boost::optional; %template(OptionalFloorplanObject) boost::optional; %template(OptionalPolygon3d) boost::optional; -%template(OptionalPolyhedron) boost::optional; // create an instantiation of the vector classes // Note JM 2019-04-16: No need to ignore std::vector::vector/resize when you have a default constructor @@ -66,8 +65,7 @@ %template(PointLatLonVector) std::vector; %template(Vector3dVector) std::vector; %template(Polygon3dVector) std::vector; -%template(PolyhedronVector) std::vector; -%template(Surface3dVector) std::vector; + %ignore std::vector::vector(size_type); %ignore std::vector::resize(size_type); @@ -96,10 +94,19 @@ %ignore std::vector::resize(size_type); %template(FloorplanObjectVector) std::vector; +%template(OptionalSurface3dEdge) boost::optional; %ignore std::vector::vector(size_type); %ignore std::vector::resize(size_type); %template(Surface3dEdgeVector) std::vector; +%ignore std::vector::vector(size_type); +%ignore std::vector::resize(size_type); +%template(Surface3dVector) std::vector; + +%ignore std::vector::vector(size_type); +%ignore std::vector::resize(size_type); +%template(PolyhedronVector) std::vector; + %template(SizeTVector) std::vector; %template(StringStringMap) std::map; diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index 0a96fbc8655..19942c4a53b 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -36,6 +36,8 @@ #include "Intersection.hpp" #include +#include + #include #include #include @@ -43,9 +45,14 @@ namespace openstudio { -Surface3dEdge::Surface3dEdge(Point3d start, Point3d end, Surface3d firstSurface, size_t firstSurfNum) - : m_start(std::move(start)), m_end(std::move(end)), m_firstSurfNum(firstSurfNum) { - m_allSurfaces.emplace_back(std::move(firstSurface)); +Surface3dEdge::Surface3dEdge(Point3d start, Point3d end, const Surface3d& firstSurface) + : m_start(std::move(start)), m_end(std::move(end)), m_firstSurfaceName(firstSurface.name) { + m_allSurfNums.push_back(firstSurface.surfNum); +} + +Surface3dEdge::Surface3dEdge(Point3d start, Point3d end, std::string t_name, size_t t_surfNum) + : m_start(std::move(start)), m_end(std::move(end)), m_firstSurfaceName(std::move(t_name)) { + m_allSurfNums.push_back(t_surfNum); } /// check equality @@ -63,23 +70,27 @@ bool Surface3dEdge::reverseEqual(const Surface3dEdge& other) const { return isAlmostEqual3dPt(m_start, other.m_end) && isAlmostEqual3dPt(m_end, other.m_start); } -Point3d Surface3dEdge::start() const { +const Point3d& Surface3dEdge::start() const { return m_start; } -Point3d Surface3dEdge::end() const { +const Point3d& Surface3dEdge::end() const { return m_end; } size_t Surface3dEdge::count() const { - return m_allSurfaces.size(); + return m_allSurfNums.size(); } size_t Surface3dEdge::firstSurfNum() const { - return m_firstSurfNum; + return m_allSurfNums.front(); +} + +std::string Surface3dEdge::firstSurfaceName() const { + return m_firstSurfaceName; } -const std::vector& Surface3dEdge::allSurfaces() const { - return m_allSurfaces; +const std::vector& Surface3dEdge::allSurfNums() const { + return m_allSurfNums; } void Surface3dEdge::markConflictedOrientation() { @@ -90,8 +101,21 @@ bool Surface3dEdge::hasConflictedOrientation() const { return m_conflictedOrientation; } -void Surface3dEdge::appendSurface(Surface3d surface) { - m_allSurfaces.emplace_back(std::move(surface)); +void Surface3dEdge::markCreated() { + m_hasBeenCreated = true; +} + +bool Surface3dEdge::hasBeenCreated() const { + return m_hasBeenCreated; +} + +void Surface3dEdge::appendSurface(const Surface3d& surface) { + m_allSurfNums.emplace_back(surface.surfNum); +} + +void Surface3dEdge::resetEdgeMatching() { + m_allSurfNums.erase(std::next(m_allSurfNums.begin()), m_allSurfNums.end()); + m_conflictedOrientation = false; } bool Surface3dEdge::containsPoint(const Point3d& testVertex) { @@ -100,13 +124,12 @@ bool Surface3dEdge::containsPoint(const Point3d& testVertex) { std::ostream& operator<<(std::ostream& os, const Surface3dEdge& edge) { os << "Surface3dEdge: start=" << edge.start() << ", end=" << edge.end() << ", count=" << edge.count() - << ", firstSurface=" << edge.allSurfaces()[0].name; + << ", firstSurface=" << edge.firstSurfaceName(); return os; } -Surface3d::Surface3d(std::vector t_vertices, std::string t_name) : vertices(std::move(t_vertices)), name(std::move(t_name)) { - int surfNum = 0; - +Surface3d::Surface3d(std::vector t_vertices, std::string t_name, size_t t_surfNum) + : vertices(std::move(t_vertices)), name(std::move(t_name)), surfNum(t_surfNum) { for (auto it = vertices.begin(); it != vertices.end(); ++it) { auto itnext = std::next(it); @@ -114,7 +137,7 @@ Surface3d::Surface3d(std::vector t_vertices, std::string t_name) : vert itnext = std::begin(vertices); } - edges.emplace_back(*it, *itnext, *this, surfNum++); + edges.emplace_back(*it, *itnext, t_name, t_surfNum); } } @@ -122,106 +145,131 @@ bool Surface3d::operator<(const Surface3d& rhs) const { return this->name < rhs.name; } -Polyhedron::Polyhedron(std::vector surfaces) : m_surfaces(std::move(surfaces)){}; - -size_t Polyhedron::numVertices() const { - size_t count = 0; - for (const auto& surface : m_surfaces) { - count += surface.vertices.size(); - } - return count; +size_t Surface3d::numConflictedEdges() const { + return std::count_if(edges.cbegin(), edges.cend(), [](const auto& edge) { return edge.hasConflictedOrientation(); }); } -std::vector Polyhedron::uniqueVertices() const { - - std::vector uniqVertices; - uniqVertices.reserve(numVertices()); +double Surface3d::ratioOfConflictedEdges() const { + return static_cast(numConflictedEdges()) / static_cast(edges.size()); +} - for (const auto& surface : m_surfaces) { - for (const auto& pt : surface.vertices) { - if (std::find_if(uniqVertices.cbegin(), uniqVertices.cend(), [&pt](const auto& unqV) { return isAlmostEqual3dPt(pt, unqV); }) - == uniqVertices.cend()) { - uniqVertices.push_back(pt); - } - } +void Surface3d::resetEdgeMatching() { + for (auto& edge : edges) { + edge.resetEdgeMatching(); } - return uniqVertices; } -std::vector Polyhedron::edgesMatches() const { - - std::vector uniqueSurface3dEdges; - uniqueSurface3dEdges.reserve(numVertices()); +Polyhedron::Polyhedron(std::vector surfaces) : m_surfaces(std::move(surfaces)) { + performEdgeMatching(); - // construct list of unique edges - for (const auto& surface : m_surfaces) { - LOG(Debug, "Surface: " << surface.name); - for (const Surface3dEdge& thisSurface3dEdge : surface.edges) { - auto itFound = std::find(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), thisSurface3dEdge); - if (itFound == uniqueSurface3dEdges.end()) { - LOG(Debug, "NOT FOUND: " << thisSurface3dEdge); - uniqueSurface3dEdges.push_back(thisSurface3dEdge); - } else { - LOG(Debug, " FOUND: " << thisSurface3dEdge); - itFound->appendSurface(surface); - if (!itFound->reverseEqual(thisSurface3dEdge)) { - LOG(Debug, " Edges are not in reverse orientation for " << thisSurface3dEdge); - itFound->markConflictedOrientation(); - } + // if all edges had two counts then it is fully enclosed + if (!hasEdgesNot2()) { + m_isEnclosedVolume = true; + } else { + LOG(Warn, "Polyhedron is not enclosed in original testing. Trying to add missing colinear points."); + updateZonePolygonsForMissingColinearPoints(); + } + if (!m_isEnclosedVolume) { + LOG(Warn, "Polyhedron is not enclosed."); + } else { + // We call the volume calculation... if this ends up being negative, we're in the case where ALL surfaces are in the wrong orientation + if (!m_hasAnySurfaceWithIncorrectOrientation) { + m_polyhedronVolume = calcPolyhedronVolume(); + if (m_polyhedronVolume < 0) { + LOG(Error, "It seems that ALL surfaces are reversed"); + m_hasAnySurfaceWithIncorrectOrientation = true; + m_isCompletelyInsideOut = true; } } } +}; - for (auto& edge : uniqueSurface3dEdges) { - LOG(Debug, edge); - } +bool Polyhedron::hasEdgesNot2() const { + return std::any_of(m_surfaces.cbegin(), m_surfaces.cend(), [](const auto& surface) { + return std::any_of(surface.edges.cbegin(), surface.edges.cend(), [](const auto& edge) { return edge.count() != 2; }); + }); +} - return uniqueSurface3dEdges; +bool Polyhedron::hasAnySurfaceWithIncorrectOrientation() const { + return m_hasAnySurfaceWithIncorrectOrientation; } -std::vector Polyhedron::edgesNotTwoForEnclosedVolumeTest() const { +bool Polyhedron::hasAddedColinearPoints() const { + return m_hasAddedColinearPoints; +} - std::vector uniqueSurface3dEdges = edgesMatches(); +bool Polyhedron::isEnclosedVolume() const { + return m_isEnclosedVolume; +} - // All edges for an enclosed polyhedron should be shared by two (and only two) sides. - // So if the count is not two for all edges, the polyhedron is not enclosed, so erase all that are 2 - uniqueSurface3dEdges.erase( - std::remove_if(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), [](const auto& edge) { return edge.count() == 2; }), - uniqueSurface3dEdges.end()); +bool Polyhedron::isCompletelyInsideOut() const { + return m_isCompletelyInsideOut; +} - return uniqueSurface3dEdges; +void Polyhedron::performEdgeMatching() { + + m_hasAnySurfaceWithIncorrectOrientation = false; + + for (size_t i = 0; i < m_surfaces.size(); ++i) { + for (size_t j = 0; j < m_surfaces.size(); ++j) { + if (i == j) { + continue; + } + auto& surface1 = m_surfaces[i]; + auto& surface2 = m_surfaces[j]; + for (Surface3dEdge& edge1 : surface1.edges) { + for (Surface3dEdge& edge2 : surface2.edges) { + if (edge1 == edge2) { + if (std::find(edge1.allSurfNums().begin(), edge1.allSurfNums().cend(), edge2.firstSurfNum()) == edge1.allSurfNums().end()) { + edge1.appendSurface(surface2); + edge2.appendSurface(surface1); + if (!edge1.reverseEqual(edge2)) { + edge1.markConflictedOrientation(); + edge2.markConflictedOrientation(); + m_hasAnySurfaceWithIncorrectOrientation = true; + } + } + } + } + } + } + } } -Polyhedron Polyhedron::updateZonePolygonsForMissingColinearPoints() const { - // Make a copy, we don't want to mutate in place - Polyhedron updZonePoly(*this); +void Polyhedron::resetEdgeMatching() { + for (auto& surface : m_surfaces) { + surface.resetEdgeMatching(); + } + m_hasAnySurfaceWithIncorrectOrientation = false; +} +void Polyhedron::updateZonePolygonsForMissingColinearPoints() { const std::vector uniqVertices = uniqueVertices(); - for (auto& surface : updZonePoly.m_surfaces) { - // for (int iterationLimiter = 0; iterationLimiter < 20; ++iterationLimiter) { // could probably be while loop but want to make sure it does not get stuck + bool anyInserted = false; + + for (auto& surface : m_surfaces) { LOG(Debug, surface.name) bool insertedVertext = true; while (insertedVertext) { insertedVertext = false; - // TODO: loop on edges and insert edge too - auto& vertices = surface.vertices; - for (auto it = vertices.begin(); it != vertices.end(); ++it) { - auto itnext = std::next(it); - if (itnext == std::end(vertices)) { - itnext = std::begin(vertices); - } - - // Don't care about surfNum - Surface3dEdge thisSurface3dEdge(*it, *itnext, surface, 0); + for (auto it = surface.edges.begin(); it != surface.edges.end(); ++it) { // now go through all the vertices and see if they are colinear with start and end vertices for (const auto& testVertex : uniqVertices) { - if (thisSurface3dEdge.containsPoint(testVertex)) { - LOG(Debug, testVertex << " is on " << thisSurface3dEdge); - vertices.insert(itnext, testVertex); + if (const boost::optional newEdge = it->splitEdge(testVertex)) { + LOG(Debug, testVertex << " is on " << *it); + auto itnext = std::next(it); + if (itnext == std::end(surface.edges)) { + itnext = std::begin(surface.edges); + } + auto before_pos = std::distance(surface.edges.begin(), itnext); + surface.edges.insert(itnext, newEdge.get()); + surface.vertices.insert(std::next(surface.vertices.begin(), before_pos), testVertex); + insertedVertext = true; + anyInserted = true; break; } } @@ -232,68 +280,110 @@ Polyhedron Polyhedron::updateZonePolygonsForMissingColinearPoints() const { } } } - return updZonePoly; + + if (anyInserted) { + resetEdgeMatching(); + performEdgeMatching(); + m_hasAddedColinearPoints = true; + m_isEnclosedVolume = !hasEdgesNot2(); + } +} + +size_t Polyhedron::numVertices() const { + return std::accumulate(m_surfaces.cbegin(), m_surfaces.cend(), 0, [](size_t sum, const auto& surface) { return sum + surface.edges.size(); }); } -std::vector edgesInBoth(const std::vector& edges1, const std::vector& edges2) { - // this is not optimized but the number of edges for a typical polyhedron is 12 and is probably rarely bigger than 20. +std::vector Polyhedron::uniqueVertices() const { + + std::vector uniqVertices; + uniqVertices.reserve(numVertices()); - // (std::set_union could be used, but that requires sorting...) - std::vector inBoth; - for (const auto& e1 : edges1) { - for (const auto& e2 : edges2) { - // If they have the same surface and are the same (within tolerance) - if ((e1.firstSurfNum() == e2.firstSurfNum()) && (e1 == e2)) { - inBoth.push_back(e1); - break; + for (const auto& surface : m_surfaces) { + for (const auto& edge : surface.edges) { + const auto& pt = edge.start(); + if (std::find_if(uniqVertices.cbegin(), uniqVertices.cend(), [&pt](const auto& unqV) { return isAlmostEqual3dPt(pt, unqV); }) + == uniqVertices.cend()) { + uniqVertices.push_back(pt); } } } - return inBoth; + return uniqVertices; } -VolumeEnclosedReturnType Polyhedron::isEnclosedVolume() const { +std::vector Polyhedron::uniqueEdges() const { - VolumeEnclosedReturnType result; + std::vector uniqueSurface3dEdges; + uniqueSurface3dEdges.reserve(numVertices()); - const std::vector edgeNot2orig = this->edgesNotTwoForEnclosedVolumeTest(); - // if all edges had two counts then it is fully enclosed - if (edgeNot2orig.empty()) { - result.isEnclosedVolume = true; - return result; - } else { // if the count is three or greater it is likely that a vertex that is colinear was counted on the faces on one edge and not - // on the "other side" of the edge Go through all the points looking for the number that are colinear and see if that is - // consistent with the number of edges found that didn't have a count of two - const Polyhedron updatedZonePoly = - updateZonePolygonsForMissingColinearPoints(); // this is done after initial test since it is computationally intensive. - const std::vector edgeNot2again = updatedZonePoly.edgesNotTwoForEnclosedVolumeTest(); - if (edgeNot2again.empty()) { - result.isEnclosedVolume = true; - return result; + // construct list of unique edges + for (const auto& surface : m_surfaces) { + for (const Surface3dEdge& thisSurface3dEdge : surface.edges) { + auto itFound = std::find(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), thisSurface3dEdge); + if (itFound == uniqueSurface3dEdges.end()) { + uniqueSurface3dEdges.push_back(thisSurface3dEdge); + } + } + } + + return uniqueSurface3dEdges; +} + +std::vector Polyhedron::edgesNotTwo(bool includeCreatedEdges) const { + + std::vector edgesNotTwo; + edgesNotTwo.reserve(numVertices()); + + // All edges for an enclosed polyhedron should be shared by two (and only two) side + for (const auto& surface : m_surfaces) { + for (const Surface3dEdge& thisSurface3dEdge : surface.edges) { + // only return a list of those edges that appear in both the original edge and the revised edges: + // this eliminates added edges that will confuse users (edges that were caught by the updateZonePolygonsForMissingColinearPoints routine) + if ((thisSurface3dEdge.count() != 2) && (includeCreatedEdges || !thisSurface3dEdge.hasBeenCreated())) { + auto itFound = std::find(edgesNotTwo.begin(), edgesNotTwo.end(), thisSurface3dEdge); + if (itFound == edgesNotTwo.end()) { + edgesNotTwo.push_back(thisSurface3dEdge); + } + } } - // only return a list of those edges that appear in both the original edge and the revised edges: - // this eliminates added edges that will confuse users (edges that were caught by the updateZonePolygonsForMissingColinearPoints routine) - result.isEnclosedVolume = false; - result.edgesNot2 = edgesInBoth(edgeNot2orig, edgeNot2again); - return result; } + for (auto& edge : edgesNotTwo) { + LOG(Debug, edge); + } + + return edgesNotTwo; +} + +boost::optional Surface3dEdge::splitEdge(Point3d testVertex) { + if (containsPoint(testVertex)) { + Surface3dEdge newEdge(*this); + this->m_end = testVertex; + newEdge.m_start = std::move(testVertex); + this->markCreated(); + newEdge.markCreated(); + return newEdge; + } + + return boost::none; } std::vector Polyhedron::findSurfacesWithIncorrectOrientation() const { - std::vector uniqueSurface3dEdges = edgesMatches(); + if (!m_isEnclosedVolume) { + LOG(Warn, "Can't lookup surfaces with incorrect orientations for a non-enclosed Polyhedron"); + return {}; + } - if (std::any_of(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), [](const auto& edge) { return edge.count() != 2; })) { - const Polyhedron updatedZonePoly = - updateZonePolygonsForMissingColinearPoints(); // this is done after initial test since it is computationally intensive. - uniqueSurface3dEdges = updatedZonePoly.edgesMatches(); + if (!m_hasAnySurfaceWithIncorrectOrientation) { + return {}; + } - if (std::any_of(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), [](const auto& edge) { return edge.count() != 2; })) { - LOG(Warn, "Can't lookup surfaces with incorrect orientations for a non-enclosed Polyhedron"); - return {}; - } + if (m_isCompletelyInsideOut) { + LOG(Error, "It seems that ALL surfaces are reversed"); + return m_surfaces; } + std::vector uniqueSurface3dEdges = uniqueEdges(); + // Remove non-conflicted edges uniqueSurface3dEdges.erase( std::remove_if(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), [](const auto& edge) { return !edge.hasConflictedOrientation(); }), @@ -303,40 +393,31 @@ std::vector Polyhedron::findSurfacesWithIncorrectOrientation() const } std::set conflictedSurfaces; - std::set> conflictedSurfacePairs; for (auto& edge : uniqueSurface3dEdges) { - const auto& surfaces = edge.allSurfaces(); - const auto& sf1 = surfaces.front(); - const auto& sf2 = surfaces.back(); - if (sf1 < sf2) { - conflictedSurfacePairs.emplace(sf1, sf2); - } else { - conflictedSurfacePairs.emplace(sf2, sf1); - } - } + const auto& surfNums = edge.allSurfNums(); + const size_t sfIndex1 = surfNums.front(); + const size_t sfIndex2 = surfNums.back(); - for (const auto& [sf1, sf2] : conflictedSurfacePairs) { - // Count number of conflicted edges... - auto c1 = std::accumulate(sf1.edges.cbegin(), sf1.edges.cend(), 0, [&uniqueSurface3dEdges](int count, const auto& edge) { - return count + std::count(uniqueSurface3dEdges.cbegin(), uniqueSurface3dEdges.cend(), edge); - }); - auto c2 = std::accumulate(sf2.edges.cbegin(), sf2.edges.cend(), 0, [&uniqueSurface3dEdges](int count, const auto& edge) { - return count + std::count(uniqueSurface3dEdges.cbegin(), uniqueSurface3dEdges.cend(), edge); - }); - LOG(Debug, sf1.name << " has " << c1 << " conflicted edges out of " << sf1.edges.size()); - LOG(Debug, sf2.name << " has " << c2 << " conflicted edges out of " << sf2.edges.size()); + const auto& sf1 = m_surfaces.at(sfIndex1); + const auto& sf2 = m_surfaces.at(sfIndex2); + + const auto c1 = sf1.ratioOfConflictedEdges(); + const auto c2 = sf2.ratioOfConflictedEdges(); + + LOG(Trace, fmt::format("'{}' has {:.2f}% conflicted edges ({}/{}), while '{}' has {:.2f}% conflicted edges ({}/{})", sf1.name, c1, + sf1.numConflictedEdges(), sf1.edges.size(), sf2.name, c2, sf2.numConflictedEdges(), sf2.edges.size())); if (c1 > c2) { conflictedSurfaces.insert(sf1); } else { conflictedSurfaces.insert(sf2); } } + return {conflictedSurfaces.begin(), conflictedSurfaces.end()}; } // boost::optional Polyhedron::calculatedVolume() const { -// auto [isVolEnclosed, edgesNot2] = isEnclosedVolume(); -// if (isVolEnclosed) { +// if (m_m_isEnclosedVolume) { // return calcPolyhedronVolume(); // } // return boost::none; @@ -364,6 +445,18 @@ double Polyhedron::calcPolyhedronVolume() const { return volume / 6.0; // Our newellArea vector has twice the length } +double Polyhedron::polyhedronVolume() const { + if (m_isEnclosedVolume && (m_isCompletelyInsideOut || !m_hasAnySurfaceWithIncorrectOrientation)) { + return m_polyhedronVolume; + } + if (!m_isEnclosedVolume) { + LOG(Error, "Polyhedron volume calculation for a non-enclosed Polyhedron will return bogus values"); + } else if (m_hasAnySurfaceWithIncorrectOrientation && !m_isCompletelyInsideOut) { + LOG(Error, "Polyhedron volume calculation for an enclosed Polyhedron but with incorrectly oriented surfaces will return bogus values"); + } + return calcPolyhedronVolume(); +} + double Polyhedron::calcDivergenceTheoremVolume() const { double volume = 0.0; for (const auto& surface : m_surfaces) { diff --git a/src/utilities/geometry/Polyhedron.hpp b/src/utilities/geometry/Polyhedron.hpp index 2c46b040b55..ace339e6c53 100644 --- a/src/utilities/geometry/Polyhedron.hpp +++ b/src/utilities/geometry/Polyhedron.hpp @@ -43,29 +43,16 @@ namespace model { class ThermalZone; } // namespace model -class Surface3dEdge; - -// A thin wrapper to improve reporting, by attaching a name to the vertices -class UTILITIES_API Surface3d -{ - public: - Surface3d() = default; - Surface3d(std::vector t_vertices, std::string t_name = "None"); - std::vector vertices; - std::string name; - std::vector edges; - // std::vector conflictedOrientation; - - bool operator<(const Surface3d& rhs) const; -}; +class Surface3d; class UTILITIES_API Surface3dEdge { public: - Surface3dEdge(Point3d start, Point3d end, Surface3d firstSurface, size_t firstSurfNum); + Surface3dEdge(Point3d start, Point3d end, const Surface3d& firstSurface); + Surface3dEdge(Point3d start, Point3d end, std::string t_name, size_t t_surfNum); - Point3d start() const; - Point3d end() const; + const Point3d& start() const; + const Point3d& end() const; /// check equality: this uses a tolerance bool operator==(const Surface3dEdge& other) const; @@ -79,53 +66,70 @@ class UTILITIES_API Surface3dEdge size_t count() const; size_t firstSurfNum() const; - void appendSurface(Surface3d surface); + std::string firstSurfaceName() const; + const std::vector& allSurfNums() const; + void appendSurface(const Surface3d& surface); // Checks whether a Point: is not almost equal to the start and end points, and that isPointOnLineBetweenPoints(start, end, testVertex) is true bool containsPoint(const Point3d& testVertex); - const std::vector& allSurfaces() const; - void markConflictedOrientation(); bool hasConflictedOrientation() const; + // Indicates this edge has been created and wasn't part of the original surface (cf updateZonePolygonsForMissingColinearPoints) + void markCreated(); + bool hasBeenCreated() const; + + void resetEdgeMatching(); + + // If it containsPoint the testVertex, Split in place the current edge from [start, vertex] vertex and returns the new next [vertex, end] + boost::optional splitEdge(Point3d testVertex); + private: Point3d m_start; Point3d m_end; - size_t m_firstSurfNum; bool m_conflictedOrientation = false; - std::vector m_allSurfaces; + bool m_hasBeenCreated = false; + std::string m_firstSurfaceName; + std::vector m_allSurfNums; }; -using Surface3dEdgeVector = std::vector; - -class VolumeEnclosedReturnType +// A thin wrapper to improve reporting, by attaching a name to the vertices +class UTILITIES_API Surface3d { public: - VolumeEnclosedReturnType() = default; + Surface3d(std::vector t_vertices, std::string t_name, size_t t_surfNum); + std::vector vertices; + std::string name; + size_t surfNum; + std::vector edges; + + size_t numConflictedEdges() const; + double ratioOfConflictedEdges() const; + + void resetEdgeMatching(); - bool isEnclosedVolume = false; - Surface3dEdgeVector edgesNot2; + bool operator<(const Surface3d& rhs) const; }; class UTILITIES_API Polyhedron { public: - Polyhedron() = default; // Default ctor, for swig - + /** This will call updateZonePolygonsForMissingColinearPoints if needed (if original Polyhedron isn't enclosed) to add any missing colinear point + * (=splitting up edges in case surface intersection hasn't been performed already) */ Polyhedron(std::vector surfaces); - // test if the volume described by the polyhedron if full enclosed (would not leak) - // This is done by checking that every edge is used exactly TWICE. - VolumeEnclosedReturnType isEnclosedVolume() const; + /** Test if the volume described by the polyhedron if full enclosed (would not leak). + * This is done by checking that every edge is used exactly TWICE. */ + bool isEnclosedVolume() const; - std::vector uniqueVertices() const; + /** All unique edges that aren't used exactly twice */ + std::vector edgesNotTwo(bool includeCreatedEdges = false) const; - std::vector edgesNotTwoForEnclosedVolumeTest() const; - - std::vector edgesMatches() const; + std::vector uniqueVertices() const; - Polyhedron updateZonePolygonsForMissingColinearPoints() const; + /** Ignores orientation of edges to return the unique edges */ + std::vector uniqueEdges() const; size_t numVertices() const; @@ -135,20 +139,47 @@ class UTILITIES_API Polyhedron // double calculatedVolume() const; // Polyhedron MUST be enclosed - double calcPolyhedronVolume() const; + double polyhedronVolume() const; // Polyhedron MUST be enclosed double calcDivergenceTheoremVolume() const; + // Whether updateZonePolygonsForMissingColinearPoints was called and ended up actually splitting up edges + bool hasAddedColinearPoints() const; + + /** In an ENCLOSED Polyhedron, all edges should be used twice. And if all surfaces are correctly oriented, each edge should match an edge that is in + * reversed order */ + bool hasAnySurfaceWithIncorrectOrientation() const; + + bool isCompletelyInsideOut() const; + + /** Finds all edges that two surface define in the **same** order (if all surfaces are correctly oriented, they should match in reverse order) + * For each matching edge, we pick a single surface between the two surfaces that define it but retainign the surface that has the largest + * proportion of conflicted edges / total number of edges */ std::vector findSurfacesWithIncorrectOrientation() const; + protected: + void performEdgeMatching(); + void resetEdgeMatching(); + void updateZonePolygonsForMissingColinearPoints(); + bool hasEdgesNot2() const; + // Internal method, result is cached. We have to call it initially to detect if polyhedron is completely inside-out + double calcPolyhedronVolume() const; + private: REGISTER_LOGGER("utilities.Polyhedron"); std::vector m_surfaces; + bool m_isEnclosedVolume = false; + bool m_hasAddedColinearPoints = false; + bool m_hasAnySurfaceWithIncorrectOrientation = false; + bool m_isCompletelyInsideOut = false; + double m_polyhedronVolume = 0.0; }; -using PolyhedronVector = std::vector; +using OptionalSurface3dEdge = boost::optional; +using Surface3dEdgeVector = std::vector; using Surface3dVector = std::vector; +using PolyhedronVector = std::vector; /// ostream operator UTILITIES_API std::ostream& operator<<(std::ostream& os, const Surface3dEdge& edge); diff --git a/src/utilities/geometry/Test/Polyhedron_GTest.cpp b/src/utilities/geometry/Test/Polyhedron_GTest.cpp index 92347af9422..006ac1f392c 100644 --- a/src/utilities/geometry/Test/Polyhedron_GTest.cpp +++ b/src/utilities/geometry/Test/Polyhedron_GTest.cpp @@ -54,50 +54,55 @@ TEST_F(GeometryFixture, Polyhedron_Enclosed) { // This is a shoebox model of a lengthy plenum-like zone. 30x10x0.3m. The south wall is split in the middle - Surface3d south1({{+0.0, +0.0, +0.3}, {+0.0, +0.0, +0.0}, {+15.0, +0.0, +0.0}, {+15.0, +0.0, +0.3}}, "1-SOUTH-1"); - Surface3d south2({{+15.0, +0.0, +0.3}, {+15.0, +0.0, +0.0}, {+30.0, +0.0, +0.0}, {+30.0, +0.0, +0.3}}, "1-SOUTH-2"); + const Surface3d south1({{+0.0, +0.0, +0.3}, {+0.0, +0.0, +0.0}, {+15.0, +0.0, +0.0}, {+15.0, +0.0, +0.3}}, "1-SOUTH-1", 0); + const Surface3d south2({{+15.0, +0.0, +0.3}, {+15.0, +0.0, +0.0}, {+30.0, +0.0, +0.0}, {+30.0, +0.0, +0.3}}, "1-SOUTH-2", 1); - Surface3d north({{+30.0, +10.0, +0.3}, {+30.0, +10.0, +0.0}, {+0.0, +10.0, +0.0}, {+0.0, +10.0, +0.3}}, "4-NORTH"); + const Surface3d north({{+30.0, +10.0, +0.3}, {+30.0, +10.0, +0.0}, {+0.0, +10.0, +0.0}, {+0.0, +10.0, +0.3}}, "4-NORTH", 2); - Surface3d east({{+30.0, +0.0, +0.3}, {+30.0, +0.0, +0.0}, {+30.0, +10.0, +0.0}, {+30.0, +10.0, +0.3}}, "3-EAST"); + const Surface3d east({{+30.0, +0.0, +0.3}, {+30.0, +0.0, +0.0}, {+30.0, +10.0, +0.0}, {+30.0, +10.0, +0.3}}, "3-EAST", 3); - Surface3d west({{+0.0, +10.0, +0.3}, {+0.0, +10.0, +0.0}, {+0.0, +0.0, +0.0}, {+0.0, +0.0, +0.3}}, "2-WEST"); + const Surface3d west({{+0.0, +10.0, +0.3}, {+0.0, +10.0, +0.0}, {+0.0, +0.0, +0.0}, {+0.0, +0.0, +0.3}}, "2-WEST", 4); - Surface3d roof({{+30.0, +0.0, +0.3}, {+30.0, +10.0, +0.3}, {+0.0, +10.0, +0.3}, {+0.0, +0.0, +0.3}}, "ROOF"); + const Surface3d roof({{+30.0, +0.0, +0.3}, {+30.0, +10.0, +0.3}, {+0.0, +10.0, +0.3}, {+0.0, +0.0, +0.3}}, "ROOF", 5); - Surface3d floor({{+0.0, +0.0, +0.0}, {+0.0, +10.0, +0.0}, {+30.0, +10.0, +0.0}, {+30.0, +0.0, +0.0}}, "FLOOR"); + const Surface3d floor({{+0.0, +0.0, +0.0}, {+0.0, +10.0, +0.0}, {+30.0, +10.0, +0.0}, {+30.0, +0.0, +0.0}}, "FLOOR", 6); - Polyhedron zonePoly({south1, south2, north, east, west, roof, floor}); + std::vector surfaces = {south1, south2, north, east, west, roof, floor}; + constexpr double volume = 30.0 * 10.0 * 0.3; { + const Polyhedron zonePoly(surfaces); + // Test individual components // 6 faces for a box, 7 in this case since one face is split in two, each with 4 vertices => 4*7 = 28 - EXPECT_EQ(28, zonePoly.numVertices()); - + // The Polyhedron is not enclosed, so it'll go through updateZonePolygonsForMissingColinearPoints + // We expect the two points from the split south walls to have been added to the roof and floor + EXPECT_EQ(30, zonePoly.numVertices()); + EXPECT_TRUE(zonePoly.isEnclosedVolume()); + EXPECT_EQ(0, zonePoly.edgesNotTwo().size()); + EXPECT_FALSE(zonePoly.hasAnySurfaceWithIncorrectOrientation()); // 8 for the box, plus two for the split of the south wall auto uniqVertices = zonePoly.uniqueVertices(); EXPECT_EQ(10, uniqVertices.size()); - std::vector edgeNot2orig = zonePoly.edgesNotTwoForEnclosedVolumeTest(); - EXPECT_EQ(6, edgeNot2orig.size()); - - auto updatedZonePoly = zonePoly.updateZonePolygonsForMissingColinearPoints(); - // We expect the two points from the split south walls to have been added to the roof and floor - EXPECT_EQ(30, updatedZonePoly.numVertices()); - - std::vector edgeNot2again = updatedZonePoly.edgesNotTwoForEnclosedVolumeTest(); - EXPECT_TRUE(edgeNot2again.empty()); + EXPECT_EQ(volume, zonePoly.polyhedronVolume()); + EXPECT_EQ(volume, zonePoly.calcDivergenceTheoremVolume()); } - // Now do it in one go - - auto r = zonePoly.isEnclosedVolume(); - EXPECT_TRUE(r.isEnclosedVolume); - EXPECT_TRUE(r.edgesNot2.empty()); - - double volume = 30.0 * 10.0 * 0.3; - EXPECT_EQ(volume, zonePoly.calcPolyhedronVolume()); - EXPECT_EQ(volume, zonePoly.calcDivergenceTheoremVolume()); + { + // Check the corner case where NONE of the surfaces are correctly oriented + for (auto& sf : surfaces) { + std::reverse(sf.vertices.begin(), sf.vertices.end()); + } + const Polyhedron flippedPoly(surfaces); + EXPECT_EQ(30, flippedPoly.numVertices()); + EXPECT_TRUE(flippedPoly.isEnclosedVolume()); + EXPECT_EQ(0, flippedPoly.edgesNotTwo().size()); + EXPECT_TRUE(flippedPoly.hasAnySurfaceWithIncorrectOrientation()); + EXPECT_TRUE(flippedPoly.isCompletelyInsideOut()); + EXPECT_EQ(surfaces.size(), flippedPoly.findSurfacesWithIncorrectOrientation().size()); + EXPECT_EQ(-volume, flippedPoly.polyhedronVolume()); + } } TEST_F(GeometryFixture, Polyhedron_Titled_Roof) { @@ -117,29 +122,29 @@ TEST_F(GeometryFixture, Polyhedron_Titled_Roof) { // ◄────┼──────────────┼─ // y 10.0 0.0 - Surface3d south2({{+15.0, +0.0, +10.3}, {+15.0, +0.0, +0.0}, {+30.0, +0.0, +0.0}, {+30.0, +0.0, +10.3}}, "1-SOUTH-2"); + const Surface3d south2({{+15.0, +0.0, +10.3}, {+15.0, +0.0, +0.0}, {+30.0, +0.0, +0.0}, {+30.0, +0.0, +10.3}}, "1-SOUTH-2", 0); // We put extra vertices here to skew the calculate that Space::volume does - Surface3d roof({{+30.0, +0.0, +10.3}, {+30.0, +10.0, +0.3}, {+0.0, +10.0, +0.3}, {+0.0, +0.0, +10.3}, {+10.0, +0.0, +10.3}, {+20.0, +0.0, +10.3}}, - "ROOF"); + const Surface3d roof( + {{+30.0, +0.0, +10.3}, {+30.0, +10.0, +0.3}, {+0.0, +10.0, +0.3}, {+0.0, +0.0, +10.3}, {+10.0, +0.0, +10.3}, {+20.0, +0.0, +10.3}}, "ROOF", 1); - Surface3d east({{+30.0, +0.0, +10.3}, {+30.0, +0.0, +0.0}, {+30.0, +10.0, +0.0}, {+30.0, +10.0, +0.3}}, "3-EAST"); + const Surface3d east({{+30.0, +0.0, +10.3}, {+30.0, +0.0, +0.0}, {+30.0, +10.0, +0.0}, {+30.0, +10.0, +0.3}}, "3-EAST", 2); - Surface3d north({{+30.0, +10.0, +0.3}, {+30.0, +10.0, +0.0}, {+0.0, +10.0, +0.0}, {+0.0, +10.0, +0.3}}, "4-NORTH"); + const Surface3d north({{+30.0, +10.0, +0.3}, {+30.0, +10.0, +0.0}, {+0.0, +10.0, +0.0}, {+0.0, +10.0, +0.3}}, "4-NORTH", 3); - Surface3d west({{+0.0, +10.0, +0.3}, {+0.0, +10.0, +0.0}, {+0.0, +0.0, +0.0}, {+0.0, +0.0, +10.3}}, "2-WEST"); + const Surface3d west({{+0.0, +10.0, +0.3}, {+0.0, +10.0, +0.0}, {+0.0, +0.0, +0.0}, {+0.0, +0.0, +10.3}}, "2-WEST", 4); - Surface3d south1({{+0.0, +0.0, +10.3}, {+0.0, +0.0, +0.0}, {+15.0, +0.0, +0.0}, {+15.0, +0.0, +10.3}}, "1-SOUTH-1"); + const Surface3d south1({{+0.0, +0.0, +10.3}, {+0.0, +0.0, +0.0}, {+15.0, +0.0, +0.0}, {+15.0, +0.0, +10.3}}, "1-SOUTH-1", 5); - Surface3d floor({{+0.0, +0.0, +0.0}, {+0.0, +10.0, +0.0}, {+30.0, +10.0, +0.0}, {+30.0, +0.0, +0.0}}, "FLOOR"); + const Surface3d floor({{+0.0, +0.0, +0.0}, {+0.0, +10.0, +0.0}, {+30.0, +10.0, +0.0}, {+30.0, +0.0, +0.0}}, "FLOOR", 6); - Polyhedron zonePoly({south1, south2, north, east, west, roof, floor}); + const Polyhedron zonePoly({south1, south2, north, east, west, roof, floor}); - auto r = zonePoly.isEnclosedVolume(); - EXPECT_TRUE(r.isEnclosedVolume); - EXPECT_TRUE(r.edgesNot2.empty()); + EXPECT_TRUE(zonePoly.isEnclosedVolume()); + EXPECT_TRUE(zonePoly.edgesNotTwo().empty()); + EXPECT_FALSE(zonePoly.hasAnySurfaceWithIncorrectOrientation()); - double volume = 30.0 * 10.0 * 0.3 + 30.0 * 10.0 * 10.0 / 2.0; - EXPECT_DOUBLE_EQ(volume, zonePoly.calcPolyhedronVolume()); + constexpr double volume = 30.0 * 10.0 * 0.3 + 30.0 * 10.0 * 10.0 / 2.0; + EXPECT_DOUBLE_EQ(volume, zonePoly.polyhedronVolume()); EXPECT_DOUBLE_EQ(volume, zonePoly.calcDivergenceTheoremVolume()); } From 80feb7c49369952732b5e0bb66e0b4041e3e73bc Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Tue, 28 Mar 2023 18:44:17 +0200 Subject: [PATCH 26/40] Allow detecting incorrectly oriented surfaces even if Polyhedron is not enclosed --- src/model/Space.cpp | 15 +++--- src/model/test/Space_GTest.cpp | 72 +++++++++++++++++++++++---- src/utilities/geometry/Polyhedron.cpp | 10 ++-- 3 files changed, 75 insertions(+), 22 deletions(-) diff --git a/src/model/Space.cpp b/src/model/Space.cpp index d687ecef18d..f3bbe616120 100644 --- a/src/model/Space.cpp +++ b/src/model/Space.cpp @@ -1000,12 +1000,15 @@ namespace model { std::vector Space_Impl::findSurfacesWithIncorrectOrientation() const { auto volumePoly = this->polyhedron(); - if (volumePoly.isEnclosedVolume()) { - return findSurfacesWithIncorrectOrientationPolyhedron(volumePoly); - } - LOG(Warn, "Can't lookup surfaces with incorrect orientations for a non-enclosed Polyhedron, falling back to the Raycasting method. " - "This will produce false-negatives for non-convex spaces such as H-shaped spaces."); - return findSurfacesWithIncorrectOrientationRaycasting(); + // Actually, its perfectly fine to lookup incorrect orientations even if the polyhedron isn't enclosed... + // If a Box space is missing one wall for eg, the opposite wall will be deemed incorrectly oriented if using ray casting. + return findSurfacesWithIncorrectOrientationPolyhedron(volumePoly); + // if (volumePoly.isEnclosedVolume()) { + // return findSurfacesWithIncorrectOrientationPolyhedron(volumePoly); + // } + // LOG(Warn, "Can't lookup surfaces with incorrect orientations for a non-enclosed Polyhedron, falling back to the Raycasting method. " + // "This will produce false-negatives for non-convex spaces such as H-shaped spaces."); + // return findSurfacesWithIncorrectOrientationRaycasting(); } bool Space_Impl::areAllSurfacesCorrectlyOriented() const { diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index e1d7cb1f460..d64477fcaeb 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3305,7 +3305,7 @@ TEST_F(ModelFixture, Issue_4837) { } } -TEST_F(ModelFixture, Space_4837_SpaceVolume) { +TEST_F(ModelFixture, Space_4837_SpaceVolume_BoxEnclosed) { Model m; @@ -3379,16 +3379,16 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_NonConvex) { Model m; - // y (=North) - // ▲ - // │ building height = 2m - // 10├────────┼────────┼ - // │ │ - // │ | │ - // │ z=0 z=1 │ - // │ | │ - // └────────┴────────┴───► x - // 0 10 20 + // y (=North) z + // ▲ ▲ + // │ building height = 2m 2├─────────────────┐ + // 10├────────┼────────┼ │ │ + // │ │ │ │ + // │ | │ 1├ ┌────────┘ + // │ z=0 z=1 │ │ │ + // │ | │ │ │ + // └────────┴────────┴───► x └────────┴────────┴───► x + // 0 10 20 0 10 20 constexpr double width = 10.0; constexpr double heightPart1 = 2.0; @@ -3520,3 +3520,53 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_Hshaped) { EXPECT_TRUE(space.isEnclosedVolume()); EXPECT_DOUBLE_EQ(spaceVolume, space.volume()); } + +TEST_F(ModelFixture, Space_4837_SpaceVolume_NonEnclosed) { + + Model m; + + constexpr double width = 10.0; + constexpr double height = 3.6; + constexpr double spaceFloorArea = width * width; + constexpr double spaceVolume = spaceFloorArea * height; + + // y (=North) + // ▲ + // │ + // 10o────────o + // │ │ + // │ │ + // │ Space 1│ + // │ │ + // o────────o───► x + // 0 10 + + // Counterclockwise points, Upper Left Corner convention + std::vector floorPointsSpace1{ + {width, width, 0.0}, + {width, 0.0, 0.0}, + {0.0, 0.0, 0.0}, + {0.0, width, 0.0}, + }; + + auto space1 = Space::fromFloorPrint(floorPointsSpace1, height, m).get(); + EXPECT_EQ(6, space1.surfaces().size()); + EXPECT_TRUE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_TRUE(space1.isEnclosedVolume()); + EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); + + // Grab a wall, delete it + auto surfaces = space1.surfaces(); + auto it = std::find_if(surfaces.begin(), surfaces.end(), [](auto& sf) { return sf.surfaceType() == "Wall"; }); + ASSERT_TRUE(it != surfaces.end()); + it->remove(); + + EXPECT_EQ(5, space1.surfaces().size()); + EXPECT_FALSE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_FALSE(space1.isEnclosedVolume()); + EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); + + auto wrongOrientations = space1.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(1, wrongOrientations.size()); + m.save("Space_4837_SpaceVolume_NonEnclosed.osm", true); +} diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index 19942c4a53b..90c878336df 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -368,11 +368,6 @@ boost::optional Surface3dEdge::splitEdge(Point3d testVertex) { std::vector Polyhedron::findSurfacesWithIncorrectOrientation() const { - if (!m_isEnclosedVolume) { - LOG(Warn, "Can't lookup surfaces with incorrect orientations for a non-enclosed Polyhedron"); - return {}; - } - if (!m_hasAnySurfaceWithIncorrectOrientation) { return {}; } @@ -382,6 +377,11 @@ std::vector Polyhedron::findSurfacesWithIncorrectOrientation() const return m_surfaces; } + if (!m_isEnclosedVolume) { + LOG(Warn, "Polyhedron is not enclosed. Looking surfaces with incorrect orientations can return false negatives."); + // return {}; + } + std::vector uniqueSurface3dEdges = uniqueEdges(); // Remove non-conflicted edges From ec90af690f5c32e6753716aeee42da03802dc6ac Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Wed, 29 Mar 2023 10:38:11 +0200 Subject: [PATCH 27/40] Add a Surface3d method to check for convexity --- src/utilities/geometry/Polyhedron.cpp | 45 ++++++++++++++++++++++++--- src/utilities/geometry/Polyhedron.hpp | 5 +++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index 90c878336df..b03285b1ddd 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -29,12 +29,13 @@ #include "Polyhedron.hpp" #include "Polygon3d.hpp" -#include "Vector3d.hpp" -#include "Point3d.hpp" + #include "Geometry.hpp" -#include "Plane.hpp" #include "Intersection.hpp" -#include +#include "Plane.hpp" +#include "Point3d.hpp" +#include "Transformation.hpp" +#include "Vector3d.hpp" #include @@ -122,6 +123,10 @@ bool Surface3dEdge::containsPoint(const Point3d& testVertex) { return !isAlmostEqual3dPt(m_start, testVertex) && !isAlmostEqual3dPt(m_end, testVertex) && isPointOnLineBetweenPoints(m_start, m_end, testVertex); } +Vector3d Surface3dEdge::asVector() const { + return m_end - m_start; +} + std::ostream& operator<<(std::ostream& os, const Surface3dEdge& edge) { os << "Surface3dEdge: start=" << edge.start() << ", end=" << edge.end() << ", count=" << edge.count() << ", firstSurface=" << edge.firstSurfaceName(); @@ -159,6 +164,38 @@ void Surface3d::resetEdgeMatching() { } } +bool Surface3d::isConvex() const { + + // const auto& a = edges.front().start(); + // const auto& b = edges.front().end(); + // const auto& c = edges.at(1).end(); + + auto ab = edges.front().asVector(); + auto bc = edges[1].asVector(); + auto outwardNormal = ab.cross(bc); + outwardNormal.normalize(); + + for (auto it = std::next(edges.begin()); it != edges.end(); ++it) { + auto itnext = std::next(it); + if (itnext == std::end(edges)) { + itnext = std::begin(edges); + } + const Point3d& a = it->start(); + const Point3d& b = it->end(); + const Point3d& c = itnext->end(); + + auto ab = b - a; + auto ac = c - a; + + auto triangleNormal = ab.cross(ac); + auto d = outwardNormal.dot(triangleNormal); + if (d < 0) { + return false; + } + } + return true; +} + Polyhedron::Polyhedron(std::vector surfaces) : m_surfaces(std::move(surfaces)) { performEdgeMatching(); diff --git a/src/utilities/geometry/Polyhedron.hpp b/src/utilities/geometry/Polyhedron.hpp index ace339e6c53..545d87e681d 100644 --- a/src/utilities/geometry/Polyhedron.hpp +++ b/src/utilities/geometry/Polyhedron.hpp @@ -82,6 +82,8 @@ class UTILITIES_API Surface3dEdge void resetEdgeMatching(); + Vector3d asVector() const; + // If it containsPoint the testVertex, Split in place the current edge from [start, vertex] vertex and returns the new next [vertex, end] boost::optional splitEdge(Point3d testVertex); @@ -107,6 +109,9 @@ class UTILITIES_API Surface3d size_t numConflictedEdges() const; double ratioOfConflictedEdges() const; + // There is no check done whatsoevever to ensure the surface is planar. + bool isConvex() const; + void resetEdgeMatching(); bool operator<(const Surface3d& rhs) const; From b00b25986aa36552dfb91960a85e60bcbdac2573 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Wed, 29 Mar 2023 10:38:37 +0200 Subject: [PATCH 28/40] Add convenience methods to create standard building shapes --- src/utilities/geometry/Polyhedron.cpp | 156 ++++++++++++++++++++++++++ src/utilities/geometry/Polyhedron.hpp | 12 ++ 2 files changed, 168 insertions(+) diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index b03285b1ddd..58c8481fa8c 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -40,8 +40,10 @@ #include #include +#include #include #include +#include #include namespace openstudio { @@ -508,4 +510,158 @@ double Polyhedron::calcDivergenceTheoremVolume() const { return volume; } +std::vector convexRegularPolygon(const Point3d& center, size_t num_sides, double side_with) { + if (num_sides < 3) { + throw std::runtime_error("Polygon must have at least three sides."); + } + + std::vector points; + points.reserve(num_sides); + const double angle = 2.0 * std::numbers::pi / num_sides; + + for (size_t i = 0; i < num_sides; i++) { + double x = center.x() + side_with * std::cos(angle * i); + double y = center.y() + side_with * std::sin(angle * i); + double z = center.z(); + points.emplace_back(x, y, z); + } + + return points; +} + +std::vector hShapedRegularPolygon(const Point3d& center, double total_length) { + + // ▲ + // │(1) (9) + // L o───┐ o───┐ ▲ + // │ │ │ │ │ l2 + // │ └───┘ │ │ + // │ x (5)│ ▼ + // │ ┌───o │ + // │(2)│ │ │ + // o───┴───┴───┴──► + // ◄──► L + // l3 + + const double l2 = total_length / 2.0; + const double l6 = total_length / 6.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - l2, y + l2, z}, // Point 1 - Upper Left Corner + {x - l2, y - l2, z}, // Point 2 + {x - l6, y - l2, z}, // + {x - l6, y - l6, z}, // + {x + l6, y - l6, z}, // Point 5 + {x + l6, y - l2, z}, // + {x + l2, y - l2, z}, // + {x + l2, y + l2, z}, // + {x + l6, y + l2, z}, // Point 9 + {x + l6, y + l6, z}, // + {x - l6, y + l6, z}, // + {x - l6, y + l2, z}, // + }; +} + +std::vector uShapedRegularPolygon(const Point3d& center, double total_length) { + + // ▲ + // │(1) (5) + // L o───┐ o───┐ ▲ + // │ │ │ │ │ l2 + // │ └───┘ │ │ + // │ x │ ▼ + // │ │ + // │(2) │ + // o───────────┴──► + // ◄──► L + // l3 + + const double l2 = total_length / 2.0; + const double l6 = total_length / 6.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - l2, y + l2, z}, // Point 1 - Upper Left Corner + {x - l2, y - l2, z}, // Point 2 + {x + l2, y - l2, z}, // + {x + l2, y + l2, z}, // + {x + l6, y + l2, z}, // Point 5 + {x + l6, y + l6, z}, // + {x - l6, y + l6, z}, // + {x - l6, y + l2, z}, // + }; +} + +std::vector tShapedRegularPolygon(const Point3d& center, double total_length) { + + // ▲ + // │(1) + // L o───────────┐ ▲ + // │ (2) │ │ l2 + // o───┐ ┌───┘ │ + // │ │ x │ ▼ + // │ │ │ + // │ │ │ (5) + // └───┴───o───────► + // ◄──► L + // l3 + + const double l2 = total_length / 2.0; + const double l6 = total_length / 6.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - l2, y + l2, z}, // Point 1 - Upper Left Corner + {x - l2, y + l6, z}, // Point 2 + {x - l6, y + l6, z}, // + {x - l6, y - l2, z}, // + {x + l6, y - l2, z}, // Point 5 + {x + l6, y + l6, z}, // + {x + l2, y + l6, z}, // + {x + l2, y + l2, z}, // + }; +} + +std::vector lShapedRegularPolygon(const Point3d& center, double total_length) { + // ▲ + // │(1) + // L o─────┐ ▲ + // │ │ │ + // │ │ (5) │ l2 + // │ x─────┐ ▼ + // │ │ + // │ │ + // o───────────┴──► + // L + + const double l2 = total_length / 2.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - l2, y + l2, z}, // Point 1 - Upper Left Corner + {x - l2, y - l2, z}, // Point 2 + {x + l2, y - l2, z}, // + {x + l2, y, z}, // + {x, y, z}, // Point 5 + {x, y + l2, z}, // + }; +} + } // namespace openstudio diff --git a/src/utilities/geometry/Polyhedron.hpp b/src/utilities/geometry/Polyhedron.hpp index 545d87e681d..a0d8976ac06 100644 --- a/src/utilities/geometry/Polyhedron.hpp +++ b/src/utilities/geometry/Polyhedron.hpp @@ -189,6 +189,18 @@ using PolyhedronVector = std::vector; /// ostream operator UTILITIES_API std::ostream& operator<<(std::ostream& os, const Surface3dEdge& edge); +// Convenience functions for testing. All them returns point in Counterclockwise order, so if creating a floor, reverse the vertices + +UTILITIES_API std::vector convexRegularPolygon(const Point3d& center, size_t num_sides, double side_with = 1.0); + +UTILITIES_API std::vector hShapedRegularPolygon(const Point3d& center, double total_length = 10.0); + +UTILITIES_API std::vector uShapedRegularPolygon(const Point3d& center, double total_length = 10.0); + +UTILITIES_API std::vector tShapedRegularPolygon(const Point3d& center, double total_length = 10.0); + +UTILITIES_API std::vector lShapedRegularPolygon(const Point3d& center, double total_length = 10.0); + } // namespace openstudio #endif // UTILITIES_GEOMETRY_POLYHEDRON_HPP From 4e1b3d4ef1b7b927ea5f4b6265f0e7e209184ae1 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Wed, 29 Mar 2023 10:49:07 +0200 Subject: [PATCH 29/40] Move the convenience functions into a new header StandardShapes.hpp with a .cpp --- src/model/test/Space_GTest.cpp | 78 +++++++ src/utilities/CMakeLists.txt | 2 + src/utilities/geometry/Geometry.i | 2 + src/utilities/geometry/Polyhedron.cpp | 156 -------------- src/utilities/geometry/Polyhedron.hpp | 12 -- src/utilities/geometry/StandardShapes.cpp | 196 ++++++++++++++++++ src/utilities/geometry/StandardShapes.hpp | 54 +++++ .../geometry/Test/Polyhedron_GTest.cpp | 43 ++++ 8 files changed, 375 insertions(+), 168 deletions(-) create mode 100644 src/utilities/geometry/StandardShapes.cpp create mode 100644 src/utilities/geometry/StandardShapes.hpp diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index d64477fcaeb..2705d67b90e 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -68,6 +68,7 @@ #include "../../utilities/geometry/Geometry.hpp" #include "../../utilities/geometry/Point3d.hpp" #include "../../utilities/geometry/Polyhedron.hpp" +#include "../../utilities/geometry/StandardShapes.hpp" #include "../../utilities/geometry/Transformation.hpp" #include "../../utilities/geometry/Vector3d.hpp" @@ -3570,3 +3571,80 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_NonEnclosed) { EXPECT_EQ(1, wrongOrientations.size()); m.save("Space_4837_SpaceVolume_NonEnclosed.osm", true); } + +TEST_F(ModelFixture, Space_4837_SpaceVolume_Convexity) { + + Model m; + + constexpr double total_length = 10.0; + + int counter = 0; + + const size_t gridsize = 4; + const size_t ntot = gridsize * gridsize; + const size_t nstandardsShapes = 4; + + auto getPos = [&total_length, &gridsize](size_t i) -> std::pair { + auto row = i / gridsize; + auto col = i % gridsize; + return {total_length * 3 * row, total_length * 3 * col}; + }; + + const Point3d p0{}; + for (size_t i = 3; i < (ntot - nstandardsShapes + 3); ++i) { + std::vector points = convexRegularPolygon(p0, i, total_length); + std::reverse(points.begin(), points.end()); + auto s_ = Space::fromFloorPrint(points, 2, m); + ASSERT_TRUE(s_); + s_->setName(fmt::format("Regular {}-sided polygon", i)); + auto [x, y] = getPos(counter++); + s_->setXOrigin(x); + s_->setYOrigin(y); + } + + { + std::vector points = hShapedPolygon(p0, total_length); + std::reverse(points.begin(), points.end()); + auto s_ = Space::fromFloorPrint(points, 2, m); + ASSERT_TRUE(s_); + s_->setName("hShapedPolygon"); + auto [x, y] = getPos(counter++); + s_->setXOrigin(x); + s_->setYOrigin(y); + } + + { + std::vector points = uShapedPolygon(p0, total_length); + std::reverse(points.begin(), points.end()); + auto s_ = Space::fromFloorPrint(points, 2, m); + ASSERT_TRUE(s_); + s_->setName("uShapedPolygon"); + auto [x, y] = getPos(counter++); + s_->setXOrigin(x); + s_->setYOrigin(y); + } + + { + std::vector points = tShapedPolygon(p0, total_length); + std::reverse(points.begin(), points.end()); + auto s_ = Space::fromFloorPrint(points, 2, m); + ASSERT_TRUE(s_); + s_->setName("tShapedPolygon"); + auto [x, y] = getPos(counter++); + s_->setXOrigin(x); + s_->setYOrigin(y); + } + + { + std::vector points = lShapedPolygon(p0, total_length); + std::reverse(points.begin(), points.end()); + auto s_ = Space::fromFloorPrint(points, 2, m); + ASSERT_TRUE(s_); + s_->setName("lShapedPolygon"); + auto [x, y] = getPos(counter++); + s_->setXOrigin(x); + s_->setYOrigin(y); + } + + m.save("Test_convexity.osm", true); +} diff --git a/src/utilities/CMakeLists.txt b/src/utilities/CMakeLists.txt index 863ac833fc2..8adac963b7e 100644 --- a/src/utilities/CMakeLists.txt +++ b/src/utilities/CMakeLists.txt @@ -152,6 +152,8 @@ set(geometry_src geometry/Polygon3d.cpp geometry/Polyhedron.hpp geometry/Polyhedron.cpp + geometry/StandardShapes.hpp + geometry/StandardShapes.cpp ../polypartition/polypartition.cpp ) diff --git a/src/utilities/geometry/Geometry.i b/src/utilities/geometry/Geometry.i index bf0b7c01e97..9a1d18f693a 100644 --- a/src/utilities/geometry/Geometry.i +++ b/src/utilities/geometry/Geometry.i @@ -25,6 +25,7 @@ #include #include #include + #include #include #include @@ -126,6 +127,7 @@ %include %include %include +%include %extend openstudio::Vector3d{ std::string __str__() const { diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index 58c8481fa8c..b03285b1ddd 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -40,10 +40,8 @@ #include #include -#include #include #include -#include #include namespace openstudio { @@ -510,158 +508,4 @@ double Polyhedron::calcDivergenceTheoremVolume() const { return volume; } -std::vector convexRegularPolygon(const Point3d& center, size_t num_sides, double side_with) { - if (num_sides < 3) { - throw std::runtime_error("Polygon must have at least three sides."); - } - - std::vector points; - points.reserve(num_sides); - const double angle = 2.0 * std::numbers::pi / num_sides; - - for (size_t i = 0; i < num_sides; i++) { - double x = center.x() + side_with * std::cos(angle * i); - double y = center.y() + side_with * std::sin(angle * i); - double z = center.z(); - points.emplace_back(x, y, z); - } - - return points; -} - -std::vector hShapedRegularPolygon(const Point3d& center, double total_length) { - - // ▲ - // │(1) (9) - // L o───┐ o───┐ ▲ - // │ │ │ │ │ l2 - // │ └───┘ │ │ - // │ x (5)│ ▼ - // │ ┌───o │ - // │(2)│ │ │ - // o───┴───┴───┴──► - // ◄──► L - // l3 - - const double l2 = total_length / 2.0; - const double l6 = total_length / 6.0; - - const double x = center.x(); - const double y = center.y(); - const double z = center.z(); - - // Counter clockwise order - return { - {x - l2, y + l2, z}, // Point 1 - Upper Left Corner - {x - l2, y - l2, z}, // Point 2 - {x - l6, y - l2, z}, // - {x - l6, y - l6, z}, // - {x + l6, y - l6, z}, // Point 5 - {x + l6, y - l2, z}, // - {x + l2, y - l2, z}, // - {x + l2, y + l2, z}, // - {x + l6, y + l2, z}, // Point 9 - {x + l6, y + l6, z}, // - {x - l6, y + l6, z}, // - {x - l6, y + l2, z}, // - }; -} - -std::vector uShapedRegularPolygon(const Point3d& center, double total_length) { - - // ▲ - // │(1) (5) - // L o───┐ o───┐ ▲ - // │ │ │ │ │ l2 - // │ └───┘ │ │ - // │ x │ ▼ - // │ │ - // │(2) │ - // o───────────┴──► - // ◄──► L - // l3 - - const double l2 = total_length / 2.0; - const double l6 = total_length / 6.0; - - const double x = center.x(); - const double y = center.y(); - const double z = center.z(); - - // Counter clockwise order - return { - {x - l2, y + l2, z}, // Point 1 - Upper Left Corner - {x - l2, y - l2, z}, // Point 2 - {x + l2, y - l2, z}, // - {x + l2, y + l2, z}, // - {x + l6, y + l2, z}, // Point 5 - {x + l6, y + l6, z}, // - {x - l6, y + l6, z}, // - {x - l6, y + l2, z}, // - }; -} - -std::vector tShapedRegularPolygon(const Point3d& center, double total_length) { - - // ▲ - // │(1) - // L o───────────┐ ▲ - // │ (2) │ │ l2 - // o───┐ ┌───┘ │ - // │ │ x │ ▼ - // │ │ │ - // │ │ │ (5) - // └───┴───o───────► - // ◄──► L - // l3 - - const double l2 = total_length / 2.0; - const double l6 = total_length / 6.0; - - const double x = center.x(); - const double y = center.y(); - const double z = center.z(); - - // Counter clockwise order - return { - {x - l2, y + l2, z}, // Point 1 - Upper Left Corner - {x - l2, y + l6, z}, // Point 2 - {x - l6, y + l6, z}, // - {x - l6, y - l2, z}, // - {x + l6, y - l2, z}, // Point 5 - {x + l6, y + l6, z}, // - {x + l2, y + l6, z}, // - {x + l2, y + l2, z}, // - }; -} - -std::vector lShapedRegularPolygon(const Point3d& center, double total_length) { - // ▲ - // │(1) - // L o─────┐ ▲ - // │ │ │ - // │ │ (5) │ l2 - // │ x─────┐ ▼ - // │ │ - // │ │ - // o───────────┴──► - // L - - const double l2 = total_length / 2.0; - - const double x = center.x(); - const double y = center.y(); - const double z = center.z(); - - // Counter clockwise order - return { - {x - l2, y + l2, z}, // Point 1 - Upper Left Corner - {x - l2, y - l2, z}, // Point 2 - {x + l2, y - l2, z}, // - {x + l2, y, z}, // - {x, y, z}, // Point 5 - {x, y + l2, z}, // - }; -} - } // namespace openstudio diff --git a/src/utilities/geometry/Polyhedron.hpp b/src/utilities/geometry/Polyhedron.hpp index a0d8976ac06..545d87e681d 100644 --- a/src/utilities/geometry/Polyhedron.hpp +++ b/src/utilities/geometry/Polyhedron.hpp @@ -189,18 +189,6 @@ using PolyhedronVector = std::vector; /// ostream operator UTILITIES_API std::ostream& operator<<(std::ostream& os, const Surface3dEdge& edge); -// Convenience functions for testing. All them returns point in Counterclockwise order, so if creating a floor, reverse the vertices - -UTILITIES_API std::vector convexRegularPolygon(const Point3d& center, size_t num_sides, double side_with = 1.0); - -UTILITIES_API std::vector hShapedRegularPolygon(const Point3d& center, double total_length = 10.0); - -UTILITIES_API std::vector uShapedRegularPolygon(const Point3d& center, double total_length = 10.0); - -UTILITIES_API std::vector tShapedRegularPolygon(const Point3d& center, double total_length = 10.0); - -UTILITIES_API std::vector lShapedRegularPolygon(const Point3d& center, double total_length = 10.0); - } // namespace openstudio #endif // UTILITIES_GEOMETRY_POLYHEDRON_HPP diff --git a/src/utilities/geometry/StandardShapes.cpp b/src/utilities/geometry/StandardShapes.cpp new file mode 100644 index 00000000000..db4a6804e75 --- /dev/null +++ b/src/utilities/geometry/StandardShapes.cpp @@ -0,0 +1,196 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#include "StandardShapes.hpp" + +#include "Point3d.hpp" +#include "Vector3d.hpp" + +#include +#include +#include +#include + +namespace openstudio { + +std::vector convexRegularPolygon(const Point3d& center, size_t num_sides, double side_with) { + if (num_sides < 3) { + throw std::runtime_error("Polygon must have at least three sides."); + } + + std::vector points; + points.reserve(num_sides); + const double angle = 2.0 * std::numbers::pi / num_sides; + + for (size_t i = 0; i < num_sides; i++) { + double x = center.x() + side_with * std::cos(angle * i); + double y = center.y() + side_with * std::sin(angle * i); + double z = center.z(); + points.emplace_back(x, y, z); + } + + return points; +} + +std::vector hShapedPolygon(const Point3d& center, double total_length) { + + // ▲ + // │(1) (9) + // L o───┐ o───┐ ▲ + // │ │ │ │ │ l2 + // │ └───┘ │ │ + // │ x (5)│ ▼ + // │ ┌───o │ + // │(2)│ │ │ + // o───┴───┴───┴──► + // ◄──► L + // l3 + + const double l2 = total_length / 2.0; + const double l6 = total_length / 6.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - l2, y + l2, z}, // Point 1 - Upper Left Corner + {x - l2, y - l2, z}, // Point 2 + {x - l6, y - l2, z}, // + {x - l6, y - l6, z}, // + {x + l6, y - l6, z}, // Point 5 + {x + l6, y - l2, z}, // + {x + l2, y - l2, z}, // + {x + l2, y + l2, z}, // + {x + l6, y + l2, z}, // Point 9 + {x + l6, y + l6, z}, // + {x - l6, y + l6, z}, // + {x - l6, y + l2, z}, // + }; +} + +std::vector uShapedPolygon(const Point3d& center, double total_length) { + + // ▲ + // │(1) (5) + // L o───┐ o───┐ ▲ + // │ │ │ │ │ l2 + // │ └───┘ │ │ + // │ x │ ▼ + // │ │ + // │(2) │ + // o───────────┴──► + // ◄──► L + // l3 + + const double l2 = total_length / 2.0; + const double l6 = total_length / 6.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - l2, y + l2, z}, // Point 1 - Upper Left Corner + {x - l2, y - l2, z}, // Point 2 + {x + l2, y - l2, z}, // + {x + l2, y + l2, z}, // + {x + l6, y + l2, z}, // Point 5 + {x + l6, y + l6, z}, // + {x - l6, y + l6, z}, // + {x - l6, y + l2, z}, // + }; +} + +std::vector tShapedPolygon(const Point3d& center, double total_length) { + + // ▲ + // │(1) + // L o───────────┐ ▲ + // │ (2) │ │ l2 + // o───┐ ┌───┘ │ + // │ │ x │ ▼ + // │ │ │ + // │ │ │ (5) + // └───┴───o───────► + // ◄──► L + // l3 + + const double l2 = total_length / 2.0; + const double l6 = total_length / 6.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - l2, y + l2, z}, // Point 1 - Upper Left Corner + {x - l2, y + l6, z}, // Point 2 + {x - l6, y + l6, z}, // + {x - l6, y - l2, z}, // + {x + l6, y - l2, z}, // Point 5 + {x + l6, y + l6, z}, // + {x + l2, y + l6, z}, // + {x + l2, y + l2, z}, // + }; +} + +std::vector lShapedPolygon(const Point3d& center, double total_length) { + // ▲ + // │(1) + // L o─────┐ ▲ + // │ │ │ + // │ │ (5) │ l2 + // │ x─────┐ ▼ + // │ │ + // │ │ + // o───────────┴──► + // L + + const double l2 = total_length / 2.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - l2, y + l2, z}, // Point 1 - Upper Left Corner + {x - l2, y - l2, z}, // Point 2 + {x + l2, y - l2, z}, // + {x + l2, y, z}, // + {x, y, z}, // Point 5 + {x, y + l2, z}, // + }; +} + +} // namespace openstudio diff --git a/src/utilities/geometry/StandardShapes.hpp b/src/utilities/geometry/StandardShapes.hpp new file mode 100644 index 00000000000..7733066e68e --- /dev/null +++ b/src/utilities/geometry/StandardShapes.hpp @@ -0,0 +1,54 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2022, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#ifndef UTILITIES_GEOMETRY_STANDARDSHAPES_HPP +#define UTILITIES_GEOMETRY_STANDARDSHAPES_HPP + +#include "../UtilitiesAPI.hpp" +#include "Point3d.hpp" + +#include + +namespace openstudio { + +// Convenience functions for testing. All them returns point in Counterclockwise order, so if creating a floor, reverse the vertices + +UTILITIES_API std::vector convexRegularPolygon(const Point3d& center, size_t num_sides, double side_with = 1.0); + +UTILITIES_API std::vector hShapedPolygon(const Point3d& center, double total_length = 10.0); + +UTILITIES_API std::vector uShapedPolygon(const Point3d& center, double total_length = 10.0); + +UTILITIES_API std::vector tShapedPolygon(const Point3d& center, double total_length = 10.0); + +UTILITIES_API std::vector lShapedPolygon(const Point3d& center, double total_length = 10.0); + +} // namespace openstudio + +#endif // UTILITIES_GEOMETRY_STANDARDSHAPES_HPP diff --git a/src/utilities/geometry/Test/Polyhedron_GTest.cpp b/src/utilities/geometry/Test/Polyhedron_GTest.cpp index 006ac1f392c..561f2900f0f 100644 --- a/src/utilities/geometry/Test/Polyhedron_GTest.cpp +++ b/src/utilities/geometry/Test/Polyhedron_GTest.cpp @@ -35,6 +35,9 @@ #include "../Polyhedron.hpp" #include "../PointLatLon.hpp" #include "../Vector3d.hpp" +#include "../StandardShapes.hpp" + +#include #include @@ -148,3 +151,43 @@ TEST_F(GeometryFixture, Polyhedron_Titled_Roof) { EXPECT_DOUBLE_EQ(volume, zonePoly.polyhedronVolume()); EXPECT_DOUBLE_EQ(volume, zonePoly.calcDivergenceTheoremVolume()); } + +TEST_F(GeometryFixture, Surface3d_Convexity) { + const Point3d p0{}; + for (size_t i = 3; i <= 16; ++i) { + const std::vector points = convexRegularPolygon(p0, i, 1.0); + const Surface3d surface(points, fmt::format("Regular {}-sided polygon", i), 0); + EXPECT_EQ(i, surface.edges.size()); + EXPECT_TRUE(surface.isConvex()); + } + + constexpr double total_length = 10.0; + + { + const std::vector points = hShapedPolygon(p0, total_length); + const Surface3d surface(points, "hShapedPolygon", 0); + EXPECT_EQ(12, surface.edges.size()); + EXPECT_FALSE(surface.isConvex()); + } + + { + const std::vector points = uShapedPolygon(p0, total_length); + const Surface3d surface(points, "uShapedPolygon", 0); + EXPECT_EQ(8, surface.edges.size()); + EXPECT_FALSE(surface.isConvex()); + } + + { + const std::vector points = tShapedPolygon(p0, total_length); + const Surface3d surface(points, "tShapedPolygon", 0); + EXPECT_EQ(8, surface.edges.size()); + EXPECT_FALSE(surface.isConvex()); + } + + { + const std::vector points = lShapedPolygon(p0, total_length); + const Surface3d surface(points, "lShapedPolygon", 0); + EXPECT_EQ(6, surface.edges.size()); + EXPECT_FALSE(surface.isConvex()); + } +} From c0775830ee4e575a4a620f9492eb26d27d8e059f Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Wed, 29 Mar 2023 12:09:20 +0200 Subject: [PATCH 30/40] add SQuare and rectangle --- src/utilities/geometry/StandardShapes.cpp | 57 +++++++++++++++++++++++ src/utilities/geometry/StandardShapes.hpp | 4 ++ 2 files changed, 61 insertions(+) diff --git a/src/utilities/geometry/StandardShapes.cpp b/src/utilities/geometry/StandardShapes.cpp index db4a6804e75..ca4a0218e9f 100644 --- a/src/utilities/geometry/StandardShapes.cpp +++ b/src/utilities/geometry/StandardShapes.cpp @@ -193,4 +193,61 @@ std::vector lShapedPolygon(const Point3d& center, double total_length) }; } +std::vector squaredPolygon(const Point3d& center, double side_with) { + + // ▲ + // │(1) + // L o───────────┐ ▲ + // │ │ l2 + // │ │ │ + // │ x │ ▼ + // │ │ + // │(2) │ + // o───────────┴──► + // L + + const double l2 = side_with / 2.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - l2, y + l2, z}, // Point 1 - Upper Left Corner + {x - l2, y - l2, z}, // Point 2 + {x + l2, y - l2, z}, // + {x + l2, y + l2, z}, // + }; +} + +std::vector rectangularPolygon(const Point3d& center, double length_x, double length_y) { + + // ▲ + // │(1) + //L_yo───────────┐ ▲ + // │ │ ly2 + // │ │ │ + // │ x │ ▼ + // │ │ + // │(2) │ + // o───────────┴──► + // L_x + + const double lx2 = length_x / 2.0; + const double ly2 = length_y / 2.0; + + const double x = center.x(); + const double y = center.y(); + const double z = center.z(); + + // Counter clockwise order + return { + {x - lx2, y + ly2, z}, // Point 1 - Upper Left Corner + {x - lx2, y - ly2, z}, // Point 2 + {x + lx2, y - ly2, z}, // + {x + lx2, y + ly2, z}, // + }; +} + } // namespace openstudio diff --git a/src/utilities/geometry/StandardShapes.hpp b/src/utilities/geometry/StandardShapes.hpp index 7733066e68e..1c2229ecf90 100644 --- a/src/utilities/geometry/StandardShapes.hpp +++ b/src/utilities/geometry/StandardShapes.hpp @@ -49,6 +49,10 @@ UTILITIES_API std::vector tShapedPolygon(const Point3d& center, double UTILITIES_API std::vector lShapedPolygon(const Point3d& center, double total_length = 10.0); +UTILITIES_API std::vector squaredPolygon(const Point3d& center, double side_with = 10.0); + +UTILITIES_API std::vector rectangularPolygon(const Point3d& center, double length_x = 20.0, double length_y = 10.0); + } // namespace openstudio #endif // UTILITIES_GEOMETRY_STANDARDSHAPES_HPP From f212b583a005d0f7040b5177ea230b9795eb0309 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Wed, 29 Mar 2023 12:10:59 +0200 Subject: [PATCH 31/40] Add PlanarSurface::isConvex --- src/model/PlanarSurface.cpp | 13 +++++++++++++ src/model/PlanarSurface.hpp | 2 ++ src/model/PlanarSurface_Impl.hpp | 6 ++++++ 3 files changed, 21 insertions(+) diff --git a/src/model/PlanarSurface.cpp b/src/model/PlanarSurface.cpp index 6864db83b41..fbc47e4f93b 100644 --- a/src/model/PlanarSurface.cpp +++ b/src/model/PlanarSurface.cpp @@ -52,6 +52,7 @@ #include "../utilities/geometry/Geometry.hpp" #include "../utilities/geometry/Transformation.hpp" +#include "../utilities/geometry/Polyhedron.hpp" #include "../utilities/core/Assert.hpp" @@ -487,6 +488,14 @@ namespace model { return m_cachedPlane.get(); } + Surface3d PlanarSurface_Impl::surface3d() const { + return {this->vertices(), this->nameString(), 0}; + } + + bool PlanarSurface_Impl::isConvex() const { + return surface3d().isConvex(); + } + std::vector> PlanarSurface_Impl::triangulation() const { if (m_cachedTriangulation.empty()) { Transformation faceTransformation = Transformation::alignFace(this->vertices()); @@ -723,6 +732,10 @@ namespace model { return getImpl()->plane(); } + bool PlanarSurface::isConvex() const { + return getImpl()->isConvex(); + } + std::vector> PlanarSurface::triangulation() const { return getImpl()->triangulation(); } diff --git a/src/model/PlanarSurface.hpp b/src/model/PlanarSurface.hpp index edc2032de7a..349320a734c 100644 --- a/src/model/PlanarSurface.hpp +++ b/src/model/PlanarSurface.hpp @@ -223,6 +223,8 @@ namespace model { /// Returns any SurfacePropertyConvectionCoefficients associated with this surface, does not return SurfacePropertyConvectionCoefficientsMultipleSurface. std::vector surfacePropertyConvectionCoefficients() const; + bool isConvex() const; + protected: /** @name Constructors and Destructors */ //@{ diff --git a/src/model/PlanarSurface_Impl.hpp b/src/model/PlanarSurface_Impl.hpp index 0366a1a7edc..3a6c025de36 100644 --- a/src/model/PlanarSurface_Impl.hpp +++ b/src/model/PlanarSurface_Impl.hpp @@ -40,6 +40,8 @@ namespace openstudio { +class Surface3d; + namespace model { class PlanarSurfaceGroup; @@ -154,6 +156,10 @@ namespace model { Plane plane() const; + Surface3d surface3d() const; + + bool isConvex() const; + std::vector> triangulation() const; Point3d centroid() const; From 8486d3451f5e605d6d0909b3a381ce93c802d84c Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Wed, 29 Mar 2023 12:11:40 +0200 Subject: [PATCH 32/40] Add Space::isConvex which checks the floorPrint() for convexity + std::vector findNonConvexSurfaces --- src/model/Space.cpp | 24 +++++++ src/model/Space.hpp | 10 +++ src/model/Space_Impl.hpp | 10 +++ src/model/test/Space_GTest.cpp | 111 ++++++++++++++++++++++++++++----- 4 files changed, 139 insertions(+), 16 deletions(-) diff --git a/src/model/Space.cpp b/src/model/Space.cpp index f3bbe616120..0e1f4792744 100644 --- a/src/model/Space.cpp +++ b/src/model/Space.cpp @@ -2926,6 +2926,22 @@ namespace model { return result; } + bool Space_Impl::isConvex() const { + auto points = floorPrint(); + if (points.empty()) { + LOG(Warn, "Can't compute a floorPrint for " << briefDescription()); + return false; + } + Surface3d sf3d(points, fmt::format("{} floorPrint", nameString()), 0); + return sf3d.isConvex(); + } + + std::vector Space_Impl::findNonConvexSurfaces() const { + auto surfaces = this->surfaces(); + surfaces.erase(std::remove_if(surfaces.begin(), surfaces.end(), [](const auto& surface) { return surface.isConvex(); }), surfaces.end()); + return surfaces; + } + bool Space_Impl::isPlenum() const { bool result = false; boost::optional thermalZone = this->thermalZone(); @@ -3632,6 +3648,14 @@ namespace model { return getImpl()->fixSurfacesWithIncorrectOrientation(); } + bool Space::isConvex() const { + return getImpl()->isConvex(); + } + + std::vector Space::findNonConvexSurfaces() const { + return getImpl()->findNonConvexSurfaces(); + } + /// @cond Space::Space(std::shared_ptr impl) : PlanarSurfaceGroup(std::move(impl)) {} /// @endcond diff --git a/src/model/Space.hpp b/src/model/Space.hpp index 4e349568d23..ace6c9b98b0 100644 --- a/src/model/Space.hpp +++ b/src/model/Space.hpp @@ -650,6 +650,16 @@ namespace model { // Returns true if the orientation of any surface has been changed bool fixSurfacesWithIncorrectOrientation(); + /** This method will check the floorPrint of the space, if that can't be computed, it's not convex. If it can, it checks whether that resulting + * Surface3d is convex. Note: having a floorPrint that's convex isn't sufficied to deem a space to be convex, the walls could still be non + * convex, but it should suit most typical applications */ + bool isConvex() const; + + /** Checks if every Surface is convex, returns the Concave ones. + * Note: having a non convex surface does not necesarilly mean that the Space is not convex + * eg: a box with a wall that is split into two L s would return false, while the Space is actually still convex. */ + std::vector findNonConvexSurfaces() const; + //@} protected: /// @cond diff --git a/src/model/Space_Impl.hpp b/src/model/Space_Impl.hpp index 2eb5bb84a9c..31efc6f3915 100644 --- a/src/model/Space_Impl.hpp +++ b/src/model/Space_Impl.hpp @@ -520,6 +520,16 @@ namespace model { // Returns true if the orientation of any surface has been changed bool fixSurfacesWithIncorrectOrientation(); + /** This method will check the floorPrint of the space, if that can't be computed, it's not convex. If it can, it checks whether that resulting + * Surface3d is convex. Note: having a floorPrint that's convex isn't sufficied to deem a space to be convex, the walls could still be non + * convex, but it should suit most typical applications */ + bool isConvex() const; + + /** Checks if every Surface is convex, returns the Concave ones. + * Note: having a non convex surface does not necesarilly mean that the Space is not convex + * eg: a box with a wall that is split into two L s would return false, while the Space is actually still convex. */ + std::vector findNonConvexSurfaces() const; + std::vector zoneMixing() const; std::vector supplyZoneMixing() const; std::vector exhaustZoneMixing() const; diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index 2705d67b90e..fcd2cd9f327 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3416,6 +3416,8 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_NonConvex) { EXPECT_EQ(spaceVolumePart1, space1.volume()); EXPECT_TRUE(space1.areAllSurfacesCorrectlyOriented()); EXPECT_TRUE(space1.isEnclosedVolume()); + EXPECT_TRUE(space1.isConvex()); + EXPECT_TRUE(space1.findNonConvexSurfaces().empty()); auto floorSurface2Points = makeFloor(width, 2 * width, 0.0, width, 1.0); auto space2 = Space::fromFloorPrint(floorSurface2Points, heightPart2, m).get(); @@ -3423,6 +3425,8 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_NonConvex) { EXPECT_EQ(spaceVolumePart2, space2.volume()); EXPECT_TRUE(space2.areAllSurfacesCorrectlyOriented()); EXPECT_TRUE(space2.isEnclosedVolume()); + EXPECT_TRUE(space2.isConvex()); + EXPECT_TRUE(space2.findNonConvexSurfaces().empty()); EXPECT_EQ(12, m.getConcreteModelObjects().size()); space1.intersectSurfaces(space2); @@ -3440,6 +3444,9 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_NonConvex) { EXPECT_TRUE(mergedSpace.isEnclosedVolume()); EXPECT_EQ(2 * spaceFloorAreaEach, mergedSpace.floorArea()); EXPECT_EQ(spaceVolume, mergedSpace.volume()); + // Space is deemed non convex because it doesn't have a floorPrint, but no surfaces are concave + EXPECT_FALSE(mergedSpace.isConvex()); + EXPECT_TRUE(mergedSpace.findNonConvexSurfaces().empty()); } TEST_F(ModelFixture, Space_4837_SpaceVolume_Hshaped) { @@ -3568,11 +3575,20 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_NonEnclosed) { EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); auto wrongOrientations = space1.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(0, wrongOrientations.size()); + + // Grab a wall, flip it + it = std::find_if(surfaces.begin(), surfaces.end(), [](auto& sf) { return sf.surfaceType() == "Wall"; }); + auto vertices = it->vertices(); + std::reverse(vertices.begin(), vertices.end()); + it->setVertices(vertices); + wrongOrientations = space1.findSurfacesWithIncorrectOrientation(); EXPECT_EQ(1, wrongOrientations.size()); + m.save("Space_4837_SpaceVolume_NonEnclosed.osm", true); } -TEST_F(ModelFixture, Space_4837_SpaceVolume_Convexity) { +TEST_F(ModelFixture, Space_Convexity) { Model m; @@ -3580,11 +3596,11 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_Convexity) { int counter = 0; - const size_t gridsize = 4; - const size_t ntot = gridsize * gridsize; - const size_t nstandardsShapes = 4; + constexpr size_t gridsize = 4; + constexpr size_t ntot = gridsize * gridsize; + constexpr size_t nstandardsShapes = 4; - auto getPos = [&total_length, &gridsize](size_t i) -> std::pair { + auto getPos = [](size_t i) -> std::pair { auto row = i / gridsize; auto col = i % gridsize; return {total_length * 3 * row, total_length * 3 * col}; @@ -3594,57 +3610,120 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_Convexity) { for (size_t i = 3; i < (ntot - nstandardsShapes + 3); ++i) { std::vector points = convexRegularPolygon(p0, i, total_length); std::reverse(points.begin(), points.end()); - auto s_ = Space::fromFloorPrint(points, 2, m); + auto s_ = Space::fromFloorPrint(points, 2, m, fmt::format("Regular {}-sided polygon", i)); ASSERT_TRUE(s_); - s_->setName(fmt::format("Regular {}-sided polygon", i)); auto [x, y] = getPos(counter++); s_->setXOrigin(x); s_->setYOrigin(y); + EXPECT_TRUE(s_->isConvex()); + EXPECT_TRUE(s_->findNonConvexSurfaces().empty()); } { std::vector points = hShapedPolygon(p0, total_length); std::reverse(points.begin(), points.end()); - auto s_ = Space::fromFloorPrint(points, 2, m); + auto s_ = Space::fromFloorPrint(points, 2, m, "hShapedPolygon"); ASSERT_TRUE(s_); - s_->setName("hShapedPolygon"); auto [x, y] = getPos(counter++); s_->setXOrigin(x); s_->setYOrigin(y); + EXPECT_FALSE(s_->isConvex()); + // Roof and floor + EXPECT_EQ(2, s_->findNonConvexSurfaces().size()); + EXPECT_EQ("hShapedPolygon Floor", s_->findNonConvexSurfaces().front().nameString()); + EXPECT_EQ("hShapedPolygon RoofCeiling", s_->findNonConvexSurfaces().back().nameString()); } { - std::vector points = uShapedPolygon(p0, total_length); + std::vector points = hShapedPolygon(p0, total_length); std::reverse(points.begin(), points.end()); - auto s_ = Space::fromFloorPrint(points, 2, m); + auto s_ = Space::fromFloorPrint(points, 2, m, "hShapedPolygon"); ASSERT_TRUE(s_); - s_->setName("uShapedPolygon"); auto [x, y] = getPos(counter++); s_->setXOrigin(x); s_->setYOrigin(y); + EXPECT_FALSE(s_->isConvex()); + // Roof and floor + EXPECT_EQ(2, s_->findNonConvexSurfaces().size()); } { std::vector points = tShapedPolygon(p0, total_length); std::reverse(points.begin(), points.end()); - auto s_ = Space::fromFloorPrint(points, 2, m); + auto s_ = Space::fromFloorPrint(points, 2, m, "tShapedPolygon"); ASSERT_TRUE(s_); - s_->setName("tShapedPolygon"); auto [x, y] = getPos(counter++); s_->setXOrigin(x); s_->setYOrigin(y); + EXPECT_FALSE(s_->isConvex()); + // Roof and floor + EXPECT_EQ(2, s_->findNonConvexSurfaces().size()); } { std::vector points = lShapedPolygon(p0, total_length); std::reverse(points.begin(), points.end()); - auto s_ = Space::fromFloorPrint(points, 2, m); + auto s_ = Space::fromFloorPrint(points, 2, m, "lShapedPolygon"); + ASSERT_TRUE(s_); + auto [x, y] = getPos(counter++); + s_->setXOrigin(x); + s_->setYOrigin(y); + EXPECT_FALSE(s_->isConvex()); + // Roof and floor + EXPECT_EQ(2, s_->findNonConvexSurfaces().size()); + } + + { + std::vector points = squaredPolygon(p0, total_length); + std::reverse(points.begin(), points.end()); + auto s_ = Space::fromFloorPrint(points, 2, m, "squaredPolygon"); + ASSERT_TRUE(s_); + auto [x, y] = getPos(counter++); + s_->setXOrigin(x); + s_->setYOrigin(y); + EXPECT_TRUE(s_->isConvex()); + EXPECT_TRUE(s_->findNonConvexSurfaces().empty()); + } + + { + std::vector points = rectangularPolygon(p0, total_length * 2, total_length); + std::reverse(points.begin(), points.end()); + auto s_ = Space::fromFloorPrint(points, 2, m, "rectangularPolygon"); ASSERT_TRUE(s_); - s_->setName("lShapedPolygon"); auto [x, y] = getPos(counter++); s_->setXOrigin(x); s_->setYOrigin(y); + EXPECT_TRUE(s_->isConvex()); + EXPECT_TRUE(s_->findNonConvexSurfaces().empty()); } + m.versionObject()->setString(1, "3.5.1"); m.save("Test_convexity.osm", true); } + +TEST_F(ModelFixture, Space_Convexity_2) { + + Model m; + ThermalZone z(m); + + Point3d p0; + constexpr double total_length = 10.0; + + for (size_t i = 0; i < 2; ++i) { + std::vector points = squaredPolygon(p0, total_length); + std::reverse(points.begin(), points.end()); + auto s_ = Space::fromFloorPrint(points, 2, m, fmt::format("squaredPolygon{}", i)); + ASSERT_TRUE(s_); + s_->setXOrigin(0.0); + s_->setYOrigin(i * total_length); + EXPECT_TRUE(s_->isConvex()); + EXPECT_TRUE(s_->findNonConvexSurfaces().empty()); + s_->setThermalZone(z); + } + auto s_ = z.combineSpaces(); + EXPECT_TRUE(s_); + // So, that space has two floor surfaces... + EXPECT_TRUE(s_->isConvex()); + // Roof and floor + EXPECT_TRUE(s_->findNonConvexSurfaces().empty()); +} From 4288f8a56ee26d887862a10c5bac1e42e91d57eb Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Wed, 29 Mar 2023 13:15:38 +0200 Subject: [PATCH 33/40] Clean up tests --- src/model/test/Space_GTest.cpp | 50 ++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 21 deletions(-) diff --git a/src/model/test/Space_GTest.cpp b/src/model/test/Space_GTest.cpp index fcd2cd9f327..12f43e5cb38 100644 --- a/src/model/test/Space_GTest.cpp +++ b/src/model/test/Space_GTest.cpp @@ -3564,28 +3564,37 @@ TEST_F(ModelFixture, Space_4837_SpaceVolume_NonEnclosed) { EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); // Grab a wall, delete it - auto surfaces = space1.surfaces(); - auto it = std::find_if(surfaces.begin(), surfaces.end(), [](auto& sf) { return sf.surfaceType() == "Wall"; }); - ASSERT_TRUE(it != surfaces.end()); - it->remove(); - - EXPECT_EQ(5, space1.surfaces().size()); - EXPECT_FALSE(space1.areAllSurfacesCorrectlyOriented()); - EXPECT_FALSE(space1.isEnclosedVolume()); - EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); + { + auto surfaces = space1.surfaces(); + auto it = std::find_if(surfaces.begin(), surfaces.end(), [](auto& sf) { return sf.surfaceType() == "Wall"; }); + ASSERT_TRUE(it != surfaces.end()); + it->remove(); + + EXPECT_EQ(5, space1.surfaces().size()); + EXPECT_TRUE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_FALSE(space1.isEnclosedVolume()); + EXPECT_DOUBLE_EQ(spaceVolume, space1.volume()); + + auto wrongOrientations = space1.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(0, wrongOrientations.size()); + } - auto wrongOrientations = space1.findSurfacesWithIncorrectOrientation(); - EXPECT_EQ(0, wrongOrientations.size()); + { + // Grab a wall, flip it + auto surfaces = space1.surfaces(); + auto it = std::find_if(surfaces.begin(), surfaces.end(), [](auto& sf) { return sf.surfaceType() == "Wall"; }); + auto vertices = it->vertices(); + std::reverse(vertices.begin(), vertices.end()); + it->setVertices(vertices); - // Grab a wall, flip it - it = std::find_if(surfaces.begin(), surfaces.end(), [](auto& sf) { return sf.surfaceType() == "Wall"; }); - auto vertices = it->vertices(); - std::reverse(vertices.begin(), vertices.end()); - it->setVertices(vertices); - wrongOrientations = space1.findSurfacesWithIncorrectOrientation(); - EXPECT_EQ(1, wrongOrientations.size()); + EXPECT_EQ(5, space1.surfaces().size()); + EXPECT_FALSE(space1.areAllSurfacesCorrectlyOriented()); + EXPECT_FALSE(space1.isEnclosedVolume()); + auto wrongOrientations = space1.findSurfacesWithIncorrectOrientation(); + EXPECT_EQ(1, wrongOrientations.size()); + } - m.save("Space_4837_SpaceVolume_NonEnclosed.osm", true); + // m.save("Space_4837_SpaceVolume_NonEnclosed.osm", true); } TEST_F(ModelFixture, Space_Convexity) { @@ -3697,8 +3706,7 @@ TEST_F(ModelFixture, Space_Convexity) { EXPECT_TRUE(s_->findNonConvexSurfaces().empty()); } - m.versionObject()->setString(1, "3.5.1"); - m.save("Test_convexity.osm", true); + // m.save("Test_convexity.osm", true); } TEST_F(ModelFixture, Space_Convexity_2) { From a69d2f8e26777de64a974cab0aee0e4dff89c92a Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Wed, 29 Mar 2023 13:44:19 +0200 Subject: [PATCH 34/40] GCC 9 doesn't have header... --- src/utilities/geometry/Polyhedron.cpp | 10 +++++++++- src/utilities/geometry/StandardShapes.cpp | 10 ++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index b03285b1ddd..491d428b1b6 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -166,6 +166,10 @@ void Surface3d::resetEdgeMatching() { bool Surface3d::isConvex() const { + // for each triangle of 3 points, we compute the triangleNormal by taking the cross product of AB x AC. + // We then take the dot product with the initial outwardNormal. If the dot product is negative, this means the triangleNomal is pointing in the + // opposite direction and we therefore have a non convex surface + // const auto& a = edges.front().start(); // const auto& b = edges.front().end(); // const auto& c = edges.at(1).end(); @@ -258,8 +262,12 @@ void Polyhedron::performEdgeMatching() { for (Surface3dEdge& edge2 : surface2.edges) { if (edge1 == edge2) { if (std::find(edge1.allSurfNums().begin(), edge1.allSurfNums().cend(), edge2.firstSurfNum()) == edge1.allSurfNums().end()) { + // appendSurface will allow use to check edge.count() later to check if count == 2. + // All edges must be count == 2 in an Enclosed Polyhedron edge1.appendSurface(surface2); edge2.appendSurface(surface1); + // In a Polyhedron that has a consistent orientation (typically all faces are in counter clockwise order), + // each edge must be matched by an edge in the **opposite** direction. If not, mark conflicted if (!edge1.reverseEqual(edge2)) { edge1.markConflictedOrientation(); edge2.markConflictedOrientation(); @@ -421,7 +429,7 @@ std::vector Polyhedron::findSurfacesWithIncorrectOrientation() const std::vector uniqueSurface3dEdges = uniqueEdges(); - // Remove non-conflicted edges + // Remove non-conflicted edges (Note: this also removes any edge that doesn't have at least one match... since these can't be conflicted) uniqueSurface3dEdges.erase( std::remove_if(uniqueSurface3dEdges.begin(), uniqueSurface3dEdges.end(), [](const auto& edge) { return !edge.hasConflictedOrientation(); }), uniqueSurface3dEdges.end()); diff --git a/src/utilities/geometry/StandardShapes.cpp b/src/utilities/geometry/StandardShapes.cpp index ca4a0218e9f..899a314fee5 100644 --- a/src/utilities/geometry/StandardShapes.cpp +++ b/src/utilities/geometry/StandardShapes.cpp @@ -32,11 +32,17 @@ #include "Point3d.hpp" #include "Vector3d.hpp" +#include + #include -#include #include #include +// GCC <10 doesn't have numbers.. +// #include / PI +// static constexpr double PI = td::numbers::pi; +static constexpr double PI = boost::math::constants::pi(); + namespace openstudio { std::vector convexRegularPolygon(const Point3d& center, size_t num_sides, double side_with) { @@ -46,7 +52,7 @@ std::vector convexRegularPolygon(const Point3d& center, size_t num_side std::vector points; points.reserve(num_sides); - const double angle = 2.0 * std::numbers::pi / num_sides; + const double angle = 2.0 * PI / num_sides; for (size_t i = 0; i < num_sides; i++) { double x = center.x() + side_with * std::cos(angle * i); From c42342792e1dc06e34c5636147c3a45fea1b6cde Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Wed, 29 Mar 2023 13:48:31 +0200 Subject: [PATCH 35/40] shadowing (cppcheck) --- src/utilities/geometry/Polyhedron.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp index 491d428b1b6..34bac57db2c 100644 --- a/src/utilities/geometry/Polyhedron.cpp +++ b/src/utilities/geometry/Polyhedron.cpp @@ -174,9 +174,9 @@ bool Surface3d::isConvex() const { // const auto& b = edges.front().end(); // const auto& c = edges.at(1).end(); - auto ab = edges.front().asVector(); - auto bc = edges[1].asVector(); - auto outwardNormal = ab.cross(bc); + auto ab1 = edges.front().asVector(); + auto bc1 = edges[1].asVector(); + auto outwardNormal = ab1.cross(bc1); outwardNormal.normalize(); for (auto it = std::next(edges.begin()); it != edges.end(); ++it) { From f422275ab2be2980f62a07cd11632918f062c94e Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 31 Mar 2023 16:56:23 +0200 Subject: [PATCH 36/40] Export the new geometry diagnostics to ThreeUserData --- src/model/ThreeJSForwardTranslator.cpp | 11 +++++++ src/utilities/geometry/ThreeJS.cpp | 44 ++++++++++++++++++++++++++ src/utilities/geometry/ThreeJS.hpp | 17 ++++++++++ 3 files changed, 72 insertions(+) diff --git a/src/model/ThreeJSForwardTranslator.cpp b/src/model/ThreeJSForwardTranslator.cpp index 08cbd81c7b2..0d3bcede902 100644 --- a/src/model/ThreeJSForwardTranslator.cpp +++ b/src/model/ThreeJSForwardTranslator.cpp @@ -207,6 +207,8 @@ namespace model { userData.setName(name); userData.setCoincidentWithOutsideObject(false); + userData.setConvex(planarSurface.isConvex()); + if (surface) { std::string surfaceType = surface->surfaceType(); userData.setSurfaceType(surfaceType); @@ -223,6 +225,15 @@ namespace model { // set boundary conditions before calling getBoundaryMaterialName userData.setBoundaryMaterialName(getBoundaryMaterialName(userData)); + + if (space) { + auto sfs = space->findSurfacesWithIncorrectOrientation(); + if (std::find(sfs.cbegin(), sfs.cend(), planarSurface) != sfs.cend()) { + userData.setCorrectlyOriented(false); + } + userData.setSpaceConvex(space->isConvex()); + userData.setSpaceEnclosed(space->isEnclosedVolume()); + } } if (shadingSurface) { diff --git a/src/utilities/geometry/ThreeJS.cpp b/src/utilities/geometry/ThreeJS.cpp index 931ad1ee454..a463ae61923 100644 --- a/src/utilities/geometry/ThreeJS.cpp +++ b/src/utilities/geometry/ThreeJS.cpp @@ -720,6 +720,10 @@ ThreeUserData::ThreeUserData(const Json::Value& value) { assertType(value, "airLoopHVACMaterialNames", Json::arrayValue); //assertType(value, "belowFloorPlenum", Json::booleanValue); //assertType(value, "aboveCeilingPlenum", Json::booleanValue); + assertType(value, "convex", Json::booleanValue); + assertType(value, "spaceConvex", Json::booleanValue); + assertType(value, "spaceEnclosed", Json::booleanValue); + assertType(value, "correctlyOriented", Json::booleanValue); m_handle = value.get("handle", "").asString(); m_name = value.get("name", "").asString(); @@ -772,6 +776,10 @@ ThreeUserData::ThreeUserData(const Json::Value& value) { } //m_belowFloorPlenum = value.get("belowFloorPlenum", "").asBool(); //m_aboveCeilingPlenum = value.get("aboveCeilingPlenum", "").asBool(); + m_convex = value.get("convex", true).asBool(); + m_spaceConvex = value.get("spaceConvex", true).asBool(); + m_spaceEnclosed = value.get("spaceEnclosed", true).asBool(); + m_correctlyOriented = value.get("correctlyOriented", true).asBool(); } Json::Value ThreeUserData::toJsonValue() const { @@ -815,6 +823,10 @@ Json::Value ThreeUserData::toJsonValue() const { result["windExposure"] = m_windExposure; result["illuminanceSetpoint"] = m_illuminanceSetpoint; result["airWall"] = m_airWall; + result["convex"] = m_convex; + result["spaceConvex"] = m_spaceConvex; + result["spaceEnclosed"] = m_spaceEnclosed; + result["correctlyOriented"] = m_correctlyOriented; Json::Value airLoopHVACNames(Json::arrayValue); for (const auto& airLoopName : m_airLoopHVACNames) { @@ -1207,6 +1219,38 @@ void ThreeUserData::addAirLoopHVACMaterialName(const std::string& s) { // } //} +bool ThreeUserData::convex() const { + return m_convex; +} + +void ThreeUserData::setConvex(bool b) { + m_convex = b; +} + +bool ThreeUserData::spaceConvex() const { + return m_spaceConvex; +} + +void ThreeUserData::setSpaceConvex(bool b) { + m_spaceConvex = b; +} + +bool ThreeUserData::spaceEnclosed() const { + return m_spaceEnclosed; +} + +void ThreeUserData::setSpaceEnclosed(bool b) { + m_spaceEnclosed = b; +} + +bool ThreeUserData::correctlyOriented() const { + return m_correctlyOriented; +} + +void ThreeUserData::setCorrectlyOriented(bool b) { + m_correctlyOriented = b; +} + ThreeSceneChild::ThreeSceneChild(const std::string& uuid, const std::string& name, const std::string& type, const std::string& geometryId, const std::string& materialId, const ThreeUserData& userData) : m_uuid(uuid), diff --git a/src/utilities/geometry/ThreeJS.hpp b/src/utilities/geometry/ThreeJS.hpp index 5b75300d15b..a8c9169fee2 100644 --- a/src/utilities/geometry/ThreeJS.hpp +++ b/src/utilities/geometry/ThreeJS.hpp @@ -316,6 +316,19 @@ class UTILITIES_API ThreeUserData //void setBelowFloorPlenum(bool v); //void setAboveCeilingPlenum(bool v); + // This Surface is convex + bool convex() const; + void setConvex(bool b); + // The Space it belongs to is convex + bool spaceConvex() const; + void setSpaceConvex(bool b); + // The Space it belongs to is enclosed + bool spaceEnclosed() const; + void setSpaceEnclosed(bool b); + // Given the space it belongs to, it is correctly oriented (or not) + bool correctlyOriented() const; + void setCorrectlyOriented(bool b); + private: friend class ThreeSceneChild; ThreeUserData(const Json::Value& value); @@ -366,6 +379,10 @@ class UTILITIES_API ThreeUserData std::vector m_airLoopHVACMaterialNames; //bool m_belowFloorPlenum; //bool m_aboveCeilingPlenum; + bool m_convex = true; + bool m_spaceConvex = true; + bool m_spaceEnclosed = true; + bool m_correctlyOriented = true; }; /// ThreeSceneChild is a child object of a ThreeSceneObject From eb74922c80d281dcbd7b881faf440b04ebf7c7dc Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 3 Apr 2023 16:18:35 +0200 Subject: [PATCH 37/40] Make Including geometry diagnostics opt-in: it's computationally intensive ``` | Test case | Opt-out | Opt-out | Opt-in | Opt-in | |----------------------------|---------|---------|--------|---------| | | Debug | Release | Debug | Release | | 7_7_Windows_Complete | 84.63 | 11.78 | 26.76 | 3.68 | | ParkUnder_Retail_Office_C2 | 120.64 | 18.08 | 15.92 | 2.13 | ``` --- src/model/ThreeJSForwardTranslator.cpp | 23 +++++++++++---- src/model/ThreeJSForwardTranslator.hpp | 6 ++++ src/utilities/geometry/ThreeJS.cpp | 40 ++++++++++++++++++-------- src/utilities/geometry/ThreeJS.hpp | 4 +++ 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/model/ThreeJSForwardTranslator.cpp b/src/model/ThreeJSForwardTranslator.cpp index 0d3bcede902..b655d6fbc50 100644 --- a/src/model/ThreeJSForwardTranslator.cpp +++ b/src/model/ThreeJSForwardTranslator.cpp @@ -193,7 +193,7 @@ namespace model { return result; } - void updateUserData(ThreeUserData& userData, const PlanarSurface& planarSurface) { + void updateUserData(ThreeUserData& userData, const PlanarSurface& planarSurface, bool includeGeometryDiagnostics) { std::string name = planarSurface.nameString(); boost::optional surface = planarSurface.optionalCast(); boost::optional shadingSurface = planarSurface.optionalCast(); @@ -207,7 +207,10 @@ namespace model { userData.setName(name); userData.setCoincidentWithOutsideObject(false); - userData.setConvex(planarSurface.isConvex()); + if (includeGeometryDiagnostics) { + userData.setIncludeGeometryDiagnostics(true); + userData.setConvex(planarSurface.isConvex()); + } if (surface) { std::string surfaceType = surface->surfaceType(); @@ -226,7 +229,7 @@ namespace model { // set boundary conditions before calling getBoundaryMaterialName userData.setBoundaryMaterialName(getBoundaryMaterialName(userData)); - if (space) { + if (includeGeometryDiagnostics && space) { auto sfs = space->findSurfacesWithIncorrectOrientation(); if (std::find(sfs.cbegin(), sfs.cend(), planarSurface) != sfs.cend()) { userData.setCorrectlyOriented(false); @@ -334,7 +337,7 @@ namespace model { } void makeGeometries(const PlanarSurface& planarSurface, std::vector& geometries, std::vector& userDatas, - bool triangulateSurfaces) { + bool triangulateSurfaces, bool includeGeometryDiagnostics) { std::string name = planarSurface.nameString(); boost::optional surface = planarSurface.optionalCast(); boost::optional planarSurfaceGroup = planarSurface.planarSurfaceGroup(); @@ -408,7 +411,7 @@ namespace model { geometries.push_back(geometry); ThreeUserData userData; - updateUserData(userData, planarSurface); + updateUserData(userData, planarSurface, includeGeometryDiagnostics); // check if the adjacent surface is truly adjacent // this controls display only, not energy model @@ -440,6 +443,14 @@ namespace model { m_logSink.setThreadId(std::this_thread::get_id()); } + bool ThreeJSForwardTranslator::includeGeometryDiagnostics() const { + return m_includeGeometryDiagnostics; + } + + void ThreeJSForwardTranslator::setIncludeGeometryDiagnostics(bool includeGeometryDiagnostics) { + m_includeGeometryDiagnostics = includeGeometryDiagnostics; + } + std::vector ThreeJSForwardTranslator::warnings() const { std::vector result = m_logSink.logMessages(); result.erase(std::remove_if(result.begin(), result.end(), [](const auto& logMessage) { return logMessage.logLevel() != Warn; }), result.end()); @@ -497,7 +508,7 @@ namespace model { for (const auto& planarSurface : planarSurfaces) { std::vector geometries; std::vector userDatas; - makeGeometries(planarSurface, geometries, userDatas, triangulateSurfaces); + makeGeometries(planarSurface, geometries, userDatas, triangulateSurfaces, m_includeGeometryDiagnostics); OS_ASSERT(geometries.size() == userDatas.size()); size_t n = geometries.size(); diff --git a/src/model/ThreeJSForwardTranslator.hpp b/src/model/ThreeJSForwardTranslator.hpp index 635f89e5cf4..32c674f6e2a 100644 --- a/src/model/ThreeJSForwardTranslator.hpp +++ b/src/model/ThreeJSForwardTranslator.hpp @@ -64,10 +64,16 @@ namespace model { /// Get error messages generated by the last translation. std::vector errors() const; + // Check if Surface is Convex, and check if its correctly oriented given the containing space, whether the space itself is Convex, Enclosed + // This is computationally intensive, so it's opt-in + bool includeGeometryDiagnostics() const; + void setIncludeGeometryDiagnostics(bool includeGeometryDiagnostics); + private: REGISTER_LOGGER("openstudio.model.ThreeJSForwardTranslator"); StringStreamLogSink m_logSink; + bool m_includeGeometryDiagnostics = false; }; } // namespace model diff --git a/src/utilities/geometry/ThreeJS.cpp b/src/utilities/geometry/ThreeJS.cpp index a463ae61923..0b6bea884cc 100644 --- a/src/utilities/geometry/ThreeJS.cpp +++ b/src/utilities/geometry/ThreeJS.cpp @@ -720,10 +720,6 @@ ThreeUserData::ThreeUserData(const Json::Value& value) { assertType(value, "airLoopHVACMaterialNames", Json::arrayValue); //assertType(value, "belowFloorPlenum", Json::booleanValue); //assertType(value, "aboveCeilingPlenum", Json::booleanValue); - assertType(value, "convex", Json::booleanValue); - assertType(value, "spaceConvex", Json::booleanValue); - assertType(value, "spaceEnclosed", Json::booleanValue); - assertType(value, "correctlyOriented", Json::booleanValue); m_handle = value.get("handle", "").asString(); m_name = value.get("name", "").asString(); @@ -776,10 +772,19 @@ ThreeUserData::ThreeUserData(const Json::Value& value) { } //m_belowFloorPlenum = value.get("belowFloorPlenum", "").asBool(); //m_aboveCeilingPlenum = value.get("aboveCeilingPlenum", "").asBool(); - m_convex = value.get("convex", true).asBool(); - m_spaceConvex = value.get("spaceConvex", true).asBool(); - m_spaceEnclosed = value.get("spaceEnclosed", true).asBool(); - m_correctlyOriented = value.get("correctlyOriented", true).asBool(); + if (checkKey(value, "convex") || checkKey(value, "spaceConvex") || checkKey(value, "spaceEnclosed") || checkKey(value, "correctlyOriented")) { + m_includeGeometryDiagnostics = true; + + assertType(value, "convex", Json::booleanValue); + assertType(value, "spaceConvex", Json::booleanValue); + assertType(value, "spaceEnclosed", Json::booleanValue); + assertType(value, "correctlyOriented", Json::booleanValue); + + m_convex = value.get("convex", true).asBool(); + m_spaceConvex = value.get("spaceConvex", true).asBool(); + m_spaceEnclosed = value.get("spaceEnclosed", true).asBool(); + m_correctlyOriented = value.get("correctlyOriented", true).asBool(); + } } Json::Value ThreeUserData::toJsonValue() const { @@ -823,10 +828,13 @@ Json::Value ThreeUserData::toJsonValue() const { result["windExposure"] = m_windExposure; result["illuminanceSetpoint"] = m_illuminanceSetpoint; result["airWall"] = m_airWall; - result["convex"] = m_convex; - result["spaceConvex"] = m_spaceConvex; - result["spaceEnclosed"] = m_spaceEnclosed; - result["correctlyOriented"] = m_correctlyOriented; + + if (m_includeGeometryDiagnostics) { + result["convex"] = m_convex; + result["spaceConvex"] = m_spaceConvex; + result["spaceEnclosed"] = m_spaceEnclosed; + result["correctlyOriented"] = m_correctlyOriented; + } Json::Value airLoopHVACNames(Json::arrayValue); for (const auto& airLoopName : m_airLoopHVACNames) { @@ -1219,6 +1227,14 @@ void ThreeUserData::addAirLoopHVACMaterialName(const std::string& s) { // } //} +bool ThreeUserData::includeGeometryDiagnostics() const { + return m_includeGeometryDiagnostics; +} + +void ThreeUserData::setIncludeGeometryDiagnostics(bool includeGeometryDiagnostics) { + m_includeGeometryDiagnostics = includeGeometryDiagnostics; +} + bool ThreeUserData::convex() const { return m_convex; } diff --git a/src/utilities/geometry/ThreeJS.hpp b/src/utilities/geometry/ThreeJS.hpp index a8c9169fee2..444a9477592 100644 --- a/src/utilities/geometry/ThreeJS.hpp +++ b/src/utilities/geometry/ThreeJS.hpp @@ -316,6 +316,9 @@ class UTILITIES_API ThreeUserData //void setBelowFloorPlenum(bool v); //void setAboveCeilingPlenum(bool v); + // If set to false, the 4 diags below aren't used + bool includeGeometryDiagnostics() const; + void setIncludeGeometryDiagnostics(bool includeGeometryDiagnostics); // This Surface is convex bool convex() const; void setConvex(bool b); @@ -379,6 +382,7 @@ class UTILITIES_API ThreeUserData std::vector m_airLoopHVACMaterialNames; //bool m_belowFloorPlenum; //bool m_aboveCeilingPlenum; + bool m_includeGeometryDiagnostics = false; bool m_convex = true; bool m_spaceConvex = true; bool m_spaceEnclosed = true; From b973c5b5f143dc7752ea23c9cb4d94f41073b02b Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 3 Apr 2023 15:50:23 +0200 Subject: [PATCH 38/40] Caching the Space level geometry diagnostics during ThreeJSForwardTranslator --- src/model/Space.cpp | 33 ++++++++++++++++++++++++++ src/model/Space.hpp | 5 ++++ src/model/Space_Impl.hpp | 7 ++++++ src/model/ThreeJSForwardTranslator.cpp | 14 +++++++++++ 4 files changed, 59 insertions(+) diff --git a/src/model/Space.cpp b/src/model/Space.cpp index 0e1f4792744..c25bc7377a7 100644 --- a/src/model/Space.cpp +++ b/src/model/Space.cpp @@ -863,6 +863,9 @@ namespace model { } bool Space_Impl::isEnclosedVolume() const { + if (m_cachedIsEnclosed.has_value()) { + return m_cachedIsEnclosed.get(); + } auto volumePoly = this->polyhedron(); auto isVolEnclosed = volumePoly.isEnclosedVolume(); if (!isVolEnclosed) { @@ -999,6 +1002,9 @@ namespace model { } std::vector Space_Impl::findSurfacesWithIncorrectOrientation() const { + if (m_cachedNonConvexSurfaces.has_value()) { + return m_cachedNonConvexSurfaces.get(); + } auto volumePoly = this->polyhedron(); // Actually, its perfectly fine to lookup incorrect orientations even if the polyhedron isn't enclosed... // If a Box space is missing one wall for eg, the opposite wall will be deemed incorrectly oriented if using ray casting. @@ -2927,6 +2933,9 @@ namespace model { } bool Space_Impl::isConvex() const { + if (m_cachedIsConvex.has_value()) { + return m_cachedIsConvex.get(); + } auto points = floorPrint(); if (points.empty()) { LOG(Warn, "Can't compute a floorPrint for " << briefDescription()); @@ -2942,6 +2951,21 @@ namespace model { return surfaces; } + void Space_Impl::cacheGeometryDiagnostics() { + m_cachedIsConvex = isConvex(); + auto volumePoly = this->polyhedron(); + m_cachedIsEnclosed = volumePoly.isEnclosedVolume(); + // Actually, its perfectly fine to lookup incorrect orientations even if the polyhedron isn't enclosed... + // If a Box space is missing one wall for eg, the opposite wall will be deemed incorrectly oriented if using ray casting. + m_cachedNonConvexSurfaces = findSurfacesWithIncorrectOrientationPolyhedron(volumePoly); + } + + void Space_Impl::resetCachedGeometryDiagnostics() { + m_cachedNonConvexSurfaces.reset(); + m_cachedIsConvex.reset(); + m_cachedIsEnclosed.reset(); + } + bool Space_Impl::isPlenum() const { bool result = false; boost::optional thermalZone = this->thermalZone(); @@ -3656,6 +3680,15 @@ namespace model { return getImpl()->findNonConvexSurfaces(); } + /// @cond + void Space::cacheGeometryDiagnostics() { + getImpl()->cacheGeometryDiagnostics(); + } + void Space::resetCachedGeometryDiagnostics() { + getImpl()->resetCachedGeometryDiagnostics(); + } + /// @endcond + /// @cond Space::Space(std::shared_ptr impl) : PlanarSurfaceGroup(std::move(impl)) {} /// @endcond diff --git a/src/model/Space.hpp b/src/model/Space.hpp index ace6c9b98b0..c55d31b2556 100644 --- a/src/model/Space.hpp +++ b/src/model/Space.hpp @@ -660,6 +660,11 @@ namespace model { * eg: a box with a wall that is split into two L s would return false, while the Space is actually still convex. */ std::vector findNonConvexSurfaces() const; + /// @cond + void cacheGeometryDiagnostics(); + void resetCachedGeometryDiagnostics(); + /// @endcond + //@} protected: /// @cond diff --git a/src/model/Space_Impl.hpp b/src/model/Space_Impl.hpp index 31efc6f3915..db7bc667139 100644 --- a/src/model/Space_Impl.hpp +++ b/src/model/Space_Impl.hpp @@ -530,6 +530,9 @@ namespace model { * eg: a box with a wall that is split into two L s would return false, while the Space is actually still convex. */ std::vector findNonConvexSurfaces() const; + void cacheGeometryDiagnostics(); + void resetCachedGeometryDiagnostics(); + std::vector zoneMixing() const; std::vector supplyZoneMixing() const; std::vector exhaustZoneMixing() const; @@ -576,6 +579,10 @@ namespace model { // helper function to get a boost polygon point from a Point3d boost::tuple point3dToTuple(const Point3d& point3d, std::vector& allPoints, double tol) const; + + mutable boost::optional> m_cachedNonConvexSurfaces; + mutable boost::optional m_cachedIsConvex; + mutable boost::optional m_cachedIsEnclosed; }; } // namespace detail diff --git a/src/model/ThreeJSForwardTranslator.cpp b/src/model/ThreeJSForwardTranslator.cpp index b655d6fbc50..1973c0e7a75 100644 --- a/src/model/ThreeJSForwardTranslator.cpp +++ b/src/model/ThreeJSForwardTranslator.cpp @@ -504,6 +504,14 @@ namespace model { std::vector::size_type N = planarSurfaces.size() + planarSurfaceGroups.size() + buildingStories.size() + buildingUnits.size() + thermalZones.size() + spaceTypes.size() + defaultConstructionSets.size() + airLoopHVACs.size() + 1; + std::vector spaces; + if (m_includeGeometryDiagnostics) { + spaces = model.getConcreteModelObjects(); + for (auto& space : spaces) { + space.cacheGeometryDiagnostics(); + } + } + // loop over all surfaces for (const auto& planarSurface : planarSurfaces) { std::vector geometries; @@ -528,6 +536,12 @@ namespace model { updatePercentage(100.0 * n / N); } + if (m_includeGeometryDiagnostics) { + for (auto& space : spaces) { + space.resetCachedGeometryDiagnostics(); + } + } + ThreeSceneObject sceneObject(toThreeUUID(toString(openstudio::createUUID())), sceneChildren); BoundingBox boundingBox; From e9d3e7096d3bdb927eb7d9ca754f4fcb1b37f8fa Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 3 Apr 2023 16:22:43 +0200 Subject: [PATCH 39/40] Add a test for exporting geometry diagnostics, serves as benchmark too ``` 1/4 Test #2562: ModelFixture.ThreeJSForwardTranslator_RefBldgOutPatientNew2004_Chicago ....................... Passed 1.39 sec 2/4 Test #2563: ModelFixture.ThreeJSForwardTranslator_RefBldgOutPatientNew2004_Chicago_GeometryDiagnostics ... Passed 1.40 sec 3/4 Test #2560: ModelFixture.ThreeJSForwardTranslator_7_7_Windows_Complete ................................... Passed 3.79 sec 4/4 Test #2561: ModelFixture.ThreeJSForwardTranslator_7_7_Windows_Complete_GeometryDiagnostics ............... Passed 3.95 sec ``` --- .../test/ThreeJSForwardTranslator_GTest.cpp | 83 ++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/src/model/test/ThreeJSForwardTranslator_GTest.cpp b/src/model/test/ThreeJSForwardTranslator_GTest.cpp index 6549587c1d1..034c2d75004 100644 --- a/src/model/test/ThreeJSForwardTranslator_GTest.cpp +++ b/src/model/test/ThreeJSForwardTranslator_GTest.cpp @@ -92,7 +92,7 @@ TEST_F(ModelFixture, ThreeJSForwardTranslator_7_7_Windows_Complete) { for (const auto& warn : ft.warnings()) { EXPECT_TRUE(false) << "Warning:" << warn.logMessage(); } - std::string json = scene.toJSON(); + std::string json = scene.toJSON(true); EXPECT_TRUE(ThreeScene::load(json)); out = resourcesPath() / toPath("model/M7-7_Windows_Complete.json"); @@ -102,6 +102,46 @@ TEST_F(ModelFixture, ThreeJSForwardTranslator_7_7_Windows_Complete) { file1.close(); } +TEST_F(ModelFixture, ThreeJSForwardTranslator_7_7_Windows_Complete_GeometryDiagnostics) { + ThreeJSForwardTranslator ft; + ft.setIncludeGeometryDiagnostics(true); + + openstudio::path out; + + osversion::VersionTranslator translator; + openstudio::path modelpath = resourcesPath() / toPath("model/7-7_Windows_Complete.osm"); + model::OptionalModel model = translator.loadModel(modelpath); + ThreeScene scene = ft.modelToThreeJS(model.get(), true); + // Ensure we get no errors or warnings, generally speaking. + EXPECT_EQ(0, ft.errors().size()); + auto warnings = ft.warnings(); + warnings.erase(std::remove_if(warnings.begin(), warnings.end(), + [](auto& warn) { + return ((warn.logMessage().find("Polyhedron is not enclosed") != std::string::npos) + || (warn.logMessage().find("edges that aren't used exactly twice") != std::string::npos) + || (warn.logMessage().find("Can't compute a floorPrint") != std::string::npos)); + }), + warnings.end()); + EXPECT_EQ(0, warnings.size()); + + for (const auto& error : ft.errors()) { + EXPECT_TRUE(false) << "Error: " << error.logMessage(); + } + + for (const auto& warning : warnings) { + EXPECT_TRUE(false) << "Warning: " << warning.logMessage(); + } + + std::string json = scene.toJSON(true); + EXPECT_TRUE(ThreeScene::load(json)); + + out = resourcesPath() / toPath("model/M7-7_Windows_Complete_geometryDiags.json"); + openstudio::filesystem::ofstream file1(out); + ASSERT_TRUE(file1.is_open()); + file1 << json; + file1.close(); +} + TEST_F(ModelFixture, ThreeJSForwardTranslator_RefBldgOutPatientNew2004_Chicago) { ThreeJSForwardTranslator ft; openstudio::path out; @@ -117,7 +157,7 @@ TEST_F(ModelFixture, ThreeJSForwardTranslator_RefBldgOutPatientNew2004_Chicago) for (const auto& warning : ft.warnings()) { EXPECT_TRUE(false) << "Warning: " << warning.logMessage(); } - std::string json = scene.toJSON(); + std::string json = scene.toJSON(true); EXPECT_TRUE(ThreeScene::load(json)); out = resourcesPath() / toPath("model/MSample_DOE-RefBldgOutPatientNew2004_Chicago.json"); openstudio::filesystem::ofstream file1(out); @@ -126,6 +166,45 @@ TEST_F(ModelFixture, ThreeJSForwardTranslator_RefBldgOutPatientNew2004_Chicago) file1.close(); } +TEST_F(ModelFixture, ThreeJSForwardTranslator_RefBldgOutPatientNew2004_Chicago_GeometryDiagnostics) { + ThreeJSForwardTranslator ft; + ft.setIncludeGeometryDiagnostics(true); + + openstudio::path out; + osversion::VersionTranslator translator; + openstudio::path modelPath = resourcesPath() / toPath("model/Sample_DOE-RefBldgOutPatientNew2004_Chicago.osm"); + model::OptionalModel model = translator.loadModel(modelPath); + ThreeScene scene = ft.modelToThreeJS(model.get(), true); + // Ensure we get no errors or warnings, generally speaking. + EXPECT_EQ(0, ft.errors().size()); + auto warnings = ft.warnings(); + warnings.erase(std::remove_if(warnings.begin(), warnings.end(), + [](auto& warn) { + return ((warn.logMessage().find("Polyhedron is not enclosed") != std::string::npos) + // || (warn.logMessage().find("edges that aren't used exactly twice") != std::string::npos) + // || (warn.logMessage().find("Can't compute a floorPrint") != std::string::npos) + ); + }), + warnings.end()); + EXPECT_EQ(0, warnings.size()); + + for (const auto& error : ft.errors()) { + EXPECT_TRUE(false) << "Error: " << error.logMessage(); + } + + for (const auto& warning : warnings) { + EXPECT_TRUE(false) << "Warning: " << warning.logMessage(); + } + + std::string json = scene.toJSON(true); + EXPECT_TRUE(ThreeScene::load(json)); + out = resourcesPath() / toPath("model/MSample_DOE-RefBldgOutPatientNew2004_Chicago_geometryDiags.json"); + openstudio::filesystem::ofstream file1(out); + ASSERT_TRUE(file1.is_open()); + file1 << json; + file1.close(); +} + TEST_F(ModelFixture, ThreeJSForwardTranslator_RefBldgSecondarySchoolNew2004_Chicago) { ThreeJSForwardTranslator ft; openstudio::path out; From e03d083cdc6f5a21cf98cefbf04ff734b66d028e Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Mon, 3 Apr 2023 17:01:48 +0200 Subject: [PATCH 40/40] Missing include for windows --- src/model/Space_Impl.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/model/Space_Impl.hpp b/src/model/Space_Impl.hpp index db7bc667139..3bd5af83386 100644 --- a/src/model/Space_Impl.hpp +++ b/src/model/Space_Impl.hpp @@ -32,6 +32,7 @@ #include "ModelAPI.hpp" #include "PlanarSurfaceGroup_Impl.hpp" +#include "Surface.hpp" #include #include