Repository: NREL/OpenStudio (language: python)

Issue:
Fix #4926 - WindowPropertyFrameAndDivider: "Outside Reveal Depth" not forward translated 
Pull request overview
---------------------

 - Fixes #4926

@brgix FYI

### Pull Request Author

<!--- Add to this list or remove from it as applicable.  This is a simple templated set of guidelines. -->

 - [ ] Model API Changes / Additions
 - [ ] Any new or modified fields have been implemented in the EnergyPlus ForwardTranslator (and ReverseTranslator as appropriate)
 - [ ] Model API methods are tested (in `src/model/test`)
 - [ ] EnergyPlus ForwardTranslator Tests (in `src/energyplus/Test`)
 - [ ] If a new object or method, added a test in NREL/OpenStudio-resources: Add Link
 - [ ] If needed, added VersionTranslation rules for the objects (`src/osversion/VersionTranslator.cpp`)
 - [ ] Verified that C# bindings built fine on Windows, partial classes used as needed, etc.
 - [ ] All new and existing tests passes
 - [ ] If methods have been deprecated, update rest of code to use the new methods

**Labels:**

 - [ ] If change to an IDD file, add the label `IDDChange`
 - [ ] If breaking existing API, add the label `APIChange`
 - [ ] If deemed ready, add label `Pull Request - Ready for CI` so that CI builds your PR

### Review Checklist

This will not be exhaustively relevant to every PR.
 - [ ] Perform a Code Review on GitHub
 - [ ] Code Style, strip trailing whitespace, etc.
 - [ ] All related changes have been implemented: model changes, model tests, FT changes, FT tests, VersionTranslation, OS App
 - [ ] Labeling is ok
 - [ ] If defect, verify by running develop branch and reproducing defect, then running PR and reproducing fix
 - [ ] If feature, test running new feature, try creative ways to break it
 - [ ] CI status: all green or justified

Frame & Divider "Outside Reveal Depth" not forward translated
Issue overview
--------------
In EnergyPlus, fenestration [outside reveals](https://bigladdersoftware.com/epx/docs/23-1/input-output-reference/group-thermal-zone-description-geometry.html#windowpropertyframeanddivider) (search for _Reveal Surface Fields_) are initiated by an _offset_ (or _setback_) of _SubSurface_ vertices vs base surface plane (e.g. a 4-in setback between brick cladding and glazing). As discussed [here](https://unmethours.com/question/94578/outside-reveal-depth-field-not-working-in-oswindowpropertyframeanddivider/), there are no observed issues with EnergyPlus' handling of _Frame and Dividers_ combined with **outside reveal** vertex _setbacks_ (when done by hand).

OpenStudio instead offers an additional _WindowPropertyFrameAndDivider_ field, [Outside Reveal Depth](https://s3.amazonaws.com/openstudio-sdk-documentation/cpp/OpenStudio-3.6.1-doc/model/html/classopenstudio_1_1model_1_1_window_property_frame_and_divider.html#aa54a833a5c8898e00819494329595d0f). The suggestion in this _Openstudio Application_ [tutorial](https://openstudiocoalition.org/tutorials/tutorial_windowproperty_frameanddivider/) (and in UMH posts) is that _SubSurface_ vertex _setbacks_ should be completed automatically during forward translation. This does not seem to be the case.

The issue could have been filed under _OpenStudio Application_'s GitHub [issues](https://github.com/openstudiocoalition/OpenStudioApplication/issues), but it seems preferable to submit an issue here given OpenStudio's _Outside Reveal Depth_ attribute.

## Current Behavior
_SubSurface_ vertices are not **offset** (vs base surface plane) during forward translation, when linked to a _WindowPropertyFrameAndDivider_ holding a non-zero _Outside Reveal Depth_.

## Expected Behavior
_SubSurface_ vertices should be **offset** automatically during forward translation.

## Steps to Reproduce
1. Recover any OpenStudio model
2. Using the SDK, add a _WindowPropertyFrameAndDivider_, link it to one (or all) glazed sub surface(s) in the model
3. Ensure the _WindowPropertyFrameAndDivider_ has a non-zero _Outside Reveal Depth_ (e.g. 0.1m or even 0.5m)
4. Forward translate (e.g. using the CLI, the App)
5. Recover generated IDF - note if _SubSurface_ planes are the same as their base surfaces

## Details
The concept of an **offset** appears in 3 places in the OpenStudio _SubSurface_ forward translation source code:
- initiated as a zero-length 3D [vector](https://github.com/NREL/OpenStudio/blob/82304dcc76303e8a4c49c87500dc64ffe65248f5/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp#L46)
- in principle, [offsets](https://github.com/NREL/OpenStudio/blob/82304dcc76303e8a4c49c87500dc64ffe65248f5/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp#L56) _SubSurface_ vertices (yet as a zero-length vector, would have no effect)
- calculates a new [offset](https://github.com/NREL/OpenStudio/blob/82304dcc76303e8a4c49c87500dc64ffe65248f5/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp#L143) vector by applying the _Outside Reveal Depth_ attribute to the _SubSurface_ outward normal (yet this **offset** doesn't seem to be reused elsewhere)

The _Outside Reveal Depth_ implementation seems _initiated_, yet _incomplete_. Apologies in advance if I'm missing something obvious.

## Possible Solution
Complete the implementation.

### Environment
 - MacOS Ventura 13.4, OpenStudio Application 1.5 (SDK 3.5.1)

### Context
Linked to this UMH [post](https://unmethours.com/question/94578/outside-reveal-depth-field-not-working-in-oswindowpropertyframeanddivider/). Thanks to @macumber for the source code links.

Frame & Divider "Outside Reveal Depth" not forward translated
Issue overview
--------------
In EnergyPlus, fenestration [outside reveals](https://bigladdersoftware.com/epx/docs/23-1/input-output-reference/group-thermal-zone-description-geometry.html#windowpropertyframeanddivider) (search for _Reveal Surface Fields_) are initiated by an _offset_ (or _setback_) of _SubSurface_ vertices vs base surface plane (e.g. a 4-in setback between brick cladding and glazing). As discussed [here](https://unmethours.com/question/94578/outside-reveal-depth-field-not-working-in-oswindowpropertyframeanddivider/), there are no observed issues with EnergyPlus' handling of _Frame and Dividers_ combined with **outside reveal** vertex _setbacks_ (when done by hand).

OpenStudio instead offers an additional _WindowPropertyFrameAndDivider_ field, [Outside Reveal Depth](https://s3.amazonaws.com/openstudio-sdk-documentation/cpp/OpenStudio-3.6.1-doc/model/html/classopenstudio_1_1model_1_1_window_property_frame_and_divider.html#aa54a833a5c8898e00819494329595d0f). The suggestion in this _Openstudio Application_ [tutorial](https://openstudiocoalition.org/tutorials/tutorial_windowproperty_frameanddivider/) (and in UMH posts) is that _SubSurface_ vertex _setbacks_ should be completed automatically during forward translation. This does not seem to be the case.

The issue could have been filed under _OpenStudio Application_'s GitHub [issues](https://github.com/openstudiocoalition/OpenStudioApplication/issues), but it seems preferable to submit an issue here given OpenStudio's _Outside Reveal Depth_ attribute.

## Current Behavior
_SubSurface_ vertices are not **offset** (vs base surface plane) during forward translation, when linked to a _WindowPropertyFrameAndDivider_ holding a non-zero _Outside Reveal Depth_.

## Expected Behavior
_SubSurface_ vertices should be **offset** automatically during forward translation.

## Steps to Reproduce
1. Recover any OpenStudio model
2. Using the SDK, add a _WindowPropertyFrameAndDivider_, link it to one (or all) glazed sub surface(s) in the model
3. Ensure the _WindowPropertyFrameAndDivider_ has a non-zero _Outside Reveal Depth_ (e.g. 0.1m or even 0.5m)
4. Forward translate (e.g. using the CLI, the App)
5. Recover generated IDF - note if _SubSurface_ planes are the same as their base surfaces

## Details
The concept of an **offset** appears in 3 places in the OpenStudio _SubSurface_ forward translation source code:
- initiated as a zero-length 3D [vector](https://github.com/NREL/OpenStudio/blob/82304dcc76303e8a4c49c87500dc64ffe65248f5/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp#L46)
- in principle, [offsets](https://github.com/NREL/OpenStudio/blob/82304dcc76303e8a4c49c87500dc64ffe65248f5/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp#L56) _SubSurface_ vertices (yet as a zero-length vector, would have no effect)
- calculates a new [offset](https://github.com/NREL/OpenStudio/blob/82304dcc76303e8a4c49c87500dc64ffe65248f5/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp#L143) vector by applying the _Outside Reveal Depth_ attribute to the _SubSurface_ outward normal (yet this **offset** doesn't seem to be reused elsewhere)

The _Outside Reveal Depth_ implementation seems _initiated_, yet _incomplete_. Apologies in advance if I'm missing something obvious.

## Possible Solution
Complete the implementation.

### Environment
 - MacOS Ventura 13.4, OpenStudio Application 1.5 (SDK 3.5.1)

### Context
Linked to this UMH [post](https://unmethours.com/question/94578/outside-reveal-depth-field-not-working-in-oswindowpropertyframeanddivider/). Thanks to @macumber for the source code links.

Some copy constructors aren't declared in SWIG
Issue overview
--------------

@shorowit reported this change of behavior between 3.6.1 and 3.7.0-alpha. This used to work in 3.6.1, and now the copy constructor isn't swigg'ed.

```
[6] 3_7_0(main)> OpenStudio::Point3d.new(OpenStudio::Point3d.new(0, 0, 0))
ArgumentError: Wrong arguments for overloaded method 'Point3d.new'.
Possible C/C++ prototypes are:
    Point3d.new()
    Point3d.new(double x, double y, double z)

from (pry):6:in `initialize'
[7] 3_7_0(main)> OpenStudio::Vector3d.new(OpenStudio::Vector3d.new(0, 0, 0))
ArgumentError: Wrong arguments for overloaded method 'Vector3d.new'.
Possible C/C++ prototypes are:
    Vector3d.new()
    Vector3d.new(double x, double y, double z)
```

## Possible Solution

**This is due to this commit of mine, where I applied Rule of 1 in the C++ code, not realizing that this had an impact on SWIG**: https://github.com/NREL/OpenStudio/commit/565bea0567882199b86a0e2b4376fdb10130d27f#diff-9ef35a3df57f646ab394775dab1b9d3212fd52c1d5bbce281c2585c6df05a952

For these geometry classes, it's probably a good idea to ensure that the copy ctor is swigged.

## Details

### Environment

Some additional details about your environment for this issue (if relevant):
 - Platform (Operating system, version): all
 - Version of OpenStudio (if using an intermediate build, include SHA): 3.7.0-alpha, 0ab02805c62a5f459e669bf3f4c65c95a1d8eed7

### Context

https://github.com/NREL/OpenStudio-HPXML/blob/5e218b5d148effc86f12cbdeb682c21fe8a63db1/BuildResidentialHPXML/resources/geometry.rb#L2360

```
length = OpenStudio::Vector3d.new(point_one - point_two).length
```


Discussion / hints:

@brgix Thanks a lot for the detailed report. This is a regression introduced at 3.5.0, and it's my fault, sorry. https://github.com/NREL/OpenStudio/commit/bb0ca64300b0c395a02c46ae9a2884340fd4efce
@brgix Thanks a lot for the detailed report. This is a regression introduced at 3.5.0, and it's my fault, sorry. https://github.com/NREL/OpenStudio/commit/bb0ca64300b0c395a02c46ae9a2884340fd4efce


Fix patch:
diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd
index e61ea1ba459..704d337481b 100644
--- a/resources/model/OpenStudio.idd
+++ b/resources/model/OpenStudio.idd
@@ -25351,7 +25351,7 @@ OS:PlantComponent:TemperatureSource,
        \note Used if Temperature Specification Type = Scheduled
 
 OS:LoadProfile:Plant,
-       \min-fields 7
+       \min-fields 10
   A1 , \field Handle
        \type handle
        \required-field
@@ -25376,10 +25376,25 @@ OS:LoadProfile:Plant,
        \type real
        \units m3/s
        \ip-units gal/min
-  A6 ; \field Flow Rate Fraction Schedule Name
+  A6 , \field Flow Rate Fraction Schedule Name
        \required-field
        \type object-list
        \object-list ScheduleNames
+  A7 , \field Plant Loop Fluid Type
+       \type choice
+       \key Water
+       \key Steam
+       \required-field
+  N2 , \field Degree of SubCooling
+       \note This field is used only when Plant Loop Fluid Type=Steam.
+       \units C
+       \minimum 1.0
+       \required-field
+  N3 ; \field Degree of Loop SubCooling
+       \note This field is used only when Plant Loop Fluid Type=Steam.
+       \units C
+       \minimum 10.0
+       \required-field
 
 OS:Pump:ConstantSpeed,
        \memo This pump model is described in the ASHRAE secondary HVAC toolkit.
diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt
index c6430334ea3..7e4caa817e2 100644
--- a/src/energyplus/CMakeLists.txt
+++ b/src/energyplus/CMakeLists.txt
@@ -748,6 +748,7 @@ set(${target_name}_test_src
   Test/LifeCycleCost_GTest.cpp
   Test/LifeCycleCostParameters_GTest.cpp
   Test/Lights_GTest.cpp
+  Test/LoadProfilePlant_GTest.cpp
   Test/Luminaire_GTest.cpp
   Test/MaterialPropertyMoisturePenetrationDepthSettings_GTest.cpp
   Test/MaterialPropertyPhaseChange_GTest.cpp
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateLoadProfilePlant.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateLoadProfilePlant.cpp
index 381a72a4e9c..9ee05cc307c 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateLoadProfilePlant.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateLoadProfilePlant.cpp
@@ -58,6 +58,15 @@ namespace energyplus {
       }
     }
 
+    // PlantLoopFluidType
+    idfObject.setString(LoadProfile_PlantFields::PlantLoopFluidType, modelObject.plantLoopFluidType());
+
+    // DegreeofSubCooling
+    idfObject.setDouble(LoadProfile_PlantFields::DegreeofSubCooling, modelObject.degreeofSubCooling());
+
+    // DegreeofLoopSubCooling
+    idfObject.setDouble(LoadProfile_PlantFields::DegreeofLoopSubCooling, modelObject.degreeofLoopSubCooling());
+
     return idfObject;
   }
 
diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp
index e71ab93ef2d..67a32e3fcd9 100644
--- a/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp
+++ b/src/energyplus/ForwardTranslator/ForwardTranslateSubSurface.cpp
@@ -43,8 +43,17 @@ namespace energyplus {
 
     idfObject.setString(FenestrationSurface_DetailedFields::Name, modelObject.name().get());
 
-    openstudio::Vector3d offset(0, 0, 0);
     idfObject.clearExtensibleGroups();
+
+    openstudio::Vector3d offset(0, 0, 0);
+    boost::optional<WindowPropertyFrameAndDivider> frameAndDivider = modelObject.windowPropertyFrameAndDivider();
+    if (frameAndDivider) {
+      if (!frameAndDivider->isOutsideRevealDepthDefaulted()) {
+        offset = -frameAndDivider->outsideRevealDepth() * modelObject.outwardNormal();
+      }
+      idfObject.setString(FenestrationSurface_DetailedFields::FrameandDividerName, frameAndDivider->name().get());
+    }
+
     for (const Point3d& point : modelObject.vertices()) {
       IdfExtensibleGroup group = idfObject.pushExtensibleGroup();
       if (group.empty()) {
@@ -53,7 +62,7 @@ namespace energyplus {
         return boost::none;
       }
 
-      Point3d newPoint = point + offset;
+      const Point3d newPoint = point + offset;
 
       group.setDouble(0, newPoint.x());
       group.setDouble(1, newPoint.y());
@@ -137,14 +146,6 @@ namespace energyplus {
       idfObject.setDouble(FenestrationSurface_DetailedFields::ViewFactortoGround, *viewFactortoGround);
     }
 
-    boost::optional<WindowPropertyFrameAndDivider> frameAndDivider = modelObject.windowPropertyFrameAndDivider();
-    if (frameAndDivider) {
-      if (!frameAndDivider->isOutsideRevealDepthDefaulted()) {
-        offset = -frameAndDivider->outsideRevealDepth() * modelObject.outwardNormal();
-      }
-      idfObject.setString(FenestrationSurface_DetailedFields::FrameandDividerName, frameAndDivider->name().get());
-    }
-
     if (!modelObject.isMultiplierDefaulted()) {
       idfObject.setDouble(FenestrationSurface_DetailedFields::Multiplier, modelObject.multiplier());
     }
diff --git a/src/energyplus/Test/LoadProfilePlant_GTest.cpp b/src/energyplus/Test/LoadProfilePlant_GTest.cpp
new file mode 100644
index 00000000000..34da1b8bd17
--- /dev/null
+++ b/src/energyplus/Test/LoadProfilePlant_GTest.cpp
@@ -0,0 +1,66 @@
+/***********************************************************************************************************************
+*  OpenStudio(R), Copyright (c) Alliance for Sustainable Energy, LLC.
+*  See also https://openstudio.net/license
+***********************************************************************************************************************/
+
+#include <gtest/gtest.h>
+#include "EnergyPlusFixture.hpp"
+
+#include "../ForwardTranslator.hpp"
+
+#include "../../model/Model.hpp"
+#include "../../model/LoadProfilePlant.hpp"
+#include "../../model/PlantLoop.hpp"
+#include "../../model/ScheduleConstant.hpp"
+
+#include <utilities/idd/LoadProfile_Plant_FieldEnums.hxx>
+
+#include <utilities/idd/IddEnums.hxx>
+#include "../../utilities/idf/IdfObject.hpp"
+#include "../../utilities/idf/IdfObject_Impl.hpp"
+
+#include "../../utilities/idf/WorkspaceObject.hpp"
+#include "../../utilities/idf/WorkspaceObject_Impl.hpp"
+
+using namespace openstudio::energyplus;
+using namespace openstudio::model;
+using namespace openstudio;
+
+TEST_F(EnergyPlusFixture, ForwardTranslator_LoadProfilePlant) {
+  Model m;
+
+  PlantLoop pl(m);
+  LoadProfilePlant lpp(m);
+  EXPECT_TRUE(pl.addDemandBranchForComponent(lpp));
+
+  ScheduleConstant loadSchedule(m);
+  loadSchedule.setName("Load Schedule");
+  EXPECT_TRUE(lpp.setLoadSchedule(loadSchedule));
+
+  EXPECT_TRUE(lpp.setPeakFlowRate(0.005));
+
+  ScheduleConstant flowRateFractionSchedule(m);
+  flowRateFractionSchedule.setName("Flow Rate Fraction Schedule");
+  EXPECT_TRUE(lpp.setFlowRateFractionSchedule(flowRateFractionSchedule));
+
+  EXPECT_TRUE(lpp.setPlantLoopFluidType("Steam"));
+  EXPECT_TRUE(lpp.setDegreeofSubCooling(6.0));
+  EXPECT_TRUE(lpp.setDegreeofLoopSubCooling(21.0));
+
+  ForwardTranslator ft;
+  Workspace w = ft.translateModel(m);
+
+  EXPECT_EQ(1u, w.getObjectsByType(IddObjectType::LoadProfile_Plant).size());
+
+  IdfObject idf_lpp = w.getObjectsByType(IddObjectType::LoadProfile_Plant)[0];
+
+  EXPECT_EQ(lpp.nameString(), idf_lpp.getString(LoadProfile_PlantFields::Name, false).get());
+  EXPECT_FALSE(idf_lpp.isEmpty(LoadProfile_PlantFields::InletNodeName));
+  EXPECT_FALSE(idf_lpp.isEmpty(LoadProfile_PlantFields::OutletNodeName));
+  EXPECT_EQ(loadSchedule.nameString(), idf_lpp.getString(LoadProfile_PlantFields::LoadScheduleName, false).get());
+  EXPECT_EQ(0.005, idf_lpp.getDouble(LoadProfile_PlantFields::PeakFlowRate, false).get());
+  EXPECT_EQ(flowRateFractionSchedule.nameString(), idf_lpp.getString(LoadProfile_PlantFields::FlowRateFractionScheduleName, false).get());
+  EXPECT_EQ("Steam", idf_lpp.getString(LoadProfile_PlantFields::PlantLoopFluidType, false).get());
+  EXPECT_EQ(6.0, idf_lpp.getDouble(LoadProfile_PlantFields::DegreeofSubCooling, false).get());
+  EXPECT_EQ(21.0, idf_lpp.getDouble(LoadProfile_PlantFields::DegreeofLoopSubCooling, false).get());
+}
diff --git a/src/energyplus/Test/WindowPropertyFrameAndDivider_GTest.cpp b/src/energyplus/Test/WindowPropertyFrameAndDivider_GTest.cpp
index aec81c9ac6f..450820aa52d 100644
--- a/src/energyplus/Test/WindowPropertyFrameAndDivider_GTest.cpp
+++ b/src/energyplus/Test/WindowPropertyFrameAndDivider_GTest.cpp
@@ -9,6 +9,7 @@
 #include "../ErrorFile.hpp"
 #include "../ForwardTranslator.hpp"
 #include "../ReverseTranslator.hpp"
+#include "../GeometryTranslator.hpp"
 
 #include "../../model/Model.hpp"
 #include "../../model/Space.hpp"
@@ -30,6 +31,8 @@
 #include "../../utilities/idf/IdfFile.hpp"
 
 #include <resources.hxx>
+#include <utilities/idd/IddEnums.hxx>
+#include <utilities/idd/FenestrationSurface_Detailed_FieldEnums.hxx>
 
 #include <sstream>
 
@@ -76,8 +79,9 @@ TEST_F(EnergyPlusFixture, WindowPropertyFrameAndDivider) {
   EXPECT_DOUBLE_EQ(-1.0, normal.y());
   EXPECT_DOUBLE_EQ(0.0, normal.z());
 
+  static constexpr double outsideRevealDepth = 1.75;
   WindowPropertyFrameAndDivider frameAndDivider(model);
-  frameAndDivider.setOutsideRevealDepth(1.0);
+  frameAndDivider.setOutsideRevealDepth(outsideRevealDepth);
 
   EXPECT_FALSE(subSurface2.allowWindowPropertyFrameAndDivider());
   EXPECT_TRUE(subSurface2.setSubSurfaceType("GlassDoor"));
@@ -86,12 +90,47 @@ TEST_F(EnergyPlusFixture, WindowPropertyFrameAndDivider) {
   EXPECT_TRUE(subSurface2.setWindowPropertyFrameAndDivider(frameAndDivider));
   ASSERT_TRUE(subSurface2.windowPropertyFrameAndDivider());
 
+
   ForwardTranslator forwardTranslator;
-  OptionalWorkspace outWorkspace = forwardTranslator.translateModel(model);
-  ASSERT_TRUE(outWorkspace);
+  auto workspace = forwardTranslator.translateModel(model);
+
+  EXPECT_EQ(2u, workspace.getObjectsByType(IddObjectType::FenestrationSurface_Detailed).size());
+  ASSERT_EQ(1u, workspace.getObjectsByType(IddObjectType::WindowProperty_FrameAndDivider).size());
+
+  auto pointEqual = [](const Point3d& a, const Point3d& b) {
+    static constexpr double tol = 1.0e-6;
+    EXPECT_NEAR(a.x(), b.x(), tol);
+    EXPECT_NEAR(a.y(), b.y(), tol);
+    EXPECT_NEAR(a.z(), b.z(), tol);
+  };
+
+  {
+    auto ss_ = workspace.getObjectByTypeAndName(IddObjectType::FenestrationSurface_Detailed, subSurface1.nameString());
+    ASSERT_TRUE(ss_);
+    EXPECT_TRUE(ss_->isEmpty(FenestrationSurface_DetailedFields::FrameandDividerName));
+    auto idf_vertices = getVertices(FenestrationSurface_DetailedFields::NumberofVertices + 1, *ss_);
+    ASSERT_EQ(vertices.size(), idf_vertices.size());
+    for (size_t i = 0; i < vertices.size(); ++i) {
+      pointEqual(vertices[i], idf_vertices[i]);
+    }
+  }
+
+  {
+    auto ss_ = workspace.getObjectByTypeAndName(IddObjectType::FenestrationSurface_Detailed, subSurface2.nameString());
+    ASSERT_TRUE(ss_);
+    auto frame_ = ss_->getTarget(FenestrationSurface_DetailedFields::FrameandDividerName);
+    ASSERT_TRUE(frame_);
+
+    auto idf_vertices = getVertices(FenestrationSurface_DetailedFields::NumberofVertices + 1, *ss_);
+    ASSERT_EQ(vertices.size(), idf_vertices.size());
+    for (size_t i = 0; i < vertices.size(); ++i) {
+      auto pt = vertices[i] + Vector3d(0.0, outsideRevealDepth, 0.0);
+      pointEqual(pt, idf_vertices[i]);
+    }
+  }
 
   ReverseTranslator reverseTranslator;
-  OptionalModel outModel = reverseTranslator.translateWorkspace(*outWorkspace);
+  OptionalModel outModel = reverseTranslator.translateWorkspace(workspace);
   ASSERT_TRUE(outModel);
 
   EXPECT_EQ(1u, outModel->getConcreteModelObjects<WindowPropertyFrameAndDivider>().size());
@@ -102,7 +141,7 @@ TEST_F(EnergyPlusFixture, WindowPropertyFrameAndDivider) {
   vertices = testSubSurface->vertices();
   ASSERT_EQ(4u, vertices.size());
   EXPECT_DOUBLE_EQ(0.0, vertices[0].x());
-  EXPECT_DOUBLE_EQ(0.0, vertices[0].y());
+  EXPECT_DOUBLE_EQ(outsideRevealDepth, vertices[0].y());
   EXPECT_DOUBLE_EQ(1.0, vertices[0].z());
 
   testSubSurface = outModel->getConcreteModelObjectByName<SubSurface>("No Offset");
diff --git a/src/model/LoadProfilePlant.cpp b/src/model/LoadProfilePlant.cpp
index aaccc38412e..dfbf9e4688d 100644
--- a/src/model/LoadProfilePlant.cpp
+++ b/src/model/LoadProfilePlant.cpp
@@ -100,6 +100,24 @@ namespace model {
       return value.get();
     }
 
+    std::string LoadProfilePlant_Impl::plantLoopFluidType() const {
+      boost::optional<std::string> value = getString(OS_LoadProfile_PlantFields::PlantLoopFluidType, true);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double LoadProfilePlant_Impl::degreeofSubCooling() const {
+      boost::optional<double> value = getDouble(OS_LoadProfile_PlantFields::DegreeofSubCooling, true);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
+    double LoadProfilePlant_Impl::degreeofLoopSubCooling() const {
+      boost::optional<double> value = getDouble(OS_LoadProfile_PlantFields::DegreeofLoopSubCooling, true);
+      OS_ASSERT(value);
+      return value.get();
+    }
+
     bool LoadProfilePlant_Impl::setLoadSchedule(Schedule& schedule) {
       bool result = setSchedule(OS_LoadProfile_PlantFields::LoadScheduleName, "LoadProfilePlant", "Load", schedule);
       return result;
@@ -124,6 +142,23 @@ namespace model {
       return getObject<ModelObject>().getModelObjectTarget<Schedule>(OS_LoadProfile_PlantFields::FlowRateFractionScheduleName);
     }
 
+    bool LoadProfilePlant_Impl::setPlantLoopFluidType(const std::string& plantLoopFluidType) {
+      bool result = setString(OS_LoadProfile_PlantFields::PlantLoopFluidType, plantLoopFluidType);
+      return result;
+    }
+
+    bool LoadProfilePlant_Impl::setDegreeofSubCooling(double degreeofSubCooling) {
+      bool result = setDouble(OS_LoadProfile_PlantFields::DegreeofSubCooling, degreeofSubCooling);
+      OS_ASSERT(result);
+      return result;
+    }
+
+    bool LoadProfilePlant_Impl::setDegreeofLoopSubCooling(double degreeofLoopSubCooling) {
+      bool result = setDouble(OS_LoadProfile_PlantFields::DegreeofLoopSubCooling, degreeofLoopSubCooling);
+      OS_ASSERT(result);
+      return result;
+    }
+
     bool LoadProfilePlant_Impl::addToNode(Node& node) {
       if (auto plant = node.plantLoop()) {
         if (plant->demandComponent(node.handle())) {
@@ -180,6 +215,12 @@ namespace model {
     setPeakFlowRate(0.002);
     ok = setFlowRateFractionSchedule(alwaysOn);
     OS_ASSERT(ok);
+    ok = setPlantLoopFluidType("Water");
+    OS_ASSERT(ok);
+    ok = setDegreeofSubCooling(5.0);
+    OS_ASSERT(ok);
+    ok = setDegreeofLoopSubCooling(20.0);
+    OS_ASSERT(ok);
   }
 
   LoadProfilePlant::LoadProfilePlant(const Model& model, Schedule& loadSchedule, Schedule& flowRateFractionSchedule)
@@ -189,6 +230,9 @@ namespace model {
     setLoadSchedule(loadSchedule);
     setPeakFlowRate(0.0);
     setFlowRateFractionSchedule(flowRateFractionSchedule);
+    setPlantLoopFluidType("Water");
+    setDegreeofSubCooling(5.0);
+    setDegreeofLoopSubCooling(20.0);
   }
 
   IddObjectType LoadProfilePlant::iddObjectType() {
@@ -207,6 +251,18 @@ namespace model {
     return getImpl<detail::LoadProfilePlant_Impl>()->flowRateFractionSchedule();
   }
 
+  std::string LoadProfilePlant::plantLoopFluidType() const {
+    return getImpl<detail::LoadProfilePlant_Impl>()->plantLoopFluidType();
+  }
+
+  double LoadProfilePlant::degreeofSubCooling() const {
+    return getImpl<detail::LoadProfilePlant_Impl>()->degreeofSubCooling();
+  }
+
+  double LoadProfilePlant::degreeofLoopSubCooling() const {
+    return getImpl<detail::LoadProfilePlant_Impl>()->degreeofLoopSubCooling();
+  }
+
   bool LoadProfilePlant::setLoadSchedule(Schedule& schedule) {
     return getImpl<detail::LoadProfilePlant_Impl>()->setLoadSchedule(schedule);
   }
@@ -219,6 +275,18 @@ namespace model {
     return getImpl<detail::LoadProfilePlant_Impl>()->setFlowRateFractionSchedule(schedule);
   }
 
+  bool LoadProfilePlant::setPlantLoopFluidType(const std::string& plantLoopFluidType) {
+    return getImpl<detail::LoadProfilePlant_Impl>()->setPlantLoopFluidType(plantLoopFluidType);
+  }
+
+  bool LoadProfilePlant::setDegreeofSubCooling(double degreeofSubCooling) {
+    return getImpl<detail::LoadProfilePlant_Impl>()->setDegreeofSubCooling(degreeofSubCooling);
+  }
+
+  bool LoadProfilePlant::setDegreeofLoopSubCooling(double degreeofLoopSubCooling) {
+    return getImpl<detail::LoadProfilePlant_Impl>()->setDegreeofLoopSubCooling(degreeofLoopSubCooling);
+  }
+
   /// @cond
   LoadProfilePlant::LoadProfilePlant(std::shared_ptr<detail::LoadProfilePlant_Impl> impl) : StraightComponent(std::move(impl)) {}
   /// @endcond
diff --git a/src/model/LoadProfilePlant.hpp b/src/model/LoadProfilePlant.hpp
index 6bf3f68a51e..6101e24891d 100644
--- a/src/model/LoadProfilePlant.hpp
+++ b/src/model/LoadProfilePlant.hpp
@@ -52,6 +52,12 @@ namespace model {
 
     Schedule flowRateFractionSchedule() const;
 
+    std::string plantLoopFluidType() const;
+
+    double degreeofSubCooling() const;
+
+    double degreeofLoopSubCooling() const;
+
     //@}
     /** @name Setters */
     //@{
@@ -62,6 +68,12 @@ namespace model {
 
     bool setFlowRateFractionSchedule(Schedule& schedule);
 
+    bool setPlantLoopFluidType(const std::string& plantLoopFluidType);
+
+    bool setDegreeofSubCooling(double degreeofSubCooling);
+
+    bool setDegreeofLoopSubCooling(double degreeofLoopSubCooling);
+
     //@}
     /** @name Other */
     //@{
diff --git a/src/model/LoadProfilePlant_Impl.hpp b/src/model/LoadProfilePlant_Impl.hpp
index 8bb5c96b09a..f825468ee79 100644
--- a/src/model/LoadProfilePlant_Impl.hpp
+++ b/src/model/LoadProfilePlant_Impl.hpp
@@ -67,6 +67,12 @@ namespace model {
 
       virtual std::vector<std::string> emsInternalVariableNames() const override;
 
+      std::string plantLoopFluidType() const;
+
+      double degreeofSubCooling() const;
+
+      double degreeofLoopSubCooling() const;
+
       //@}
       /** @name Setters */
       //@{
@@ -77,6 +83,12 @@ namespace model {
 
       bool setFlowRateFractionSchedule(Schedule& schedule);
 
+      bool setPlantLoopFluidType(const std::string& plantLoopFluidType);
+
+      bool setDegreeofSubCooling(double degreeofSubCooling);
+
+      bool setDegreeofLoopSubCooling(double degreeofLoopSubCooling);
+
       //@}
       /** @name Other */
       //@{
diff --git a/src/utilities/core/FilesystemHelpers.cpp b/src/utilities/core/FilesystemHelpers.cpp
index 38dabf95a46..a7ec714dc7a 100644
--- a/src/utilities/core/FilesystemHelpers.cpp
+++ b/src/utilities/core/FilesystemHelpers.cpp
@@ -137,16 +137,14 @@ namespace filesystem {
   }
 
   openstudio::path create_temporary_directory(const openstudio::path& basename) {
-    // making this count static/atomic so that we reduce the chance of collisions
-    // on each run of the binary. This is threadsafe, with the atomic
-    static std::atomic<unsigned int> count = 0;
-    constexpr unsigned int allowed_attempts = 1000;
-
     const auto base_temp_dir = openstudio::filesystem::temp_directory_path();
-    // std::filesystem::unique_path doesn't exist, if moving to std::filesystem, use emoveBraces(createUUID)
+    // std::filesystem::unique_path doesn't exist, if moving to std::filesystem, use removeBraces(createUUID())
     auto upath = boost::filesystem::unique_path();
     const auto temp_dir = base_temp_dir / fmt::format("{}-{}-{}-", basename.string(), upath.string(), std::time(nullptr));
 
+    // unique_path is supposed to be unique already...
+    unsigned int count = 0;
+    constexpr unsigned int allowed_attempts = 1000;
     while (count < allowed_attempts) {
       // concat number to path basename, without adding a new path element
       auto full_pathname = temp_dir;
diff --git a/src/utilities/geometry/Geometry.i b/src/utilities/geometry/Geometry.i
index 9a1d18f693a..bcbdf86ab06 100644
--- a/src/utilities/geometry/Geometry.i
+++ b/src/utilities/geometry/Geometry.i
@@ -169,6 +169,14 @@
   }
 }
 
+%extend openstudio::Surface3d {
+  std::string __str__() const {
+    std::ostringstream os;
+    os << *self;
+    return os.str();
+  }
+}
+
 %extend openstudio::Transformation {
 
   std::string __str__() const {
diff --git a/src/utilities/geometry/Plane.hpp b/src/utilities/geometry/Plane.hpp
index 8166c2e6887..64e95c4ed80 100644
--- a/src/utilities/geometry/Plane.hpp
+++ b/src/utilities/geometry/Plane.hpp
@@ -33,12 +33,12 @@ class UTILITIES_API Plane
   /// throws openstudio::Exception if cannot compute plane for these points.
   Plane(const std::vector<Point3d>& points);
 
-  // Copy and move operators are implicitly declared (Rule of 1)
+  // Copy and move operators are implicitly declared (Rule of 1), but we want the copy ctor for SWIG so we have to define all of them
   // There's no need to check if the length of the normal is zero since we never allow another plane to not satisfy this condition
-  // Plane(const Plane& other) = default;
-  // Plane(Plane&& other) = default;
-  // Plane& operator=(const Plane&) = default;
-  // Plane& operator=(Plane&&) = default;
+  Plane(const Plane& other) = default;
+  Plane(Plane&& other) noexcept = default;
+  Plane& operator=(const Plane&) = default;
+  Plane& operator=(Plane&&) noexcept = default;
   // ~Plane() noexcept = default;
 
   /// get the outward normal of this plane
diff --git a/src/utilities/geometry/Point3d.hpp b/src/utilities/geometry/Point3d.hpp
index 46f0cfe6094..7bd1a0dcc68 100644
--- a/src/utilities/geometry/Point3d.hpp
+++ b/src/utilities/geometry/Point3d.hpp
@@ -27,11 +27,11 @@ class UTILITIES_API Point3d
   /// constructor with x, y, z
   Point3d(double x, double y, double z);
 
-  // Copy and move operators are implicitly declared
-  // Point3d(const Point3d& other) = default;
-  // Point3d(Point3d&& other) = default;
-  // Point3d& operator=(const Point3d&) = default;
-  // Point3d& operator=(Point3d&&) = default;
+  // Copy and move operators are implicitly declared, but we want the copy ctor for SWIG so we have to define all of them
+  Point3d(const Point3d& other) = default;
+  Point3d(Point3d&& other) noexcept = default;
+  Point3d& operator=(const Point3d&) = default;
+  Point3d& operator=(Point3d&&) noexcept = default;
   // ~Point3d() noexcept = default;
 
   /// get x
diff --git a/src/utilities/geometry/Polygon3d.hpp b/src/utilities/geometry/Polygon3d.hpp
index fdabe3f2d30..d85c9729abb 100644
--- a/src/utilities/geometry/Polygon3d.hpp
+++ b/src/utilities/geometry/Polygon3d.hpp
@@ -27,11 +27,11 @@ class UTILITIES_API Polygon3d
   // Constructs a polygon with an outer path and one or more inner paths
   Polygon3d(const Point3dVector& outerPath, const Point3dVectorVector& innerPaths);
 
-  // Copy and move operators are implicitly declared (Rule of 1)
-  // Polygon3d(const Polygon3d& other) = default;
-  // Polygon3d(Polygon3d&& other) = default;
-  // Polygon3d& operator=(const Polygon3d&) = default;
-  // Polygon3d& operator=(Polygon3d&&) = default;
+  // Copy and move operators are implicitly declared (Rule of 1), but we want the copy ctor for SWIG so we have to define all of them
+  Polygon3d(const Polygon3d& other) = default;
+  Polygon3d(Polygon3d&& other) noexcept = default;
+  Polygon3d& operator=(const Polygon3d&) = default;
+  Polygon3d& operator=(Polygon3d&&) noexcept = default;
   // ~Polygon3d() noexcept = default;
 
   // Assigns an outer path for the polygon
diff --git a/src/utilities/geometry/Polyhedron.cpp b/src/utilities/geometry/Polyhedron.cpp
index bdf3293b574..71fb420ab5b 100644
--- a/src/utilities/geometry/Polyhedron.cpp
+++ b/src/utilities/geometry/Polyhedron.cpp
@@ -104,8 +104,8 @@ Vector3d Surface3dEdge::asVector() const {
 }
 
 std::ostream& operator<<(std::ostream& os, const Surface3dEdge& edge) {
-  os << "Surface3dEdge: start=" << edge.start() << ", end=" << edge.end() << ", count=" << edge.count()
-     << ", firstSurface=" << edge.firstSurfaceName();
+  os << "Surface3dEdge: start=" << edge.start() << ", end=" << edge.end() << ", count=" << edge.count() << ", firstSurface='"
+     << edge.firstSurfaceName() << "'";
   return os;
 }
 
@@ -118,10 +118,23 @@ Surface3d::Surface3d(std::vector<Point3d> t_vertices, std::string t_name, size_t
       itnext = std::begin(vertices);
     }
 
-    edges.emplace_back(*it, *itnext, t_name, t_surfNum);
+    edges.emplace_back(*it, *itnext, name, surfNum);
   }
 }
 
+std::ostream& operator<<(std::ostream& os, const Surface3d& surface3d) {
+  os << "Surface3d ";
+  if (!surface3d.name.empty()) {
+    os << "'" << surface3d.name << "' ";
+  }
+  os << "= [\n";
+  for (const auto& pt : surface3d.vertices) {
+    os << "  " << pt << ",\n";
+  }
+  os << "]";
+  return os;
+}
+
 bool Surface3d::operator<(const Surface3d& rhs) const {
   return this->name < rhs.name;
 }
@@ -492,4 +505,8 @@ double Polyhedron::calcDivergenceTheoremVolume() const {
   return volume;
 }
 
+std::vector<Surface3d> Polyhedron::surface3ds() const {
+  return m_surfaces;
+}
+
 }  // namespace openstudio
diff --git a/src/utilities/geometry/Polyhedron.hpp b/src/utilities/geometry/Polyhedron.hpp
index fa8baf738d9..df93c8ae26e 100644
--- a/src/utilities/geometry/Polyhedron.hpp
+++ b/src/utilities/geometry/Polyhedron.hpp
@@ -138,6 +138,8 @@ class UTILITIES_API Polyhedron
     * proportion of conflicted edges / total number of edges */
   std::vector<Surface3d> findSurfacesWithIncorrectOrientation() const;
 
+  std::vector<Surface3d> surface3ds() const;
+
  protected:
   void performEdgeMatching();
   void resetEdgeMatching();
@@ -164,6 +166,7 @@ using PolyhedronVector = std::vector<Polyhedron>;
 
 /// ostream operator
 UTILITIES_API std::ostream& operator<<(std::ostream& os, const Surface3dEdge& edge);
+UTILITIES_API std::ostream& operator<<(std::ostream& os, const Surface3d& surface3d);
 
 }  // namespace openstudio
 
diff --git a/src/utilities/geometry/Transformation.hpp b/src/utilities/geometry/Transformation.hpp
index b336d1168c5..9f1e82f6f9e 100644
--- a/src/utilities/geometry/Transformation.hpp
+++ b/src/utilities/geometry/Transformation.hpp
@@ -35,11 +35,11 @@ class UTILITIES_API Transformation
   /// constructor from storage, asserts vector is size 16
   Transformation(const Vector& vector);
 
-  // Copy and move operators are implicitly declared (Rule of 1)
-  // Transformation(const Transformation& other) = default;
-  // Transformation(Transformation&& other) = default;
-  // Transformation& operator=(const Transformation&) = default;
-  // Transformation& operator=(Transformation&&) = default;
+  // Copy and move operators are implicitly declared (Rule of 1), but we want the copy ctor for SWIG so we have to define all of them
+  Transformation(const Transformation& other) = default;
+  Transformation(Transformation&& other) noexcept = default;
+  Transformation& operator=(const Transformation&) = default;
+  Transformation& operator=(Transformation&&) noexcept = default;
   // ~Transformation() noexcept = default;
 
   /// rotation about origin defined by axis and angle (radians)
diff --git a/src/utilities/geometry/Vector3d.hpp b/src/utilities/geometry/Vector3d.hpp
index b036f01dfbc..f85b0d447cb 100644
--- a/src/utilities/geometry/Vector3d.hpp
+++ b/src/utilities/geometry/Vector3d.hpp
@@ -24,11 +24,11 @@ class UTILITIES_API Vector3d
   /// constructor with x, y, z
   Vector3d(double x, double y, double z);
 
-  // Copy and move operators are implicitly declared  (Rule of 1)
-  // Vector3d(const Vector3d& other) = default;
-  // Vector3d(Vector3d&& other) = default;
-  // Vector3d& operator=(const Vector3d&) = default;
-  // Vector3d& operator=(Vector3d&&) = default;
+  // Copy and move operators are implicitly declared  (Rule of 1), but we want the copy ctor for SWIG so we have to define all of them
+  Vector3d(const Vector3d& other) = default;
+  Vector3d(Vector3d&& other) noexcept = default;
+  Vector3d& operator=(const Vector3d&) = default;
+  Vector3d& operator=(Vector3d&&) noexcept = default;
   // ~Vector3d() noexcept = default;
 
   /// get x
diff --git a/src/utilities/mainpage.hpp b/src/utilities/mainpage.hpp
index ba54b26221c..6f5a547f9b1 100644
--- a/src/utilities/mainpage.hpp
+++ b/src/utilities/mainpage.hpp
@@ -55,10 +55,13 @@ namespace openstudio {
  *
  *  \section data_sec Data
  *
- *  Structures for storing data such as \link Vector.hpp vectors\endlink,
- *  \link Matrix.hpp matrices\endlink, and \link TimeSeries time series\endlink. The Attribute
- *  class is used for reporting measures in particular; class EndUses and the enumeration classes in
- *  DataEnums.hpp are also of interest.
+ *  Structures for storing data such as \link Vector vectors\endlink,
+ *  \link Matrix matrices\endlink, and \link TimeSeries time series\endlink. The Attribute
+ *  class provides a way for storing data additional values attached to objects,
+ *  and is useful for reporting measures in particular. EndUses and associated enumeration
+ *  classes EndUseType, EndUseCategoryType, and EndUseFuelType are helpful to break out energy use in reporting.
+ *  FuelType, AppGFuelType, and ComponentType are useful to determine fuel and component sources
+ *  for standards code. These and other enumerations are listed in DataEnums.hpp.
  *
  *  \section filetypes_sec Filetypes
  *


Test patch:
diff --git a/src/model/test/LoadProfilePlant_GTest.cpp b/src/model/test/LoadProfilePlant_GTest.cpp
index 7f5b2f54be6..01408ba1cce 100644
--- a/src/model/test/LoadProfilePlant_GTest.cpp
+++ b/src/model/test/LoadProfilePlant_GTest.cpp
@@ -9,6 +9,60 @@
 
 #include "../LoadProfilePlant.hpp"
 #include "../LoadProfilePlant_Impl.hpp"
+#include "../ScheduleRuleset.hpp"
+#include "../ScheduleRuleset_Impl.hpp"
+#include "../ScheduleConstant.hpp"
+#include "../ScheduleConstant_Impl.hpp"
 
 using namespace openstudio;
 using namespace openstudio::model;
+
+TEST_F(ModelFixture, LoadProfilePlant_LoadProfilePlant) {
+  ::testing::FLAGS_gtest_death_test_style = "threadsafe";
+
+  ASSERT_EXIT(
+    {
+      Model m;
+      LoadProfilePlant lpp(m);
+
+      exit(0);
+    },
+    ::testing::ExitedWithCode(0), "");
+
+  Model m;
+  LoadProfilePlant lpp(m);
+
+  ASSERT_TRUE(lpp.loadSchedule().optionalCast<ScheduleRuleset>());
+  EXPECT_EQ(0.002, lpp.peakFlowRate());
+  ASSERT_TRUE(lpp.flowRateFractionSchedule().optionalCast<ScheduleConstant>());
+  EXPECT_EQ("Water", lpp.plantLoopFluidType());
+  EXPECT_EQ(5.0, lpp.degreeofSubCooling());
+  EXPECT_EQ(20.0, lpp.degreeofLoopSubCooling());
+}
+
+TEST_F(ModelFixture, LoadProfilePlant_GettersSetters) {
+  Model m;
+  LoadProfilePlant lpp(m);
+
+  ScheduleConstant loadSchedule(m);
+  loadSchedule.setName("Load Schedule");
+  EXPECT_TRUE(lpp.setLoadSchedule(loadSchedule));
+  EXPECT_EQ(loadSchedule, lpp.flowRateFractionSchedule());
+
+  EXPECT_TRUE(lpp.setPeakFlowRate(0.005));
+  EXPECT_EQ(0.005, lpp.peakFlowRate());
+
+  ScheduleConstant flowRateFractionSchedule(m);
+  flowRateFractionSchedule.setName("Flow Rate Fraction Schedule");
+  EXPECT_TRUE(lpp.setFlowRateFractionSchedule(flowRateFractionSchedule));
+  EXPECT_EQ(flowRateFractionSchedule, lpp.flowRateFractionSchedule());
+
+  EXPECT_TRUE(lpp.setPlantLoopFluidType("Steam"));
+  EXPECT_EQ("Steam", lpp.plantLoopFluidType());
+
+  EXPECT_TRUE(lpp.setDegreeofSubCooling(6.0));
+  EXPECT_EQ(6.0, lpp.degreeofSubCooling());
+
+  EXPECT_TRUE(lpp.setDegreeofLoopSubCooling(21.0));
+  EXPECT_EQ(21.0, lpp.degreeofLoopSubCooling());
+}