From 9e619582ed694c0782f73adae349cabd23c487f2 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 29 Sep 2022 11:50:20 +0200 Subject: [PATCH 01/10] Add a VT test for #4699 - ZoneHVACPackagedTerminalXXX --- .../test/3_5_0/test_vt_ZoneHVACPackaged.osm | 360 ++++++++++++++++++ .../test/3_5_0/test_vt_ZoneHVACPackaged.rb | 31 ++ .../test/VersionTranslator_GTest.cpp | 91 +++++ 3 files changed, 482 insertions(+) create mode 100644 src/osversion/test/3_5_0/test_vt_ZoneHVACPackaged.osm create mode 100644 src/osversion/test/3_5_0/test_vt_ZoneHVACPackaged.rb diff --git a/src/osversion/test/3_5_0/test_vt_ZoneHVACPackaged.osm b/src/osversion/test/3_5_0/test_vt_ZoneHVACPackaged.osm new file mode 100644 index 0000000000..4d85ab9ec7 --- /dev/null +++ b/src/osversion/test/3_5_0/test_vt_ZoneHVACPackaged.osm @@ -0,0 +1,360 @@ + +OS:Version, + {f2bf6811-825f-4f83-af96-b22b0908f434}, !- Handle + 3.4.0; !- Version Identifier + +OS:Coil:Heating:DX:SingleSpeed, + {405cb32f-90c9-4c2c-b22a-ab246f71d243}, !- Handle + Coil Heating DX Single Speed 1, !- Name + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Availability Schedule Name + Autosize, !- Rated Total Heating Capacity {W} + 5, !- Rated COP {W/W} + Autosize, !- Rated Air Flow Rate {m3/s} + 773.3, !- Rated Supply Fan Power Per Volume Flow Rate {W/(m3/s)} + , !- Air Inlet Node Name + , !- Air Outlet Node Name + {9ccb40b4-6d59-4b04-adb4-161de6730946}, !- Total Heating Capacity Function of Temperature Curve Name + {f4080dc7-e573-461c-9b26-3f90ba7e1fdb}, !- Total Heating Capacity Function of Flow Fraction Curve Name + {cfcc34af-f893-4947-94b8-5ea9624b9256}, !- Energy Input Ratio Function of Temperature Curve Name + {9bdf7dad-cd90-400e-b291-4e62bce4cd3f}, !- Energy Input Ratio Function of Flow Fraction Curve Name + {60ae2897-36f4-4a0e-b581-fb4a6a941dec}, !- Part Load Fraction Correlation Curve Name + , !- Defrost Energy Input Ratio Function of Temperature Curve Name + , !- Minimum Outdoor Dry-Bulb Temperature for Compressor Operation {C} + , !- Maximum Outdoor Dry-Bulb Temperature for Defrost Operation {C} + , !- Crankcase Heater Capacity {W} + , !- Maximum Outdoor Dry-Bulb Temperature for Crankcase Heater Operation {C} + Resistive, !- Defrost Strategy + Timed, !- Defrost Control + 0.166667, !- Defrost Time Period Fraction + 2000; !- Resistive Defrost Heater Capacity {W} + +OS:Schedule:Constant, + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Handle + Always On Discrete, !- Name + {1a2f843f-ad5d-46a6-a190-83232b9c63f4}, !- Schedule Type Limits Name + 1; !- Value + +OS:ScheduleTypeLimits, + {1a2f843f-ad5d-46a6-a190-83232b9c63f4}, !- Handle + OnOff, !- Name + 0, !- Lower Limit Value + 1, !- Upper Limit Value + Discrete, !- Numeric Type + Availability; !- Unit Type + +OS:Curve:Cubic, + {9ccb40b4-6d59-4b04-adb4-161de6730946}, !- Handle + Curve Cubic 1, !- Name + 0.758746, !- Coefficient1 Constant + 0.027626, !- Coefficient2 x + 0.000148716, !- Coefficient3 x**2 + 3.4992e-06, !- Coefficient4 x**3 + -20, !- Minimum Value of x + 20; !- Maximum Value of x + +OS:Curve:Cubic, + {f4080dc7-e573-461c-9b26-3f90ba7e1fdb}, !- Handle + Curve Cubic 2, !- Name + 0.84, !- Coefficient1 Constant + 0.16, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0, !- Coefficient4 x**3 + 0.5, !- Minimum Value of x + 1.5; !- Maximum Value of x + +OS:Curve:Cubic, + {cfcc34af-f893-4947-94b8-5ea9624b9256}, !- Handle + Curve Cubic 3, !- Name + 1.19248, !- Coefficient1 Constant + -0.0300438, !- Coefficient2 x + 0.00103745, !- Coefficient3 x**2 + -2.3328e-05, !- Coefficient4 x**3 + -20, !- Minimum Value of x + 20; !- Maximum Value of x + +OS:Curve:Quadratic, + {9bdf7dad-cd90-400e-b291-4e62bce4cd3f}, !- Handle + Curve Quadratic 1, !- Name + 1.3824, !- Coefficient1 Constant + -0.4336, !- Coefficient2 x + 0.0512, !- Coefficient3 x**2 + 0, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Curve:Quadratic, + {60ae2897-36f4-4a0e-b581-fb4a6a941dec}, !- Handle + Curve Quadratic 2, !- Name + 0.75, !- Coefficient1 Constant + 0.25, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Coil:Cooling:DX:SingleSpeed, + {c3dc2852-18f2-4199-a93b-2da0c5ed3f64}, !- Handle + Coil Cooling DX Single Speed 1, !- Name + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Availability Schedule Name + autosize, !- Rated Total Cooling Capacity {W} + autosize, !- Rated Sensible Heat Ratio + 3, !- Rated COP {W/W} + autosize, !- Rated Air Flow Rate {m3/s} + 773.3, !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + , !- Air Inlet Node Name + , !- Air Outlet Node Name + {20cbc7d0-9047-47f4-b3cf-7ebce6dc86ed}, !- Total Cooling Capacity Function of Temperature Curve Name + {63462c10-09fc-4c5a-8312-bbe6e8b828bc}, !- Total Cooling Capacity Function of Flow Fraction Curve Name + {ef75106e-4029-43dc-a1ca-21dac784d198}, !- Energy Input Ratio Function of Temperature Curve Name + {192ff408-13b7-48ed-b324-45aef010bb3a}, !- Energy Input Ratio Function of Flow Fraction Curve Name + {2665cb2e-73c1-4ff6-b337-8f13740c0d91}, !- 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, + {20cbc7d0-9047-47f4-b3cf-7ebce6dc86ed}, !- 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, + {63462c10-09fc-4c5a-8312-bbe6e8b828bc}, !- Handle + Curve Quadratic 3, !- 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, + {ef75106e-4029-43dc-a1ca-21dac784d198}, !- 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, + {192ff408-13b7-48ed-b324-45aef010bb3a}, !- Handle + Curve Quadratic 4, !- 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, + {2665cb2e-73c1-4ff6-b337-8f13740c0d91}, !- Handle + Curve Quadratic 5, !- 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, + {e90e9d96-bf46-4b1e-9a99-5ea9da8c61f5}, !- Handle + Coil Heating Electric 1, !- Name + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Availability Schedule Name + , !- Efficiency + , !- Nominal Capacity {W} + , !- Air Inlet Node Name + ; !- Air Outlet Node Name + +OS:Fan:ConstantVolume, + {6600a5aa-c5e7-4eb2-8d4c-5fcbf38c5dbb}, !- Handle + PTHP Fan, !- Name + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Availability Schedule Name + , !- Fan Total Efficiency + , !- Pressure Rise {Pa} + AutoSize, !- Maximum Flow Rate {m3/s} + , !- Motor Efficiency + , !- Motor In Airstream Fraction + , !- Air Inlet Node Name + , !- Air Outlet Node Name + ; !- End-Use Subcategory + +OS:ZoneHVAC:PackagedTerminalHeatPump, + {bddf0afb-148c-4e76-8d36-479a2e08a2ef}, !- Handle + Zone HVAC Packaged Terminal Heat Pump 1, !- Name + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Availability Schedule Name + , !- Air Inlet Node Name + , !- Air Outlet Node Name + OutdoorAir:Mixer, !- Outdoor Air Mixer Object Type + , !- Outdoor Air Mixer Name + Autosize, !- Supply Air Flow Rate During Cooling Operation {m3/s} + Autosize, !- Supply Air Flow Rate During Heating Operation {m3/s} + Autosize, !- Supply Air Flow Rate When No Cooling or Heating is Needed {m3/s} + Autosize, !- Outdoor Air Flow Rate During Cooling Operation {m3/s} + Autosize, !- Outdoor Air Flow Rate During Heating Operation {m3/s} + Autosize, !- Outdoor Air Flow Rate When No Cooling or Heating is Needed {m3/s} + {6600a5aa-c5e7-4eb2-8d4c-5fcbf38c5dbb}, !- Supply Air Fan Name + {405cb32f-90c9-4c2c-b22a-ab246f71d243}, !- Heating Coil Name + , !- Heating Convergence Tolerance {dimensionless} + , !- Minimum Outdoor Dry-Bulb Temperature for Compressor Operation {C} + {c3dc2852-18f2-4199-a93b-2da0c5ed3f64}, !- Cooling Coil Name + , !- Cooling Convergence Tolerance {dimensionless} + {e90e9d96-bf46-4b1e-9a99-5ea9da8c61f5}, !- Supplemental Heating Coil Name + Autosize, !- Maximum Supply Air Temperature from Supplemental Heater {C} + , !- Maximum Outdoor Dry-Bulb Temperature for Supplemental Heater Operation {C} + , !- Fan Placement + ; !- Supply Air Fan Operating Mode Schedule Name + +OS:Coil:Heating:Electric, + {06692db9-5485-4524-8135-fc0f2ac8c40d}, !- Handle + Coil Heating Electric 2, !- Name + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Availability Schedule Name + , !- Efficiency + , !- Nominal Capacity {W} + , !- Air Inlet Node Name + ; !- Air Outlet Node Name + +OS:Coil:Cooling:DX:SingleSpeed, + {d8b44275-6385-4ddd-8890-47ff167c4652}, !- Handle + Coil Cooling DX Single Speed 2, !- Name + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Availability Schedule Name + autosize, !- Rated Total Cooling Capacity {W} + autosize, !- Rated Sensible Heat Ratio + 3, !- Rated COP {W/W} + autosize, !- Rated Air Flow Rate {m3/s} + 773.3, !- Rated Evaporator Fan Power Per Volume Flow Rate {W/(m3/s)} + , !- Air Inlet Node Name + , !- Air Outlet Node Name + {66fc8437-d62b-4abe-8971-0aca40d45c4a}, !- Total Cooling Capacity Function of Temperature Curve Name + {0fe5e1aa-db99-4aa1-947f-377e904875ec}, !- Total Cooling Capacity Function of Flow Fraction Curve Name + {c339821c-d155-4f36-865a-a55e1321dae5}, !- Energy Input Ratio Function of Temperature Curve Name + {15a0df0a-d826-4d8b-94b7-e2291ee426a5}, !- Energy Input Ratio Function of Flow Fraction Curve Name + {fe1f5765-b70e-4436-92a1-145ca6f84746}, !- 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, + {66fc8437-d62b-4abe-8971-0aca40d45c4a}, !- Handle + Curve Biquadratic 3, !- 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, + {0fe5e1aa-db99-4aa1-947f-377e904875ec}, !- Handle + Curve Quadratic 6, !- 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, + {c339821c-d155-4f36-865a-a55e1321dae5}, !- Handle + Curve Biquadratic 4, !- 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, + {15a0df0a-d826-4d8b-94b7-e2291ee426a5}, !- Handle + Curve Quadratic 7, !- 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, + {fe1f5765-b70e-4436-92a1-145ca6f84746}, !- Handle + Curve Quadratic 8, !- Name + 0.85, !- Coefficient1 Constant + 0.15, !- Coefficient2 x + 0, !- Coefficient3 x**2 + 0, !- Minimum Value of x + 1; !- Maximum Value of x + +OS:Fan:ConstantVolume, + {048e8bf0-1f9b-40d4-a0b0-d787991f3d94}, !- Handle + PTAC Fan, !- Name + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Availability Schedule Name + 0.75, !- Fan Total Efficiency + 265, !- Pressure Rise {Pa} + 0.5, !- Maximum Flow Rate {m3/s} + 0.89, !- Motor Efficiency + 0.92, !- Motor In Airstream Fraction + , !- Air Inlet Node Name + , !- Air Outlet Node Name + PTAC Fans; !- End-Use Subcategory + +OS:ZoneHVAC:PackagedTerminalAirConditioner, + {f1f8d2af-4f9a-4c72-ae93-dd11d9d6ab49}, !- Handle + Zone HVAC Packaged Terminal Air Conditioner 1, !- Name + {3f9d2cbc-47cd-4719-8f61-27cebb66d356}, !- Availability Schedule Name + , !- Air Inlet Node Name + , !- Air Outlet Node Name + OutdoorAir:Mixer, !- Outdoor Air Mixer Object Type + , !- Outdoor Air Mixer Name + Autosize, !- Supply Air Flow Rate During Cooling Operation {m3/s} + Autosize, !- Supply Air Flow Rate During Heating Operation {m3/s} + Autosize, !- Supply Air Flow Rate When No Cooling or Heating is Needed {m3/s} + Autosize, !- Outdoor Air Flow Rate During Cooling Operation {m3/s} + Autosize, !- Outdoor Air Flow Rate During Heating Operation {m3/s} + Autosize, !- Outdoor Air Flow Rate When No Cooling or Heating is Needed {m3/s} + {048e8bf0-1f9b-40d4-a0b0-d787991f3d94}, !- Supply Air Fan Name + {06692db9-5485-4524-8135-fc0f2ac8c40d}, !- Heating Coil Name + {d8b44275-6385-4ddd-8890-47ff167c4652}, !- Cooling Coil Name + DrawThrough, !- Fan Placement + ; !- Supply Air Fan Operating Mode Schedule Name + diff --git a/src/osversion/test/3_5_0/test_vt_ZoneHVACPackaged.rb b/src/osversion/test/3_5_0/test_vt_ZoneHVACPackaged.rb new file mode 100644 index 0000000000..4b86101b61 --- /dev/null +++ b/src/osversion/test/3_5_0/test_vt_ZoneHVACPackaged.rb @@ -0,0 +1,31 @@ +#require '/usr/local/openstudio-3.4.0/Ruby/openstudio' + +include OpenStudio::Model + +m = Model.new + +pthp_hc = CoilHeatingDXSingleSpeed.new(m) +pthp_cc = CoilCoolingDXSingleSpeed.new(m) +pthp_suppHC = CoilHeatingElectric.new(m) +pthp_fan = FanConstantVolume.new(m) +pthp_fan.setName("PTHP Fan") +pthp = ZoneHVACPackagedTerminalHeatPump.new(m, m.alwaysOnDiscreteSchedule, pthp_fan, pthp_hc, pthp_cc, pthp_suppHC) +pthp.resetSupplyAirFanOperatingModeSchedule + +ptac_hc = CoilHeatingElectric.new(m) +ptac_cc = CoilCoolingDXSingleSpeed.new(m) +ptac_fan = FanConstantVolume.new(m) +ptac_fan.setName("PTAC Fan") +ptac = ZoneHVACPackagedTerminalAirConditioner.new(m, m.alwaysOnDiscreteSchedule, ptac_fan, ptac_hc, ptac_cc) +ptac.resetSupplyAirFanOperatingModeSchedule + +# Leaving the pthp fan will all defaults, harcoding this one so we test both +# cases and ensure the resulting Fan:SystemModel is correct +ptac_fan.setFanTotalEfficiency(0.75) +ptac_fan.setPressureRise(265) +ptac_fan.setMaximumFlowRate(0.5) +ptac_fan.setMotorEfficiency(0.89) +ptac_fan.setMotorInAirstreamFraction(0.92) +ptac_fan.setEndUseSubcategory("PTAC Fans") + +m.save('test_vt_ZoneHVACPackaged.osm', true) diff --git a/src/osversion/test/VersionTranslator_GTest.cpp b/src/osversion/test/VersionTranslator_GTest.cpp index 8d6ce36e64..89a399a866 100644 --- a/src/osversion/test/VersionTranslator_GTest.cpp +++ b/src/osversion/test/VersionTranslator_GTest.cpp @@ -53,6 +53,7 @@ #include "../../utilities/idf/IdfExtensibleGroup.hpp" #include "../../utilities/idf/WorkspaceExtensibleGroup.hpp" +#include #include #include #include @@ -2228,3 +2229,93 @@ TEST_F(OSVersionFixture, update_3_4_0_to_3_5_0_CoilHeatingGasMultiStage) { ASSERT_TRUE(coil.getTarget(2)); EXPECT_EQ("Always On Discrete", coil.getTarget(2)->nameString()); } + +TEST_F(OSVersionFixture, update_3_4_0_to_3_5_0_ZoneHVACPackaged) { + openstudio::path path = resourcesPath() / toPath("osversion/3_5_0/test_vt_ZoneHVACPackaged.osm"); + osversion::VersionTranslator vt; + boost::optional model = vt.loadModel(path); + ASSERT_TRUE(model) << "Failed to load " << path; + + openstudio::path outPath = resourcesPath() / toPath("osversion/3_3_0/test_vt_ZoneHVACPackaged_updated.osm"); + model->save(outPath, true); + + EXPECT_EQ(2, model->getObjectsByType("OS:Fan:SystemModel").size()); + { + std::vector ptacs = model->getObjectsByType("OS:ZoneHVAC:PackagedTerminalAirConditioner"); + ASSERT_EQ(1u, ptacs.size()); + auto& ptac = ptacs.front(); + + // Check the Supply Air Fan Operating Mode Schedule + ASSERT_TRUE(ptac.getTarget(17)); + WorkspaceObject fanOpSch = ptac.getTarget(17).get(); + EXPECT_EQ("Always Off Discrete", fanOpSch.nameString()); + EXPECT_EQ(0.0, fanOpSch.getDouble(3).get()); + + // Check the Fan, converted from Fan:ConstantVolume to Fan:SystemModel + ASSERT_TRUE(ptac.getTarget(13)); + WorkspaceObject fan = ptac.getTarget(13).get(); + + EXPECT_EQ(IddObjectType::OS_Fan_SystemModel, fan.iddObject().type()); + EXPECT_EQ("PTAC Fan", fan.getString(OS_Fan_SystemModelFields::Name).get()); + EXPECT_EQ("Always On Discrete", fan.getString(OS_Fan_SystemModelFields::AvailabilityScheduleName).get()); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::AirInletNodeName)); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::AirOutletNodeName)); + EXPECT_EQ(0.5, fan.getDouble(OS_Fan_SystemModelFields::DesignMaximumAirFlowRate).get()); + EXPECT_EQ("Discrete", fan.getString(OS_Fan_SystemModelFields::SpeedControlMethod).get()); + EXPECT_EQ(0.0, fan.getDouble(OS_Fan_SystemModelFields::ElectricPowerMinimumFlowRateFraction).get()); + EXPECT_EQ(265.0, fan.getDouble(OS_Fan_SystemModelFields::DesignPressureRise).get()); + EXPECT_EQ(0.89, fan.getDouble(OS_Fan_SystemModelFields::MotorEfficiency).get()); + EXPECT_EQ(0.92, fan.getDouble(OS_Fan_SystemModelFields::MotorInAirStreamFraction).get()); + EXPECT_EQ("Autosize", fan.getString(OS_Fan_SystemModelFields::DesignElectricPowerConsumption).get()); + EXPECT_EQ("TotalEfficiencyAndPressure", fan.getString(OS_Fan_SystemModelFields::DesignPowerSizingMethod).get()); + EXPECT_EQ(840.0, fan.getDouble(OS_Fan_SystemModelFields::ElectricPowerPerUnitFlowRate).get()); + EXPECT_EQ(1.66667, fan.getDouble(OS_Fan_SystemModelFields::ElectricPowerPerUnitFlowRatePerUnitPressure).get()); + EXPECT_EQ(0.75, fan.getDouble(OS_Fan_SystemModelFields::FanTotalEfficiency).get()); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::ElectricPowerFunctionofFlowFractionCurveName)); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::NightVentilationModePressureRise)); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::NightVentilationModeFlowFraction)); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::MotorLossZoneName)); + EXPECT_EQ(0.0, fan.getDouble(OS_Fan_SystemModelFields::MotorLossRadiativeFraction).get()); + EXPECT_EQ("PTAC Fans", fan.getString(OS_Fan_SystemModelFields::EndUseSubcategory).get()); + } + + { + std::vector pthps = model->getObjectsByType("OS:ZoneHVAC:PackagedTerminalHeatPump"); + ASSERT_EQ(1u, pthps.size()); + auto& pthp = pthps.front(); + + // Check the Supply Air Fan Operating Mode Schedule + ASSERT_TRUE(pthp.getTarget(23)); + WorkspaceObject fanOpSch = pthp.getTarget(23).get(); + EXPECT_EQ("Always Off Discrete", fanOpSch.nameString()); + EXPECT_EQ(0.0, fanOpSch.getDouble(3).get()); + + // Check the Fan, converted from Fan:ConstantVolume to Fan:SystemModel + ASSERT_TRUE(pthp.getTarget(13)); + WorkspaceObject fan = pthp.getTarget(13).get(); + + // This one is all defaulted, ensure we get the SAME values + EXPECT_EQ(IddObjectType::OS_Fan_SystemModel, fan.iddObject().type()); + EXPECT_EQ("PTHP Fan", fan.getString(OS_Fan_SystemModelFields::Name).get()); + EXPECT_EQ("Always On Discrete", fan.getString(OS_Fan_SystemModelFields::AvailabilityScheduleName).get()); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::AirInletNodeName)); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::AirOutletNodeName)); + EXPECT_EQ("AutoSize", fan.getString(OS_Fan_SystemModelFields::DesignMaximumAirFlowRate).get()); + EXPECT_EQ("Discrete", fan.getString(OS_Fan_SystemModelFields::SpeedControlMethod).get()); + EXPECT_EQ(0.0, fan.getDouble(OS_Fan_SystemModelFields::ElectricPowerMinimumFlowRateFraction).get()); + EXPECT_EQ(250.0, fan.getDouble(OS_Fan_SystemModelFields::DesignPressureRise).get()); + EXPECT_EQ(0.9, fan.getDouble(OS_Fan_SystemModelFields::MotorEfficiency).get()); + EXPECT_EQ(1.0, fan.getDouble(OS_Fan_SystemModelFields::MotorInAirStreamFraction).get()); + EXPECT_EQ("Autosize", fan.getString(OS_Fan_SystemModelFields::DesignElectricPowerConsumption).get()); + EXPECT_EQ("TotalEfficiencyAndPressure", fan.getString(OS_Fan_SystemModelFields::DesignPowerSizingMethod).get()); + EXPECT_EQ(840.0, fan.getDouble(OS_Fan_SystemModelFields::ElectricPowerPerUnitFlowRate).get()); + EXPECT_EQ(1.66667, fan.getDouble(OS_Fan_SystemModelFields::ElectricPowerPerUnitFlowRatePerUnitPressure).get()); + EXPECT_EQ(0.7, fan.getDouble(OS_Fan_SystemModelFields::FanTotalEfficiency).get()); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::ElectricPowerFunctionofFlowFractionCurveName)); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::NightVentilationModePressureRise)); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::NightVentilationModeFlowFraction)); + EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::MotorLossZoneName)); + EXPECT_EQ(0.0, fan.getDouble(OS_Fan_SystemModelFields::MotorLossRadiativeFraction).get()); + EXPECT_EQ("General", fan.getString(OS_Fan_SystemModelFields::EndUseSubcategory).get()); + } +} From 9e5fadab490105eec03ba1d96181ae92b3a1b09e Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 29 Sep 2022 10:28:35 +0200 Subject: [PATCH 02/10] Fix #4699 - Write non trivial VT rules for ZoneHVACPackagedTerminalXXX --- src/osversion/VersionTranslator.cpp | 277 ++++++++++++++++++++++++---- 1 file changed, 243 insertions(+), 34 deletions(-) diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index 2e4a0eeea5..9c02012fc9 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -63,9 +63,11 @@ #include -#include +#include +#include #include #include +#include #include #include @@ -6920,6 +6922,99 @@ namespace osversion { IdfFile targetIdf(idd_3_5_0.iddFile()); ss << targetIdf.versionObject().get(); + // ZoneHVAC:Packaged AirConditionner / HeatPump: prescan + // In E+ 22.1.0, you could have a Packaged system with a Fan:ConstantVolume and a blank schedule for Supply Air Fan Operating Mode Schedule Name + // and it would behave like a cycling fan (which it shouldn't have done). This is now disallowed in E+ 22.2.0, and you also cannot set a Schedule + // with 0 values with a Fan:ConstantVolume. So we must replace these fans with a Fan:SystemModel (that mimics a Fan:OnOff really, just planning + // for the future + avoid having to create 2 curves for FanOnOff) + std::vector packagedFanCVHandleStrs; + { + std::vector fanCVs = idf_3_4_0.getObjectsByType(idf_3_4_0.iddFile().getObject("OS:Fan:ConstantVolume").get()); + std::vector fanCVHandleStrs; + fanCVHandleStrs.reserve(fanCVs.size()); + packagedFanCVHandleStrs.reserve(fanCVs.size()); + std::transform(fanCVs.cbegin(), fanCVs.cend(), std::back_inserter(fanCVHandleStrs), + [](const auto& idfObject) { return idfObject.getString(0).get(); }); + for (const auto& ptac : idf_3_4_0.getObjectsByType(idf_3_4_0.iddFile().getObject("OS:ZoneHVAC:PackagedTerminalAirConditioner").get())) { + // If the Supply Air Fan Operating Mode Schedule is empty + if (ptac.isEmpty(17)) { + if (auto fanHandleStr_ = ptac.getString(13, false, true)) { + if (std::find(fanCVHandleStrs.cbegin(), fanCVHandleStrs.cend(), fanHandleStr_.get()) != fanCVHandleStrs.cend()) { + packagedFanCVHandleStrs.push_back(fanHandleStr_.get()); + } + } + } + } + for (const auto& pthp : idf_3_4_0.getObjectsByType(idf_3_4_0.iddFile().getObject("OS:ZoneHVAC:PackagedTerminalHeatPump").get())) { + // If the Supply Air Fan Operating Mode Schedule is empty + if (pthp.isEmpty(23)) { + if (auto fanName_ = pthp.getString(13, false, true)) { + if (std::find(fanCVHandleStrs.cbegin(), fanCVHandleStrs.cend(), fanName_.get()) != fanCVHandleStrs.cend()) { + packagedFanCVHandleStrs.push_back(fanName_.get()); + } + } + } + } + } + + std::string alwaysOnDiscreteScheduleHandleStr; + std::string alwaysOffDiscreteScheduleHandleStr; + + auto getOrCreateAlwaysDiscreteScheduleHandleStr = [this, &ss, &idf_3_4_0, &idd_3_5_0, &alwaysOnDiscreteScheduleHandleStr, + &alwaysOffDiscreteScheduleHandleStr](bool isAlwaysOn) -> std::string { + auto& discreteSchHandleStr = isAlwaysOn ? alwaysOnDiscreteScheduleHandleStr : alwaysOffDiscreteScheduleHandleStr; + if (!discreteSchHandleStr.empty()) { + return discreteSchHandleStr; + } + std::string name = isAlwaysOn ? "Always On Discrete" : "Always Off Discrete"; + double val = isAlwaysOn ? 1.0 : 0.0; + // Add an alwaysOnDiscreteSchedule if one does not already exist + for (const IdfObject& object : idf_3_4_0.getObjectsByType(idf_3_4_0.iddFile().getObject("OS:Schedule:Constant").get())) { + if (boost::optional name_ = object.getString(1)) { + if (istringEqual(name_.get(), name)) { + if (boost::optional value = object.getDouble(3)) { + if (equal(value.get(), val)) { + discreteSchHandleStr = object.getString(0).get(); + break; + } + } + } + } + } + + if (discreteSchHandleStr.empty()) { + auto discreteSch = IdfObject(idd_3_5_0.getObject("OS:Schedule:Constant").get()); + + discreteSchHandleStr = toString(createUUID()); + discreteSch.setString(0, discreteSchHandleStr); + discreteSch.setString(1, name); + discreteSch.setDouble(3, val); + + IdfObject typeLimits(idd_3_5_0.getObject("OS:ScheduleTypeLimits").get()); + typeLimits.setString(0, toString(createUUID())); + typeLimits.setString(1, name + " Limits"); + typeLimits.setDouble(2, 0.0); + typeLimits.setDouble(3, 1.0); + typeLimits.setString(4, "Discrete"); + typeLimits.setString(5, "Availability"); + + discreteSch.setString(2, typeLimits.getString(0).get()); + + ss << discreteSch; + ss << typeLimits; + + // Register new objects + m_new.push_back(discreteSch); + m_new.push_back(typeLimits); + } + + return discreteSchHandleStr; + }; + + if (!packagedFanCVHandleStrs.empty()) { + alwaysOffDiscreteScheduleHandleStr = getOrCreateAlwaysDiscreteScheduleHandleStr(false); + } // End locating or creating alwaysOnDiscreteSchedule + for (const IdfObject& object : idf_3_4_0.objects()) { auto iddname = object.iddObject().name(); @@ -7343,46 +7438,160 @@ namespace osversion { IdfObject newObject(iddObject.get()); if (object.isEmpty(2)) { - // Add an always on discrete schedule if one does not already exist - boost::optional alwaysOnSchedule; - for (const IdfObject& object : idf_3_4_0.objects()) { - if (object.iddObject().name() == "OS:Schedule:Constant") { - if (boost::optional name = object.getString(1)) { - if (istringEqual(name.get(), "Always On Discrete")) { - if (boost::optional value = object.getDouble(3)) { - if (equal(value.get(), 1.0)) { - alwaysOnSchedule = object; - } - } - } - } + newObject.setString(2, getOrCreateAlwaysDiscreteScheduleHandleStr(true)); + } + + m_refactored.push_back(RefactoredObjectData(object, newObject)); + ss << newObject; + + } else if (iddname == "OS:ZoneHVAC:PackagedTerminalHeatPump") { + + if (!object.isEmpty(23)) { + ss << object; + + } else { + auto iddObject = idd_3_5_0.getObject(iddname); + IdfObject newObject(iddObject.get()); + + for (size_t i = 0; i < object.numFields(); ++i) { + if ((value = object.getString(i))) { + newObject.setString(i, value.get()); } } + // alwaysOffDiscreteScheduleHandleStr has already been initialized above + newObject.setString(23, alwaysOffDiscreteScheduleHandleStr); + + m_refactored.push_back(RefactoredObjectData(object, newObject)); + ss << newObject; + } + } else if (iddname == "OS:ZoneHVAC:PackagedTerminalAirConditioner") { + + if (!object.isEmpty(17)) { + ss << object; - if (!alwaysOnSchedule) { - alwaysOnSchedule = IdfObject(idd_3_5_0.getObject("OS:Schedule:Constant").get()); - alwaysOnSchedule->setString(0, toString(createUUID())); - alwaysOnSchedule->setString(1, "Always On Discrete"); - alwaysOnSchedule->setDouble(3, 1.0); - IdfObject typeLimits(idd_3_5_0.getObject("OS:ScheduleTypeLimits").get()); - typeLimits.setString(0, toString(createUUID())); - typeLimits.setString(1, "Always On Discrete Limits"); - typeLimits.setDouble(2, 0.0); - typeLimits.setDouble(3, 1.0); - typeLimits.setString(4, "Discrete"); - typeLimits.setString(5, "Availability"); - alwaysOnSchedule->setString(2, typeLimits.getString(0).get()); - ss << alwaysOnSchedule.get(); - ss << typeLimits; - m_new.push_back(alwaysOnSchedule.get()); - m_new.push_back(typeLimits); + } else { + auto iddObject = idd_3_5_0.getObject(iddname); + IdfObject newObject(iddObject.get()); + + for (size_t i = 0; i < object.numFields(); ++i) { + if ((value = object.getString(i))) { + newObject.setString(i, value.get()); + } } + // alwaysOffDiscreteScheduleHandleStr has already been initialized above + newObject.setString(17, alwaysOffDiscreteScheduleHandleStr); - newObject.setString(2, alwaysOnSchedule->getString(0).get()); + m_refactored.push_back(RefactoredObjectData(object, newObject)); + ss << newObject; } - m_refactored.push_back(RefactoredObjectData(object, newObject)); - ss << newObject; + } else if (iddname == "OS:Fan:ConstantVolume") { + std::string fanHandleStr = object.getString(0).get(); + if (std::find(packagedFanCVHandleStrs.cbegin(), packagedFanCVHandleStrs.cend(), fanHandleStr) == packagedFanCVHandleStrs.cend()) { + ss << object; + } else { + LOG(Warn, "Fan:ConstantVolume " + << object.nameString() + << " is used in a Packaged System (PTAC or PTHP) that does not have a Supply Air Fan Operating Mode Schedule. " + "In 22.1.0 this would effectively, and mistakenly, function as a cycling fan, but this is now disallowed in E+ 22.2.0. " + "In order to retain a similar functionality and energy usage, this will be replaced by a Fan:SystemModel " + "with an always Off Schedule (cycling fan, similar to a Fan:OnOff)"); + IdfObject newObject(idd_3_5_0.getObject("OS:Fan:SystemModel").get()); + // Handle + if ((value = object.getString(0))) { + newObject.setString(0, value.get()); + } + + // Name + if ((value = object.getString(1))) { + newObject.setString(1, value.get()); + } + + // Availability Schedule Name + if ((value = object.getString(2))) { + newObject.setString(2, value.get()); + } + + // Note the use of "true" to return default. Fan:ConstantVolume has way more defaulted fields, while Fan:SystemModel adheres to the newer + // "make \required-field and hardcode in ctor" doctrine, AND has different defaults than Fan:ConstantVolume. So we do this to fulfil two + // goals: Put a value in all required-fields AND set the same values + // Fan Total Efficiency + if ((value = object.getString(3, true))) { + newObject.setString(15, value.get()); + } + + // Pressure Rise + if ((value = object.getString(4, true))) { + newObject.setString(8, value.get()); + } + + // Maximum Flow Rate + if ((value = object.getString(5, true))) { + newObject.setString(5, value.get()); + } + + // Motor Efficiency + if ((value = object.getString(6, true))) { + newObject.setString(9, value.get()); + } + + // Motor In Airstream Fraction + if ((value = object.getString(7, true))) { + newObject.setString(10, value.get()); + } + + // Nodes should be blank since it's inside a containing ZoneHVAC + // Air Inlet Node Name + if ((value = object.getString(8))) { + newObject.setString(3, value.get()); + } + + // Air Outlet Node Name + if ((value = object.getString(9))) { + newObject.setString(4, value.get()); + } + + // End-Use Subcategory + if ((value = object.getString(10, true))) { + newObject.setString(21, value.get()); + } + + // Speed Control Method + newObject.setString(6, "Discrete"); + + // Electric Power Minimum Flow Rate Fraction + newObject.setDouble(7, 0.0); + + // Design Electric Power Consumption + newObject.setString(11, "Autosize"); + + // Design Power Sizing Method + newObject.setString(12, "TotalEfficiencyAndPressure"); + + // Electric Power Per Unit Flow Rate (not used given Power Sizing Method, but required-field & set in Ctor) + newObject.setDouble(13, 840.0); + + // Electric Power Per Unit Flow Rate Per Unit Pressure (not used given Power Sizing Method, but required-field & set in Ctor) + newObject.setDouble(14, 1.66667); + + // Electric Power Function of Flow Fraction Curve Name + newObject.setString(16, ""); + + // Night Ventilation Mode Pressure Rise + newObject.setString(17, ""); + + // Night Ventilation Mode Flow Fraction + newObject.setString(18, ""); + + // Motor Loss Zone Name + newObject.setString(19, ""); + + // Motor Loss Radiative Fraction + newObject.setDouble(20, 0.0); + + m_refactored.push_back(RefactoredObjectData(object, newObject)); + ss << newObject; + } // No-op } else { From f729cfb01b10ff35008f913451b7c6c681422970 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 29 Sep 2022 10:31:23 +0200 Subject: [PATCH 03/10] Rename release notes to 3.5.0 --- ...d => OpenStudio_Release_Notes_3_5_0_TBD.md} | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) rename developer/doc/ReleaseNotes/{OpenStudio_Release_Notes_3_4_1_TBD.md => OpenStudio_Release_Notes_3_5_0_TBD.md} (93%) diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_4_1_TBD.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md similarity index 93% rename from developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_4_1_TBD.md rename to developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md index 80fa128c3a..35bc049580 100644 --- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_4_1_TBD.md +++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md @@ -1,8 +1,8 @@ -# OpenStudio Version 3.4.1 (TDB) +# OpenStudio Version 3.5.0 (TDB) _Release Notes_ - _TDB_ -These release notes describe version 3.4.1 of the OpenStudio SDK developed by the National Renewable Energy Laboratory (NREL), Buildings and Thermal Sciences Center, Commercial Buildings Research Group, Tools Development Section, and associated collaborators. The notes are organized into the following sections: +These release notes describe version 3.5.0 of the OpenStudio SDK developed by the National Renewable Energy Laboratory (NREL), Buildings and Thermal Sciences Center, Commercial Buildings Research Group, Tools Development Section, and associated collaborators. The notes are organized into the following sections: - Overview - Where to Find OpenStudio Documentation @@ -15,7 +15,7 @@ As of April 2020, development and distribution of the OpenStudioApplication and Below is the list of components that is included in this SDK installer: -__**OpenStudio SDK 3.4.1**__ +__**OpenStudio SDK 3.5.0**__ - EnergyPlus - Command Line Interface (CLI) - Radiance @@ -33,11 +33,11 @@ __**OpenStudio SDK 3.4.1**__ # Installation Notes -OpenStudio SDK 3.4.1 is supported on 64-bit Windows 7 – 10, OS X 10.15, and Ubuntu 18.04, 20.04 +OpenStudio SDK 3.5.0 is supported on 64-bit Windows 7 – 10, OS X 10.15, and Ubuntu 18.04, 20.04 -OpenStudio SDK 3.4.1 supports [EnergyPlus Release 22.1.0](https://github.com/NREL/EnergyPlus/releases/tag/v22.1.0), which is bundled with the OpenStudio installer. It is no longer necessary to download and install EnergyPlus separately. Other builds of EnergyPlus are not supported by OpenStudio SDK 3.4.1. +OpenStudio SDK 3.5.0 supports [EnergyPlus Release 22.1.0](https://github.com/NREL/EnergyPlus/releases/tag/v22.1.0), which is bundled with the OpenStudio installer. It is no longer necessary to download and install EnergyPlus separately. Other builds of EnergyPlus are not supported by OpenStudio SDK 3.5.0. -OpenStudio SDK 3.4.1 supports Radiance 5.0.a.12, which is bundled with the OpenStudio installer; users no longer must install Radiance separately, and OpenStudio will use the included Radiance version regardless of any other versions that may be installed on the system. Other builds of Radiance are not supported by OpenStudio SDK 3.4.1. +OpenStudio SDK 3.5.0 supports Radiance 5.0.a.12, which is bundled with the OpenStudio installer; users no longer must install Radiance separately, and OpenStudio will use the included Radiance version regardless of any other versions that may be installed on the system. Other builds of Radiance are not supported by OpenStudio SDK 3.5.0. As usual, you can refer to the **[OpenStudio SDK Compatibility Matrix](https://github.com/NREL/OpenStudio/wiki/OpenStudio-SDK-Version-Compatibility-Matrix)** for more information. @@ -52,7 +52,7 @@ For help with common installation problems please visit, http://nrel.github.io/O # OpenStudio SDK: Changelog -The 3.4.1 is a minor release. This update includes several new features, performance improvements, and bug fixes. +The 3.5.0 is a minor release. This update includes several new features, performance improvements, and bug fixes. You can find the list of Pull Requests that got into this release (**NEEDS UPDATE**) [here](https://github.com/NREL/OpenStudio/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aclosed+created%3A2021-04-27..2022-09-26+). @@ -60,7 +60,7 @@ You can find the list of Pull Requests that got into this release (**NEEDS UPDAT As of OpenStudio SDK 3.2.0, Python bindings are officially supported and distributed through Python Package Index (PyPI). To install, users will need to have Python3 installed along with pip and simply run the following command in a terminal window. -`pip install openstudio==3.4.1` +`pip install openstudio==3.5.0` Please see [openstudio on PyPi](https://pypi.org/project/openstudio/) for further instructions on how to install. Users can also visit the test channel at [openstudio on TestPyPi](https://test.pypi.org/project/openstudio/) to install development bindings. @@ -83,7 +83,7 @@ You can also refer to the [OpenStudio SDK Python Binding Version Compatibility M * `Coil:Cooling:DX:SingleSpeed`, `Coil:Cooling:DX:MultiSpeed:StageData`, and `Coil:Cooling:DX:CurveFit:Speed`: `ratedEvaporatorFanPowerPerVolumeFlowRate` and `setRatedEvaporatorFanPowerPerVolumeFlowRate` in favor of `ratedEvaporatorFanPowerPerVolumeFlowRate2017` and `setRatedEvaporatorFanPowerPerVolumeFlowRate2017` * `Coil:Heating:DX:SingleSpeed` and `Coil:Heating:DX:MultiSpeed:StageData`: `ratedSupplyFanPowerPerVolumeFlowRate` and `setRatedSupplyFanPowerPerVolumeFlowRate` in favor of `ratedSupplyFanPowerPerVolumeFlowRate2017` and `setRatedSupplyFanPowerPerVolumeFlowRate2017` * [#4666](https://github.com/NREL/OpenStudio/pull/4666) - Changes related to availability schedule methods - * `Coil:Heating:Gas:MultiStage` has an API-breaking change related to its `availabilitySchedule` getter. It is now a required field that returns `Schedule` instead of `boost::optional`. Method `resetAvailabilitySchedule` is also removed. + * `Coil:Heating:Gas:MultiStage` has an API-breaking change related to its `availabilitySchedule` getter. It is now a required field that returns `Schedule` instead of `boost::optional`. Method `resetAvailabilitySchedule` is also removed. ## Minor changes and bug fixes From 3c15fdf5480e240d7fadce904d3ef33545998cae Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 29 Sep 2022 11:32:46 +0200 Subject: [PATCH 04/10] API Break: make Supply Air Fan Operating Mode Schedule required-field for --- .../OpenStudio_Release_Notes_3_5_0_TBD.md | 3 ++ resources/model/OpenStudio.idd | 2 + ...ZoneHVACPackagedTerminalAirConditioner.cpp | 43 +++++++++++-------- ...ZoneHVACPackagedTerminalAirConditioner.hpp | 4 +- ...VACPackagedTerminalAirConditioner_Impl.hpp | 5 +-- .../ZoneHVACPackagedTerminalHeatPump.cpp | 42 ++++++++++-------- .../ZoneHVACPackagedTerminalHeatPump.hpp | 4 +- .../ZoneHVACPackagedTerminalHeatPump_Impl.hpp | 5 +-- 8 files changed, 59 insertions(+), 49 deletions(-) diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md index 35bc049580..bd7bab8b38 100644 --- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md +++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md @@ -84,6 +84,9 @@ You can also refer to the [OpenStudio SDK Python Binding Version Compatibility M * `Coil:Heating:DX:SingleSpeed` and `Coil:Heating:DX:MultiSpeed:StageData`: `ratedSupplyFanPowerPerVolumeFlowRate` and `setRatedSupplyFanPowerPerVolumeFlowRate` in favor of `ratedSupplyFanPowerPerVolumeFlowRate2017` and `setRatedSupplyFanPowerPerVolumeFlowRate2017` * [#4666](https://github.com/NREL/OpenStudio/pull/4666) - Changes related to availability schedule methods * `Coil:Heating:Gas:MultiStage` has an API-breaking change related to its `availabilitySchedule` getter. It is now a required field that returns `Schedule` instead of `boost::optional`. Method `resetAvailabilitySchedule` is also removed. +* [#4701](https://github.com/NREL/OpenStudio/pull/4701) - `ZoneHVACPackagedTerminalAirConditioner` and `ZoneHVACPackagedTerminalHeatPump` + * `ZoneHVACPackagedTerminalAirConditioner` and `ZoneHVACPackagedTerminalHeatPump` have an API-breaking change related to its `supplyAirFanOperatingModeSchedule` getter. It is now a required field that returns `Schedule` instead of `boost::optional`. Method `resetSupplyAirFanOperatingModeSchedule` is also removed. It is set to `alwaysOffDiscreteSchedule` (=Cycling) in the Constructor + * There are unusual VersionTranslation Rules for Packaged Systems (PTAC or PTHP) that use a `FanConstantVolum` and that do not have a `Supply Air Fan Operating Mode Schedule`. In 22.1.0 this would effectively, and mistakenly, function as a cycling fan, but this is now disallowed in E+ 22.2.0. In order to retain a similar functionality and energy usage, the `FanConstantVolume` will be replaced by a `FanSystemModel` with an Always Off Schedule (=cycling fan, similar to a `Fan:OnOff`) ## Minor changes and bug fixes diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd index 6b0aa46e98..a4fc5dfc0f 100644 --- a/resources/model/OpenStudio.idd +++ b/resources/model/OpenStudio.idd @@ -27545,6 +27545,7 @@ OS:ZoneHVAC:PackagedTerminalHeatPump, \note cycling fan operation (fan cycles with cooling or heating coil). Schedule Name values greater \note than 0 denote constant fan operation (fan runs continually regardless of coil operation). \note The fan operating mode defaults to cycling fan operation if this field is left blank. + \required-field \type object-list \object-list ScheduleNames @@ -27659,6 +27660,7 @@ OS:ZoneHVAC:PackagedTerminalAirConditioner, \note Enter the name of a schedule that controls fan operation. Schedule Name values of 0 denote \note cycling fan operation (fan cycles with cooling or heating coil). Schedule Name values greater \note than 0 denote constant fan operation (fan runs continually regardless of coil operation). + \required-field \type object-list \object-list ScheduleNames diff --git a/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp b/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp index 5851405525..52099a4f0a 100644 --- a/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp +++ b/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp @@ -301,9 +301,19 @@ namespace model { return isEmpty(OS_ZoneHVAC_PackagedTerminalAirConditionerFields::FanPlacement); } - boost::optional ZoneHVACPackagedTerminalAirConditioner_Impl::supplyAirFanOperatingModeSchedule() const { - return getObject().getModelObjectTarget( - OS_ZoneHVAC_PackagedTerminalAirConditionerFields::SupplyAirFanOperatingModeScheduleName); + Schedule ZoneHVACPackagedTerminalAirConditioner_Impl::supplyAirFanOperatingModeSchedule() const { + boost::optional value = optionalSupplyAirFanOperatingModeSchedule(); + if (!value) { + // it is an error if we get here, however we don't want to crash + // so we hook up to global always on schedule + LOG(Error, "Required availability schedule not set, using 'Always Off' schedule"); + value = this->model().alwaysOffDiscreteSchedule(); + OS_ASSERT(value); + const_cast(this)->setSupplyAirFanOperatingModeSchedule(*value); // NOLINT + value = optionalSupplyAirFanOperatingModeSchedule(); + } + OS_ASSERT(value); + return value.get(); } bool ZoneHVACPackagedTerminalAirConditioner_Impl::setAvailabilitySchedule(Schedule& schedule) { @@ -502,11 +512,6 @@ namespace model { return result; } - void ZoneHVACPackagedTerminalAirConditioner_Impl::resetSupplyAirFanOperatingModeSchedule() { - bool result = setString(OS_ZoneHVAC_PackagedTerminalAirConditionerFields::SupplyAirFanOperatingModeScheduleName, ""); - OS_ASSERT(result); - } - boost::optional ZoneHVACPackagedTerminalAirConditioner_Impl::optionalAvailabilitySchedule() const { return getObject().getModelObjectTarget(OS_ZoneHVAC_PackagedTerminalAirConditionerFields::AvailabilityScheduleName); } @@ -520,6 +525,11 @@ namespace model { return getObject().getModelObjectTarget(OS_ZoneHVAC_PackagedTerminalAirConditionerFields::CoolingCoilName); } + boost::optional ZoneHVACPackagedTerminalAirConditioner_Impl::optionalSupplyAirFanOperatingModeSchedule() const { + return getObject().getModelObjectTarget( + OS_ZoneHVAC_PackagedTerminalAirConditionerFields::SupplyAirFanOperatingModeScheduleName); + } + boost::optional ZoneHVACPackagedTerminalAirConditioner_Impl::availabilityScheduleAsModelObject() const { OptionalModelObject result = availabilitySchedule(); return result; @@ -600,13 +610,9 @@ namespace model { if (intermediate) { Schedule schedule(*intermediate); return setSupplyAirFanOperatingModeSchedule(schedule); - } else { - return false; } - } else { - resetSupplyAirFanOperatingModeSchedule(); } - return true; + return false; } boost::optional ZoneHVACPackagedTerminalAirConditioner_Impl::autosizedSupplyAirFlowRateDuringCoolingOperation() const { @@ -693,7 +699,10 @@ namespace model { setHeatingCoil(heatingCoil); setCoolingCoil(coolingCoil); setFanPlacement("DrawThrough"); - resetSupplyAirFanOperatingModeSchedule(); + // When Blank, E+ defaults to 0 (cycling) + auto alwaysOff = model.alwaysOffDiscreteSchedule(); + ok = setSupplyAirFanOperatingModeSchedule(alwaysOff); + OS_ASSERT(ok); autosizeSupplyAirFlowRateDuringCoolingOperation(); autosizeSupplyAirFlowRateDuringHeatingOperation(); @@ -873,7 +882,7 @@ namespace model { std::shared_ptr impl) : ZoneHVACComponent(std::move(impl)) {} - boost::optional ZoneHVACPackagedTerminalAirConditioner::supplyAirFanOperatingModeSchedule() const { + Schedule ZoneHVACPackagedTerminalAirConditioner::supplyAirFanOperatingModeSchedule() const { return getImpl()->supplyAirFanOperatingModeSchedule(); } @@ -881,10 +890,6 @@ namespace model { return getImpl()->setSupplyAirFanOperatingModeSchedule(schedule); } - void ZoneHVACPackagedTerminalAirConditioner::resetSupplyAirFanOperatingModeSchedule() { - getImpl()->resetSupplyAirFanOperatingModeSchedule(); - } - Schedule ZoneHVACPackagedTerminalAirConditioner::availabilitySchedule() const { return getImpl()->availabilitySchedule(); } diff --git a/src/model/ZoneHVACPackagedTerminalAirConditioner.hpp b/src/model/ZoneHVACPackagedTerminalAirConditioner.hpp index a4299f0c66..c1f6cfb71f 100644 --- a/src/model/ZoneHVACPackagedTerminalAirConditioner.hpp +++ b/src/model/ZoneHVACPackagedTerminalAirConditioner.hpp @@ -121,7 +121,7 @@ namespace model { bool isFanPlacementDefaulted() const; - boost::optional supplyAirFanOperatingModeSchedule() const; + Schedule supplyAirFanOperatingModeSchedule() const; //@} /** @name Setters */ @@ -176,8 +176,6 @@ namespace model { * fan continuously. */ bool setSupplyAirFanOperatingModeSchedule(Schedule& schedule); - void resetSupplyAirFanOperatingModeSchedule(); - //@} /** @name Other */ //@{ diff --git a/src/model/ZoneHVACPackagedTerminalAirConditioner_Impl.hpp b/src/model/ZoneHVACPackagedTerminalAirConditioner_Impl.hpp index 86fd0e8c31..b865154520 100644 --- a/src/model/ZoneHVACPackagedTerminalAirConditioner_Impl.hpp +++ b/src/model/ZoneHVACPackagedTerminalAirConditioner_Impl.hpp @@ -122,7 +122,7 @@ namespace model { bool isFanPlacementDefaulted() const; - boost::optional supplyAirFanOperatingModeSchedule() const; + Schedule supplyAirFanOperatingModeSchedule() const; boost::optional autosizedSupplyAirFlowRateDuringCoolingOperation() const; @@ -190,8 +190,6 @@ namespace model { bool setSupplyAirFanOperatingModeSchedule(Schedule& schedule); - void resetSupplyAirFanOperatingModeSchedule(); - //@} /** @name Other */ //@{ @@ -206,6 +204,7 @@ namespace model { boost::optional optionalSupplyAirFan() const; boost::optional optionalHeatingCoil() const; boost::optional optionalCoolingCoil() const; + boost::optional optionalSupplyAirFanOperatingModeSchedule() const; boost::optional availabilityScheduleAsModelObject() const; boost::optional supplyAirFanAsModelObject() const; diff --git a/src/model/ZoneHVACPackagedTerminalHeatPump.cpp b/src/model/ZoneHVACPackagedTerminalHeatPump.cpp index 8979b27759..c5b5472a7a 100644 --- a/src/model/ZoneHVACPackagedTerminalHeatPump.cpp +++ b/src/model/ZoneHVACPackagedTerminalHeatPump.cpp @@ -360,9 +360,19 @@ namespace model { return isEmpty(OS_ZoneHVAC_PackagedTerminalHeatPumpFields::FanPlacement); } - boost::optional ZoneHVACPackagedTerminalHeatPump_Impl::supplyAirFanOperatingModeSchedule() const { - return getObject().getModelObjectTarget( - OS_ZoneHVAC_PackagedTerminalHeatPumpFields::SupplyAirFanOperatingModeScheduleName); + Schedule ZoneHVACPackagedTerminalHeatPump_Impl::supplyAirFanOperatingModeSchedule() const { + boost::optional value = optionalSupplyAirFanOperatingModeSchedule(); + if (!value) { + // it is an error if we get here, however we don't want to crash + // so we hook up to global always on schedule + LOG(Error, "Required availability schedule not set, using 'Always Off' schedule"); + value = this->model().alwaysOffDiscreteSchedule(); + OS_ASSERT(value); + const_cast(this)->setSupplyAirFanOperatingModeSchedule(*value); // NOLINT + value = optionalSupplyAirFanOperatingModeSchedule(); + } + OS_ASSERT(value); + return value.get(); } bool ZoneHVACPackagedTerminalHeatPump_Impl::setAvailabilitySchedule(Schedule& schedule) { @@ -625,11 +635,6 @@ namespace model { return result; } - void ZoneHVACPackagedTerminalHeatPump_Impl::resetSupplyAirFanOperatingModeSchedule() { - bool result = setString(OS_ZoneHVAC_PackagedTerminalHeatPumpFields::SupplyAirFanOperatingModeScheduleName, ""); - OS_ASSERT(result); - } - boost::optional ZoneHVACPackagedTerminalHeatPump_Impl::optionalAvailabilitySchedule() const { return getObject().getModelObjectTarget(OS_ZoneHVAC_PackagedTerminalHeatPumpFields::AvailabilityScheduleName); } @@ -646,6 +651,11 @@ namespace model { return getObject().getModelObjectTarget(OS_ZoneHVAC_PackagedTerminalHeatPumpFields::SupplementalHeatingCoilName); } + boost::optional ZoneHVACPackagedTerminalHeatPump_Impl::optionalSupplyAirFanOperatingModeSchedule() const { + return getObject().getModelObjectTarget( + OS_ZoneHVAC_PackagedTerminalHeatPumpFields::SupplyAirFanOperatingModeScheduleName); + } + boost::optional ZoneHVACPackagedTerminalHeatPump_Impl::availabilityScheduleAsModelObject() const { OptionalModelObject result = availabilitySchedule(); return result; @@ -741,13 +751,9 @@ namespace model { if (intermediate) { Schedule schedule(*intermediate); return setSupplyAirFanOperatingModeSchedule(schedule); - } else { - return false; } - } else { - resetSupplyAirFanOperatingModeSchedule(); } - return true; + return false; } boost::optional ZoneHVACPackagedTerminalHeatPump_Impl::autosizedSupplyAirFlowRateDuringCoolingOperation() const { @@ -844,6 +850,10 @@ namespace model { setHeatingCoil(heatingCoil); setCoolingCoil(coolingCoil); setSupplementalHeatingCoil(supplementalHeatingCoil); + // When Blank, E+ defaults to 0 (cycling) + auto alwaysOff = model.alwaysOffDiscreteSchedule(); + ok = setSupplyAirFanOperatingModeSchedule(alwaysOff); + OS_ASSERT(ok); autosizeSupplyAirFlowRateDuringCoolingOperation(); autosizeSupplyAirFlowRateDuringHeatingOperation(); @@ -1113,10 +1123,6 @@ namespace model { return getImpl()->setSupplyAirFanOperatingModeSchedule(schedule); } - void ZoneHVACPackagedTerminalHeatPump::resetSupplyAirFanOperatingModeSchedule() { - getImpl()->resetSupplyAirFanOperatingModeSchedule(); - } - bool ZoneHVACPackagedTerminalHeatPump::setSupplyAirFan(HVACComponent& hvacComponent) { return getImpl()->setSupplyAirFan(hvacComponent); } @@ -1137,7 +1143,7 @@ namespace model { return getImpl()->availabilitySchedule(); } - boost::optional ZoneHVACPackagedTerminalHeatPump::supplyAirFanOperatingModeSchedule() const { + Schedule ZoneHVACPackagedTerminalHeatPump::supplyAirFanOperatingModeSchedule() const { return getImpl()->supplyAirFanOperatingModeSchedule(); } diff --git a/src/model/ZoneHVACPackagedTerminalHeatPump.hpp b/src/model/ZoneHVACPackagedTerminalHeatPump.hpp index 9c01ef8540..30c55a2129 100644 --- a/src/model/ZoneHVACPackagedTerminalHeatPump.hpp +++ b/src/model/ZoneHVACPackagedTerminalHeatPump.hpp @@ -145,7 +145,7 @@ namespace model { bool isFanPlacementDefaulted() const; - boost::optional supplyAirFanOperatingModeSchedule() const; + Schedule supplyAirFanOperatingModeSchedule() const; //@} /** @name Setters */ @@ -223,8 +223,6 @@ namespace model { * fan continuously. */ bool setSupplyAirFanOperatingModeSchedule(Schedule& schedule); - void resetSupplyAirFanOperatingModeSchedule(); - //@} /** @name Other */ //@{ diff --git a/src/model/ZoneHVACPackagedTerminalHeatPump_Impl.hpp b/src/model/ZoneHVACPackagedTerminalHeatPump_Impl.hpp index f24120de56..e637290b5a 100644 --- a/src/model/ZoneHVACPackagedTerminalHeatPump_Impl.hpp +++ b/src/model/ZoneHVACPackagedTerminalHeatPump_Impl.hpp @@ -143,7 +143,7 @@ namespace model { bool isFanPlacementDefaulted() const; - boost::optional supplyAirFanOperatingModeSchedule() const; + Schedule supplyAirFanOperatingModeSchedule() const; boost::optional autosizedSupplyAirFlowRateDuringCoolingOperation() const; @@ -235,8 +235,6 @@ namespace model { bool setSupplyAirFanOperatingModeSchedule(Schedule& schedule); - void resetSupplyAirFanOperatingModeSchedule(); - //@} /** @name Other */ //@{ @@ -252,6 +250,7 @@ namespace model { boost::optional optionalHeatingCoil() const; boost::optional optionalCoolingCoil() const; boost::optional optionalSupplementalHeatingCoil() const; + boost::optional optionalSupplyAirFanOperatingModeSchedule() const; boost::optional availabilityScheduleAsModelObject() const; boost::optional supplyAirFanAsModelObject() const; From d0f5f97076112dd018c98532ef89af6f05ae1009 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 29 Sep 2022 11:04:35 +0200 Subject: [PATCH 05/10] Modernize the ZoneHVACPackaged files --- ...ZoneHVACPackagedTerminalAirConditioner.cpp | 48 +++++++++---------- ...ZoneHVACPackagedTerminalAirConditioner.hpp | 14 +++--- ...VACPackagedTerminalAirConditioner_Impl.hpp | 8 ++-- .../ZoneHVACPackagedTerminalHeatPump.cpp | 31 ++++++------ .../ZoneHVACPackagedTerminalHeatPump.hpp | 14 +++--- .../ZoneHVACPackagedTerminalHeatPump_Impl.hpp | 8 ++-- 6 files changed, 61 insertions(+), 62 deletions(-) diff --git a/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp b/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp index 52099a4f0a..acc142b6f4 100644 --- a/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp +++ b/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp @@ -69,15 +69,15 @@ namespace model { : ZoneHVACComponent_Impl(other, model, keepHandle) {} ModelObject ZoneHVACPackagedTerminalAirConditioner_Impl::clone(Model model) const { - ZoneHVACPackagedTerminalAirConditioner ptacClone = ZoneHVACComponent_Impl::clone(model).cast(); + auto ptacClone = ZoneHVACComponent_Impl::clone(model).cast(); - HVACComponent supplyFanClone = this->supplyAirFan().clone(model).cast(); + auto supplyFanClone = this->supplyAirFan().clone(model).cast(); auto t_heatingCoil = heatingCoil(); - HVACComponent heatingCoilClone = t_heatingCoil.clone(model).cast(); + auto heatingCoilClone = t_heatingCoil.clone(model).cast(); auto t_coolingCoil = coolingCoil(); - HVACComponent coolingCoilClone = t_coolingCoil.clone(model).cast(); + auto coolingCoilClone = t_coolingCoil.clone(model).cast(); ptacClone.setSupplyAirFan(supplyFanClone); @@ -132,12 +132,13 @@ namespace model { std::vector ZoneHVACPackagedTerminalAirConditioner_Impl::getScheduleTypeKeys(const Schedule& schedule) const { std::vector result; UnsignedVector fieldIndices = getSourceIndices(schedule.handle()); - UnsignedVector::const_iterator b(fieldIndices.begin()), e(fieldIndices.end()); + UnsignedVector::const_iterator b(fieldIndices.begin()); + UnsignedVector::const_iterator e(fieldIndices.end()); if (std::find(b, e, OS_ZoneHVAC_PackagedTerminalAirConditionerFields::AvailabilityScheduleName) != e) { - result.push_back(ScheduleTypeKey("ZoneHVACPackagedTerminalAirConditioner", "Availability")); + result.emplace_back("ZoneHVACPackagedTerminalAirConditioner", "Availability"); } if (std::find(b, e, OS_ZoneHVAC_PackagedTerminalAirConditionerFields::SupplyAirFanOperatingModeScheduleName) != e) { - result.push_back(ScheduleTypeKey("ZoneHVACPackagedTerminalAirConditioner", "Supply Air Fan Operating Mode")); + result.emplace_back("ZoneHVACPackagedTerminalAirConditioner", "Supply Air Fan Operating Mode"); } return result; } @@ -172,7 +173,7 @@ namespace model { LOG(Error, "Required availability schedule not set, using 'Always On' schedule"); value = this->model().alwaysOnDiscreteSchedule(); OS_ASSERT(value); - const_cast(this)->setAvailabilitySchedule(*value); + const_cast(this)->setAvailabilitySchedule(*value); // NOLINT value = optionalAvailabilitySchedule(); } OS_ASSERT(value); @@ -322,12 +323,12 @@ namespace model { return result; } - bool ZoneHVACPackagedTerminalAirConditioner_Impl::setOutdoorAirMixerObjectType(std::string outdoorAirMixerObjectType) { + bool ZoneHVACPackagedTerminalAirConditioner_Impl::setOutdoorAirMixerObjectType(const std::string& outdoorAirMixerObjectType) { bool result = setString(OS_ZoneHVAC_PackagedTerminalAirConditionerFields::OutdoorAirMixerObjectType, outdoorAirMixerObjectType); return result; } - bool ZoneHVACPackagedTerminalAirConditioner_Impl::setOutdoorAirMixerName(std::string outdoorAirMixerName) { + bool ZoneHVACPackagedTerminalAirConditioner_Impl::setOutdoorAirMixerName(const std::string& outdoorAirMixerName) { bool result = setString(OS_ZoneHVAC_PackagedTerminalAirConditionerFields::OutdoorAirMixerName, outdoorAirMixerName); OS_ASSERT(result); return result; @@ -459,11 +460,9 @@ namespace model { bool ZoneHVACPackagedTerminalAirConditioner_Impl::setHeatingCoil(HVACComponent& heatingCoil) { bool isAllowedType = false; - if (heatingCoil.iddObjectType() == IddObjectType::OS_Coil_Heating_Gas) { - isAllowedType = true; - } else if (heatingCoil.iddObjectType() == IddObjectType::OS_Coil_Heating_Electric) { - isAllowedType = true; - } else if (heatingCoil.iddObjectType() == IddObjectType::OS_Coil_Heating_Water) { + auto iddObjectType = heatingCoil.iddObjectType(); + if ((iddObjectType == IddObjectType::OS_Coil_Heating_Gas) || (iddObjectType == IddObjectType::OS_Coil_Heating_Electric) + || (iddObjectType == IddObjectType::OS_Coil_Heating_Water)) { isAllowedType = true; } @@ -479,10 +478,10 @@ namespace model { bool ZoneHVACPackagedTerminalAirConditioner_Impl::setCoolingCoil(HVACComponent& coolingCoil) { bool isAllowedType = false; - if ((coolingCoil.iddObjectType() == IddObjectType::OS_Coil_Cooling_DX_SingleSpeed) - || (coolingCoil.iddObjectType() == IddObjectType::OS_Coil_Cooling_DX_VariableSpeed) - || (coolingCoil.iddObjectType() == IddObjectType::OS_CoilSystem_Cooling_DX_HeatExchangerAssisted) - || (coolingCoil.iddObjectType() == IddObjectType::OS_Coil_Cooling_DX)) { + auto iddObjectType = coolingCoil.iddObjectType(); + if ((iddObjectType == IddObjectType::OS_Coil_Cooling_DX_SingleSpeed) || (iddObjectType == IddObjectType::OS_Coil_Cooling_DX_VariableSpeed) + || (iddObjectType == IddObjectType::OS_CoilSystem_Cooling_DX_HeatExchangerAssisted) + || (iddObjectType == IddObjectType::OS_Coil_Cooling_DX)) { isAllowedType = true; } @@ -496,7 +495,7 @@ namespace model { } } - bool ZoneHVACPackagedTerminalAirConditioner_Impl::setFanPlacement(std::string fanPlacement) { + bool ZoneHVACPackagedTerminalAirConditioner_Impl::setFanPlacement(const std::string& fanPlacement) { bool result = setString(OS_ZoneHVAC_PackagedTerminalAirConditionerFields::FanPlacement, fanPlacement); return result; } @@ -713,8 +712,7 @@ namespace model { } IddObjectType ZoneHVACPackagedTerminalAirConditioner::iddObjectType() { - IddObjectType result(IddObjectType::OS_ZoneHVAC_PackagedTerminalAirConditioner); - return result; + return IddObjectType::OS_ZoneHVAC_PackagedTerminalAirConditioner; } std::vector ZoneHVACPackagedTerminalAirConditioner::outdoorAirMixerObjectTypeValues() { @@ -798,11 +796,11 @@ namespace model { return getImpl()->isFanPlacementDefaulted(); } - bool ZoneHVACPackagedTerminalAirConditioner::setOutdoorAirMixerObjectType(std::string outdoorAirMixerObjectType) { + bool ZoneHVACPackagedTerminalAirConditioner::setOutdoorAirMixerObjectType(const std::string& outdoorAirMixerObjectType) { return getImpl()->setOutdoorAirMixerObjectType(outdoorAirMixerObjectType); } - bool ZoneHVACPackagedTerminalAirConditioner::setOutdoorAirMixerName(std::string outdoorAirMixerName) { + bool ZoneHVACPackagedTerminalAirConditioner::setOutdoorAirMixerName(const std::string& outdoorAirMixerName) { return getImpl()->setOutdoorAirMixerName(outdoorAirMixerName); } @@ -870,7 +868,7 @@ namespace model { getImpl()->autosizeOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(); } - bool ZoneHVACPackagedTerminalAirConditioner::setFanPlacement(std::string fanPlacement) { + bool ZoneHVACPackagedTerminalAirConditioner::setFanPlacement(const std::string& fanPlacement) { return getImpl()->setFanPlacement(fanPlacement); } diff --git a/src/model/ZoneHVACPackagedTerminalAirConditioner.hpp b/src/model/ZoneHVACPackagedTerminalAirConditioner.hpp index c1f6cfb71f..9c9092711c 100644 --- a/src/model/ZoneHVACPackagedTerminalAirConditioner.hpp +++ b/src/model/ZoneHVACPackagedTerminalAirConditioner.hpp @@ -56,7 +56,7 @@ namespace model { ZoneHVACPackagedTerminalAirConditioner(const Model& model, Schedule& availabilitySchedule, HVACComponent& supplyAirFan, HVACComponent& heatingCoil, HVACComponent& coolingCoil); - virtual ~ZoneHVACPackagedTerminalAirConditioner() {} + virtual ~ZoneHVACPackagedTerminalAirConditioner() = default; //@} @@ -129,9 +129,9 @@ namespace model { bool setAvailabilitySchedule(Schedule& schedule); - bool setOutdoorAirMixerObjectType(std::string outdoorAirMixerObjectType); + bool setOutdoorAirMixerObjectType(const std::string& outdoorAirMixerObjectType); - bool setOutdoorAirMixerName(std::string outdoorAirMixerName); + bool setOutdoorAirMixerName(const std::string& outdoorAirMixerName); bool setSupplyAirFlowRateDuringCoolingOperation(double supplyAirFlowRateDuringCoolingOperation); @@ -167,7 +167,7 @@ namespace model { bool setCoolingCoil(HVACComponent& coolingCoil); - bool setFanPlacement(std::string fanPlacement); + bool setFanPlacement(const std::string& fanPlacement); void resetFanPlacement(); @@ -195,7 +195,7 @@ namespace model { //@} protected: /// @cond - typedef detail::ZoneHVACPackagedTerminalAirConditioner_Impl ImplType; + using ImplType = detail::ZoneHVACPackagedTerminalAirConditioner_Impl; explicit ZoneHVACPackagedTerminalAirConditioner(std::shared_ptr impl); @@ -210,10 +210,10 @@ namespace model { }; /** \relates ZoneHVACPackagedTerminalAirConditioner*/ - typedef boost::optional OptionalZoneHVACPackagedTerminalAirConditioner; + using OptionalZoneHVACPackagedTerminalAirConditioner = boost::optional; /** \relates ZoneHVACPackagedTerminalAirConditioner*/ - typedef std::vector ZoneHVACPackagedTerminalAirConditionerVector; + using ZoneHVACPackagedTerminalAirConditionerVector = std::vector; } // namespace model } // namespace openstudio diff --git a/src/model/ZoneHVACPackagedTerminalAirConditioner_Impl.hpp b/src/model/ZoneHVACPackagedTerminalAirConditioner_Impl.hpp index b865154520..9524483fd4 100644 --- a/src/model/ZoneHVACPackagedTerminalAirConditioner_Impl.hpp +++ b/src/model/ZoneHVACPackagedTerminalAirConditioner_Impl.hpp @@ -56,7 +56,7 @@ namespace model { ZoneHVACPackagedTerminalAirConditioner_Impl(const ZoneHVACPackagedTerminalAirConditioner_Impl& other, Model_Impl* model, bool keepHandle); - virtual ~ZoneHVACPackagedTerminalAirConditioner_Impl() {} + virtual ~ZoneHVACPackagedTerminalAirConditioner_Impl() = default; //@} /** @name Virtual Methods */ @@ -146,9 +146,9 @@ namespace model { bool setAvailabilitySchedule(Schedule& schedule); - bool setOutdoorAirMixerObjectType(std::string outdoorAirMixerObjectType); + bool setOutdoorAirMixerObjectType(const std::string& outdoorAirMixerObjectType); - bool setOutdoorAirMixerName(std::string outdoorAirMixerName); + bool setOutdoorAirMixerName(const std::string& outdoorAirMixerName); bool setSupplyAirFlowRateDuringCoolingOperation(boost::optional supplyAirFlowRateDuringCoolingOperation); @@ -184,7 +184,7 @@ namespace model { bool setCoolingCoil(HVACComponent& coolingCoil); - bool setFanPlacement(std::string fanPlacement); + bool setFanPlacement(const std::string& fanPlacement); void resetFanPlacement(); diff --git a/src/model/ZoneHVACPackagedTerminalHeatPump.cpp b/src/model/ZoneHVACPackagedTerminalHeatPump.cpp index c5b5472a7a..792eeeacc0 100644 --- a/src/model/ZoneHVACPackagedTerminalHeatPump.cpp +++ b/src/model/ZoneHVACPackagedTerminalHeatPump.cpp @@ -67,19 +67,19 @@ namespace model { : ZoneHVACComponent_Impl(other, model, keepHandle) {} ModelObject ZoneHVACPackagedTerminalHeatPump_Impl::clone(Model model) const { - ZoneHVACPackagedTerminalHeatPump pthpClone = ZoneHVACComponent_Impl::clone(model).cast(); + auto pthpClone = ZoneHVACComponent_Impl::clone(model).cast(); //Schedule scheduleClone = this->availabilitySchedule().clone(model).cast(); - HVACComponent supplyFanClone = this->supplyAirFan().clone(model).cast(); + auto supplyFanClone = this->supplyAirFan().clone(model).cast(); auto t_heatingCoil = heatingCoil(); - HVACComponent heatingCoilClone = t_heatingCoil.clone(model).cast(); + auto heatingCoilClone = t_heatingCoil.clone(model).cast(); auto t_coolingCoil = coolingCoil(); - HVACComponent coolingCoilClone = t_coolingCoil.clone(model).cast(); + auto coolingCoilClone = t_coolingCoil.clone(model).cast(); - HVACComponent supplementalHeatingCoilClone = this->supplementalHeatingCoil().clone(model).cast(); + auto supplementalHeatingCoilClone = this->supplementalHeatingCoil().clone(model).cast(); //pthpClone.setAvailabilitySchedule(scheduleClone); @@ -128,12 +128,13 @@ namespace model { std::vector ZoneHVACPackagedTerminalHeatPump_Impl::getScheduleTypeKeys(const Schedule& schedule) const { std::vector result; UnsignedVector fieldIndices = getSourceIndices(schedule.handle()); - UnsignedVector::const_iterator b(fieldIndices.begin()), e(fieldIndices.end()); + UnsignedVector::const_iterator b(fieldIndices.begin()); + UnsignedVector::const_iterator e(fieldIndices.end()); if (std::find(b, e, OS_ZoneHVAC_PackagedTerminalHeatPumpFields::AvailabilityScheduleName) != e) { - result.push_back(ScheduleTypeKey("ZoneHVACPackagedTerminalHeatPump", "Availability")); + result.emplace_back("ZoneHVACPackagedTerminalHeatPump", "Availability"); } if (std::find(b, e, OS_ZoneHVAC_PackagedTerminalHeatPumpFields::SupplyAirFanOperatingModeScheduleName) != e) { - result.push_back(ScheduleTypeKey("ZoneHVACPackagedTerminalHeatPump", "Supply Air Fan Operating Mode")); + result.emplace_back("ZoneHVACPackagedTerminalHeatPump", "Supply Air Fan Operating Mode"); } return result; } @@ -171,7 +172,7 @@ namespace model { LOG(Error, "Required availability schedule not set, using 'Always On' schedule"); value = this->model().alwaysOnDiscreteSchedule(); OS_ASSERT(value); - const_cast(this)->setAvailabilitySchedule(*value); + const_cast(this)->setAvailabilitySchedule(*value); // NOLINT value = optionalAvailabilitySchedule(); } OS_ASSERT(value); @@ -381,12 +382,12 @@ namespace model { return result; } - bool ZoneHVACPackagedTerminalHeatPump_Impl::setOutdoorAirMixerObjectType(std::string outdoorAirMixerObjectType) { + bool ZoneHVACPackagedTerminalHeatPump_Impl::setOutdoorAirMixerObjectType(const std::string& outdoorAirMixerObjectType) { bool result = setString(OS_ZoneHVAC_PackagedTerminalHeatPumpFields::OutdoorAirMixerObjectType, outdoorAirMixerObjectType); return result; } - bool ZoneHVACPackagedTerminalHeatPump_Impl::setOutdoorAirMixerName(std::string outdoorAirMixerName) { + bool ZoneHVACPackagedTerminalHeatPump_Impl::setOutdoorAirMixerName(const std::string& outdoorAirMixerName) { bool result = setString(OS_ZoneHVAC_PackagedTerminalHeatPumpFields::OutdoorAirMixerName, outdoorAirMixerName); OS_ASSERT(result); return result; @@ -619,7 +620,7 @@ namespace model { OS_ASSERT(result); } - bool ZoneHVACPackagedTerminalHeatPump_Impl::setFanPlacement(std::string fanPlacement) { + bool ZoneHVACPackagedTerminalHeatPump_Impl::setFanPlacement(const std::string& fanPlacement) { bool result = setString(OS_ZoneHVAC_PackagedTerminalHeatPumpFields::FanPlacement, fanPlacement); return result; } @@ -990,11 +991,11 @@ namespace model { return getImpl()->isFanPlacementDefaulted(); } - bool ZoneHVACPackagedTerminalHeatPump::setOutdoorAirMixerObjectType(std::string outdoorAirMixerObjectType) { + bool ZoneHVACPackagedTerminalHeatPump::setOutdoorAirMixerObjectType(const std::string& outdoorAirMixerObjectType) { return getImpl()->setOutdoorAirMixerObjectType(outdoorAirMixerObjectType); } - bool ZoneHVACPackagedTerminalHeatPump::setOutdoorAirMixerName(std::string outdoorAirMixerName) { + bool ZoneHVACPackagedTerminalHeatPump::setOutdoorAirMixerName(const std::string& outdoorAirMixerName) { return getImpl()->setOutdoorAirMixerName(outdoorAirMixerName); } @@ -1107,7 +1108,7 @@ namespace model { getImpl()->resetMaximumOutdoorDryBulbTemperatureforSupplementalHeaterOperation(); } - bool ZoneHVACPackagedTerminalHeatPump::setFanPlacement(std::string fanPlacement) { + bool ZoneHVACPackagedTerminalHeatPump::setFanPlacement(const std::string& fanPlacement) { return getImpl()->setFanPlacement(fanPlacement); } diff --git a/src/model/ZoneHVACPackagedTerminalHeatPump.hpp b/src/model/ZoneHVACPackagedTerminalHeatPump.hpp index 30c55a2129..401a76e20c 100644 --- a/src/model/ZoneHVACPackagedTerminalHeatPump.hpp +++ b/src/model/ZoneHVACPackagedTerminalHeatPump.hpp @@ -57,7 +57,7 @@ namespace model { ZoneHVACPackagedTerminalHeatPump(const Model& model, Schedule& availabilitySchedule, HVACComponent& supplyAirFan, HVACComponent& heatingCoil, HVACComponent& coolingCoil, HVACComponent& supplementalHeatingCoil); - virtual ~ZoneHVACPackagedTerminalHeatPump() {} + virtual ~ZoneHVACPackagedTerminalHeatPump() = default; //@} @@ -153,9 +153,9 @@ namespace model { bool setAvailabilitySchedule(Schedule& schedule); - bool setOutdoorAirMixerObjectType(std::string outdoorAirMixerObjectType); + bool setOutdoorAirMixerObjectType(const std::string& outdoorAirMixerObjectType); - bool setOutdoorAirMixerName(std::string outdoorAirMixerName); + bool setOutdoorAirMixerName(const std::string& outdoorAirMixerName); bool setSupplyAirFlowRateDuringCoolingOperation(double supplyAirFlowRateDuringCoolingOperation); @@ -214,7 +214,7 @@ namespace model { void resetMaximumOutdoorDryBulbTemperatureforSupplementalHeaterOperation(); - bool setFanPlacement(std::string fanPlacement); + bool setFanPlacement(const std::string& fanPlacement); void resetFanPlacement(); @@ -244,7 +244,7 @@ namespace model { //@} protected: /// @cond - typedef detail::ZoneHVACPackagedTerminalHeatPump_Impl ImplType; + using ImplType = detail::ZoneHVACPackagedTerminalHeatPump_Impl; explicit ZoneHVACPackagedTerminalHeatPump(std::shared_ptr impl); @@ -259,10 +259,10 @@ namespace model { }; /** \relates ZoneHVACPackagedTerminalHeatPump*/ - typedef boost::optional OptionalZoneHVACPackagedTerminalHeatPump; + using OptionalZoneHVACPackagedTerminalHeatPump = boost::optional; /** \relates ZoneHVACPackagedTerminalHeatPump*/ - typedef std::vector ZoneHVACPackagedTerminalHeatPumpVector; + using ZoneHVACPackagedTerminalHeatPumpVector = std::vector; } // namespace model } // namespace openstudio diff --git a/src/model/ZoneHVACPackagedTerminalHeatPump_Impl.hpp b/src/model/ZoneHVACPackagedTerminalHeatPump_Impl.hpp index e637290b5a..ecd38604e7 100644 --- a/src/model/ZoneHVACPackagedTerminalHeatPump_Impl.hpp +++ b/src/model/ZoneHVACPackagedTerminalHeatPump_Impl.hpp @@ -57,7 +57,7 @@ namespace model { ZoneHVACPackagedTerminalHeatPump_Impl(const ZoneHVACPackagedTerminalHeatPump_Impl& other, Model_Impl* model, bool keepHandle); - virtual ~ZoneHVACPackagedTerminalHeatPump_Impl() {} + virtual ~ZoneHVACPackagedTerminalHeatPump_Impl() = default; //@} /** @name Virtual Methods */ @@ -169,9 +169,9 @@ namespace model { bool setAvailabilitySchedule(Schedule& schedule); - bool setOutdoorAirMixerObjectType(std::string outdoorAirMixerObjectType); + bool setOutdoorAirMixerObjectType(const std::string& outdoorAirMixerObjectType); - bool setOutdoorAirMixerName(std::string outdoorAirMixerName); + bool setOutdoorAirMixerName(const std::string& outdoorAirMixerName); bool setSupplyAirFlowRateDuringCoolingOperation(boost::optional supplyAirFlowRateDuringCoolingOperation); @@ -229,7 +229,7 @@ namespace model { void resetMaximumOutdoorDryBulbTemperatureforSupplementalHeaterOperation(); - bool setFanPlacement(std::string fanPlacement); + bool setFanPlacement(const std::string& fanPlacement); void resetFanPlacement(); From a3292004158123529f8fc9a4f9e39849176a9b81 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 29 Sep 2022 11:14:14 +0200 Subject: [PATCH 06/10] Set Fan Op Sch to alwaysOn if FanConstantVolume is passed, alwaysOn otherwise --- .../OpenStudio_Release_Notes_3_5_0_TBD.md | 6 ++++-- .../ZoneHVACPackagedTerminalAirConditioner.cpp | 14 ++++++++++---- src/model/ZoneHVACPackagedTerminalHeatPump.cpp | 14 ++++++++++---- 3 files changed, 24 insertions(+), 10 deletions(-) diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md index bd7bab8b38..48b468d9b7 100644 --- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md +++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_5_0_TBD.md @@ -85,8 +85,10 @@ You can also refer to the [OpenStudio SDK Python Binding Version Compatibility M * [#4666](https://github.com/NREL/OpenStudio/pull/4666) - Changes related to availability schedule methods * `Coil:Heating:Gas:MultiStage` has an API-breaking change related to its `availabilitySchedule` getter. It is now a required field that returns `Schedule` instead of `boost::optional`. Method `resetAvailabilitySchedule` is also removed. * [#4701](https://github.com/NREL/OpenStudio/pull/4701) - `ZoneHVACPackagedTerminalAirConditioner` and `ZoneHVACPackagedTerminalHeatPump` - * `ZoneHVACPackagedTerminalAirConditioner` and `ZoneHVACPackagedTerminalHeatPump` have an API-breaking change related to its `supplyAirFanOperatingModeSchedule` getter. It is now a required field that returns `Schedule` instead of `boost::optional`. Method `resetSupplyAirFanOperatingModeSchedule` is also removed. It is set to `alwaysOffDiscreteSchedule` (=Cycling) in the Constructor - * There are unusual VersionTranslation Rules for Packaged Systems (PTAC or PTHP) that use a `FanConstantVolum` and that do not have a `Supply Air Fan Operating Mode Schedule`. In 22.1.0 this would effectively, and mistakenly, function as a cycling fan, but this is now disallowed in E+ 22.2.0. In order to retain a similar functionality and energy usage, the `FanConstantVolume` will be replaced by a `FanSystemModel` with an Always Off Schedule (=cycling fan, similar to a `Fan:OnOff`) + * `ZoneHVACPackagedTerminalAirConditioner` and `ZoneHVACPackagedTerminalHeatPump` have an API-breaking change related to its `supplyAirFanOperatingModeSchedule` getter. It is now a required field that returns `Schedule` instead of `boost::optional`. Method `resetSupplyAirFanOperatingModeSchedule` is also removed. + * It is set to `alwaysOnDiscreteSchedule` (=Constant) in the Constructor if you provide a `FanConstantVolume` (This is **required** by E+) + * It is set to `alwaysOffDiscreteSchedule` (=Cycling) in the Constructor if you provide any other fan types (E+ treats a blank schedule as always off) + * There are unusual `VersionTranslator` Rules for Packaged Systems (PTAC or PTHP) that use a `FanConstantVolume` and that do not have a `Supply Air Fan Operating Mode Schedule`. In 22.1.0 this would effectively, and mistakenly, function as a cycling fan, but this is now disallowed in E+ 22.2.0. In order to retain a similar functionality and energy usage, the `FanConstantVolume` will be replaced by a `FanSystemModel` with an Always Off Schedule (=cycling fan, similar to a `Fan:OnOff`), mapping inputs such as pressure rise and efficiency appropriately. ## Minor changes and bug fixes diff --git a/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp b/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp index acc142b6f4..367231d666 100644 --- a/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp +++ b/src/model/ZoneHVACPackagedTerminalAirConditioner.cpp @@ -698,10 +698,16 @@ namespace model { setHeatingCoil(heatingCoil); setCoolingCoil(coolingCoil); setFanPlacement("DrawThrough"); - // When Blank, E+ defaults to 0 (cycling) - auto alwaysOff = model.alwaysOffDiscreteSchedule(); - ok = setSupplyAirFanOperatingModeSchedule(alwaysOff); - OS_ASSERT(ok); + // When Blank, E+ defaults to 0 (cycling). If it's a FanConstantVolume though, you must provide an always On or E+ will Fatal. + if (supplyAirFan.iddObjectType() == IddObjectType::OS_Fan_ConstantVolume) { + auto alwaysOn = model.alwaysOnDiscreteSchedule(); + ok = setSupplyAirFanOperatingModeSchedule(alwaysOn); + OS_ASSERT(ok); + } else { + auto alwaysOff = model.alwaysOffDiscreteSchedule(); + ok = setSupplyAirFanOperatingModeSchedule(alwaysOff); + OS_ASSERT(ok); + } autosizeSupplyAirFlowRateDuringCoolingOperation(); autosizeSupplyAirFlowRateDuringHeatingOperation(); diff --git a/src/model/ZoneHVACPackagedTerminalHeatPump.cpp b/src/model/ZoneHVACPackagedTerminalHeatPump.cpp index 792eeeacc0..486e400484 100644 --- a/src/model/ZoneHVACPackagedTerminalHeatPump.cpp +++ b/src/model/ZoneHVACPackagedTerminalHeatPump.cpp @@ -851,10 +851,16 @@ namespace model { setHeatingCoil(heatingCoil); setCoolingCoil(coolingCoil); setSupplementalHeatingCoil(supplementalHeatingCoil); - // When Blank, E+ defaults to 0 (cycling) - auto alwaysOff = model.alwaysOffDiscreteSchedule(); - ok = setSupplyAirFanOperatingModeSchedule(alwaysOff); - OS_ASSERT(ok); + // When Blank, E+ defaults to 0 (cycling). If it's a FanConstantVolume though, you must provide an always On or E+ will Fatal. + if (supplyAirFan.iddObjectType() == IddObjectType::OS_Fan_ConstantVolume) { + auto alwaysOn = model.alwaysOnDiscreteSchedule(); + ok = setSupplyAirFanOperatingModeSchedule(alwaysOn); + OS_ASSERT(ok); + } else { + auto alwaysOff = model.alwaysOffDiscreteSchedule(); + ok = setSupplyAirFanOperatingModeSchedule(alwaysOff); + OS_ASSERT(ok); + } autosizeSupplyAirFlowRateDuringCoolingOperation(); autosizeSupplyAirFlowRateDuringHeatingOperation(); From 01c5f7adca9fb3ebc250e570a8eb861b1e965c7c Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Thu, 29 Sep 2022 11:51:11 +0200 Subject: [PATCH 07/10] Add model test and adjust FT to avoid unnecessary optional --- ...ZoneHVACPackagedTerminalAirConditioner.cpp | 7 +++--- ...nslateZoneHVACPackagedTerminalHeatPump.cpp | 7 +++--- ...ACPackagedTerminalAirConditioner_GTest.cpp | 22 +++++++++++++++++ ...ZoneHVACPackagedTerminalHeatPump_GTest.cpp | 24 +++++++++++++++++++ 4 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateZoneHVACPackagedTerminalAirConditioner.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateZoneHVACPackagedTerminalAirConditioner.cpp index e68fb23ef2..975d3dda6c 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateZoneHVACPackagedTerminalAirConditioner.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateZoneHVACPackagedTerminalAirConditioner.cpp @@ -359,10 +359,9 @@ namespace energyplus { // SupplyAirFanOperatingModeScheduleName - if (boost::optional schedule = modelObject.supplyAirFanOperatingModeSchedule()) { - if (boost::optional _schedule = translateAndMapModelObject(schedule.get())) { - idfObject.setString(ZoneHVAC_PackagedTerminalAirConditionerFields::SupplyAirFanOperatingModeScheduleName, _schedule->name().get()); - } + Schedule fanOpSchedule = modelObject.supplyAirFanOperatingModeSchedule(); + if (boost::optional _schedule = translateAndMapModelObject(fanOpSchedule)) { + idfObject.setString(ZoneHVAC_PackagedTerminalAirConditionerFields::SupplyAirFanOperatingModeScheduleName, _schedule->name().get()); } return idfObject; diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateZoneHVACPackagedTerminalHeatPump.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateZoneHVACPackagedTerminalHeatPump.cpp index 17864f9b67..394d02a51a 100644 --- a/src/energyplus/ForwardTranslator/ForwardTranslateZoneHVACPackagedTerminalHeatPump.cpp +++ b/src/energyplus/ForwardTranslator/ForwardTranslateZoneHVACPackagedTerminalHeatPump.cpp @@ -433,10 +433,9 @@ namespace energyplus { // SupplyAirFanOperatingModeScheduleName - if (boost::optional schedule = modelObject.supplyAirFanOperatingModeSchedule()) { - if (boost::optional _schedule = translateAndMapModelObject(schedule.get())) { - idfObject.setString(ZoneHVAC_PackagedTerminalHeatPumpFields::SupplyAirFanOperatingModeScheduleName, _schedule->name().get()); - } + Schedule fanOpSchedule = modelObject.supplyAirFanOperatingModeSchedule(); + if (boost::optional _schedule = translateAndMapModelObject(fanOpSchedule)) { + idfObject.setString(ZoneHVAC_PackagedTerminalHeatPumpFields::SupplyAirFanOperatingModeScheduleName, _schedule->name().get()); } return idfObject; diff --git a/src/model/test/ZoneHVACPackagedTerminalAirConditioner_GTest.cpp b/src/model/test/ZoneHVACPackagedTerminalAirConditioner_GTest.cpp index 7c7ec66da0..e241ee6221 100644 --- a/src/model/test/ZoneHVACPackagedTerminalAirConditioner_GTest.cpp +++ b/src/model/test/ZoneHVACPackagedTerminalAirConditioner_GTest.cpp @@ -55,6 +55,8 @@ #include "../ZoneHVACPackagedTerminalAirConditioner.hpp" #include "../ZoneHVACPackagedTerminalAirConditioner_Impl.hpp" #include "../ScheduleCompact.hpp" +#include "../FanOnOff.hpp" +#include "../FanSystemModel.hpp" using namespace openstudio; @@ -264,3 +266,23 @@ TEST_F(ModelFixture, ZoneHVACPackagedTerminalAirConditioner_CoilSystemCoolingDXH model::ZoneHVACPackagedTerminalAirConditioner ptac(m, s, fan, heatingCoil, coolingCoil); } + +TEST_F(ModelFixture, ZoneHVACPackagedTerminalAirConditioner_SupplyAirFanOpSch) { + model::Model m; + model::CoilHeatingWater heatingCoil(m); + model::CoilSystemCoolingDXHeatExchangerAssisted coolingCoil(m); + model::FanConstantVolume fanCV(m); + model::FanSystemModel fanSystemModel(m); + model::FanOnOff fanOnOff(m); + auto alwaysOn = m.alwaysOnDiscreteSchedule(); + auto alwaysOff = m.alwaysOffDiscreteSchedule(); + + model::ZoneHVACPackagedTerminalAirConditioner ptacCV(m, alwaysOn, fanCV, heatingCoil, coolingCoil); + EXPECT_EQ(alwaysOn, ptacCV.supplyAirFanOperatingModeSchedule()); + + model::ZoneHVACPackagedTerminalAirConditioner ptacSystemModel(m, alwaysOn, fanSystemModel, heatingCoil, coolingCoil); + EXPECT_EQ(alwaysOff, ptacSystemModel.supplyAirFanOperatingModeSchedule()); + + model::ZoneHVACPackagedTerminalAirConditioner ptacOnOff(m, alwaysOn, fanOnOff, heatingCoil, coolingCoil); + EXPECT_EQ(alwaysOff, ptacOnOff.supplyAirFanOperatingModeSchedule()); +} diff --git a/src/model/test/ZoneHVACPackagedTerminalHeatPump_GTest.cpp b/src/model/test/ZoneHVACPackagedTerminalHeatPump_GTest.cpp index 2ec603faee..3361413692 100644 --- a/src/model/test/ZoneHVACPackagedTerminalHeatPump_GTest.cpp +++ b/src/model/test/ZoneHVACPackagedTerminalHeatPump_GTest.cpp @@ -55,6 +55,9 @@ #include "../ZoneHVACPackagedTerminalHeatPump.hpp" #include "../ZoneHVACPackagedTerminalHeatPump_Impl.hpp" #include "../ScheduleCompact.hpp" +#include "../FanOnOff.hpp" +#include "../FanSystemModel.hpp" + #include using namespace openstudio; @@ -310,3 +313,24 @@ TEST_F(ModelFixture, ZoneHVACPackagedTerminalHeatPump_CoilSystemCoolingDXHeatExc model::ZoneHVACPackagedTerminalHeatPump pthp(m, availabilitySchedule, fan, heatingCoil, coolingCoil, supplementalHeatingCoil); } + +TEST_F(ModelFixture, ZoneHVACPackagedTerminalHeatPump_SupplyAirFanOpSch) { + model::Model m; + model::CoilHeatingDXVariableSpeed heatingCoil(m); + model::CoilCoolingDXVariableSpeed coolingCoil(m); + model::CoilHeatingElectric supplementalHeatingCoil(m); + model::FanConstantVolume fanCV(m); + model::FanSystemModel fanSystemModel(m); + model::FanOnOff fanOnOff(m); + auto alwaysOn = m.alwaysOnDiscreteSchedule(); + auto alwaysOff = m.alwaysOffDiscreteSchedule(); + + model::ZoneHVACPackagedTerminalHeatPump pthpCV(m, alwaysOn, fanCV, heatingCoil, coolingCoil, supplementalHeatingCoil); + EXPECT_EQ(alwaysOn, pthpCV.supplyAirFanOperatingModeSchedule()); + + model::ZoneHVACPackagedTerminalHeatPump pthpSystemModel(m, alwaysOn, fanSystemModel, heatingCoil, coolingCoil, supplementalHeatingCoil); + EXPECT_EQ(alwaysOff, pthpSystemModel.supplyAirFanOperatingModeSchedule()); + + model::ZoneHVACPackagedTerminalHeatPump pthpOnOff(m, alwaysOn, fanOnOff, heatingCoil, coolingCoil, supplementalHeatingCoil); + EXPECT_EQ(alwaysOff, pthpOnOff.supplyAirFanOperatingModeSchedule()); +} From e56f31a6545319b63ef454ac1849719bdf73cde7 Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 30 Sep 2022 09:46:10 +0200 Subject: [PATCH 08/10] Fix #4703 - adjust VT rules for Coil:Heating:Gas:MultiStage Hotfix #4666 --- src/osversion/VersionTranslator.cpp | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/osversion/VersionTranslator.cpp b/src/osversion/VersionTranslator.cpp index 9c02012fc9..5e54027547 100644 --- a/src/osversion/VersionTranslator.cpp +++ b/src/osversion/VersionTranslator.cpp @@ -7434,15 +7434,22 @@ namespace osversion { // ------------------------------------------------ // * Availability Schedule * 2 - auto iddObject = idd_3_5_0.getObject(iddname); - IdfObject newObject(iddObject.get()); + if (!object.isEmpty(2)) { + ss << object; + } else { - if (object.isEmpty(2)) { + auto iddObject = idd_3_5_0.getObject(iddname); + IdfObject newObject(iddObject.get()); + for (size_t i = 0; i < object.numFields(); ++i) { + if ((value = object.getString(i))) { + newObject.setString(i, value.get()); + } + } newObject.setString(2, getOrCreateAlwaysDiscreteScheduleHandleStr(true)); - } - m_refactored.push_back(RefactoredObjectData(object, newObject)); - ss << newObject; + m_refactored.push_back(RefactoredObjectData(object, newObject)); + ss << newObject; + } } else if (iddname == "OS:ZoneHVAC:PackagedTerminalHeatPump") { From 171fc524dae9d978e16da8178867cd6da41e3b7d Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 30 Sep 2022 10:09:02 +0200 Subject: [PATCH 09/10] Unbreak Ubuntu --- src/osversion/test/VersionTranslator_GTest.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/osversion/test/VersionTranslator_GTest.cpp b/src/osversion/test/VersionTranslator_GTest.cpp index 89a399a866..c8193edeb4 100644 --- a/src/osversion/test/VersionTranslator_GTest.cpp +++ b/src/osversion/test/VersionTranslator_GTest.cpp @@ -2255,7 +2255,7 @@ TEST_F(OSVersionFixture, update_3_4_0_to_3_5_0_ZoneHVACPackaged) { ASSERT_TRUE(ptac.getTarget(13)); WorkspaceObject fan = ptac.getTarget(13).get(); - EXPECT_EQ(IddObjectType::OS_Fan_SystemModel, fan.iddObject().type()); + EXPECT_EQ(IddObjectType(IddObjectType::OS_Fan_SystemModel), fan.iddObject().type()); EXPECT_EQ("PTAC Fan", fan.getString(OS_Fan_SystemModelFields::Name).get()); EXPECT_EQ("Always On Discrete", fan.getString(OS_Fan_SystemModelFields::AvailabilityScheduleName).get()); EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::AirInletNodeName)); @@ -2295,7 +2295,7 @@ TEST_F(OSVersionFixture, update_3_4_0_to_3_5_0_ZoneHVACPackaged) { WorkspaceObject fan = pthp.getTarget(13).get(); // This one is all defaulted, ensure we get the SAME values - EXPECT_EQ(IddObjectType::OS_Fan_SystemModel, fan.iddObject().type()); + EXPECT_EQ(IddObjectType(IddObjectType::OS_Fan_SystemModel), fan.iddObject().type()); EXPECT_EQ("PTHP Fan", fan.getString(OS_Fan_SystemModelFields::Name).get()); EXPECT_EQ("Always On Discrete", fan.getString(OS_Fan_SystemModelFields::AvailabilityScheduleName).get()); EXPECT_TRUE(fan.isEmpty(OS_Fan_SystemModelFields::AirInletNodeName)); From 46881f69913fc01f34d37ba1dc5f9044b21a700e Mon Sep 17 00:00:00 2001 From: Julien Marrec Date: Fri, 30 Sep 2022 10:35:43 +0200 Subject: [PATCH 10/10] Use a custom build of E+ on my fork https://github.com/jmarrec/EnergyPlus/releases/tag/v22.2.0-WithIHGFix --- CMakeLists.txt | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0683de4fb5..353394a650 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,11 +191,14 @@ set(ENERGYPLUS_VERSION_MINOR 2) set(ENERGYPLUS_VERSION_PATCH 0) set(ENERGYPLUS_VERSION "${ENERGYPLUS_VERSION_MAJOR}.${ENERGYPLUS_VERSION_MINOR}.${ENERGYPLUS_VERSION_PATCH}") # Build SHA is not required to have a value, but if it does OpenStudio will require this build. -set(ENERGYPLUS_BUILD_SHA "c249759bad") +set(ENERGYPLUS_BUILD_SHA "aa78da9668") # ENERGYPLUS_RELEASE_NAME is used to locate the E+ download # from the github releases -set(ENERGYPLUS_RELEASE_NAME "v22.2.0") +set(ENERGYPLUS_RELEASE_NAME "v22.2.0-WithIHGFix") + +# TODO: Temporary change to a fork until a patched release is issued on NREL's +set(ENERGYPLUS_REPO "jmarrec") # Radiance set(RADIANCE_VERSION "5.0.a.12") @@ -579,21 +582,21 @@ endif() if(UNIX) if(APPLE) if (ARCH MATCHES "arm64") - set(ENERGYPLUS_EXPECTED_HASH 48af06ee5b4b0393444e6e57f4adadd5) + set(ENERGYPLUS_EXPECTED_HASH 35ba21891e7059987391f1ab59958025) set(ENERGYPLUS_PLATFORM "Darwin-macOS12.1-arm64") else() - set(ENERGYPLUS_EXPECTED_HASH 92a76c5d60cf91536bdeacbe780d135a) + set(ENERGYPLUS_EXPECTED_HASH 481fafde9496735d809e810bd95b720f) set(ENERGYPLUS_PLATFORM "Darwin-macOS10.15-x86_64") endif() elseif(LSB_RELEASE_ID_SHORT MATCHES "CentOS") # TODO: There aren't any redhat releases anymore, see PR #3145 too - set(ENERGYPLUS_EXPECTED_HASH ebf23ac4f54a6c4f9ac0da561de4196e) + set(ENERGYPLUS_EXPECTED_HASH ebf23ac4f54a6c4f9ac0da561de4196e) # TODO: not updated yet set(ENERGYPLUS_PLATFORM "Centos7-x86_64") else() if(LSB_RELEASE_VERSION_SHORT MATCHES "20.04") - set(ENERGYPLUS_EXPECTED_HASH f8a45aa0a01523b5f904d5c2ae8302f8) + set(ENERGYPLUS_EXPECTED_HASH fd2b9e55a15227f872601e9e57ffe819) else() # 18.04 - set(ENERGYPLUS_EXPECTED_HASH 58b8397f55c2a1ede7ed08c5892e62ed) + set(ENERGYPLUS_EXPECTED_HASH 05a97ef513fa3f2ac7678bd9eef026db) endif() set(ENERGYPLUS_PLATFORM "Linux${ENERGYPLUS_SYSTEM_VERSION}-x86_64") endif() @@ -603,7 +606,7 @@ if(UNIX) endif() if(NOT EXISTS "${PROJECT_BINARY_DIR}/${ENERGYPLUS_PATH}.tar.gz" OR NOT "${ENERGYPLUS_HASH}" MATCHES "${ENERGYPLUS_EXPECTED_HASH}") message(STATUS "Downloading EnergyPlus ${ENERGYPLUS_VERSION} (${ENERGYPLUS_PLATFORM})") - message(STATUS "https://github.com/NREL/EnergyPlus/releases/download/${ENERGYPLUS_RELEASE_NAME}/${ENERGYPLUS_PATH}.tar.gz") # TODO: Temp: custom build on my fork + message(STATUS "https://github.com/${ENERGYPLUS_REPO}/EnergyPlus/releases/download/${ENERGYPLUS_RELEASE_NAME}/${ENERGYPLUS_PATH}.tar.gz") if(LSB_RELEASE_ID_SHORT MATCHES "CentOS") file(DOWNLOAD "http://openstudio-resources.s3.amazonaws.com/dependencies/${ENERGYPLUS_PATH}.tar.gz" "${PROJECT_BINARY_DIR}/${ENERGYPLUS_PATH}.tar.gz" @@ -611,7 +614,7 @@ if(UNIX) SHOW_PROGRESS EXPECTED_MD5 ${ENERGYPLUS_EXPECTED_HASH}) else() - file(DOWNLOAD "https://github.com/NREL/EnergyPlus/releases/download/${ENERGYPLUS_RELEASE_NAME}/${ENERGYPLUS_PATH}.tar.gz" "${PROJECT_BINARY_DIR}/${ENERGYPLUS_PATH}.tar.gz" + file(DOWNLOAD "https://github.com/${ENERGYPLUS_REPO}/EnergyPlus/releases/download/${ENERGYPLUS_RELEASE_NAME}/${ENERGYPLUS_PATH}.tar.gz" "${PROJECT_BINARY_DIR}/${ENERGYPLUS_PATH}.tar.gz" INACTIVITY_TIMEOUT 300 # 5-min timeout SHOW_PROGRESS EXPECTED_MD5 ${ENERGYPLUS_EXPECTED_HASH}) @@ -625,11 +628,11 @@ elseif(WIN32) if(CMAKE_SIZEOF_VOID_P EQUAL 8) # 64 bit set(ENERGYPLUS_PATH "EnergyPlus-${ENERGYPLUS_VERSION}-${ENERGYPLUS_BUILD_SHA}-Windows-x86_64") set(ENERGYPLUS_ARCH 64) - set(ENERGYPLUS_EXPECTED_HASH c6d296be45420d6e497f33727f044676) + set(ENERGYPLUS_EXPECTED_HASH 8611314c5056abedca59144627e79078) else() set(ENERGYPLUS_PATH "EnergyPlus-${ENERGYPLUS_VERSION}-${ENERGYPLUS_BUILD_SHA}-Windows-i386") set(ENERGYPLUS_ARCH 32) - set(ENERGYPLUS_EXPECTED_HASH 68108677fceb17bd58be1c9c7a68f418) + set(ENERGYPLUS_EXPECTED_HASH 76afec50c80fc4b53f2f4da572573688) endif() if(EXISTS "${PROJECT_BINARY_DIR}/${ENERGYPLUS_PATH}.zip") file(MD5 "${PROJECT_BINARY_DIR}/${ENERGYPLUS_PATH}.zip" ENERGYPLUS_HASH) @@ -637,7 +640,7 @@ elseif(WIN32) if(NOT EXISTS "${PROJECT_BINARY_DIR}/${ENERGYPLUS_PATH}.zip" OR NOT "${ENERGYPLUS_HASH}" MATCHES "${ENERGYPLUS_EXPECTED_HASH}") message(STATUS "Downloading EnergyPlus ${ENERGYPLUS_VERSION} (${ENERGYPLUS_ARCH}-bit)") - file(DOWNLOAD "https://github.com/NREL/EnergyPlus/releases/download/${ENERGYPLUS_RELEASE_NAME}/${ENERGYPLUS_PATH}.zip" "${PROJECT_BINARY_DIR}/${ENERGYPLUS_PATH}.zip" + file(DOWNLOAD "https://github.com/${ENERGYPLUS_REPO}/EnergyPlus/releases/download/${ENERGYPLUS_RELEASE_NAME}/${ENERGYPLUS_PATH}.zip" "${PROJECT_BINARY_DIR}/${ENERGYPLUS_PATH}.zip" INACTIVITY_TIMEOUT 300 # 5 minute timeout SHOW_PROGRESS EXPECTED_MD5 ${ENERGYPLUS_EXPECTED_HASH})