Repository: NREL/OpenStudio (language: python)

Issue:
API breaking changes to consider
Enhancement Request
--------------

This is meant as a running list of API breaking changes we should consider for a future version.


## Detailed Description

### Getters returning an optional<X> when there is a default in the IDD, or when there is a Ctor harcoded value and no `reset`

- [ ] CoilCoolingDXSingleSpeed: ratedCOP, ratedEvaporatorFanPowerPerVolumeFlowRate, and others return an optional<double> when it should be a double.  The IDD has a default **AND** the ctor still hardcodes the same default... AND there isn't a `reset` function either... 
https://github.com/NREL/OpenStudio/blob/7801af2670f7fdf4f0ea71d9a3288d4bbe256065/src/model/CoilCoolingDXSingleSpeed.hpp#L92-L96
   - ratedCOP
   - ratedEvaporatorFanPowerPerVolumeFlowRate
   - nominalTimeForCondensateRemovalToBegin
   - ratioOfInitialMoistureEvaporationRateAndSteadyStateLatentCapacity
   - maximumCyclingRate
   - latentCapacityTimeConstant
   - evaporativeCondenserEffectiveness
   - crankcaseHeaterCapacity
   - maximumOutdoorDryBulbTemperatureForCrankcaseHeaterOperation
   - basinHeaterCapacity
   - basinHeaterSetpointTemperature
   - **Should we just make all these required-field so we don't need `reset` and `isDefaulted` methods?** Same for CoilCoolingDXTwoSpeed below.

- [ ] CoilCoolingDXTwoSpeed
   - ratedHighSpeedCOP
   - ratedLowSpeedCOP
   - highSpeedEvaporativeCondenserEffectiveness
   - lowSpeedEvaporativeCondenserEffectiveness
   - basinHeaterCapacity (sets a different value between ctors)
   - basinHeaterSetpointTemperature (sets a different value between ctors)

- [x] EvaporativeFluidCooler:SingleSpeed
    - performanceInputMethod (make required-field, and change boost::optional<std::string> to std::string)
    - Cf  #4642

### Others

API breaking changes to consider
Enhancement Request
--------------

This is meant as a running list of API breaking changes we should consider for a future version.


## Detailed Description

### Getters returning an optional<X> when there is a default in the IDD, or when there is a Ctor harcoded value and no `reset`

- [ ] CoilCoolingDXSingleSpeed: ratedCOP, ratedEvaporatorFanPowerPerVolumeFlowRate, and others return an optional<double> when it should be a double.  The IDD has a default **AND** the ctor still hardcodes the same default... AND there isn't a `reset` function either... 
https://github.com/NREL/OpenStudio/blob/7801af2670f7fdf4f0ea71d9a3288d4bbe256065/src/model/CoilCoolingDXSingleSpeed.hpp#L92-L96
   - ratedCOP
   - ratedEvaporatorFanPowerPerVolumeFlowRate
   - nominalTimeForCondensateRemovalToBegin
   - ratioOfInitialMoistureEvaporationRateAndSteadyStateLatentCapacity
   - maximumCyclingRate
   - latentCapacityTimeConstant
   - evaporativeCondenserEffectiveness
   - crankcaseHeaterCapacity
   - maximumOutdoorDryBulbTemperatureForCrankcaseHeaterOperation
   - basinHeaterCapacity
   - basinHeaterSetpointTemperature
   - **Should we just make all these required-field so we don't need `reset` and `isDefaulted` methods?** Same for CoilCoolingDXTwoSpeed below.

- [ ] CoilCoolingDXTwoSpeed
   - ratedHighSpeedCOP
   - ratedLowSpeedCOP
   - highSpeedEvaporativeCondenserEffectiveness
   - lowSpeedEvaporativeCondenserEffectiveness
   - basinHeaterCapacity (sets a different value between ctors)
   - basinHeaterSetpointTemperature (sets a different value between ctors)

- [x] EvaporativeFluidCooler:SingleSpeed
    - performanceInputMethod (make required-field, and change boost::optional<std::string> to std::string)
    - Cf  #4642

### Others



Discussion / hints:

Fix patch:
diff --git a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_4_1_TBD.md b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_4_1_TBD.md
index 4f82839e709..6b5d9e10755 100644
--- a/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_4_1_TBD.md
+++ b/developer/doc/ReleaseNotes/OpenStudio_Release_Notes_3_4_1_TBD.md
@@ -70,6 +70,8 @@ You can also refer to the [OpenStudio SDK Python Binding Version Compatibility M
 
 * [#4616](https://github.com/NREL/OpenStudio/pull/4616) - Addresses #4611, allow non-Quadratic curves for the EIR-f-PLR for the Chiller:Electric:EIR object
     * `Chiller:Electric:EIR` has a few API-breaking changes related to its Curves. The types for the constructor, getters and setters used to be explicit (eg: `CurveBiquadratic`): it is now the base class, more generic, `Curve` type for added flexibility.
+* [#4642](https://github.com/NREL/OpenStudio/pull/4642) - Addresses #4575, API change for EvaporativeCoolerFluid:SingleSpeed
+    * `EvaporativeCoolerFluid:SingleSpeed` has an API-breaking change related to its `performanceInputMethod` getter. It is now a required field that returns `std::string` instead of `boost::optional<std::string>`.
 
 
 ## Minor changes and bug fixes
diff --git a/resources/energyplus/ProposedEnergy+.idd b/resources/energyplus/ProposedEnergy+.idd
index 6677c432ede..7e1b94767e3 100644
--- a/resources/energyplus/ProposedEnergy+.idd
+++ b/resources/energyplus/ProposedEnergy+.idd
@@ -45957,6 +45957,7 @@ EvaporativeFluidCooler:SingleSpeed,
        \minimum> 0.0
        \ip-units gal/min
   A4 , \field Performance Input Method
+       \required-field
        \type choice
        \key UFactorTimesAreaAndDesignWaterFlowRate
        \key StandardDesignCapacity
diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd
index ad99daf1db9..351fb03aea3 100644
--- a/resources/model/OpenStudio.idd
+++ b/resources/model/OpenStudio.idd
@@ -21593,6 +21593,7 @@ OS:EvaporativeFluidCooler:SingleSpeed,
        \minimum> 0.0
        \ip-units gal/min
   A5 , \field Performance Input Method
+       \required-field
        \type Choice
        \key UFactorTimesAreaAndDesignWaterFlowRate
        \key StandardDesignCapacity
diff --git a/src/model/EvaporativeFluidCoolerSingleSpeed.cpp b/src/model/EvaporativeFluidCoolerSingleSpeed.cpp
index 02f41ac7d54..d0cbdd0691a 100644
--- a/src/model/EvaporativeFluidCoolerSingleSpeed.cpp
+++ b/src/model/EvaporativeFluidCoolerSingleSpeed.cpp
@@ -165,8 +165,10 @@ namespace model {
       return value.get();
     }
 
-    boost::optional<std::string> EvaporativeFluidCoolerSingleSpeed_Impl::performanceInputMethod() const {
-      return getString(OS_EvaporativeFluidCooler_SingleSpeedFields::PerformanceInputMethod, true);
+    std::string EvaporativeFluidCoolerSingleSpeed_Impl::performanceInputMethod() const {
+      boost::optional<std::string> value = getString(OS_EvaporativeFluidCooler_SingleSpeedFields::PerformanceInputMethod, true);
+      OS_ASSERT(value);
+      return value.get();
     }
 
     boost::optional<double> EvaporativeFluidCoolerSingleSpeed_Impl::standardDesignCapacity() const {
@@ -315,22 +317,11 @@ namespace model {
       return result;
     }
 
-    bool EvaporativeFluidCoolerSingleSpeed_Impl::setPerformanceInputMethod(boost::optional<std::string> performanceInputMethod) {
-      bool result(false);
-      if (performanceInputMethod) {
-        result = setString(OS_EvaporativeFluidCooler_SingleSpeedFields::PerformanceInputMethod, performanceInputMethod.get());
-      } else {
-        resetPerformanceInputMethod();
-        result = true;
-      }
+    bool EvaporativeFluidCoolerSingleSpeed_Impl::setPerformanceInputMethod(const std::string& performanceInputMethod) {
+      bool result = setString(OS_EvaporativeFluidCooler_SingleSpeedFields::PerformanceInputMethod, performanceInputMethod);
       return result;
     }
 
-    void EvaporativeFluidCoolerSingleSpeed_Impl::resetPerformanceInputMethod() {
-      bool result = setString(OS_EvaporativeFluidCooler_SingleSpeedFields::PerformanceInputMethod, "");
-      OS_ASSERT(result);
-    }
-
     bool EvaporativeFluidCoolerSingleSpeed_Impl::setStandardDesignCapacity(boost::optional<double> standardDesignCapacity) {
       bool result(false);
       if (standardDesignCapacity) {
@@ -637,10 +628,13 @@ namespace model {
     : StraightComponent(EvaporativeFluidCoolerSingleSpeed::iddObjectType(), model) {
     OS_ASSERT(getImpl<detail::EvaporativeFluidCoolerSingleSpeed_Impl>());
 
+    bool ok = true;
     autosizeDesignAirFlowRate();
     autosizeFanPoweratDesignAirFlowRate();
-    setDesignSprayWaterFlowRate(0.03);
-    setPerformanceInputMethod("UFactorTimesAreaAndDesignWaterFlowRate");
+    ok = setDesignSprayWaterFlowRate(0.03);
+    OS_ASSERT(ok);
+    ok = setPerformanceInputMethod("UFactorTimesAreaAndDesignWaterFlowRate");
+    OS_ASSERT(ok);
     resetStandardDesignCapacity();
     autosizeUfactorTimesAreaValueatDesignAirFlowRate();
     autosizeDesignWaterFlowRate();
@@ -650,10 +644,13 @@ namespace model {
     resetDesignEnteringAirWetbulbTemperature();
     setCapacityControl("FanCycling");
     setSizingFactor(1.0);
-    setEvaporationLossMode("SaturatedExit");
+    ok = setEvaporationLossMode("SaturatedExit");
+    OS_ASSERT(ok);
     setDriftLossPercent(0.008);
-    setBlowdownCalculationMode("ConcentrationRatio");
-    setBlowdownConcentrationRatio(3.0);
+    ok = setBlowdownCalculationMode("ConcentrationRatio");
+    OS_ASSERT(ok);
+    ok = setBlowdownConcentrationRatio(3.0);
+    OS_ASSERT(ok);
     resetBlowdownMakeupWaterUsageSchedule();
     setString(OS_EvaporativeFluidCooler_SingleSpeedFields::SupplyWaterStorageTankName, "");
   }
@@ -700,7 +697,7 @@ namespace model {
     return getImpl<detail::EvaporativeFluidCoolerSingleSpeed_Impl>()->designSprayWaterFlowRate();
   }
 
-  boost::optional<std::string> EvaporativeFluidCoolerSingleSpeed::performanceInputMethod() const {
+  std::string EvaporativeFluidCoolerSingleSpeed::performanceInputMethod() const {
     return getImpl<detail::EvaporativeFluidCoolerSingleSpeed_Impl>()->performanceInputMethod();
   }
 
@@ -816,14 +813,10 @@ namespace model {
     return getImpl<detail::EvaporativeFluidCoolerSingleSpeed_Impl>()->setDesignSprayWaterFlowRate(designSprayWaterFlowRate);
   }
 
-  bool EvaporativeFluidCoolerSingleSpeed::setPerformanceInputMethod(std::string performanceInputMethod) {
+  bool EvaporativeFluidCoolerSingleSpeed::setPerformanceInputMethod(const std::string& performanceInputMethod) {
     return getImpl<detail::EvaporativeFluidCoolerSingleSpeed_Impl>()->setPerformanceInputMethod(performanceInputMethod);
   }
 
-  void EvaporativeFluidCoolerSingleSpeed::resetPerformanceInputMethod() {
-    getImpl<detail::EvaporativeFluidCoolerSingleSpeed_Impl>()->resetPerformanceInputMethod();
-  }
-
   bool EvaporativeFluidCoolerSingleSpeed::setStandardDesignCapacity(double standardDesignCapacity) {
     return getImpl<detail::EvaporativeFluidCoolerSingleSpeed_Impl>()->setStandardDesignCapacity(standardDesignCapacity);
   }
diff --git a/src/model/EvaporativeFluidCoolerSingleSpeed.hpp b/src/model/EvaporativeFluidCoolerSingleSpeed.hpp
index d93472d6ad6..84056fdf09e 100644
--- a/src/model/EvaporativeFluidCoolerSingleSpeed.hpp
+++ b/src/model/EvaporativeFluidCoolerSingleSpeed.hpp
@@ -81,7 +81,7 @@ namespace model {
 
     double designSprayWaterFlowRate() const;
 
-    boost::optional<std::string> performanceInputMethod() const;
+    std::string performanceInputMethod() const;
 
     boost::optional<double> standardDesignCapacity() const;
 
@@ -143,9 +143,7 @@ namespace model {
 
     bool setDesignSprayWaterFlowRate(double designSprayWaterFlowRate);
 
-    bool setPerformanceInputMethod(std::string performanceInputMethod);
-
-    void resetPerformanceInputMethod();
+    bool setPerformanceInputMethod(const std::string& performanceInputMethod);
 
     bool setStandardDesignCapacity(double standardDesignCapacity);
 
diff --git a/src/model/EvaporativeFluidCoolerSingleSpeed_Impl.hpp b/src/model/EvaporativeFluidCoolerSingleSpeed_Impl.hpp
index b1aba3fe78d..0b02b0653f7 100644
--- a/src/model/EvaporativeFluidCoolerSingleSpeed_Impl.hpp
+++ b/src/model/EvaporativeFluidCoolerSingleSpeed_Impl.hpp
@@ -86,7 +86,7 @@ namespace model {
 
       double designSprayWaterFlowRate() const;
 
-      boost::optional<std::string> performanceInputMethod() const;
+      std::string performanceInputMethod() const;
 
       boost::optional<double> standardDesignCapacity() const;
 
@@ -163,9 +163,7 @@ namespace model {
 
       bool setDesignSprayWaterFlowRate(double designSprayWaterFlowRate);
 
-      bool setPerformanceInputMethod(boost::optional<std::string> performanceInputMethod);
-
-      void resetPerformanceInputMethod();
+      bool setPerformanceInputMethod(const std::string& performanceInputMethod);
 
       void resetOutdoorAirInletNode();
 


Test patch:
diff --git a/src/model/test/EvaporativeFluidCoolerSingleSpeed_GTest.cpp b/src/model/test/EvaporativeFluidCoolerSingleSpeed_GTest.cpp
index d58772f54e3..167308c34c7 100644
--- a/src/model/test/EvaporativeFluidCoolerSingleSpeed_GTest.cpp
+++ b/src/model/test/EvaporativeFluidCoolerSingleSpeed_GTest.cpp
@@ -55,6 +55,7 @@
 #include "../ScheduleCompact.hpp"
 #include "../ScheduleCompact_Impl.hpp"
 
+using namespace openstudio;
 using namespace openstudio::model;
 
 TEST_F(ModelFixture, EvaporativeFluidCoolerSingleSpeed_DefaultConstructor) {
@@ -69,7 +70,7 @@ TEST_F(ModelFixture, EvaporativeFluidCoolerSingleSpeed_DefaultConstructor) {
       EXPECT_TRUE(testObject.isDesignAirFlowRateAutosized());
       EXPECT_TRUE(testObject.isFanPoweratDesignAirFlowRateAutosized());
       EXPECT_DOUBLE_EQ(0.03, testObject.designSprayWaterFlowRate());
-      EXPECT_EQ("UFactorTimesAreaAndDesignWaterFlowRate", testObject.performanceInputMethod().get());
+      EXPECT_EQ("UFactorTimesAreaAndDesignWaterFlowRate", testObject.performanceInputMethod());
       EXPECT_FALSE(testObject.standardDesignCapacity());
       EXPECT_TRUE(testObject.isUfactorTimesAreaValueatDesignAirFlowRateAutosized());
       EXPECT_TRUE(testObject.isDesignWaterFlowRateAutosized());
@@ -212,7 +213,7 @@ TEST_F(ModelFixture, EvaporativeFluidCoolerSingleSpeed_CloneOneModelWithDefaultD
   EXPECT_TRUE(testObjectClone.isDesignAirFlowRateAutosized());
   EXPECT_TRUE(testObjectClone.isFanPoweratDesignAirFlowRateAutosized());
   EXPECT_DOUBLE_EQ(0.03, testObjectClone.designSprayWaterFlowRate());
-  EXPECT_EQ("UFactorTimesAreaAndDesignWaterFlowRate", testObjectClone.performanceInputMethod().get());
+  EXPECT_EQ("UFactorTimesAreaAndDesignWaterFlowRate", testObjectClone.performanceInputMethod());
   EXPECT_FALSE(testObjectClone.standardDesignCapacity());
   EXPECT_TRUE(testObjectClone.isUfactorTimesAreaValueatDesignAirFlowRateAutosized());
   EXPECT_TRUE(testObjectClone.isDesignWaterFlowRateAutosized());
@@ -243,7 +244,7 @@ TEST_F(ModelFixture, EvaporativeFluidCoolerSingleSpeed_CloneOneModelWithCustomDa
   EXPECT_DOUBLE_EQ(999.0, testObjectClone.designAirFlowRate().get());
   EXPECT_DOUBLE_EQ(999.0, testObjectClone.fanPoweratDesignAirFlowRate().get());
   EXPECT_DOUBLE_EQ(999.0, testObjectClone.designSprayWaterFlowRate());
-  EXPECT_EQ("StandardDesignCapacity", testObjectClone.performanceInputMethod().get());
+  EXPECT_EQ("StandardDesignCapacity", testObjectClone.performanceInputMethod());
   EXPECT_DOUBLE_EQ(1.0, testObjectClone.standardDesignCapacity().get());
 }
 
@@ -259,7 +260,7 @@ TEST_F(ModelFixture, EvaporativeFluidCoolerSingleSpeed_CloneTwoModelsWithDefault
   EXPECT_TRUE(testObjectClone2.isDesignAirFlowRateAutosized());
   EXPECT_TRUE(testObjectClone2.isFanPoweratDesignAirFlowRateAutosized());
   EXPECT_DOUBLE_EQ(0.03, testObjectClone2.designSprayWaterFlowRate());
-  EXPECT_EQ("UFactorTimesAreaAndDesignWaterFlowRate", testObjectClone2.performanceInputMethod().get());
+  EXPECT_EQ("UFactorTimesAreaAndDesignWaterFlowRate", testObjectClone2.performanceInputMethod());
   EXPECT_FALSE(testObjectClone2.standardDesignCapacity());
   EXPECT_TRUE(testObjectClone2.isUfactorTimesAreaValueatDesignAirFlowRateAutosized());
   EXPECT_TRUE(testObjectClone2.isDesignWaterFlowRateAutosized());
@@ -332,13 +333,13 @@ TEST_F(ModelFixture, EvaporativeFluidCoolerSingleSpeed_PerformanceInputMethod) {
   Model model;
   EvaporativeFluidCoolerSingleSpeed testObject = EvaporativeFluidCoolerSingleSpeed(model);
 
-  EXPECT_EQ("UFactorTimesAreaAndDesignWaterFlowRate", testObject.performanceInputMethod().get());
+  EXPECT_EQ("UFactorTimesAreaAndDesignWaterFlowRate", testObject.performanceInputMethod());
 
   testObject.setPerformanceInputMethod("StandardDesignCapacity");
-  EXPECT_EQ("StandardDesignCapacity", testObject.performanceInputMethod().get());
+  EXPECT_EQ("StandardDesignCapacity", testObject.performanceInputMethod());
 
   testObject.setPerformanceInputMethod("UserSpecifiedDesignCapacity");
-  EXPECT_EQ("UserSpecifiedDesignCapacity", testObject.performanceInputMethod().get());
+  EXPECT_EQ("UserSpecifiedDesignCapacity", testObject.performanceInputMethod());
 
   EXPECT_FALSE(testObject.setPerformanceInputMethod("Not Valid Entry"));
 }
diff --git a/src/model/test/EvaporativeFluidCoolerTwoSpeed_GTest.cpp b/src/model/test/EvaporativeFluidCoolerTwoSpeed_GTest.cpp
index 3b29f24dd1e..4e66f96aec8 100644
--- a/src/model/test/EvaporativeFluidCoolerTwoSpeed_GTest.cpp
+++ b/src/model/test/EvaporativeFluidCoolerTwoSpeed_GTest.cpp
@@ -36,3 +36,40 @@
 
 using namespace openstudio;
 using namespace openstudio::model;
+
+TEST_F(ModelFixture, EvaporativeFluidCoolerTwoSpeed_DefaultConstructor) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  ASSERT_EXIT(
+    {
+      Model model;
+
+      EvaporativeFluidCoolerTwoSpeed testObject = EvaporativeFluidCoolerTwoSpeed(model);
+
+      EXPECT_TRUE(testObject.isHighFanSpeedAirFlowRateAutosized());
+      EXPECT_TRUE(testObject.isHighFanSpeedFanPowerAutosized());
+      EXPECT_TRUE(testObject.isLowFanSpeedAirFlowRateAutosized());
+      EXPECT_DOUBLE_EQ(0.5, testObject.lowFanSpeedAirFlowRateSizingFactor());
+      EXPECT_TRUE(testObject.isLowFanSpeedFanPowerAutosized());
+      EXPECT_DOUBLE_EQ(0.5, testObject.lowFanSpeedFanPowerSizingFactor());
+      EXPECT_DOUBLE_EQ(0.002208, testObject.designSprayWaterFlowRate());
+      EXPECT_EQ("UFactorTimesAreaAndDesignWaterFlowRate", testObject.performanceInputMethod());
+      EXPECT_DOUBLE_EQ(1.25, testObject.heatRejectionCapacityandNominalCapacitySizingRatio());
+      EXPECT_TRUE(testObject.isLowSpeedUserSpecifiedDesignCapacityAutosized());
+      EXPECT_TRUE(testObject.isLowSpeedStandardDesignCapacityAutosized());
+      EXPECT_DOUBLE_EQ(0.5, testObject.lowSpeedStandardCapacitySizingFactor());
+      EXPECT_TRUE(testObject.isHighFanSpeedUfactorTimesAreaValueAutosized());
+      EXPECT_TRUE(testObject.isLowFanSpeedUfactorTimesAreaValueAutosized());
+      EXPECT_DOUBLE_EQ(0.6, testObject.lowFanSpeedUFactorTimesAreaSizingFactor());
+      EXPECT_DOUBLE_EQ(0.5, testObject.lowSpeedUserSpecifiedDesignCapacitySizingFactor());
+      EXPECT_DOUBLE_EQ(1.0, testObject.highSpeedSizingFactor());
+      EXPECT_EQ("SaturatedExit", testObject.evaporationLossMode());
+      EXPECT_DOUBLE_EQ(0.008, testObject.driftLossPercent());
+      EXPECT_EQ("ConcentrationRatio", testObject.blowdownCalculationMode());
+      EXPECT_DOUBLE_EQ(3.0, testObject.blowdownConcentrationRatio());
+      EXPECT_TRUE(testObject.isDesignWaterFlowRateAutosized());
+
+      exit(0);
+    },
+    ::testing::ExitedWithCode(0), "");
+}