diff --git a/developer/ruby/SubProjectClassGenerators/ModelClassGenerator.rb b/developer/ruby/SubProjectClassGenerators/ModelClassGenerator.rb index 5899906f87b..567b5fcf3f6 100644 --- a/developer/ruby/SubProjectClassGenerators/ModelClassGenerator.rb +++ b/developer/ruby/SubProjectClassGenerators/ModelClassGenerator.rb @@ -488,8 +488,8 @@ def cppIncludes() end } if @hasScheduleFields - result << "#include \"../../model/ScheduleTypeLimits.hpp\"\n" - result << "#include \"../../model/ScheduleTypeRegistry.hpp\"\n" + result << "#include \"ScheduleTypeLimits.hpp\"\n" + result << "#include \"ScheduleTypeRegistry.hpp\"\n" end result << "\n" if preamble == "" @@ -1267,7 +1267,7 @@ def cppPublicClassPublicMethods() result << " return getImpl()->" << field.setterName << "(" << field.setterArgumentName << ");\n" result << "}\n\n" else - result << "void " << @className << "::" << field.setterName << "(" << field.publicClassSetterType << " " << field.setterArgumentName << ") {\n" + result << "bool " << @className << "::" << field.setterName << "(" << field.publicClassSetterType << " " << field.setterArgumentName << ") {\n" result << " getImpl()->" << field.setterName << "(" << field.setterArgumentName << ");\n" result << "}\n\n" end @@ -1429,8 +1429,8 @@ def gtestIncludes() @nonextensibleFields.each { |field| if field.isObjectList? result << preamble - result << "#include \"../model/" << field.objectListClassName << ".hpp\"\n" - result << "#include \"../model/" << field.objectListClassName << "_Impl.hpp\"\n\n" + result << "#include \"../" << field.objectListClassName << ".hpp\"\n" + result << "#include \"../" << field.objectListClassName << "_Impl.hpp\"\n\n" preamble = "" end } @@ -1580,7 +1580,7 @@ def gtestGetterSetters end if !bad_val.nil? - result << " Bad Value\n"; + result << " // Bad Value\n"; result << " EXPECT_FALSE(#{instanceName}." << field.setterName << "(#{bad_val}));\n"; if field.optionalGetter? diff --git a/developer/ruby/SubProjectClassGenerators/TranslatorGenerator.rb b/developer/ruby/SubProjectClassGenerators/TranslatorGenerator.rb index 54a1f6517e1..fb8323cb5d8 100644 --- a/developer/ruby/SubProjectClassGenerators/TranslatorGenerator.rb +++ b/developer/ruby/SubProjectClassGenerators/TranslatorGenerator.rb @@ -335,41 +335,17 @@ def generateForwardTranslateFunction() result << " // " << field.name << ": " << (field.isRequired? ? "Required" : "Optional") << (field.isNode? ? " Node": " Object") << "\n" if field.optionalGetter? result << " if (" << field.getterReturnType() << " _" << field.getterName << " = "<< field.getterName() << "()) {\n" - result << " if ( boost::optional _owo = translateAndMapModelObject(_" << field.getterName << ".get()) ) {\n" + result << " if ( boost::optional _owo = translateAndMapModelObject(_" << field.getterName << ".get()) ) {\n" result << " idfObject.setString(" << field.fieldEnum << ", _owo->nameString());\n" result << " }\n" result << " }\n" else - result << " " << field.getterReturnType << " " << field.getterName << " = modelObject." << field.getterName << "();" - result << " if ( boost::optional _owo = translateAndMapModelObject(" << field.getterName << ") ) {\n" + result << " " << field.getterReturnType << " " << field.getterName << " = modelObject." << field.getterName << "();\n" + result << " if ( boost::optional _owo = translateAndMapModelObject(" << field.getterName << ") ) {\n" result << " idfObject.setString(" << field.fieldEnum << ", _owo->nameString());\n" result << " }\n" end - result << " if ( (_wo = workspaceObject.getTarget(#{field.fieldEnum})) ) {\n" - result << " if( (_mo = translateAndMapWorkspaceObject(_wo.get())) ) {\n" - result << " // TODO: check return types\n" - result << " if (" << field.getterReturnType(true) << " _" - result << field.getterName << " = _mo->optionalCast<" << field.getterReturnType(false) << ">()) {\n" - result << " modelObject." << field.setterName << "(_" << field.getterName << ".get());\n" - result << " } else {\n" - result << " LOG(Warn, workspaceObject.briefDescription() << \" has a wrong type for '" << field.name << "'\");\n" - result << " }\n" - if field.isRequired? - result << " } else {\n" - result << ' LOG(Error, "For " << workspaceObject.briefDescription()' - result << " << \", cannot reverse translate required object '" << field.name << "'\");" << "\n" - result << " return result;\n" - result << " }\n" - result << " } else {\n" - result << ' LOG(Error, "For " << workspaceObject.briefDescription()' - result << " << \", cannot find required object '" << field.name << "'\");" << "\n" - result << " return result;\n" - result << " }\n" - else - result << " }\n" - result << " }\n" - end else prefix = "" need_closing = false @@ -427,7 +403,7 @@ def generateForwardTranslateFunction() result << " // " << field.name << ": " << (field.isRequired? ? "Required" : "Optional") << " " << cat << "\n" result << " " << field.getterReturnType << " " << field.getterName << " = modelObject." << field.getterName << "();\n" - result << " idfObject." << field.setterAccessor << "(" << field.fieldEnum << ", " << field.getterName << ")\n\n" + result << " idfObject." << field.setterAccessor << "(" << field.fieldEnum << ", " << field.getterName << ");\n\n" end diff --git a/resources/model/OpenStudio.idd b/resources/model/OpenStudio.idd index 06a72e92957..d0a3b0c4efc 100644 --- a/resources/model/OpenStudio.idd +++ b/resources/model/OpenStudio.idd @@ -28184,6 +28184,95 @@ OS:Pipe:Outdoor, \units m \minimum> 0.0 +OS:SwimmingPool:Indoor, + \memo Specifies an indoor swimming pools linked to a floor surface. + \memo The pool is assumed to cover the entire floor to which it is linked. + \min-fields 17 + A1, \field Handle + \type handle + \required-field + A2, \field Name + \required-field + \type alpha + \reference ConnectionObject + A3, \field Surface Name + \required-field + \note Name of the floor surface where the pool is located. + \type object-list + \object-list FloorSurfaceNames + N1, \field Average Depth + \required-field + \type real + \units m + A4, \field Activity Factor Schedule Name + \required-field + \type object-list + \object-list ScheduleNames + A5, \field Make-up Water Supply Schedule Name + \required-field + \type object-list + \object-list ScheduleNames + A6, \field Cover Schedule Name + \required-field + \type object-list + \object-list ScheduleNames + N2, \field Cover Evaporation Factor + \type real + \minimum 0.0 + \maximum 1.0 + \required-field + N3, \field Cover Convection Factor + \type real + \minimum 0.0 + \maximum 1.0 + \required-field + N4, \field Cover Short-Wavelength Radiation Factor + \type real + \minimum 0.0 + \maximum 1.0 + \required-field + N5, \field Cover Long-Wavelength Radiation Factor + \type real + \minimum 0.0 + \maximum 1.0 + \required-field + A7, \field Pool Water Inlet Node + \required-field + \type object-list + \object-list ConnectionNames + A8, \field Pool Water Outlet Node + \required-field + \type object-list + \object-list ConnectionNames + N6, \field Pool Heating System Maximum Water Flow Rate + \type real + \units m3/s + \ip-units gal/min + \minimum 0.0 + \required-field + N7, \field Pool Miscellaneous Equipment Power + \note Power input per pool water flow rate + \units W-s/m3 + \ip-units W-min/gal + \type real + \minimum 0.0 + \required-field + A9, \field Setpoint Temperature Schedule + \required-field + \type object-list + \object-list ScheduleNames + N8, \field Maximum Number of People + \required-field + \minimum 0.0 + A10, \field People Schedule + \type object-list + \object-list ScheduleNames + \required-field + A11; \field People Heat Gain Schedule + \type object-list + \object-list ScheduleNames + \required-field + \group Solar Collectors OS:SolarCollectorPerformance:FlatPlate, diff --git a/src/energyplus/CMakeLists.txt b/src/energyplus/CMakeLists.txt index 86edf95f5e8..02487570b05 100644 --- a/src/energyplus/CMakeLists.txt +++ b/src/energyplus/CMakeLists.txt @@ -354,6 +354,7 @@ set(${target_name}_src ForwardTranslator/ForwardTranslateSurfacePropertyExposedFoundationPerimeter.cpp ForwardTranslator/ForwardTranslateSurfacePropertyOtherSideCoefficients.cpp ForwardTranslator/ForwardTranslateSurfacePropertyOtherSideConditionsModel.cpp + ForwardTranslator/ForwardTranslateSwimmingPoolIndoor.cpp ForwardTranslator/ForwardTranslateTableMultiVariableLookup.cpp ForwardTranslator/ForwardTranslateTemperingValve.cpp ForwardTranslator/ForwardTranslateThermalStorageIceDetailed.cpp @@ -531,6 +532,7 @@ set(${target_name}_src ReverseTranslator/ReverseTranslateSurfaceConvectionAlgorithmInside.cpp ReverseTranslator/ReverseTranslateSurfaceConvectionAlgorithmOutside.cpp ReverseTranslator/ReverseTranslateSurfacePropertyExposedFoundationPerimeter.cpp + ReverseTranslator/ReverseTranslateSwimmingPoolIndoor.cpp ReverseTranslator/ReverseTranslateThermostatSetpointDualSetpoint.cpp ReverseTranslator/ReverseTranslateTimestep.cpp ReverseTranslator/ReverseTranslateVersion.cpp @@ -654,6 +656,7 @@ set(${target_name}_test_src Test/Surface_GTest.cpp Test/SurfaceControlMovableInsulation_GTest.cpp Test/SurfacePropertyConvectionCoefficients_GTest.cpp + Test/SwimmingPoolIndoor_GTest.cpp Test/TableMultiVariableLookup_GTest.cpp Test/ThermalStorageChilledWaterStratified_GTest.cpp Test/ThermalZone_GTest.cpp diff --git a/src/energyplus/ForwardTranslator.cpp b/src/energyplus/ForwardTranslator.cpp index 0f7fc8cd3bf..0611c95642a 100644 --- a/src/energyplus/ForwardTranslator.cpp +++ b/src/energyplus/ForwardTranslator.cpp @@ -3083,6 +3083,12 @@ boost::optional ForwardTranslator::translateAndMapModelObject(ModelOb retVal = translateSubSurface(subSurface); break; } + case openstudio::IddObjectType::OS_SwimmingPool_Indoor: + { + model::SwimmingPoolIndoor obj = modelObject.cast(); + retVal = translateSwimmingPoolIndoor(obj); + break; + } case openstudio::IddObjectType::OS_Table_MultiVariableLookup : { model::TableMultiVariableLookup table = modelObject.cast(); diff --git a/src/energyplus/ForwardTranslator.hpp b/src/energyplus/ForwardTranslator.hpp index dadedef2c3c..1f0f4607290 100644 --- a/src/energyplus/ForwardTranslator.hpp +++ b/src/energyplus/ForwardTranslator.hpp @@ -408,6 +408,7 @@ class SurfacePropertyConvectionCoefficientsMultipleSurface; class SurfacePropertyExposedFoundationPerimeter; class SurfacePropertyOtherSideCoefficients; class SurfacePropertyOtherSideConditionsModel; +class SwimmingPoolIndoor; class TableMultiVariableLookup; class TemperingValve; class ThermalZone; @@ -1265,6 +1266,8 @@ class ENERGYPLUS_API ForwardTranslator { boost::optional translateSurfacePropertyOtherSideConditionsModel(model::SurfacePropertyOtherSideConditionsModel & modelObject); + boost::optional translateSwimmingPoolIndoor(model::SwimmingPoolIndoor & modelObject); + boost::optional translateTableMultiVariableLookup( model::TableMultiVariableLookup & modelObject ); boost::optional translateTemperingValve( model::TemperingValve & modelObject ); diff --git a/src/energyplus/ForwardTranslator/ForwardTranslateSwimmingPoolIndoor.cpp b/src/energyplus/ForwardTranslator/ForwardTranslateSwimmingPoolIndoor.cpp new file mode 100644 index 00000000000..85a24ab9aa6 --- /dev/null +++ b/src/energyplus/ForwardTranslator/ForwardTranslateSwimmingPoolIndoor.cpp @@ -0,0 +1,184 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#include "../ForwardTranslator.hpp" +#include "../../model/Model.hpp" + +#include "../../model/SwimmingPoolIndoor.hpp" + +#include "../../model/Surface.hpp" +#include "../../model/Schedule.hpp" +#include "../../model/Node.hpp" + +#include +// #include "../../utilities/idd/IddEnums.hpp" +#include + +using namespace openstudio::model; + +namespace openstudio { + +namespace energyplus { + +boost::optional ForwardTranslator::translateSwimmingPoolIndoor( model::SwimmingPoolIndoor& modelObject ) +{ + + // There are a bunch of required fields, so do not register it until everthing looks fine (so not using createRegisterAndNameIdfObject) + IdfObject idfObject( openstudio::IddObjectType::SwimmingPool_Indoor ); + + // Name + idfObject.setName(modelObject.nameString()); + + // Surface Name: Required Object + Surface surface = modelObject.surface(); + if (!openstudio::istringEqual(surface.surfaceType(), "Floor")) { + LOG(Error, "Only surfaceTypes of 'Floor' accepted for SwimmingPoolIndoor. " << modelObject.briefDescription() << "'s Surface is " + << surface.briefDescription() << " which has a surface Type of '" << surface.surfaceType() << "'."); + return boost::none; + } + + if (auto _surface = translateAndMapModelObject(surface)) { + idfObject.setString(SwimmingPool_IndoorFields::SurfaceName, _surface->nameString()); + } else { + LOG(Error, modelObject.briefDescription() << "'s Surface cannot be translated: " << surface.briefDescription()); + } + + // Average Depth: Required Double + double averageDepth = modelObject.averageDepth(); + idfObject.setDouble(SwimmingPool_IndoorFields::AverageDepth, averageDepth); + + + // Activity Factor Schedule Name: Required Object + Schedule activityFactorSchedule = modelObject.activityFactorSchedule(); + if (auto _sch = translateAndMapModelObject(activityFactorSchedule)) { + idfObject.setString(SwimmingPool_IndoorFields::ActivityFactorScheduleName, _sch->nameString()); + } else { + LOG(Error, "Missing required 'Activity Factor Schedule Name' for " << modelObject.briefDescription()); + return boost::none; + } + + // Make-up Water Supply Schedule Name: Required Object + Schedule makeupWaterSupplySchedule = modelObject.makeupWaterSupplySchedule(); + if (auto _sch = translateAndMapModelObject(makeupWaterSupplySchedule)) { + idfObject.setString(SwimmingPool_IndoorFields::MakeupWaterSupplyScheduleName, _sch->nameString()); + } else { + LOG(Error, "Missing required 'Make-up Water Supply Schedule Name' for " << modelObject.briefDescription()); + return boost::none; + } + + // Cover Schedule Name: Required Object + Schedule coverSchedule = modelObject.coverSchedule(); + if (auto _sch = translateAndMapModelObject(coverSchedule)) { + idfObject.setString(SwimmingPool_IndoorFields::CoverScheduleName, _sch->nameString()); + } else { + LOG(Error, "Missing required 'Cover Schedule Name' for " << modelObject.briefDescription()); + return boost::none; + } + + // Cover Evaporation Factor: Optional Double + double coverEvaporationFactor = modelObject.coverEvaporationFactor(); + idfObject.setDouble(SwimmingPool_IndoorFields::CoverEvaporationFactor, coverEvaporationFactor); + + // Cover Convection Factor: Optional Double + double coverConvectionFactor = modelObject.coverConvectionFactor(); + idfObject.setDouble(SwimmingPool_IndoorFields::CoverConvectionFactor, coverConvectionFactor); + + + // Cover Short-Wavelength Radiation Factor: Optional Double + double coverShortWavelengthRadiationFactor = modelObject.coverShortWavelengthRadiationFactor(); + idfObject.setDouble(SwimmingPool_IndoorFields::CoverShortWavelengthRadiationFactor, coverShortWavelengthRadiationFactor); + + + // Cover Long-Wavelength Radiation Factor: Optional Double + double coverLongWavelengthRadiationFactor = modelObject.coverLongWavelengthRadiationFactor(); + idfObject.setDouble(SwimmingPool_IndoorFields::CoverLongWavelengthRadiationFactor, coverLongWavelengthRadiationFactor); + + + // Pool Water Inlet Node: Required Node + if (boost::optional _node = modelObject.poolWaterInletNode()) { + idfObject.setString(SwimmingPool_IndoorFields::PoolWaterInletNode, _node->nameString()); + } else { + LOG(Error, "Missing required 'Pool Water Inlet Node' for " << modelObject.briefDescription()); + } + + // Pool Water Outlet Node: Required Node + if (boost::optional _node = modelObject.poolWaterOutletNode()) { + idfObject.setString(SwimmingPool_IndoorFields::PoolWaterOutletNode, _node->nameString()); + } else { + LOG(Error, "Missing required 'Pool Water Outlet Node' for " << modelObject.briefDescription()); + } + + // Pool Heating System Maximum Water Flow Rate + idfObject.setDouble(SwimmingPool_IndoorFields::PoolHeatingSystemMaximumWaterFlowRate, modelObject.poolHeatingSystemMaximumWaterFlowRate()); + + // Pool Miscellaneous Equipment Power + idfObject.setDouble(SwimmingPool_IndoorFields::PoolMiscellaneousEquipmentPower, modelObject.poolMiscellaneousEquipmentPower()); + + // Setpoint Temperature Schedule: Required Object + Schedule setpointTemperatureSchedule = modelObject.setpointTemperatureSchedule(); + if (auto _sch = translateAndMapModelObject(setpointTemperatureSchedule)) { + idfObject.setString(SwimmingPool_IndoorFields::SetpointTemperatureSchedule, _sch->nameString()); + } else { + LOG(Error, "Missing required 'Setpoint Temperature Schedule Name' for " << modelObject.briefDescription()); + return boost::none; + } + + // Maximum Number of People: Required Double + double maximumNumberofPeople = modelObject.maximumNumberofPeople(); + idfObject.setDouble(SwimmingPool_IndoorFields::MaximumNumberofPeople, maximumNumberofPeople); + + + // People Schedule: Optional Object (but enforced in E+ source) + Schedule peopleSchedule = modelObject.peopleSchedule(); + if (auto _sch = translateAndMapModelObject(peopleSchedule)) { + idfObject.setString(SwimmingPool_IndoorFields::PeopleSchedule, _sch->nameString()); + } else { + LOG(Error, "Missing required 'People Schedule Name' for " << modelObject.briefDescription()); + return boost::none; + } + + // People Heat Gain Schedule: Optional Object (but enforced in E+ source) + Schedule peopleHeatGainSchedule = modelObject.peopleHeatGainSchedule(); + if (auto _sch = translateAndMapModelObject(peopleHeatGainSchedule)) { + idfObject.setString(SwimmingPool_IndoorFields::PeopleHeatGainSchedule, _sch->nameString()); + } else { + LOG(Error, "Missing required 'People Heat Gain Schedule Name' for " << modelObject.briefDescription()); + return boost::none; + } + + + // We made it, register it + m_idfObjects.push_back(idfObject); + + return idfObject; + +} // End of translate function + +} // end namespace energyplus +} // end namespace openstudio diff --git a/src/energyplus/ReverseTranslator.cpp b/src/energyplus/ReverseTranslator.cpp index 8d570d73ddc..5e64b598300 100644 --- a/src/energyplus/ReverseTranslator.cpp +++ b/src/energyplus/ReverseTranslator.cpp @@ -988,6 +988,11 @@ boost::optional ReverseTranslator::translateAndMapWorkspaceObject(c modelObject = translateSurfacePropertyExposedFoundationPerimeter(workspaceObject); break; } + //case openstudio::IddObjectType::SwimmingPool_Indoor : + //{ + //modelObject = translateSwimmingPoolIndoor(workspaceObject); + //break; + //} case openstudio::IddObjectType::ThermostatSetpoint_DualSetpoint : { modelObject = translateThermostatSetpointDualSetpoint(workspaceObject); diff --git a/src/energyplus/ReverseTranslator.hpp b/src/energyplus/ReverseTranslator.hpp index 036be19be0d..e6aad2ad2ec 100644 --- a/src/energyplus/ReverseTranslator.hpp +++ b/src/energyplus/ReverseTranslator.hpp @@ -327,6 +327,8 @@ class ENERGYPLUS_API ReverseTranslator { boost::optional translateSurfacePropertyExposedFoundationPerimeter(const WorkspaceObject & workspaceObject); + boost::optional translateSwimmingPoolIndoor(const WorkspaceObject & workspaceObject); + boost::optional translateThermostatSetpointDualSetpoint(const WorkspaceObject & workspaceObject); boost::optional translateTimestep(const WorkspaceObject & workspaceObject); diff --git a/src/energyplus/ReverseTranslator/ReverseTranslateSwimmingPoolIndoor.cpp b/src/energyplus/ReverseTranslator/ReverseTranslateSwimmingPoolIndoor.cpp new file mode 100644 index 00000000000..c315041d1e2 --- /dev/null +++ b/src/energyplus/ReverseTranslator/ReverseTranslateSwimmingPoolIndoor.cpp @@ -0,0 +1,230 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#include "../ReverseTranslator.hpp" + +#include "../../model/SwimmingPoolIndoor.hpp" + +#include "../../model/Surface.hpp" +#include "../../model/Surface_Impl.hpp" + +#include "../../model/Schedule.hpp" +#include "../../model/Schedule_Impl.hpp" + +#include "../../model/Node.hpp" +#include "../../model/Node_Impl.hpp" + +#include +#include + +using namespace openstudio::model; + +namespace openstudio { + +namespace energyplus { + +boost::optional ReverseTranslator::translateSwimmingPoolIndoor( const WorkspaceObject & workspaceObject ) +{ + boost::optional _wo; + boost::optional _mo; + + // Surface Name: Required Object, and as Ctor arg. And will throw if not the right SurfaceType... + boost::optional _surface; + if ( (_wo = workspaceObject.getTarget(SwimmingPool_IndoorFields::SurfaceName)) ) { + if( (_mo = translateAndMapWorkspaceObject(_wo.get())) ) { + // TODO: check return types + if ( (_surface = _mo->optionalCast()) ) { + if (_surface->surfaceType() != "Floor") { + LOG(Warn, workspaceObject.briefDescription() << " has a surface assigned, but it is NOT of type 'Floor' like it should"); + return::boost::none; + } + } else { + LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Surface Name'"); + return boost::none; + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot reverse translate required object 'Surface Name'"); + return boost::none; + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot find required object 'Surface Name'"); + return boost::none; + } + + // Instantiate an object of the class to store the values, + // but we don't return it until we know it's ok + openstudio::model::SwimmingPoolIndoor modelObject( m_model, _surface.get() ); + + // Name + if (boost::optional _name = workspaceObject.name()) { + modelObject.setName(_name.get()); + } + + + // Average Depth: Required Double + if (boost::optional _averageDepth = workspaceObject.getDouble(SwimmingPool_IndoorFields::AverageDepth)) { + modelObject.setAverageDepth(_averageDepth.get()); + } else { + LOG(Warn, "For " << workspaceObject.briefDescription() << ", cannot find required property 'Average Depth', using default"); + return boost::none; + } + + // Activity Factor Schedule Name: Required Object + if ( (_wo = workspaceObject.getTarget(SwimmingPool_IndoorFields::ActivityFactorScheduleName)) ) { + if( (_mo = translateAndMapWorkspaceObject(_wo.get())) ) { + if (boost::optional _activityFactorSchedule = _mo->optionalCast()) { + modelObject.setActivityFactorSchedule(_activityFactorSchedule.get()); + } else { + LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Activity Factor Schedule Name'"); + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot reverse translate required object 'Activity Factor Schedule Name'"); + return boost::none; + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot find required object 'Activity Factor Schedule Name'"); + return boost::none; + } + // Make-up Water Supply Schedule Name: Required Object + if ( (_wo = workspaceObject.getTarget(SwimmingPool_IndoorFields::MakeupWaterSupplyScheduleName)) ) { + if( (_mo = translateAndMapWorkspaceObject(_wo.get())) ) { + if (boost::optional _makeupWaterSupplySchedule = _mo->optionalCast()) { + modelObject.setMakeupWaterSupplySchedule(_makeupWaterSupplySchedule.get()); + } else { + LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Make-up Water Supply Schedule Name'"); + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot reverse translate required object 'Make-up Water Supply Schedule Name'"); + return boost::none; + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot find required object 'Make-up Water Supply Schedule Name'"); + return boost::none; + } + // Cover Schedule Name: Required Object + if ( (_wo = workspaceObject.getTarget(SwimmingPool_IndoorFields::CoverScheduleName)) ) { + if( (_mo = translateAndMapWorkspaceObject(_wo.get())) ) { + if (boost::optional _coverSchedule = _mo->optionalCast()) { + modelObject.setCoverSchedule(_coverSchedule.get()); + } else { + LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Cover Schedule Name'"); + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot reverse translate required object 'Cover Schedule Name'"); + return boost::none; + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot find required object 'Cover Schedule Name'"); + return boost::none; + } + // Cover Evaporation Factor: Optional Double + if (boost::optional _coverEvaporationFactor = workspaceObject.getDouble(SwimmingPool_IndoorFields::CoverEvaporationFactor)) { + modelObject.setCoverEvaporationFactor(_coverEvaporationFactor.get()); + } + + // Cover Convection Factor: Optional Double + if (boost::optional _coverConvectionFactor = workspaceObject.getDouble(SwimmingPool_IndoorFields::CoverConvectionFactor)) { + modelObject.setCoverConvectionFactor(_coverConvectionFactor.get()); + } + + // Cover Short-Wavelength Radiation Factor: Optional Double + if (boost::optional _coverShortWavelengthRadiationFactor = workspaceObject.getDouble(SwimmingPool_IndoorFields::CoverShortWavelengthRadiationFactor)) { + modelObject.setCoverShortWavelengthRadiationFactor(_coverShortWavelengthRadiationFactor.get()); + } + + // Cover Long-Wavelength Radiation Factor: Optional Double + if (boost::optional _coverLongWavelengthRadiationFactor = workspaceObject.getDouble(SwimmingPool_IndoorFields::CoverLongWavelengthRadiationFactor)) { + modelObject.setCoverLongWavelengthRadiationFactor(_coverLongWavelengthRadiationFactor.get()); + } + + // Pool Water Inlet Node: Required Node + + // Pool Water Outlet Node: Required Node + + // Pool Heating System Maximum Water Flow Rate: Optional Double + if (boost::optional _poolHeatingSystemMaximumWaterFlowRate = workspaceObject.getDouble(SwimmingPool_IndoorFields::PoolHeatingSystemMaximumWaterFlowRate)) { + modelObject.setPoolHeatingSystemMaximumWaterFlowRate(_poolHeatingSystemMaximumWaterFlowRate.get()); + } + + // Pool Miscellaneous Equipment Power: Optional Double + if (boost::optional _poolMiscellaneousEquipmentPower = workspaceObject.getDouble(SwimmingPool_IndoorFields::PoolMiscellaneousEquipmentPower)) { + modelObject.setPoolMiscellaneousEquipmentPower(_poolMiscellaneousEquipmentPower.get()); + } + + // Setpoint Temperature Schedule: Required Object + if ( (_wo = workspaceObject.getTarget(SwimmingPool_IndoorFields::SetpointTemperatureSchedule)) ) { + if( (_mo = translateAndMapWorkspaceObject(_wo.get())) ) { + if (boost::optional _setpointTemperatureSchedule = _mo->optionalCast()) { + modelObject.setSetpointTemperatureSchedule(_setpointTemperatureSchedule.get()); + } else { + LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'Setpoint Temperature Schedule'"); + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot reverse translate required object 'Setpoint Temperature Schedule'"); + return boost::none; + } + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot find required object 'Setpoint Temperature Schedule'"); + return boost::none; + } + // Maximum Number of People: Required Double + if (boost::optional _maximumNumberofPeople = workspaceObject.getDouble(SwimmingPool_IndoorFields::MaximumNumberofPeople)) { + modelObject.setMaximumNumberofPeople(_maximumNumberofPeople.get()); + } else { + LOG(Error, "For " << workspaceObject.briefDescription() << ", cannot find required property 'Maximum Number of People'"); + return boost::none; + } + + // People Schedule: Optional Object + if ( (_wo = workspaceObject.getTarget(SwimmingPool_IndoorFields::PeopleSchedule)) ) { + if( (_mo = translateAndMapWorkspaceObject(_wo.get())) ) { + if (boost::optional _peopleSchedule = _mo->optionalCast()) { + modelObject.setPeopleSchedule(_peopleSchedule.get()); + } else { + LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'People Schedule'"); + } + } + } + // People Heat Gain Schedule: Optional Object + if ( (_wo = workspaceObject.getTarget(SwimmingPool_IndoorFields::PeopleHeatGainSchedule)) ) { + if( (_mo = translateAndMapWorkspaceObject(_wo.get())) ) { + if (boost::optional _peopleHeatGainSchedule = _mo->optionalCast()) { + modelObject.setPeopleHeatGainSchedule(_peopleHeatGainSchedule.get()); + } else { + LOG(Warn, workspaceObject.briefDescription() << " has a wrong type for 'People Heat Gain Schedule'"); + } + } + } + + return modelObject; + +} // End of translate function + +} // end namespace energyplus +} // end namespace openstudio diff --git a/src/energyplus/Test/SwimmingPoolIndoor_GTest.cpp b/src/energyplus/Test/SwimmingPoolIndoor_GTest.cpp new file mode 100644 index 00000000000..84ac551e979 --- /dev/null +++ b/src/energyplus/Test/SwimmingPoolIndoor_GTest.cpp @@ -0,0 +1,239 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#include +#include "EnergyPlusFixture.hpp" + +#include "../ForwardTranslator.hpp" +#include "../ReverseTranslator.hpp" + +#include "../../model/Model.hpp" +#include "../../model/SwimmingPoolIndoor.hpp" +#include "../../model/PlantLoop.hpp" +#include "../../model/Node.hpp" +#include "../../model/Surface.hpp" +#include "../../model/Space.hpp" +#include "../../model/ThermalZone.hpp" +#include "../../model/Schedule.hpp" +#include "../../model/ScheduleConstant.hpp" + +#include "../../utilities/idf/IdfFile.hpp" +#include "../../utilities/idf/Workspace.hpp" +#include "../../utilities/idf/IdfObject.hpp" +#include "../../utilities/idf/WorkspaceObject.hpp" +#include "../../utilities/geometry/Point3d.hpp" + +#include +#include + +#include + +using namespace openstudio::energyplus; +using namespace openstudio::model; +using namespace openstudio; + +TEST_F(EnergyPlusFixture, ForwardTranslator_SwimmingPoolIndoor) { + + ForwardTranslator ft; + + // Create a model + Model m; + + Point3dVector floorPrint; + floorPrint.push_back(Point3d(0, 10, 0)); + floorPrint.push_back(Point3d(10, 10, 0)); + floorPrint.push_back(Point3d(10, 0, 0)); + floorPrint.push_back(Point3d(0, 0, 0)); + boost::optional space1 = Space::fromFloorPrint(floorPrint, 3, m); + ASSERT_TRUE(space1); + auto surfaces = space1->surfaces(); + EXPECT_EQ(6u, surfaces.size()); + + // Space needs to be in a ThermalZone or it's not translated + ThermalZone z(m); + EXPECT_TRUE(space1->setThermalZone(z)); + + auto floorSurfaceIt = std::find_if(std::begin(surfaces), std::end(surfaces), [](const auto& surface) { return surface.surfaceType() == "Floor"; }); + ASSERT_NE(floorSurfaceIt, std::end(surfaces)); + Surface floorSurface = *floorSurfaceIt; + + SwimmingPoolIndoor swimmingPoolIndoor(m, floorSurface); + + + // Average Depth: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setAverageDepth(3)); + EXPECT_EQ(3, swimmingPoolIndoor.averageDepth()); + + // Activity Factor Schedule Name: Required Object + { + ScheduleConstant sch(m); + sch.setName("Activity Factor Schedule"); + EXPECT_TRUE(swimmingPoolIndoor.setActivityFactorSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.activityFactorSchedule()); + } + + // Make-up Water Supply Schedule Name: Required Object + { + ScheduleConstant sch(m); + sch.setName("Make-up Water Supply Schedule"); + EXPECT_TRUE(swimmingPoolIndoor.setMakeupWaterSupplySchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.makeupWaterSupplySchedule()); + } + + // Cover Schedule Name: Required Object + { + ScheduleConstant sch(m); + sch.setName("Cover Schedule"); + EXPECT_TRUE(swimmingPoolIndoor.setCoverSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.coverSchedule()); + } + + // Cover Evaporation Factor: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setCoverEvaporationFactor(0.5)); + EXPECT_EQ(0.5, swimmingPoolIndoor.coverEvaporationFactor()); + + // Cover Convection Factor: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setCoverConvectionFactor(0.6)); + EXPECT_EQ(0.6, swimmingPoolIndoor.coverConvectionFactor()); + + // Cover Short-Wavelength Radiation Factor: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setCoverShortWavelengthRadiationFactor(0.7)); + EXPECT_EQ(0.7, swimmingPoolIndoor.coverShortWavelengthRadiationFactor()); + + // Cover Long-Wavelength Radiation Factor: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setCoverLongWavelengthRadiationFactor(0.8)); + EXPECT_EQ(0.8, swimmingPoolIndoor.coverLongWavelengthRadiationFactor()); + + // Pool Heating System Maximum Water Flow Rate: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setPoolHeatingSystemMaximumWaterFlowRate(0.1)); + EXPECT_EQ(0.1, swimmingPoolIndoor.poolHeatingSystemMaximumWaterFlowRate()); + + // Pool Miscellaneous Equipment Power: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setPoolMiscellaneousEquipmentPower(2000.0)); + EXPECT_EQ(2000., swimmingPoolIndoor.poolMiscellaneousEquipmentPower()); + + // Setpoint Temperature Schedule: Required Object + { + ScheduleConstant sch(m); + sch.setName("Setpoint Temperature"); + EXPECT_TRUE(swimmingPoolIndoor.setSetpointTemperatureSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.setpointTemperatureSchedule()); + } + + // Maximum Number of People: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setMaximumNumberofPeople(12.5)); + EXPECT_EQ(12.5, swimmingPoolIndoor.maximumNumberofPeople()); + + + // People Schedule: Required Object + { + ScheduleConstant sch(m); + sch.setName("People Schedule"); + EXPECT_TRUE(swimmingPoolIndoor.setPeopleSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.peopleSchedule()); + } + + // People Heat Gain Schedule: Required Object + { + ScheduleConstant sch(m); + sch.setName("People Heat Gain Schedule"); + EXPECT_TRUE(swimmingPoolIndoor.setPeopleHeatGainSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.peopleHeatGainSchedule()); + } + + + // Not on a PlantLoop: not translated + { + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idfObjs = w.getObjectsByType(IddObjectType::SwimmingPool_Indoor); + ASSERT_EQ(0u, idfObjs.size()); + } + + PlantLoop p(m); + EXPECT_TRUE(p.addDemandBranchForComponent(swimmingPoolIndoor)); + ASSERT_TRUE(swimmingPoolIndoor.inletModelObject()); + swimmingPoolIndoor.inletModelObject()->setName("Pool Inlet Node"); + ASSERT_TRUE(swimmingPoolIndoor.outletModelObject()); + swimmingPoolIndoor.outletModelObject()->setName("Pool Outlet Node"); + + { + Workspace w = ft.translateModel(m); + + WorkspaceObjectVector idfObjs = w.getObjectsByType(IddObjectType::SwimmingPool_Indoor); + ASSERT_EQ(1u, idfObjs.size()); + WorkspaceObject idf_pool(idfObjs[0]); + + EXPECT_EQ(swimmingPoolIndoor.nameString(), idf_pool.getString(SwimmingPool_IndoorFields::Name).get()); + + EXPECT_EQ(3.0, idf_pool.getDouble(SwimmingPool_IndoorFields::AverageDepth).get()); + EXPECT_EQ(0.5, idf_pool.getDouble(SwimmingPool_IndoorFields::CoverEvaporationFactor).get()); + EXPECT_EQ(0.6, idf_pool.getDouble(SwimmingPool_IndoorFields::CoverConvectionFactor).get()); + EXPECT_EQ(0.7, idf_pool.getDouble(SwimmingPool_IndoorFields::CoverShortWavelengthRadiationFactor).get()); + EXPECT_EQ(0.8, idf_pool.getDouble(SwimmingPool_IndoorFields::CoverLongWavelengthRadiationFactor).get()); + EXPECT_EQ(0.1, idf_pool.getDouble(SwimmingPool_IndoorFields::PoolHeatingSystemMaximumWaterFlowRate).get()); + EXPECT_EQ(2000.0, idf_pool.getDouble(SwimmingPool_IndoorFields::PoolMiscellaneousEquipmentPower).get()); + EXPECT_EQ(12.5, idf_pool.getDouble(SwimmingPool_IndoorFields::MaximumNumberofPeople).get()); + + EXPECT_EQ("Activity Factor Schedule", idf_pool.getString(SwimmingPool_IndoorFields::ActivityFactorScheduleName).get()); + EXPECT_EQ("Make-up Water Supply Schedule", idf_pool.getString(SwimmingPool_IndoorFields::MakeupWaterSupplyScheduleName).get()); + EXPECT_EQ("Cover Schedule", idf_pool.getString(SwimmingPool_IndoorFields::CoverScheduleName).get()); + EXPECT_EQ("Setpoint Temperature", idf_pool.getString(SwimmingPool_IndoorFields::SetpointTemperatureSchedule).get()); + EXPECT_EQ("People Schedule", idf_pool.getString(SwimmingPool_IndoorFields::PeopleSchedule).get()); + EXPECT_EQ("People Heat Gain Schedule", idf_pool.getString(SwimmingPool_IndoorFields::PeopleHeatGainSchedule).get()); + + EXPECT_EQ("Pool Inlet Node", idf_pool.getString(SwimmingPool_IndoorFields::PoolWaterInletNode).get()); + EXPECT_EQ("Pool Outlet Node", idf_pool.getString(SwimmingPool_IndoorFields::PoolWaterOutletNode).get()); + } +} + +//TEST_F(EnergyPlusFixture, ReverseTranslator_SwimmingPoolIndoor) { + + //ReverseTranslator rt; + + //Workspace w(StrictnessLevel::None, IddFileType::EnergyPlus); + + //// Not there, Model shouldn't have it either + //Model m = rt.translateWorkspace(w); + //EXPECT_FALSE(m.getOptionalUniqueModelObject()); + + //OptionalWorkspaceObject _i_pool = w.addObject(IdfObject(IddObjectType::SwimmingPool_Indoor)); + //ASSERT_TRUE(_i_pool); + + //EXPECT_TRUE(_i_pool->setString(SwimmingPool_IndoorFields::SwimmingPoolIndoor, boolToString(json))); + //EXPECT_TRUE(_i_pool->setString(SwimmingPool_IndoorFields::OutputCBOR, boolToString(cbor))); + //EXPECT_TRUE(_i_pool->setString(SwimmingPool_IndoorFields::OutputMessagePack, boolToString(msgpack))); + + //Model m = rt.translateWorkspace(w); + + //// Get the unique object + //auto pools = m.getConcreteModelObjects(); + //ASSERT_EQ(1u, pools.size()); + +//} diff --git a/src/model/CMakeLists.txt b/src/model/CMakeLists.txt index f79a8912b88..bf94e52cf7b 100644 --- a/src/model/CMakeLists.txt +++ b/src/model/CMakeLists.txt @@ -1430,6 +1430,9 @@ set(${target_name}_src SurfacePropertyOtherSideConditionsModel.cpp SurfacePropertyOtherSideConditionsModel.hpp SurfacePropertyOtherSideConditionsModel_Impl.hpp + SwimmingPoolIndoor.cpp + SwimmingPoolIndoor.hpp + SwimmingPoolIndoor_Impl.hpp TableMultiVariableLookup.hpp TableMultiVariableLookup_Impl.hpp TableMultiVariableLookup.cpp @@ -2070,6 +2073,7 @@ set(${target_name}_test_src test/SurfacePropertyConvectionCoefficients_GTest.cpp test/SurfacePropertyOtherSideCoefficients_GTest.cpp test/SurfacePropertyExposedFoundationPerimeter_GTest.cpp + test/SwimmingPoolIndoor_GTest.cpp test/TableMultiVariableLookup_GTest.cpp test/ThermalZone_GTest.cpp test/ThermalStorageIceDetailed_GTest.cpp diff --git a/src/model/ConcreteModelObjects.hpp b/src/model/ConcreteModelObjects.hpp index 463f0a438cd..67482bdb2e6 100644 --- a/src/model/ConcreteModelObjects.hpp +++ b/src/model/ConcreteModelObjects.hpp @@ -453,6 +453,7 @@ #include "SurfacePropertyExposedFoundationPerimeter.hpp" #include "SurfacePropertyOtherSideCoefficients.hpp" #include "SurfacePropertyOtherSideConditionsModel.hpp" +#include "SwimmingPoolIndoor.hpp" #include "TableMultiVariableLookup.hpp" #include "TemperingValve.hpp" #include "ThermalZone.hpp" @@ -943,6 +944,7 @@ #include "SurfacePropertyExposedFoundationPerimeter_Impl.hpp" #include "SurfacePropertyOtherSideCoefficients_Impl.hpp" #include "SurfacePropertyOtherSideConditionsModel_Impl.hpp" +#include "SwimmingPoolIndoor_Impl.hpp" #include "TableMultiVariableLookup_Impl.hpp" #include "TemperingValve_Impl.hpp" #include "ThermalZone_Impl.hpp" diff --git a/src/model/Model.cpp b/src/model/Model.cpp index aec8f78e3d1..3956499eb55 100644 --- a/src/model/Model.cpp +++ b/src/model/Model.cpp @@ -3142,6 +3142,7 @@ detail::Model_Impl::ModelObjectCreator::ModelObjectCreator() { REGISTER_CONSTRUCTOR(SurfacePropertyExposedFoundationPerimeter); REGISTER_CONSTRUCTOR(SurfacePropertyOtherSideCoefficients); REGISTER_CONSTRUCTOR(SurfacePropertyOtherSideConditionsModel); + REGISTER_CONSTRUCTOR(SwimmingPoolIndoor); REGISTER_CONSTRUCTOR(TableMultiVariableLookup); REGISTER_CONSTRUCTOR(TemperingValve); REGISTER_CONSTRUCTOR(ThermochromicGlazing); @@ -3640,6 +3641,7 @@ detail::Model_Impl::ModelObjectCreator::ModelObjectCreator() { REGISTER_COPYCONSTRUCTORS(SurfacePropertyExposedFoundationPerimeter); REGISTER_COPYCONSTRUCTORS(SurfacePropertyOtherSideCoefficients); REGISTER_COPYCONSTRUCTORS(SurfacePropertyOtherSideConditionsModel); + REGISTER_COPYCONSTRUCTORS(SwimmingPoolIndoor); REGISTER_COPYCONSTRUCTORS(TableMultiVariableLookup); REGISTER_COPYCONSTRUCTORS(TemperingValve); REGISTER_COPYCONSTRUCTORS(ThermochromicGlazing); diff --git a/src/model/ModelHVAC.i b/src/model/ModelHVAC.i index 7978943c694..2a091c8e88f 100644 --- a/src/model/ModelHVAC.i +++ b/src/model/ModelHVAC.i @@ -175,6 +175,7 @@ MODELOBJECT_TEMPLATES(ChillerAbsorption); MODELOBJECT_TEMPLATES(SolarCollectorPerformanceFlatPlate); MODELOBJECT_TEMPLATES(SolarCollectorPerformanceIntegralCollectorStorage); MODELOBJECT_TEMPLATES(SolarCollectorPerformancePhotovoltaicThermalSimple); +MODELOBJECT_TEMPLATES(SwimmingPoolIndoor); MODELOBJECT_TEMPLATES(SetpointManagerFollowOutdoorAirTemperature); MODELOBJECT_TEMPLATES(SetpointManagerFollowSystemNodeTemperature); @@ -285,7 +286,7 @@ SWIG_MODELOBJECT(ChillerAbsorption, 1); SWIG_MODELOBJECT(SolarCollectorPerformanceFlatPlate, 1); SWIG_MODELOBJECT(SolarCollectorPerformanceIntegralCollectorStorage, 1); SWIG_MODELOBJECT(SolarCollectorPerformancePhotovoltaicThermalSimple, 1); - +SWIG_MODELOBJECT(SwimmingPoolIndoor,1); SWIG_MODELOBJECT(SetpointManagerFollowOutdoorAirTemperature,1); SWIG_MODELOBJECT(SetpointManagerFollowSystemNodeTemperature,1); diff --git a/src/model/ScheduleTypeRegistry.cpp b/src/model/ScheduleTypeRegistry.cpp index 22bbb8a12b7..d5517517140 100644 --- a/src/model/ScheduleTypeRegistry.cpp +++ b/src/model/ScheduleTypeRegistry.cpp @@ -328,6 +328,12 @@ ScheduleTypeRegistrySingleton::ScheduleTypeRegistrySingleton() {"SurfacePropertyConvectionCoefficients","Convection Coefficient 2","convectionCoefficient2Schedule",true,"",OptionalDouble(),OptionalDouble() }, {"SurfacePropertyConvectionCoefficientsMultipleSurface","Convection Coefficient 1","convectionCoefficient1Schedule",true,"",OptionalDouble(),OptionalDouble() }, {"SurfacePropertyConvectionCoefficientsMultipleSurface","Convection Coefficient 2","convectionCoefficient2Schedule",true,"",OptionalDouble(),OptionalDouble() }, + {"SwimmingPoolIndoor","Activity Factor","activityFactorSchedule",true,"",0.0,OptionalDouble()}, // can exceed 1.0, for wave pools for eg + {"SwimmingPoolIndoor","Make-up Water Supply","makeupWaterSupplySchedule",true,"Temperature",OptionalDouble(),OptionalDouble()}, + {"SwimmingPoolIndoor","Cover","coverSchedule",true,"",0.0,1.0}, + {"SwimmingPoolIndoor","Setpoint Temperature Schedule","setpointTemperatureSchedule",true,"Temperature",OptionalDouble(),OptionalDouble()}, + {"SwimmingPoolIndoor","People Schedule","peopleSchedule",true,"",0.0,1.0}, + {"SwimmingPoolIndoor","People Heat Gain Schedule","peopleHeatGainSchedule",true,"ActivityLevel",0.0,OptionalDouble()}, {"ThermalStorageIceDetailed","Availability Schedule","availabilitySchedule",false,"Availability",0.0,1.0}, {"ThermalStorageChilledWaterStratified","Setpoint Temperature","setpointTemperatureSchedule",true,"Temperature",OptionalDouble(),OptionalDouble()}, {"ThermalStorageChilledWaterStratified","Ambient Temperature","ambientTemperatureSchedule",true,"Temperature",OptionalDouble(),OptionalDouble()}, diff --git a/src/model/SwimmingPoolIndoor.cpp b/src/model/SwimmingPoolIndoor.cpp new file mode 100644 index 00000000000..48d87ae64c9 --- /dev/null +++ b/src/model/SwimmingPoolIndoor.cpp @@ -0,0 +1,632 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#include "SwimmingPoolIndoor.hpp" +#include "SwimmingPoolIndoor_Impl.hpp" + +#include "Model.hpp" +#include "Model_Impl.hpp" +#include "Surface.hpp" +#include "Surface_Impl.hpp" +#include "Schedule.hpp" +#include "Schedule_Impl.hpp" +#include "Node.hpp" +#include "Node_Impl.hpp" +#include "PlantLoop.hpp" +#include "PlantLoop_Impl.hpp" +#include "ScheduleRuleset.hpp" + +#include "ScheduleTypeLimits.hpp" +#include "ScheduleTypeRegistry.hpp" + +#include +#include + +#include "../utilities/units/Unit.hpp" + +#include "../utilities/core/Assert.hpp" + +namespace openstudio { +namespace model { + +namespace detail { + + SwimmingPoolIndoor_Impl::SwimmingPoolIndoor_Impl(const IdfObject& idfObject, + Model_Impl* model, + bool keepHandle) + : StraightComponent_Impl(idfObject,model,keepHandle) + { + OS_ASSERT(idfObject.iddObject().type() == SwimmingPoolIndoor::iddObjectType()); + } + + SwimmingPoolIndoor_Impl::SwimmingPoolIndoor_Impl(const openstudio::detail::WorkspaceObject_Impl& other, + Model_Impl* model, + bool keepHandle) + : StraightComponent_Impl(other,model,keepHandle) + { + OS_ASSERT(other.iddObject().type() == SwimmingPoolIndoor::iddObjectType()); + } + + SwimmingPoolIndoor_Impl::SwimmingPoolIndoor_Impl(const SwimmingPoolIndoor_Impl& other, + Model_Impl* model, + bool keepHandle) + : StraightComponent_Impl(other,model,keepHandle) + {} + + const std::vector& SwimmingPoolIndoor_Impl::outputVariableNames() const + { + static std::vector result{ + "Indoor Pool Makeup Water Rate", + "Indoor Pool Makeup Water Volume", + "Indoor Pool Makeup Water Temperature", + "Indoor Pool Water Temperature", + "Indoor Pool Inlet Water Temperature", + "Indoor Pool Inlet Water Mass Flow Rate", + "Indoor Pool Miscellaneous Equipment Power", + "Indoor Pool Miscellaneous Equipment Energy", + "Indoor Pool Water Heating Rate", + "Indoor Pool Water Heating Energy", + "Indoor Pool Radiant to Convection by Cover", + "Indoor Pool People Heat Gain", + "Indoor Pool Current Activity Factor", + "Indoor Pool Current Cover Factor", + "Indoor Pool Saturation Pressure at Pool Temperature", + "Indoor Pool Partial Pressure of Water Vapor in Air", + "Indoor Pool Current Cover Evaporation Factor", + "Indoor Pool Current Cover Convective Factor", + "Indoor Pool Current Cover SW Radiation Factor", + "Indoor Pool Current Cover LW Radiation Factor", + "Indoor Pool Evaporative Heat Loss Rate", + "Indoor Pool Evaporative Heat Loss Energy" + }; + return result; + } + + IddObjectType SwimmingPoolIndoor_Impl::iddObjectType() const { + return SwimmingPoolIndoor::iddObjectType(); + } + + std::vector SwimmingPoolIndoor_Impl::getScheduleTypeKeys(const Schedule& schedule) const + { + std::vector result; + UnsignedVector fieldIndices = getSourceIndices(schedule.handle()); + UnsignedVector::const_iterator b(fieldIndices.begin()), e(fieldIndices.end()); + if (std::find(b,e,OS_SwimmingPool_IndoorFields::ActivityFactorScheduleName) != e) + { + result.push_back(ScheduleTypeKey("SwimmingPoolIndoor","Activity Factor")); + } + if (std::find(b,e,OS_SwimmingPool_IndoorFields::MakeupWaterSupplyScheduleName) != e) + { + result.push_back(ScheduleTypeKey("SwimmingPoolIndoor","Make-up Water Supply")); + } + if (std::find(b,e,OS_SwimmingPool_IndoorFields::CoverScheduleName) != e) + { + result.push_back(ScheduleTypeKey("SwimmingPoolIndoor","Cover")); + } + if (std::find(b,e,OS_SwimmingPool_IndoorFields::SetpointTemperatureSchedule) != e) + { + result.push_back(ScheduleTypeKey("SwimmingPoolIndoor","Setpoint Temperature Schedule")); + } + if (std::find(b,e,OS_SwimmingPool_IndoorFields::PeopleSchedule) != e) + { + result.push_back(ScheduleTypeKey("SwimmingPoolIndoor","People Schedule")); + } + if (std::find(b,e,OS_SwimmingPool_IndoorFields::PeopleHeatGainSchedule) != e) + { + result.push_back(ScheduleTypeKey("SwimmingPoolIndoor","People Heat Gain Schedule")); + } + return result; + } + + unsigned SwimmingPoolIndoor_Impl::inletPort() const + { + return OS_SwimmingPool_IndoorFields::PoolWaterInletNode; + } + + unsigned SwimmingPoolIndoor_Impl::outletPort() const + { + return OS_SwimmingPool_IndoorFields::PoolWaterOutletNode; + } + + bool SwimmingPoolIndoor_Impl::addToNode(Node & node) + { + if( boost::optional plant = node.plantLoop() ) { + if( plant->demandComponent(node.handle()) ) { + return StraightComponent_Impl::addToNode(node); + } + } + + return false; + } + + Surface SwimmingPoolIndoor_Impl::surface() const { + boost::optional value = optionalSurface(); + if (!value) { + LOG_AND_THROW(briefDescription() << " does not have an Surface attached."); + } + return value.get(); + } + + double SwimmingPoolIndoor_Impl::averageDepth() const { + boost::optional value = getDouble(OS_SwimmingPool_IndoorFields::AverageDepth,true); + OS_ASSERT(value); + return value.get(); + } + + Schedule SwimmingPoolIndoor_Impl::activityFactorSchedule() const { + boost::optional value = optionalActivityFactorSchedule(); + if (!value) { + LOG_AND_THROW(briefDescription() << " does not have an Activity Factor Schedule attached."); + } + return value.get(); + } + + Schedule SwimmingPoolIndoor_Impl::makeupWaterSupplySchedule() const { + boost::optional value = optionalMakeupWaterSupplySchedule(); + if (!value) { + LOG_AND_THROW(briefDescription() << " does not have an Makeup Water Supply Schedule attached."); + } + return value.get(); + } + + Schedule SwimmingPoolIndoor_Impl::coverSchedule() const { + boost::optional value = optionalCoverSchedule(); + if (!value) { + LOG_AND_THROW(briefDescription() << " does not have an Cover Schedule attached."); + } + return value.get(); + } + + double SwimmingPoolIndoor_Impl::coverEvaporationFactor() const { + boost::optional value = getDouble(OS_SwimmingPool_IndoorFields::CoverEvaporationFactor,true); + OS_ASSERT(value); + return value.get(); + } + + double SwimmingPoolIndoor_Impl::coverConvectionFactor() const { + boost::optional value = getDouble(OS_SwimmingPool_IndoorFields::CoverConvectionFactor,true); + OS_ASSERT(value); + return value.get(); + } + + double SwimmingPoolIndoor_Impl::coverShortWavelengthRadiationFactor() const { + boost::optional value = getDouble(OS_SwimmingPool_IndoorFields::CoverShortWavelengthRadiationFactor,true); + OS_ASSERT(value); + return value.get(); + } + + double SwimmingPoolIndoor_Impl::coverLongWavelengthRadiationFactor() const { + boost::optional value = getDouble(OS_SwimmingPool_IndoorFields::CoverLongWavelengthRadiationFactor,true); + OS_ASSERT(value); + return value.get(); + } + + double SwimmingPoolIndoor_Impl::poolHeatingSystemMaximumWaterFlowRate() const { + boost::optional value = getDouble(OS_SwimmingPool_IndoorFields::PoolHeatingSystemMaximumWaterFlowRate,true); + OS_ASSERT(value); + return value.get(); + } + + double SwimmingPoolIndoor_Impl::poolMiscellaneousEquipmentPower() const { + boost::optional value = getDouble(OS_SwimmingPool_IndoorFields::PoolMiscellaneousEquipmentPower,true); + OS_ASSERT(value); + return value.get(); + } + + Schedule SwimmingPoolIndoor_Impl::setpointTemperatureSchedule() const { + boost::optional value = optionalSetpointTemperatureSchedule(); + if (!value) { + LOG_AND_THROW(briefDescription() << " does not have an Setpoint Temperature Schedule attached."); + } + return value.get(); + } + + double SwimmingPoolIndoor_Impl::maximumNumberofPeople() const { + boost::optional value = getDouble(OS_SwimmingPool_IndoorFields::MaximumNumberofPeople,true); + OS_ASSERT(value); + return value.get(); + } + + Schedule SwimmingPoolIndoor_Impl::peopleSchedule() const { + boost::optional value = optionalPeopleSchedule(); + if (!value) { + LOG_AND_THROW(briefDescription() << " does not have an People Schedule attached."); + } + return value.get(); + } + + Schedule SwimmingPoolIndoor_Impl::peopleHeatGainSchedule() const { + boost::optional value = optionalPeopleHeatGainSchedule(); + if (!value) { + LOG_AND_THROW(briefDescription() << " does not have an People Heat Gain Schedule attached."); + } + return value.get(); + } + + bool SwimmingPoolIndoor_Impl::setSurface(const Surface& floorSurface) { + if (!openstudio::istringEqual(floorSurface.surfaceType(), "Floor")) { + LOG(Error, "Only surfaceTypes of 'Floor' accepted: Unable to set " << briefDescription() << "'s Surface to " + << floorSurface.briefDescription() << " which has a surface Type of '" << floorSurface.surfaceType() << "'."); + return false; + } + bool result = setPointer(OS_SwimmingPool_IndoorFields::SurfaceName, floorSurface.handle()); + return result; + } + + bool SwimmingPoolIndoor_Impl::setAverageDepth(double averageDepth) { + bool result = setDouble(OS_SwimmingPool_IndoorFields::AverageDepth, averageDepth); + return result; + } + + bool SwimmingPoolIndoor_Impl::setActivityFactorSchedule(Schedule& schedule) { + bool result = setSchedule(OS_SwimmingPool_IndoorFields::ActivityFactorScheduleName, + "SwimmingPoolIndoor", + "Activity Factor", + schedule); + return result; + } + + bool SwimmingPoolIndoor_Impl::setMakeupWaterSupplySchedule(Schedule& schedule) { + bool result = setSchedule(OS_SwimmingPool_IndoorFields::MakeupWaterSupplyScheduleName, + "SwimmingPoolIndoor", + "Make-up Water Supply", + schedule); + return result; + } + + bool SwimmingPoolIndoor_Impl::setCoverSchedule(Schedule& schedule) { + bool result = setSchedule(OS_SwimmingPool_IndoorFields::CoverScheduleName, + "SwimmingPoolIndoor", + "Cover", + schedule); + return result; + } + + bool SwimmingPoolIndoor_Impl::setCoverEvaporationFactor(double coverEvaporationFactor) { + bool result = setDouble(OS_SwimmingPool_IndoorFields::CoverEvaporationFactor, coverEvaporationFactor); + return result; + } + + bool SwimmingPoolIndoor_Impl::setCoverConvectionFactor(double coverConvectionFactor) { + bool result = setDouble(OS_SwimmingPool_IndoorFields::CoverConvectionFactor, coverConvectionFactor); + return result; + } + + bool SwimmingPoolIndoor_Impl::setCoverShortWavelengthRadiationFactor(double coverShortWavelengthRadiationFactor) { + bool result = setDouble(OS_SwimmingPool_IndoorFields::CoverShortWavelengthRadiationFactor, coverShortWavelengthRadiationFactor); + return result; + } + + bool SwimmingPoolIndoor_Impl::setCoverLongWavelengthRadiationFactor(double coverLongWavelengthRadiationFactor) { + bool result = setDouble(OS_SwimmingPool_IndoorFields::CoverLongWavelengthRadiationFactor, coverLongWavelengthRadiationFactor); + return result; + } + + bool SwimmingPoolIndoor_Impl::setPoolHeatingSystemMaximumWaterFlowRate(double poolHeatingSystemMaximumWaterFlowRate) { + bool result = setDouble(OS_SwimmingPool_IndoorFields::PoolHeatingSystemMaximumWaterFlowRate, poolHeatingSystemMaximumWaterFlowRate); + return result; + } + + bool SwimmingPoolIndoor_Impl::setPoolMiscellaneousEquipmentPower(double poolMiscellaneousEquipmentPower) { + bool result = setDouble(OS_SwimmingPool_IndoorFields::PoolMiscellaneousEquipmentPower, poolMiscellaneousEquipmentPower); + return result; + } + + bool SwimmingPoolIndoor_Impl::setSetpointTemperatureSchedule(Schedule& schedule) { + bool result = setSchedule(OS_SwimmingPool_IndoorFields::SetpointTemperatureSchedule, + "SwimmingPoolIndoor", + "Setpoint Temperature Schedule", + schedule); + return result; + } + + bool SwimmingPoolIndoor_Impl::setMaximumNumberofPeople(double maximumNumberofPeople) { + bool result = setDouble(OS_SwimmingPool_IndoorFields::MaximumNumberofPeople, maximumNumberofPeople); + return result; + } + + bool SwimmingPoolIndoor_Impl::setPeopleSchedule(Schedule& schedule) { + bool result = setSchedule(OS_SwimmingPool_IndoorFields::PeopleSchedule, + "SwimmingPoolIndoor", + "People Schedule", + schedule); + return result; + } + + bool SwimmingPoolIndoor_Impl::setPeopleHeatGainSchedule(Schedule& schedule) { + bool result = setSchedule(OS_SwimmingPool_IndoorFields::PeopleHeatGainSchedule, + "SwimmingPoolIndoor", + "People Heat Gain Schedule", + schedule); + return result; + } + + boost::optional SwimmingPoolIndoor_Impl::optionalSurface() const { + return getObject().getModelObjectTarget(OS_SwimmingPool_IndoorFields::SurfaceName); + } + + boost::optional SwimmingPoolIndoor_Impl::optionalActivityFactorSchedule() const { + return getObject().getModelObjectTarget(OS_SwimmingPool_IndoorFields::ActivityFactorScheduleName); + } + + boost::optional SwimmingPoolIndoor_Impl::optionalMakeupWaterSupplySchedule() const { + return getObject().getModelObjectTarget(OS_SwimmingPool_IndoorFields::MakeupWaterSupplyScheduleName); + } + + boost::optional SwimmingPoolIndoor_Impl::optionalCoverSchedule() const { + return getObject().getModelObjectTarget(OS_SwimmingPool_IndoorFields::CoverScheduleName); + } + + boost::optional SwimmingPoolIndoor_Impl::optionalSetpointTemperatureSchedule() const { + return getObject().getModelObjectTarget(OS_SwimmingPool_IndoorFields::SetpointTemperatureSchedule); + } + + boost::optional SwimmingPoolIndoor_Impl::optionalPeopleSchedule() const { + return getObject().getModelObjectTarget(OS_SwimmingPool_IndoorFields::PeopleSchedule); + } + + boost::optional SwimmingPoolIndoor_Impl::optionalPeopleHeatGainSchedule() const { + return getObject().getModelObjectTarget(OS_SwimmingPool_IndoorFields::PeopleHeatGainSchedule); + } + + // convenience + boost::optional SwimmingPoolIndoor_Impl::poolWaterInletNode() const + { + boost::optional result; + + if (auto mo = inletModelObject()) { + result = mo->optionalCast(); + } + return result; + } + + boost::optional SwimmingPoolIndoor_Impl::poolWaterOutletNode() const + { + boost::optional result; + + if (auto mo = outletModelObject()) { + result = mo->optionalCast(); + } + return result; + } + +} // detail + +SwimmingPoolIndoor::SwimmingPoolIndoor(const Model& model, const Surface& floorSurface) + : StraightComponent(SwimmingPoolIndoor::iddObjectType(),model) +{ + OS_ASSERT(getImpl()); + + // Appropriately handle the following required object-list fields. + // OS_SwimmingPool_IndoorFields::SurfaceName + // OS_SwimmingPool_IndoorFields::ActivityFactorScheduleName + // OS_SwimmingPool_IndoorFields::MakeupWaterSupplyScheduleName + // OS_SwimmingPool_IndoorFields::CoverScheduleName + // OS_SwimmingPool_IndoorFields::PoolWaterInletNode + // OS_SwimmingPool_IndoorFields::PoolWaterOutletNode + // OS_SwimmingPool_IndoorFields::SetpointTemperatureSchedule + // OS_SwimmingPool_IndoorFields::PeopleSchedule + // OS_SwimmingPool_IndoorFields::PeopleHeatGainSchedule + + bool ok = setSurface(floorSurface); + if (!ok) { + LOG_AND_THROW(floorSurface.briefDescription() << " is not a valid surface for a SwimmingPool:Indoor object"); + } + + + // IDD Defaults + setCoverEvaporationFactor(0.0); + setCoverConvectionFactor(0.0); + setCoverShortWavelengthRadiationFactor(0.0); + setCoverLongWavelengthRadiationFactor(0.0); + + // No IDD defaults + + // It makes sense to assume zero + setPoolMiscellaneousEquipmentPower(0.0); + // Abritrary depth of 2m... + setAverageDepth(2.0); + + // Assume pool is always uncovered + auto alwaysOff = model.alwaysOffDiscreteSchedule(); + ok = setCoverSchedule(alwaysOff); + OS_ASSERT(ok); + + auto alwaysOn = model.alwaysOnDiscreteSchedule(); + ok = setPeopleSchedule(alwaysOn); + OS_ASSERT(ok); + + ok = setActivityFactorSchedule(alwaysOn); + OS_ASSERT(ok); + + + // These don't have defaults in the E+ IDD, and are hard to make sensible defaults for, so use numbers from 5ZoneSwimmingPool + setPoolHeatingSystemMaximumWaterFlowRate(0.1); + setMaximumNumberofPeople(15.0); + + // 16.67? take as arg to Ctor? + auto makeUpSch = ScheduleRuleset(model, 16.67); + makeUpSch.setName("Pool MakeUp Water Temperature Schedule"); + ok = setMakeupWaterSupplySchedule(makeUpSch); + OS_ASSERT(ok); + + // Assume 300W? take as arg to Ctor? + auto gainSch = ScheduleRuleset(model, 300.0); + gainSch.setName("Pool People Heat Gain Schedule"); + ok = setPeopleHeatGainSchedule(gainSch); + OS_ASSERT(ok); + + auto tempSch = ScheduleRuleset(model, 27.0); + tempSch.setName("Pool Setpoint Temperature Schedule"); + ok = setSetpointTemperatureSchedule(tempSch); + OS_ASSERT(ok); +} + +IddObjectType SwimmingPoolIndoor::iddObjectType() { + return IddObjectType(IddObjectType::OS_SwimmingPool_Indoor); +} + +Surface SwimmingPoolIndoor::surface() const { + return getImpl()->surface(); +} + +double SwimmingPoolIndoor::averageDepth() const { + return getImpl()->averageDepth(); +} + +Schedule SwimmingPoolIndoor::activityFactorSchedule() const { + return getImpl()->activityFactorSchedule(); +} + +Schedule SwimmingPoolIndoor::makeupWaterSupplySchedule() const { + return getImpl()->makeupWaterSupplySchedule(); +} + +Schedule SwimmingPoolIndoor::coverSchedule() const { + return getImpl()->coverSchedule(); +} + +double SwimmingPoolIndoor::coverEvaporationFactor() const { + return getImpl()->coverEvaporationFactor(); +} + +double SwimmingPoolIndoor::coverConvectionFactor() const { + return getImpl()->coverConvectionFactor(); +} + +double SwimmingPoolIndoor::coverShortWavelengthRadiationFactor() const { + return getImpl()->coverShortWavelengthRadiationFactor(); +} + +double SwimmingPoolIndoor::coverLongWavelengthRadiationFactor() const { + return getImpl()->coverLongWavelengthRadiationFactor(); +} + +double SwimmingPoolIndoor::poolHeatingSystemMaximumWaterFlowRate() const { + return getImpl()->poolHeatingSystemMaximumWaterFlowRate(); +} + +double SwimmingPoolIndoor::poolMiscellaneousEquipmentPower() const { + return getImpl()->poolMiscellaneousEquipmentPower(); +} + +Schedule SwimmingPoolIndoor::setpointTemperatureSchedule() const { + return getImpl()->setpointTemperatureSchedule(); +} + +double SwimmingPoolIndoor::maximumNumberofPeople() const { + return getImpl()->maximumNumberofPeople(); +} + +Schedule SwimmingPoolIndoor::peopleSchedule() const { + return getImpl()->peopleSchedule(); +} + +Schedule SwimmingPoolIndoor::peopleHeatGainSchedule() const { + return getImpl()->peopleHeatGainSchedule(); +} + +bool SwimmingPoolIndoor::setSurface(const Surface& floorSurface) { + return getImpl()->setSurface(floorSurface); +} + +bool SwimmingPoolIndoor::setAverageDepth(double averageDepth) { + return getImpl()->setAverageDepth(averageDepth); +} + +bool SwimmingPoolIndoor::setActivityFactorSchedule(Schedule& schedule) { + return getImpl()->setActivityFactorSchedule(schedule); +} + +bool SwimmingPoolIndoor::setMakeupWaterSupplySchedule(Schedule& schedule) { + return getImpl()->setMakeupWaterSupplySchedule(schedule); +} + +bool SwimmingPoolIndoor::setCoverSchedule(Schedule& schedule) { + return getImpl()->setCoverSchedule(schedule); +} + +bool SwimmingPoolIndoor::setCoverEvaporationFactor(double coverEvaporationFactor) { + return getImpl()->setCoverEvaporationFactor(coverEvaporationFactor); +} + +bool SwimmingPoolIndoor::setCoverConvectionFactor(double coverConvectionFactor) { + return getImpl()->setCoverConvectionFactor(coverConvectionFactor); +} + +bool SwimmingPoolIndoor::setCoverShortWavelengthRadiationFactor(double coverShortWavelengthRadiationFactor) { + return getImpl()->setCoverShortWavelengthRadiationFactor(coverShortWavelengthRadiationFactor); +} + +bool SwimmingPoolIndoor::setCoverLongWavelengthRadiationFactor(double coverLongWavelengthRadiationFactor) { + return getImpl()->setCoverLongWavelengthRadiationFactor(coverLongWavelengthRadiationFactor); +} + +bool SwimmingPoolIndoor::setPoolHeatingSystemMaximumWaterFlowRate(double poolHeatingSystemMaximumWaterFlowRate) { + return getImpl()->setPoolHeatingSystemMaximumWaterFlowRate(poolHeatingSystemMaximumWaterFlowRate); +} + +bool SwimmingPoolIndoor::setPoolMiscellaneousEquipmentPower(double poolMiscellaneousEquipmentPower) { + return getImpl()->setPoolMiscellaneousEquipmentPower(poolMiscellaneousEquipmentPower); +} + +bool SwimmingPoolIndoor::setSetpointTemperatureSchedule(Schedule& schedule) { + return getImpl()->setSetpointTemperatureSchedule(schedule); +} + +bool SwimmingPoolIndoor::setMaximumNumberofPeople(double maximumNumberofPeople) { + return getImpl()->setMaximumNumberofPeople(maximumNumberofPeople); +} + +bool SwimmingPoolIndoor::setPeopleSchedule(Schedule& schedule) { + return getImpl()->setPeopleSchedule(schedule); +} + +bool SwimmingPoolIndoor::setPeopleHeatGainSchedule(Schedule& schedule) { + return getImpl()->setPeopleHeatGainSchedule(schedule); +} + +/// @cond +SwimmingPoolIndoor::SwimmingPoolIndoor(std::shared_ptr impl) + : StraightComponent(impl) +{} +/// @endcond + + +boost::optional SwimmingPoolIndoor::poolWaterInletNode() const { + return getImpl()->poolWaterInletNode(); +} + +boost::optional SwimmingPoolIndoor::poolWaterOutletNode() const { + return getImpl()->poolWaterOutletNode(); +} + +} // model +} // openstudio + diff --git a/src/model/SwimmingPoolIndoor.hpp b/src/model/SwimmingPoolIndoor.hpp new file mode 100644 index 00000000000..782abb7ef92 --- /dev/null +++ b/src/model/SwimmingPoolIndoor.hpp @@ -0,0 +1,168 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#ifndef MODEL_SWIMMINGPOOLINDOOR_HPP +#define MODEL_SWIMMINGPOOLINDOOR_HPP + +#include +#include "StraightComponent.hpp" + +namespace openstudio { + +namespace model { + +class Surface; +class Schedule; +class Node; + +namespace detail { + + class SwimmingPoolIndoor_Impl; + +} // detail + +/** SwimmingPoolIndoor is a StraightComponent that wraps the OpenStudio IDD object 'OS:SwimmingPool:Indoor'. */ +class MODEL_API SwimmingPoolIndoor : public StraightComponent { + public: + /** @name Constructors and Destructors */ + //@{ + + explicit SwimmingPoolIndoor(const Model& model, const Surface& floorSurface); + + virtual ~SwimmingPoolIndoor() {} + + //@} + + static IddObjectType iddObjectType(); + + /** @name Getters */ + //@{ + + Surface surface() const; + + double averageDepth() const; + + Schedule activityFactorSchedule() const; + + Schedule makeupWaterSupplySchedule() const; + + Schedule coverSchedule() const; + + double coverEvaporationFactor() const; + + double coverConvectionFactor() const; + + double coverShortWavelengthRadiationFactor() const; + + double coverLongWavelengthRadiationFactor() const; + + double poolHeatingSystemMaximumWaterFlowRate() const; + + double poolMiscellaneousEquipmentPower() const; + + Schedule setpointTemperatureSchedule() const; + + double maximumNumberofPeople() const; + + Schedule peopleSchedule() const; + + Schedule peopleHeatGainSchedule() const; + + //@} + /** @name Setters */ + //@{ + + // Set the Pool's surface object. Surface MUST be of type 'Floor' + bool setSurface(const Surface& floorSurface); + + bool setAverageDepth(double averageDepth); + + bool setActivityFactorSchedule(Schedule& schedule); + + bool setMakeupWaterSupplySchedule(Schedule& schedule); + + bool setCoverSchedule(Schedule& schedule); + + bool setCoverEvaporationFactor(double coverEvaporationFactor); + + bool setCoverConvectionFactor(double coverConvectionFactor); + + bool setCoverShortWavelengthRadiationFactor(double coverShortWavelengthRadiationFactor); + + bool setCoverLongWavelengthRadiationFactor(double coverLongWavelengthRadiationFactor); + + bool setPoolHeatingSystemMaximumWaterFlowRate(double poolHeatingSystemMaximumWaterFlowRate); + + bool setPoolMiscellaneousEquipmentPower(double poolMiscellaneousEquipmentPower); + + bool setSetpointTemperatureSchedule(Schedule& schedule); + + bool setMaximumNumberofPeople(double maximumNumberofPeople); + + bool setPeopleSchedule(Schedule& schedule); + + bool setPeopleHeatGainSchedule(Schedule& schedule); + + //@} + /** @name Other */ + //@{ + + // Convenience function to return the inletNode of the Pool object + boost::optional poolWaterInletNode() const; + + // Convenience function to return the Outlet Node of the Pool object + boost::optional poolWaterOutletNode() const; + + //@} + protected: + /// @cond + typedef detail::SwimmingPoolIndoor_Impl ImplType; + + explicit SwimmingPoolIndoor(std::shared_ptr impl); + + friend class detail::SwimmingPoolIndoor_Impl; + friend class Model; + friend class IdfObject; + friend class openstudio::detail::IdfObject_Impl; + /// @endcond + private: + REGISTER_LOGGER("openstudio.model.SwimmingPoolIndoor"); +}; + +/** \relates SwimmingPoolIndoor*/ +typedef boost::optional OptionalSwimmingPoolIndoor; + +/** \relates SwimmingPoolIndoor*/ +typedef std::vector SwimmingPoolIndoorVector; + +} // model +} // openstudio + +#endif // MODEL_SWIMMINGPOOLINDOOR_HPP + diff --git a/src/model/SwimmingPoolIndoor_Impl.hpp b/src/model/SwimmingPoolIndoor_Impl.hpp new file mode 100644 index 00000000000..9b9af46e9bc --- /dev/null +++ b/src/model/SwimmingPoolIndoor_Impl.hpp @@ -0,0 +1,186 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#ifndef MODEL_SWIMMINGPOOLINDOOR_IMPL_HPP +#define MODEL_SWIMMINGPOOLINDOOR_IMPL_HPP + +#include +#include "StraightComponent_Impl.hpp" + +namespace openstudio { +namespace model { + +class Surface; +class Schedule; +class Node; + +namespace detail { + + /** SwimmingPoolIndoor_Impl is a StraightComponent_Impl that is the implementation class for SwimmingPoolIndoor.*/ + class MODEL_API SwimmingPoolIndoor_Impl : public StraightComponent_Impl { + public: + /** @name Constructors and Destructors */ + //@{ + + SwimmingPoolIndoor_Impl(const IdfObject& idfObject, + Model_Impl* model, + bool keepHandle); + + SwimmingPoolIndoor_Impl(const openstudio::detail::WorkspaceObject_Impl& other, + Model_Impl* model, + bool keepHandle); + + SwimmingPoolIndoor_Impl(const SwimmingPoolIndoor_Impl& other, + Model_Impl* model, + bool keepHandle); + + virtual ~SwimmingPoolIndoor_Impl() {} + + //@} + /** @name Virtual Methods */ + //@{ + + virtual const std::vector& outputVariableNames() const override; + + virtual IddObjectType iddObjectType() const override; + + virtual std::vector getScheduleTypeKeys(const Schedule& schedule) const override; + + virtual unsigned inletPort() const override; + + virtual unsigned outletPort() const override; + + virtual bool addToNode(Node & node) override; + + //@} + /** @name Getters */ + //@{ + + Surface surface() const; + + double averageDepth() const; + + Schedule activityFactorSchedule() const; + + Schedule makeupWaterSupplySchedule() const; + + Schedule coverSchedule() const; + + double coverEvaporationFactor() const; + + double coverConvectionFactor() const; + + double coverShortWavelengthRadiationFactor() const; + + double coverLongWavelengthRadiationFactor() const; + + double poolHeatingSystemMaximumWaterFlowRate() const; + + double poolMiscellaneousEquipmentPower() const; + + Schedule setpointTemperatureSchedule() const; + + double maximumNumberofPeople() const; + + Schedule peopleSchedule() const; + + Schedule peopleHeatGainSchedule() const; + + //@} + /** @name Setters */ + //@{ + + bool setSurface(const Surface& floorSurface); + + bool setAverageDepth(double averageDepth); + + bool setActivityFactorSchedule(Schedule& schedule); + + bool setMakeupWaterSupplySchedule(Schedule& schedule); + + bool setCoverSchedule(Schedule& schedule); + + bool setCoverEvaporationFactor(double coverEvaporationFactor); + + bool setCoverConvectionFactor(double coverConvectionFactor); + + bool setCoverShortWavelengthRadiationFactor(double coverShortWavelengthRadiationFactor); + + bool setCoverLongWavelengthRadiationFactor(double coverLongWavelengthRadiationFactor); + + bool setPoolWaterInletNode(const Connection& connection); + + bool setPoolWaterOutletNode(const Connection& connection); + + bool setPoolHeatingSystemMaximumWaterFlowRate(double poolHeatingSystemMaximumWaterFlowRate); + + bool setPoolMiscellaneousEquipmentPower(double poolMiscellaneousEquipmentPower); + + bool setSetpointTemperatureSchedule(Schedule& schedule); + + bool setMaximumNumberofPeople(double maximumNumberofPeople); + + bool setPeopleSchedule(Schedule& schedule); + + bool setPeopleHeatGainSchedule(Schedule& schedule); + + //@} + /** @name Other */ + //@{ + + // Convenience function to return the inletNode of the Pool object + boost::optional poolWaterInletNode() const; + + // Convenience function to return the Outlet Node of the Pool object + boost::optional poolWaterOutletNode() const; + + //@} + protected: + private: + REGISTER_LOGGER("openstudio.model.SwimmingPoolIndoor"); + + // Optional getters for use by methods like children() so can remove() if the constructor fails. + // There are other ways for the public versions of these getters to fail--perhaps all required + // objects should be returned as boost::optionals + boost::optional optionalSurface() const; + boost::optional optionalActivityFactorSchedule() const; + boost::optional optionalMakeupWaterSupplySchedule() const; + boost::optional optionalCoverSchedule() const; + boost::optional optionalSetpointTemperatureSchedule() const; + boost::optional optionalPeopleSchedule() const; + boost::optional optionalPeopleHeatGainSchedule() const; + }; + +} // detail + +} // model +} // openstudio + +#endif // MODEL_SWIMMINGPOOLINDOOR_IMPL_HPP + diff --git a/src/model/test/SwimmingPoolIndoor_GTest.cpp b/src/model/test/SwimmingPoolIndoor_GTest.cpp new file mode 100644 index 00000000000..1a427666a05 --- /dev/null +++ b/src/model/test/SwimmingPoolIndoor_GTest.cpp @@ -0,0 +1,263 @@ +/*********************************************************************************************************************** +* OpenStudio(R), Copyright (c) 2008-2020, Alliance for Sustainable Energy, LLC, and other contributors. All rights reserved. +* +* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the +* following conditions are met: +* +* (1) Redistributions of source code must retain the above copyright notice, this list of conditions and the following +* disclaimer. +* +* (2) Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following +* disclaimer in the documentation and/or other materials provided with the distribution. +* +* (3) Neither the name of the copyright holder nor the names of any contributors may be used to endorse or promote products +* derived from this software without specific prior written permission from the respective party. +* +* (4) Other than as required in clauses (1) and (2), distributions in any form of modifications or other derivative works +* may not use the "OpenStudio" trademark, "OS", "os", or any other confusingly similar designation without specific prior +* written permission from Alliance for Sustainable Energy, LLC. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND ANY CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, +* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S), ANY CONTRIBUTORS, THE UNITED STATES GOVERNMENT, OR THE UNITED +* STATES DEPARTMENT OF ENERGY, NOR ANY OF THEIR EMPLOYEES, BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +***********************************************************************************************************************/ + +#include "ModelFixture.hpp" + +#include "../SwimmingPoolIndoor.hpp" +#include "../SwimmingPoolIndoor_Impl.hpp" + +#include "../Surface.hpp" +#include "../Space.hpp" +#include "../ScheduleConstant.hpp" +#include "../ScheduleRuleset.hpp" +#include "../AirLoopHVAC.hpp" +#include "../AirLoopHVACZoneSplitter.hpp" +#include "../PlantLoop.hpp" +#include "../Node.hpp" +#include "../Node_Impl.hpp" + +#include "../../utilities/geometry/Point3d.hpp" +#include + +using namespace openstudio; +using namespace openstudio::model; + +TEST_F(ModelFixture, SwimmingPoolIndoor_GettersSetters) { + Model m; + + Point3dVector floorPrint; + floorPrint.push_back(Point3d(0, 10, 0)); + floorPrint.push_back(Point3d(10, 10, 0)); + floorPrint.push_back(Point3d(10, 0, 0)); + floorPrint.push_back(Point3d(0, 0, 0)); + boost::optional space1 = Space::fromFloorPrint(floorPrint, 3, m); + ASSERT_TRUE(space1); + auto surfaces = space1->surfaces(); + EXPECT_EQ(6u, surfaces.size()); + + auto wallSurfaceIt = std::find_if(std::begin(surfaces), std::end(surfaces), [](const auto& surface) { return surface.surfaceType() == "Wall"; }); + ASSERT_NE(wallSurfaceIt, std::end(surfaces)); + Surface wallSurface = *wallSurfaceIt; + + auto floorSurfaceIt = std::find_if(std::begin(surfaces), std::end(surfaces), [](const auto& surface) { return surface.surfaceType() == "Floor"; }); + ASSERT_NE(floorSurfaceIt, std::end(surfaces)); + Surface floorSurface = *floorSurfaceIt; + + ASSERT_ANY_THROW(SwimmingPoolIndoor(m, wallSurface)); + + SwimmingPoolIndoor swimmingPoolIndoor(m, floorSurface); + + swimmingPoolIndoor.setName("My SwimmingPoolIndoor"); + + // Surface Name: Required Object + EXPECT_FALSE(swimmingPoolIndoor.setSurface(wallSurface)); + EXPECT_EQ(floorSurface, swimmingPoolIndoor.surface()); + + floorPrint.clear(); + floorPrint.push_back(Point3d(10, 10, 0)); + floorPrint.push_back(Point3d(20, 10, 0)); + floorPrint.push_back(Point3d(20, 0, 0)); + floorPrint.push_back(Point3d(10, 0, 0)); + boost::optional space2 = Space::fromFloorPrint(floorPrint, 3, m); + ASSERT_TRUE(space2); + auto surfaces2 = space2->surfaces(); + auto floorSurfaceIt2 = std::find_if(std::begin(surfaces), std::end(surfaces), [](const auto& surface) { return surface.surfaceType() == "Floor"; }); + ASSERT_NE(floorSurfaceIt2, std::end(surfaces2)); + Surface floorSurface2 = *floorSurfaceIt2; + EXPECT_TRUE(swimmingPoolIndoor.setSurface(floorSurface2)); + EXPECT_EQ(floorSurface2, swimmingPoolIndoor.surface()); + + // Average Depth: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setAverageDepth(3)); + EXPECT_EQ(3, swimmingPoolIndoor.averageDepth()); + + // Activity Factor Schedule Name: Required Object + { + ScheduleConstant sch(m); + EXPECT_TRUE(swimmingPoolIndoor.setActivityFactorSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.activityFactorSchedule()); + } + + // Make-up Water Supply Schedule Name: Required Object + { + ScheduleConstant sch(m); + EXPECT_TRUE(swimmingPoolIndoor.setMakeupWaterSupplySchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.makeupWaterSupplySchedule()); + } + + // Cover Schedule Name: Required Object + { + ScheduleConstant sch(m); + EXPECT_TRUE(swimmingPoolIndoor.setCoverSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.coverSchedule()); + } + + // Cover Evaporation Factor: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setCoverEvaporationFactor(0.5)); + EXPECT_EQ(0.5, swimmingPoolIndoor.coverEvaporationFactor()); + // Bad Value + EXPECT_FALSE(swimmingPoolIndoor.setCoverEvaporationFactor(-10.0)); + EXPECT_EQ(0.5, swimmingPoolIndoor.coverEvaporationFactor()); + + // Cover Convection Factor: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setCoverConvectionFactor(0.6)); + EXPECT_EQ(0.6, swimmingPoolIndoor.coverConvectionFactor()); + // Bad Value + EXPECT_FALSE(swimmingPoolIndoor.setCoverConvectionFactor(-10.0)); + EXPECT_EQ(0.6, swimmingPoolIndoor.coverConvectionFactor()); + + // Cover Short-Wavelength Radiation Factor: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setCoverShortWavelengthRadiationFactor(0.7)); + EXPECT_EQ(0.7, swimmingPoolIndoor.coverShortWavelengthRadiationFactor()); + // Bad Value + EXPECT_FALSE(swimmingPoolIndoor.setCoverShortWavelengthRadiationFactor(-10.0)); + EXPECT_EQ(0.7, swimmingPoolIndoor.coverShortWavelengthRadiationFactor()); + + // Cover Long-Wavelength Radiation Factor: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setCoverLongWavelengthRadiationFactor(0.8)); + EXPECT_EQ(0.8, swimmingPoolIndoor.coverLongWavelengthRadiationFactor()); + // Bad Value + EXPECT_FALSE(swimmingPoolIndoor.setCoverLongWavelengthRadiationFactor(-10.0)); + EXPECT_EQ(0.8, swimmingPoolIndoor.coverLongWavelengthRadiationFactor()); + + // Pool Heating System Maximum Water Flow Rate: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setPoolHeatingSystemMaximumWaterFlowRate(0.1)); + EXPECT_EQ(0.1, swimmingPoolIndoor.poolHeatingSystemMaximumWaterFlowRate()); + // Bad Value + EXPECT_FALSE(swimmingPoolIndoor.setPoolHeatingSystemMaximumWaterFlowRate(-10.0)); + EXPECT_EQ(0.1, swimmingPoolIndoor.poolHeatingSystemMaximumWaterFlowRate()); + + // Pool Miscellaneous Equipment Power: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setPoolMiscellaneousEquipmentPower(2000.0)); + EXPECT_EQ(2000., swimmingPoolIndoor.poolMiscellaneousEquipmentPower()); + // Bad Value + EXPECT_FALSE(swimmingPoolIndoor.setPoolMiscellaneousEquipmentPower(-10.0)); + EXPECT_EQ(2000., swimmingPoolIndoor.poolMiscellaneousEquipmentPower()); + + // Setpoint Temperature Schedule: Required Object + { + ScheduleConstant sch(m); + EXPECT_TRUE(swimmingPoolIndoor.setSetpointTemperatureSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.setpointTemperatureSchedule()); + } + + // Maximum Number of People: Required Double + EXPECT_TRUE(swimmingPoolIndoor.setMaximumNumberofPeople(12.5)); + EXPECT_EQ(12.5, swimmingPoolIndoor.maximumNumberofPeople()); + // Bad Value + EXPECT_FALSE(swimmingPoolIndoor.setMaximumNumberofPeople(-10.0)); + EXPECT_EQ(12.5, swimmingPoolIndoor.maximumNumberofPeople()); + + // People Schedule: Required Object + { + ScheduleConstant sch(m); + EXPECT_TRUE(swimmingPoolIndoor.setPeopleSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.peopleSchedule()); + } + + // People Heat Gain Schedule: Required Object + { + ScheduleConstant sch(m); + EXPECT_TRUE(swimmingPoolIndoor.setPeopleHeatGainSchedule(sch)); + EXPECT_EQ(sch, swimmingPoolIndoor.peopleHeatGainSchedule()); + } +} + +TEST_F(ModelFixture, SwimmingPoolIndoor_addToNode) { + + Model m; + + Point3dVector floorPrint; + floorPrint.push_back(Point3d(0, 10, 0)); + floorPrint.push_back(Point3d(10, 10, 0)); + floorPrint.push_back(Point3d(10, 0, 0)); + floorPrint.push_back(Point3d(0, 0, 0)); + boost::optional space1 = Space::fromFloorPrint(floorPrint, 3, m); + ASSERT_TRUE(space1); + auto surfaces = space1->surfaces(); + EXPECT_EQ(6u, surfaces.size()); + + auto floorSurfaceIt = std::find_if(std::begin(surfaces), std::end(surfaces), [](const auto& surface) { return surface.surfaceType() == "Floor"; }); + ASSERT_NE(floorSurfaceIt, std::end(surfaces)); + Surface floorSurface = *floorSurfaceIt; + + + SwimmingPoolIndoor swimmingPoolIndoor(m, floorSurface); + EXPECT_FALSE(swimmingPoolIndoor.inletModelObject()); + EXPECT_FALSE(swimmingPoolIndoor.outletModelObject()); + EXPECT_FALSE(swimmingPoolIndoor.poolWaterInletNode()); + EXPECT_FALSE(swimmingPoolIndoor.poolWaterOutletNode()); + + // Not accepted on any AirLoopHVAC + AirLoopHVAC airLoop = AirLoopHVAC(m); + + Node supplyOutletNode = airLoop.supplyOutletNode(); + + EXPECT_FALSE(swimmingPoolIndoor.addToNode(supplyOutletNode)); + EXPECT_EQ((unsigned)2, airLoop.supplyComponents().size() ); + + Node inletNode = airLoop.zoneSplitter().lastOutletModelObject()->cast(); + + EXPECT_FALSE(swimmingPoolIndoor.addToNode(inletNode)); + EXPECT_EQ((unsigned)5, airLoop.demandComponents().size()); + + PlantLoop plantLoop(m); + + // This should de settable to the demand side only + supplyOutletNode = plantLoop.supplyOutletNode(); + EXPECT_FALSE(swimmingPoolIndoor.addToNode(supplyOutletNode)); + EXPECT_EQ((unsigned)5, plantLoop.supplyComponents().size() ); + EXPECT_FALSE(swimmingPoolIndoor.poolWaterInletNode()); + EXPECT_FALSE(swimmingPoolIndoor.poolWaterOutletNode()); + + // This should be settable to the demand side + Node demandOutletNode = plantLoop.demandOutletNode(); + EXPECT_TRUE(swimmingPoolIndoor.addToNode(demandOutletNode)); + EXPECT_EQ((unsigned)7, plantLoop.demandComponents().size() ); + EXPECT_TRUE(swimmingPoolIndoor.poolWaterInletNode()); + EXPECT_TRUE(swimmingPoolIndoor.poolWaterOutletNode()); + + SwimmingPoolIndoor swimmingPoolIndoorClone = swimmingPoolIndoor.clone(m).cast(); + EXPECT_EQ((unsigned)5, plantLoop.supplyComponents().size()); + EXPECT_EQ((unsigned)7, plantLoop.demandComponents().size() ); + + EXPECT_TRUE(swimmingPoolIndoor.poolWaterInletNode()); + EXPECT_TRUE(swimmingPoolIndoor.poolWaterOutletNode()); + EXPECT_FALSE(swimmingPoolIndoorClone.poolWaterInletNode()); + EXPECT_FALSE(swimmingPoolIndoorClone.poolWaterOutletNode()); + + EXPECT_TRUE(swimmingPoolIndoorClone.addToNode(demandOutletNode)); + EXPECT_EQ((unsigned)5, plantLoop.supplyComponents().size() ); + EXPECT_EQ((unsigned)9, plantLoop.demandComponents().size() ); + + EXPECT_TRUE(swimmingPoolIndoor.poolWaterInletNode()); + EXPECT_TRUE(swimmingPoolIndoor.poolWaterOutletNode()); + EXPECT_TRUE(swimmingPoolIndoorClone.poolWaterInletNode()); + EXPECT_TRUE(swimmingPoolIndoorClone.poolWaterOutletNode()); +}