From 58fbca26252ac63f8ecdb55c03f2a24acf4f62fd Mon Sep 17 00:00:00 2001 From: Edwin Lee Date: Mon, 18 Oct 2021 11:24:36 -0500 Subject: [PATCH 01/10] Change regression baseline to new baseline branch [actions skip] [decent_ci_skip] --- .decent_ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.decent_ci.yaml b/.decent_ci.yaml index 93619ffb86a..96eaaa77128 100644 --- a/.decent_ci.yaml +++ b/.decent_ci.yaml @@ -3,7 +3,7 @@ results_path : _posts results_base_url : https://nrel.github.io/EnergyPlusBuildResults regression_repository : NREL/EnergyPlusRegressionTool regression_branch : master # this is the branch of NREL/EnergyPlusRegressionTool to use -regression_baseline_default : develop # this is the branch to use as the baseline for regressions +regression_baseline_default : SpaceReleaseBranchBaseline # this is the branch to use as the baseline for regressions regression_baseline_develop : "" regression_baseline_master : "" notification_recipients: From 7d06300148727bf31cc5d34713c2fb0213e8b9b8 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Oct 2021 14:42:45 -0500 Subject: [PATCH 02/10] Space-doc fixes --- .../overview/general-modeling-overview.tex | 78 ++++++++++++- ...oup-internal-gains-people-lights-other.tex | 2 +- ...roup-thermal-zone-description-geometry.tex | 105 ++++++++++++++---- 3 files changed, 160 insertions(+), 25 deletions(-) diff --git a/doc/engineering-reference/src/overview/general-modeling-overview.tex b/doc/engineering-reference/src/overview/general-modeling-overview.tex index 02b12d969ba..a70d6467745 100644 --- a/doc/engineering-reference/src/overview/general-modeling-overview.tex +++ b/doc/engineering-reference/src/overview/general-modeling-overview.tex @@ -1,6 +1,6 @@ \section{General Modeling Overview}\label{general-modeling-overview} -The EnergyPlus program is a collection of many program modules that work together to calculate the energy required for heating and cooling a building using a variety of systems and energy sources. It does this by simulating the building and associated energy systems when they are exposed to different environmental and operating conditions. The core of the simulation is a model of the building that is based on fundamental heat balance principles. Since it is relatively meaningless to state: ``based on fundamental heat balance principles'', the model will be described in greater detail in later sections of this document in concert with the C++ code which is used to describe the model. It turns out that the model itself is relatively simple compared with the data organization and control that is needed to simulate the great many combinations of system types, primary energy plant arrangements, schedules, and environments. The next section shows this overall organization in schematic form. Later sections will expand on the details within the blocks of the schematic. +The EnergyPlus program is a collection of many program modules that work together to calculate the energy required for heating and cooling a building using a variety of systems and energy sources. It does this by simulating the building and associated energy systems when they are exposed to different environmental and operating conditions. The core of the simulation is a model of the building that is based on fundamental heat balance principles. Since it is relatively meaningless to state: ``based on fundamental heat balance principles'', the model will be described in greater detail in later sections of this document in concert with the C++ code which is used to describe the model. It turns out that the model itself is relatively simple compared with the data organization and control that is needed to simulate the great many combinations of system types, primary energy plant arrangements, schedules, and environments. Figure \ref{fig:energyplus-program-schematic} shows this overall organization in schematic form. Later sections will expand on the details within the blocks of the schematic. \begin{figure}[hbtp] % fig 1 \centering @@ -8,3 +8,79 @@ \section{General Modeling Overview}\label{general-modeling-overview} \caption{EnergyPlus Program Schematic \protect \label{fig:energyplus-program-schematic}} \end{figure} +\section{Building Surfaces, Spaces, Zones, and Enclosures}\label{building-spaces-zones-enclosures} +The EnergyPlus building model consists of four main constructs: surfaces, spaces, zones, and enclosures. These are defined below along with some assumptions and relationship rules. + +\begin{description} + \item[Surface] - a geometric plane which is attached to a Zone and a Space. + \begin{itemize} + \item + A Surface can be opaque, transparent, or an air boundary. + \item + Surfaces may store and transfer heat and moisture. + \item + The inside and outside face of each Surface has a single uniform surface temperature calculated from the surface heat balance. + \item + Each Surface belongs to one Zone and one Space. + \item + Inter-Space and inter-Zone Surfaces are modeled as two linked surfaces. + \item + Air boundary surfaces combine one or more spaces into a common enclosure. + \item + Inter-Space surfaces connecting spaces that are part of the same Zone will see the same air temperature. They may or may not be in the same enclosure. + \item + Inter-Space surfaces connecting spaces that are in different Zones may see different air temperatures. They may or may not be in the same enclosure. + \end{itemize} + + \item[Space] - A collection of one or more Surfaces and internal gains. + \begin{itemize} + \item + Each Space belongs to one Zone. + \item + Spaces may be user-specified or generated by default so that every surface belongs to a Space and every Zone has at least one Space. + \item + A Space may have only floor surface(s) or may be fully enclosed (floors, walls, ceilings, etc). + \item + Each Space belongs to one Enclosure (implicitly assigned). See Enclosure below for more details. + \item + There is no heat balance at the Space level; the heat balance is done at the Zone level. + \item + Internal gains are modeled at the Space level and combined for the Zone heat balance. + \item + Each Space is assigned a Space Type which is used for output reports and submeters. + \end{itemize} + + \item[Zone] - An air mass connecting Surfaces, internal gains, and HVAC equipment for heat balance and HVAC control. + \begin{itemize} + \item + Each Zone is comprised of one or more Spaces. + \item + If no Spaces are specified for a Zone, a Space will automatically be created. + \item + If any surfaces in a Zone do not have a user-assigned Space, a Space will be automatically created for those surfaces. + \item + The Zone heat balance solves for the zone air temperature and humidity (or a Room Air Model with multiple air nodes) and includes all Surfaces and internal gains from its Spaces. + \item + HVAC systems are connected at the Zone level. + \end{itemize} + + \item[Enclosure] - A continuous volume connecting Surfaces for radiant, solar, and daylighting exchange. + \begin{itemize} + \item + Each Enclosure is comprised of one or more Spaces. + \item + If a Space has a floor surface(s) plus any other surfaces (walls, ceiling, roof, etc.), then it is its own enclosure. + \item + If a Space has only a floor surface(s), then it is part of the zone enclosure. + \item + Any surfaces with a blank Space is part of the zone enclosure. + \item + Air boundaries can be used to combine Spaces into a common enclosure. + \item + All Surfaces and internal radiant gains associated with the Spaces are included in the Enclosure. + \item + Enclosures only distribute radiant (thermal), solar, and visible energy to and from the Surfaces. + \item + There is no full heat balance at the Enclosure level. Each Enclosure only balances the radiant/solar flux on each Surface. These fluxes then become part of the Surface inside heat balance. + \end{itemize} +\end{description} diff --git a/doc/input-output-reference/src/overview/group-internal-gains-people-lights-other.tex b/doc/input-output-reference/src/overview/group-internal-gains-people-lights-other.tex index d3218c2da0d..f8493582564 100644 --- a/doc/input-output-reference/src/overview/group-internal-gains-people-lights-other.tex +++ b/doc/input-output-reference/src/overview/group-internal-gains-people-lights-other.tex @@ -243,7 +243,7 @@ \subsubsection{Inputs}\label{inputs-025} \begin{figure}[hbtp] % fig 48 \centering \includegraphics[width=0.9\textwidth, height=0.9\textheight, keepaspectratio=true]{media/image083.png} -\caption{Graphical representation fo the dynamic predictive clothing insulation model \protect \label{fig:graphical-representation-fo-the-dynamic}} +\caption{Graphical representation of the dynamic predictive clothing insulation model \protect \label{fig:graphical-representation-of-the-dynamic}} \end{figure} \paragraph{Field: Clothing Insulation Calculation Method Schedule Name}\label{field-clothing-insulation-calculation-method-schedule-name} diff --git a/doc/input-output-reference/src/overview/group-thermal-zone-description-geometry.tex b/doc/input-output-reference/src/overview/group-thermal-zone-description-geometry.tex index deab3254103..a2d39676c59 100644 --- a/doc/input-output-reference/src/overview/group-thermal-zone-description-geometry.tex +++ b/doc/input-output-reference/src/overview/group-thermal-zone-description-geometry.tex @@ -13,13 +13,13 @@ \subsection{Space}\label{space} Input references to Space Names must have a matching Space object. Default space names may not be referenced in the input except for \hyperref[outputvariable]{Output:Variable} keys). -Space geometry is specified by attaching surfaces to a space using the ``Space Name'' field. If a Space has only floor surface(s) assigned to it, the Space is assumed to share the same enclosure with other such Spaces in the same Zone (and with any surfaces that are not explicitly assinged to a space). If a Space also has other types of surfaces (non-floor) then the Space forms its own enclosure unless it is connected to other spaces with air boundaries (see \hyperref[constructionairboundary]{Construction:AirBoundary}). +Space geometry is specified by attaching surfaces to a space using the ``Space Name'' field. If a Space has only floor surface(s) and internal mass assigned to it, the Space is assumed to share the same enclosure with other such Spaces in the same Zone (and with any surfaces that are not explicitly assinged to a space). If a Space also has other types of surfaces (e.g. wall, ceiling, or roof) then the Space forms its own enclosure unless it is connected to other spaces with air boundaries (see \hyperref[constructionairboundary]{Construction:AirBoundary}). \subsubsection{Inputs}\label{space-inputs-048} \paragraph{Field: Name}\label{space-object-name} -The name of the Space object. Must be unique across Zone and Space names. +The name of the Space object. This name must be unique across Zone, Space, ZoneList, and SpaceList names. \paragraph{Field: Zone Name}\label{space-zone-name} @@ -49,9 +49,9 @@ \subsection{SpaceList}\label{spacelist} \subsubsection{Inputs}\label{inputs-1-045space} -\paragraph{Field: Space List Name}\label{field-space-list-name-000} +\paragraph{Field: Name}\label{field-space-list-name-000} -The name of the SpaceList object. Must be unique across SpaceLists and Spaces. +The name of the SpaceList object. This name must be unique across Zone, Space, ZoneList, and SpaceList names. \paragraph{Field: Space \textless{}\#\textgreater{} Name}\label{field-space-name} @@ -82,7 +82,7 @@ \subsubsection{Inputs}\label{inputs-048} \paragraph{Field: Name}\label{zone-object-name} -The name of the Zone object. Must be unique across Zone and Space names. +The name of the Zone object. This name must be unique across Zone, Space, ZoneList, and SpaceList names. \paragraph{Field: Direction of Relative North}\label{field-direction-of-relative-north} @@ -200,6 +200,7 @@ \subsection{Space Thermal Output(s)}\label{Space-thermal-outputs} Zone,Sum,Space Total Internal Total Heating Energy {[}J{]} \item Zone,Average,Space Total Internal Total Heating Rate {[}W{]} +\end{itemize} \subsection{Zone Thermal Output(s)}\label{zone-thermal-outputs} @@ -454,9 +455,9 @@ \subsection{ZoneList}\label{zonelist} \subsubsection{Inputs}\label{inputs-1-045} -\paragraph{Field: Zone List Name}\label{field-zone-list-name-000} +\paragraph{Field: Name}\label{field-zone-list-name-000} -The name of the ZoneList object. Must be unique across ZoneLists. +The name of the ZoneList object. This name must be unique across Zone, Space, ZoneList, and SpaceList names. \paragraph{Field: Zone \textless{}\#\textgreater{} Name}\label{field-zone-1---zone-20-name} @@ -750,7 +751,11 @@ \subsubsection{Inputs}\label{inputs-4-035} \paragraph{Field: Zone Name}\label{field-zone-name-012} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-012} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Azimuth Angle} @@ -802,7 +807,11 @@ \subsubsection{Inputs}\label{inputs-5-032} \paragraph{Field: Zone Name}\label{field-zone-name-1-009} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-1-009} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Azimuth Angle}\label{field-azimuth-angle-1} @@ -854,7 +863,11 @@ \subsubsection{Inputs}\label{inputs-6-029} \paragraph{Field: Zone Name}\label{field-zone-name-2-007} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-2-007} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Azimuth Angle}\label{field-azimuth-angle-2} @@ -904,7 +917,11 @@ \subsubsection{Inputs}\label{inputs-7-028} \paragraph{Field: Zone Name}\label{field-zone-name-3-006} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-3-006} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Outside Boundary Condition Object}\label{field-outside-boundary-condition-object} @@ -962,8 +979,11 @@ \subsubsection{Inputs}\label{inputs-8-026} \paragraph{Field: Zone Name}\label{field-zone-name-4-006} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-4-006} +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Azimuth Angle}\label{field-azimuth-angle-4} The Azimuth Angle indicates the direction of the outward normal for the roof. The angle is specified in degrees where East = 90, South = 180, West = 270, North = 0. @@ -1012,8 +1032,11 @@ \subsubsection{Inputs}\label{inputs-9-024} \paragraph{Field: Zone Name}\label{field-zone-name-5-005} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. +\paragraph{Field: Space Name}\label{field-space-name-5-005} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Azimuth Angle}\label{field-azimuth-angle-5} The Azimuth Angle indicates the direction of the outward normal for the roof. The angle is specified in degrees where East = 90, South = 180, West = 270, North = 0. @@ -1062,7 +1085,11 @@ \subsubsection{Inputs}\label{inputs-10-022} \paragraph{Field: Zone Name}\label{field-zone-name-6-004} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-6-004} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Outside Boundary Condition Object}\label{field-outside-boundary-condition-object-1} @@ -1120,7 +1147,11 @@ \subsubsection{Inputs}\label{inputs-11-021} \paragraph{Field: Zone Name}\label{field-zone-name-7-004} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-7-004} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Azimuth Angle}\label{field-azimuth-angle-7} @@ -1170,7 +1201,11 @@ \subsubsection{Inputs}\label{inputs-12-019} \paragraph{Field: Zone Name}\label{field-zone-name-8-003} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-8-003} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Azimuth Angle}\label{field-azimuth-angle-8} @@ -1220,7 +1255,11 @@ \subsubsection{Inputs}\label{inputs-13-016} \paragraph{Field: Zone Name}\label{field-zone-name-9-001} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-9-001} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Outside Boundary Condition Object}\label{field-outside-boundary-condition-object-2} @@ -1751,7 +1790,11 @@ \subsubsection{Inputs}\label{inputs-20-007} \paragraph{Field: Zone Name}\label{field-zone-name-10-000} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-10-000} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Outside Boundary Condition}\label{field-outside-boundary-condition} @@ -1864,7 +1907,11 @@ \subsubsection{Inputs}\label{inputs-21-007} \paragraph{Field: Zone Name}\label{field-zone-name-11-000} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-11-000} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Outside Boundary Condition}\label{field-outside-boundary-condition-1} @@ -1973,7 +2020,11 @@ \subsubsection{Inputs}\label{inputs-22-006} \paragraph{Field: Zone Name}\label{field-zone-name-12-000} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-12-000} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space named or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Outside Boundary Condition}\label{field-outside-boundary-condition-2} @@ -2142,7 +2193,11 @@ \subsubsection{Inputs}\label{inputs-23-006} \paragraph{Field: Zone Name}\label{field-zone-name-13} -This is the zone name to which the surface belongs. +This is the zone name to which the surface belongs. This field is required. + +\paragraph{Field: Space Name}\label{field-space-name-13} + +This is the space name to which the surface belongs. If this field is left blank, it will be automatically assigned to a space name or -Remainder. See \hyperref[space]{Space} for more details. \paragraph{Field: Outside Boundary Condition}\label{field-outside-boundary-condition-3} @@ -2440,7 +2495,7 @@ \subsection{Window Modeling Options}\label{window-modeling-options} \subsection{InternalMass}\label{internalmass} -Any surface that would logically be described as an interior wall, floor or ceiling can just as easily be described as Internal Mass. Internal Mass surface types only exchange energy with the zone in which they are described; they do not see any other zones. There are two approaches to using internal mass. The first approach is to have several pieces of internal mass with each piece having a different construction type. The other approach is to choose an average construction type and combine all of the interior surfaces into a single internal mass. Similar to internal surfaces with an adiabatic boundary condition, the zone will only exchange energy with the inside of the Internal Mass construction. If both sides of the surface exchange energy with the zone then the user should input twice the area when defining the Internal Mass object. Note that furniture and other large objects within a zone can be described using internal mass. However, simplifying calculations using internal mass must be used with caution when the ``FullInteriorAndExterior'' or ``FullInteriorAndExteriorWithReflections'' Solar Distribution model (see Building parameters) is chosen. A single Internal Mass object can be applied to a set of zones. This requires specifying a zone list name instead of a zone name in the input field \textit{Zone or ZoneList Name}. +Any surface that would logically be described as an interior wall, floor or ceiling can just as easily be described as Internal Mass. Internal Mass surface types only exchange energy with the zone in which they are described; they do not see any other zones. There are two approaches to using internal mass. The first approach is to have several pieces of internal mass with each piece having a different construction type. The other approach is to choose an average construction type and combine all of the interior surfaces into a single internal mass. Similar to internal surfaces with an adiabatic boundary condition, the zone will only exchange energy with the inside of the Internal Mass construction. If both sides of the surface exchange energy with the zone then the user should input twice the area when defining the Internal Mass object. Note that furniture and other large objects within a zone can be described using internal mass. However, simplifying calculations using internal mass must be used with caution when the ``FullInteriorAndExterior'' or ``FullInteriorAndExteriorWithReflections'' Solar Distribution model (see Building parameters) is chosen. A single Internal Mass object can be applied to a set of zones or spaces by specifying a \hyperref[zonelist]{ZoneList} or \hyperref[spacelist]{SpaceList} name. \subsubsection{Inputs}\label{inputs-25-004} @@ -2468,7 +2523,11 @@ \subsubsection{Inputs}\label{inputs-25-004} \paragraph{Field: Zone or ZoneList Name}\label{field-zone-or-zonelist-name-14} -This field is the name of the zone (ref: Zone) or ZoneList (ref: ZoneList) and represents a particular internal mass object in a thermal zone or set of thermal zones in the building. When the ZoneList option is used then this internal mass object is applied to each of the zones in the zone list. The name of the actual internal mass object in each zone becomes and should be less than the standard length (100 characters) for a name field. If it is greater than this standard length, it may be difficult to specify in output reporting as it will be truncated. A warning will be shown if the generated name is greater than 100 characters. If it duplicates another such concatenated name, there will be a severe error and terminate the run. +This field is the name of the \hyperref[zone]{Zone} or \hyperref[zonelist]{ZoneList} in which the internal mass will be added. When the ZoneList option is used then this internal mass object is applied to each of zone in the list. The name of the actual internal mass object in each zone becomes and should be less than the standard length (100 characters) for a name field. If it is greater than this standard length, it may be difficult to specify in output reporting as it will be truncated. A warning will be shown if the generated name is greater than 100 characters. If it duplicates another such concatenated name, there will be a severe error and terminate the run. + +\paragraph{Field: Space or SpaceList Name}\label{field-space-or-spacelist-name-14} + +This field is the name of the \hyperref[space]{Space} or \hyperref[spacelist]{SpaceList} in which the internal mass will be added. When the SpaceList option is used then this internal mass object is applied to each space in the list. The name of the actual internal mass object in each space becomes and should be less than the standard length (100 characters) for a name field. If it is greater than this standard length, it may be difficult to specify in output reporting as it will be truncated. A warning will be shown if the generated name is greater than 100 characters. If it duplicates another such concatenated name, there will be a severe error and terminate the run. This field is ignored when a ZoneList Name is specified for Zone or ZoneList Name. If a Space Name is used, then the Space must be part of Zone Name. If a SpaceList Name is used, then the Zone Name is ignored (even though it is a required field), and the surface is assigned to the corresponding Zone(s) for each Space in the SpaceList. \paragraph{Field: Surface Area}\label{field-surface-area} From b5cc69f8779d6128d8962698f49af12a7369f40a Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Oct 2021 15:04:56 -0500 Subject: [PATCH 03/10] Space-IDD notes and references --- idd/Energy+.idd.in | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/idd/Energy+.idd.in b/idd/Energy+.idd.in index 40528cdd734..6b185cd4656 100644 --- a/idd/Energy+.idd.in +++ b/idd/Energy+.idd.in @@ -9261,10 +9261,13 @@ Space, \min-fields 3 \extensible:1 A1, \field Name + \note Name of the Space. + \note This name must be unique across Zone, Space, ZoneList, and SpaceList names. \required-field \type alpha \reference SpaceNames \reference SpaceAndSpaceListNames + \reference ZoneAndZoneListAndSpaceAndSpaceListNames A2, \field Zone Name \required-field \type object-list @@ -9300,11 +9303,13 @@ SpaceList, \min-fields 2 \extensible:1 A1 , \field Name - \note Name of the Space List + \note Name of the SpaceList. + \note This name must be unique across Zone, Space, ZoneList, and SpaceList names. \required-field \type alpha \reference SpaceListNames \reference SpaceAndSpaceListNames + \reference ZoneAndZoneListAndSpaceAndSpaceListNames A2 , \field Space 1 Name \begin-extensible \required-field @@ -9468,11 +9473,14 @@ Zone, \memo (default space names may not be referenced except in output variable keys). \format vertices A1 , \field Name + \note Name of the Zone. + \note This name must be unique across Zone, Space, ZoneList, and SpaceList names. \required-field \type alpha \reference ZoneNames \reference OutFaceEnvNames \reference ZoneAndZoneListNames + \reference ZoneAndZoneListAndSpaceAndSpaceListNames \reference AirflowNetworkNodeAndZoneNames N1 , \field Direction of Relative North \units deg @@ -9571,11 +9579,13 @@ ZoneList, \min-fields 2 \extensible:1 - repeat last field, remembering to remove ; from "inner" fields. A1 , \field Name - \note Name of the Zone List + \note Name of the ZoneList. + \note This name must be unique across Zone, Space, ZoneList, and SpaceList names. \required-field \type alpha \reference ZoneListNames \reference ZoneAndZoneListNames + \reference ZoneAndZoneListAndSpaceAndSpaceListNames A2 , \field Zone 1 Name \begin-extensible \required-field From e7fb2a5fa602c9131cbed0c3ac463f82eda2726c Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Oct 2021 15:07:15 -0500 Subject: [PATCH 04/10] Space-Fix 9135 DesignSpecification:OutdoorAir:SpaceList --- src/EnergyPlus/DataSizing.cc | 18 ++++++++--- src/EnergyPlus/DataSizing.hh | 2 +- src/EnergyPlus/ZoneEquipmentManager.cc | 45 +++++++++++++++++--------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/EnergyPlus/DataSizing.cc b/src/EnergyPlus/DataSizing.cc index 56c66576826..9f6995f3422 100644 --- a/src/EnergyPlus/DataSizing.cc +++ b/src/EnergyPlus/DataSizing.cc @@ -517,9 +517,11 @@ Real64 calcDesignSpecificationOutdoorAir(EnergyPlusData &state, auto &thisDSOA = state.dataSize->OARequirements(DSOAPtr); - if (thisDSOA.numDSOA == 1) { + if (thisDSOA.numDSOA == 0) { + // This is a simple DesignSpecification:OutdoorAir return thisDSOA.calcOAFlowRate(state, ActualZoneNum, UseOccSchFlag, UseMinOASchFlag, PerPersonNotSet, MaxOAVolFlowFlag); } else { + // This is a DesignSpecification:OutdoorAir:SpaceList for (int dsoaCount = 1; dsoaCount <= thisDSOA.numDSOA; ++dsoaCount) { totOAFlowRate += state.dataSize->OARequirements(thisDSOA.dsoaIndexes(dsoaCount)) .calcOAFlowRate(state, @@ -539,11 +541,13 @@ Real64 OARequirementsData::desFlowPerZoneArea(EnergyPlusData &state, ) { Real64 desFlowPA = 0.0; - if (this->numDSOA == 1) { + if (this->numDSOA == 0) { + // This is a simple DesignSpecification:OutdoorAir if (this->OAFlowMethod != DataSizing::OAFlowPPer && this->OAFlowMethod != DataSizing::OAFlow && this->OAFlowMethod != DataSizing::OAFlowACH) { desFlowPA = this->OAFlowPerArea; } } else { + // This is a DesignSpecification:OutdoorAir:SpaceList Real64 sumAreaOA = 0.0; for (int dsoaCount = 1; dsoaCount <= this->numDSOA; ++dsoaCount) { auto const thisDSOA = state.dataSize->OARequirements(this->dsoaIndexes(dsoaCount)); @@ -565,12 +569,14 @@ Real64 OARequirementsData::desFlowPerZonePerson(EnergyPlusData &state, ) { Real64 desFlowPP = 0.0; - if (this->numDSOA == 1) { + if (this->numDSOA == 0) { + // This is a simple DesignSpecification:OutdoorAir if (this->OAFlowMethod != DataSizing::OAFlowPerArea && this->OAFlowMethod != DataSizing::OAFlow && this->OAFlowMethod != DataSizing::OAFlowACH) { desFlowPP = this->OAFlowPerPerson; } } else { + // This is a DesignSpecification:OutdoorAir:SpaceList Real64 sumPeopleOA = 0.0; for (int dsoaCount = 1; dsoaCount <= this->numDSOA; ++dsoaCount) { auto const thisDSOA = state.dataSize->OARequirements(this->dsoaIndexes(dsoaCount)); @@ -639,7 +645,11 @@ Real64 OARequirementsData::calcOAFlowRate(EnergyPlusData &state, if (spaceNum > 0) { floorArea = state.dataHeatBal->space(spaceNum).floorArea; // TODO MJW: For now just proportion space volume by floor area - volume = thisZone.Volume * state.dataHeatBal->space(spaceNum).floorArea / thisZone.FloorArea; + if (thisZone.FloorArea > 0.0) { + volume = thisZone.Volume * state.dataHeatBal->space(spaceNum).floorArea / thisZone.FloorArea; + } else { + volume = 0.0; + } nomTotOccupants = state.dataHeatBal->space(spaceNum).totOccupants; curNumOccupants = state.dataHeatBal->spaceIntGain(spaceNum).NOFOCC; maxOccupants = state.dataHeatBal->space(spaceNum).maxOccupants; diff --git a/src/EnergyPlus/DataSizing.hh b/src/EnergyPlus/DataSizing.hh index 0a93e479487..91d72142a8f 100644 --- a/src/EnergyPlus/DataSizing.hh +++ b/src/EnergyPlus/DataSizing.hh @@ -959,7 +959,7 @@ namespace DataSizing { // Holds complete data for a single DesignSpecification:OutdoorAir object or // a list of indexes from a DesignSpecification:OutdoorAir:SpaceList object std::string Name; // Name of DesignSpecification:OutdoorAir or DesignSpecification:OutdoorAir:SpaceList object - int numDSOA = 1; // Number of DesignSpecification:OutdoorAir objects for this instance + int numDSOA = 0; // Number of DesignSpecification:OutdoorAir objects for this instance (zero if not a list) EPVector dsoaIndexes; // Indexes to DesignSpecification:OutdoorAir objects (if this is a DSOA:SpaceList object) EPVector dsoaSpaceNames; // Names of spaces if this is a (if this is a DSOA:SpaceList object) EPVector dsoaSpaceIndexes; // Indexes to Spaces (if this is a DSOA:SpaceList object) diff --git a/src/EnergyPlus/ZoneEquipmentManager.cc b/src/EnergyPlus/ZoneEquipmentManager.cc index bb5829336f0..d2aa88974dc 100644 --- a/src/EnergyPlus/ZoneEquipmentManager.cc +++ b/src/EnergyPlus/ZoneEquipmentManager.cc @@ -1322,6 +1322,34 @@ void SetUpZoneSizingArrays(EnergyPlusData &state) state.dataSize->CalcFinalZoneSizing(CtrlZoneNum).MinOA); } } + + // Populate DesignSpecification:OutdoorAir:SpaceList spaces + for (int oaIndex = 1; oaIndex <= state.dataSize->NumOARequirements; ++oaIndex) { + auto &thisOAReq = state.dataSize->OARequirements(oaIndex); + // If this is a DesignSpecification:OutdoorAir:SpaceList check to make sure spaces are valid and belong to this zone + if (thisOAReq.numDSOA > 0) { + for (int spaceCounter = 1; spaceCounter <= thisOAReq.numDSOA; ++spaceCounter) { + std::string thisSpaceName = thisOAReq.dsoaSpaceNames(spaceCounter); + int thisSpaceNum = UtilityRoutines::FindItemInList(thisSpaceName, state.dataHeatBal->space); + if (thisSpaceNum > 0) { + thisOAReq.dsoaSpaceIndexes.emplace_back(thisSpaceNum); + } else { + ShowSevereError(state, "SetUpZoneSizingArrays: DesignSpecification:OutdoorAir:SpaceList=" + thisOAReq.Name); + ShowContinueError(state, "Space Name=" + thisSpaceName + " not found."); + ErrorsFound = true; + } + // Check for duplicate spaces + for (int loop = 1; loop <= int(thisOAReq.dsoaSpaceIndexes.size()) - 1; ++loop) { + if (thisSpaceNum == thisOAReq.dsoaSpaceIndexes(loop)) { + ShowSevereError(state, "SetUpZoneSizingArrays: DesignSpecification:OutdoorAir:SpaceList=" + thisOAReq.Name); + ShowContinueError(state, "Space Name=" + thisSpaceName + " appears more than once in list."); + ErrorsFound = true; + } + } + } + } + } + // Use the max occupancy data from the PEOPLE structure to calculate design min OA for each zone // Calculate the zone design minimum outside air flow rate from the 3 Zone Sizing OA inputs and // from the specified OA method @@ -1336,30 +1364,17 @@ void SetUpZoneSizingArrays(EnergyPlusData &state) if (DSOAPtr > 0) { auto &thisOAReq = state.dataSize->OARequirements(DSOAPtr); // If this is a DesignSpecification:OutdoorAir:SpaceList check to make sure spaces are valid and belong to this zone - if (thisOAReq.numDSOA > 1) { + if (thisOAReq.numDSOA > 0) { for (int spaceCounter = 1; spaceCounter <= thisOAReq.numDSOA; ++spaceCounter) { std::string thisSpaceName = thisOAReq.dsoaSpaceNames(spaceCounter); - int thisSpaceNum = UtilityRoutines::FindItemInList(thisSpaceName, state.dataHeatBal->space); + int thisSpaceNum = thisOAReq.dsoaSpaceIndexes(spaceCounter); if (thisSpaceNum > 0) { - thisOAReq.dsoaSpaceIndexes.emplace_back(thisSpaceNum); if (state.dataHeatBal->space(thisSpaceNum).zoneNum != state.dataSize->FinalZoneSizing(CtrlZoneNum).ActualZoneNum) { ShowSevereError(state, "SetUpZoneSizingArrays: DesignSpecification:OutdoorAir:SpaceList=" + thisOAReq.Name); ShowContinueError(state, "is invalid for Sizing:Zone=" + state.dataSize->FinalZoneSizing(CtrlZoneNum).ZoneName); ShowContinueError(state, "All spaces in the list must be part of this zone."); ErrorsFound = true; } - } else { - ShowSevereError(state, "SetUpZoneSizingArrays: DesignSpecification:OutdoorAir:SpaceList=" + thisOAReq.Name); - ShowContinueError(state, "Space Name=" + thisSpaceName + " not found."); - ErrorsFound = true; - } - // Check for duplicate spaces - for (int loop = 1; loop <= int(thisOAReq.dsoaSpaceIndexes.size()) - 1; ++loop) { - if (thisSpaceNum == thisOAReq.dsoaSpaceIndexes(loop)) { - ShowSevereError(state, "SetUpZoneSizingArrays: DesignSpecification:OutdoorAir:SpaceList=" + thisOAReq.Name); - ShowContinueError(state, "Space Name=" + thisSpaceName + " appears more than once in list."); - ErrorsFound = true; - } } } } From 9527b473e18cdfd5943f50ee674a4673539ae847 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Oct 2021 15:08:18 -0500 Subject: [PATCH 05/10] Space-Fix 9119 Daylighting:ReferencePoint space name --- src/EnergyPlus/DaylightingManager.cc | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/EnergyPlus/DaylightingManager.cc b/src/EnergyPlus/DaylightingManager.cc index 63095aeaaea..4cc7e5a8601 100644 --- a/src/EnergyPlus/DaylightingManager.cc +++ b/src/EnergyPlus/DaylightingManager.cc @@ -5414,10 +5414,15 @@ void GetInputDayliteRefPt(EnergyPlusData &state, bool &ErrorsFound) pt.Name = state.dataIPShortCut->cAlphaArgs(1); pt.ZoneNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->Zone); if (pt.ZoneNum == 0) { - ShowSevereError(state, - cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid " + - state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" + state.dataIPShortCut->cAlphaArgs(2) + "\"."); - ErrorsFound = true; + int spaceNum = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(2), state.dataHeatBal->space); + if (spaceNum == 0) { + ShowSevereError(state, + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\", invalid " + + state.dataIPShortCut->cAlphaFieldNames(2) + "=\"" + state.dataIPShortCut->cAlphaArgs(2) + "\"."); + ErrorsFound = true; + } else { + pt.ZoneNum = state.dataHeatBal->space(spaceNum).zoneNum; + } } pt.x = state.dataIPShortCut->rNumericArgs(1); pt.y = state.dataIPShortCut->rNumericArgs(2); From 24c2a0c44a06b02f1aa8da305e4600abd736295d Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Oct 2021 15:09:17 -0500 Subject: [PATCH 06/10] Space-Fix 9136 internal mass Space or SpaceList field --- src/EnergyPlus/SurfaceGeometry.cc | 84 +++++++++++++++++++++++-------- 1 file changed, 64 insertions(+), 20 deletions(-) diff --git a/src/EnergyPlus/SurfaceGeometry.cc b/src/EnergyPlus/SurfaceGeometry.cc index fccb73f6480..6675205a18b 100644 --- a/src/EnergyPlus/SurfaceGeometry.cc +++ b/src/EnergyPlus/SurfaceGeometry.cc @@ -7039,7 +7039,9 @@ namespace SurfaceGeometry { if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) ZLItem = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->ZoneList); if (Item1 > 0) { - ++NumIntMassSurfaces; + if (state.dataIPShortCut->lAlphaFieldBlanks(4)) { + ++NumIntMassSurfaces; + } state.dataSurface->IntMassObjects(Item).NumOfZones = 1; state.dataSurface->IntMassObjects(Item).ZoneListActive = false; state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr = Item1; @@ -7070,6 +7072,16 @@ namespace SurfaceGeometry { state.dataSurface->IntMassObjects(Item).numOfSpaces = 1; state.dataSurface->IntMassObjects(Item).spaceListActive = false; state.dataSurface->IntMassObjects(Item).spaceOrSpaceListPtr = Item1; + if (!state.dataSurface->IntMassObjects(Item).ZoneListActive) { + if (state.dataHeatBal->space(Item1).zoneNum != state.dataSurface->IntMassObjects(Item).ZoneOrZoneListPtr) { + ShowSevereError(state, + cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\" invalid " + + state.dataIPShortCut->cAlphaFieldNames(4) + "=\"" + state.dataIPShortCut->cAlphaArgs(4) + + "\" is not part of Zone =\"" + state.dataIPShortCut->cAlphaArgs(3) + "\"."); + ErrorsFound = true; + errFlag = true; + } + } } else if (SLItem > 0) { int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces); NumIntMassSurfaces += numOfSpaces; @@ -7079,7 +7091,7 @@ namespace SurfaceGeometry { } else { ShowSevereError(state, cCurrentModuleObject + "=\"" + state.dataIPShortCut->cAlphaArgs(1) + "\" invalid " + - state.dataIPShortCut->cAlphaFieldNames(3) + "=\"" + state.dataIPShortCut->cAlphaArgs(3) + "\" not found."); + state.dataIPShortCut->cAlphaFieldNames(4) + "=\"" + state.dataIPShortCut->cAlphaArgs(4) + "\" not found."); ++SurfNum; state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::INVALID; ErrorsFound = true; @@ -7110,35 +7122,51 @@ namespace SurfaceGeometry { } if (NumIntMassSurfaces > 0) { + int spaceNum = 0; for (int Loop = 1; Loop <= TotIntMass; ++Loop) { + int numberOfZonesOrSpaces = 1; + if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) { + numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).NumOfZones; + } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) { + numberOfZonesOrSpaces = state.dataSurface->IntMassObjects(Loop).numOfSpaces; + } - for (int Item1 = 1; Item1 <= state.dataSurface->IntMassObjects(Loop).NumOfZones; ++Item1) { + for (int Item1 = 1; Item1 <= numberOfZonesOrSpaces; ++Item1) { ++SurfNum; state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Construction = state.dataSurface->IntMassObjects(Loop).Construction; - if (!state.dataSurface->IntMassObjects(Loop).ZoneListActive) { + if (!state.dataSurface->IntMassObjects(Loop).ZoneListActive && !state.dataSurface->IntMassObjects(Loop).spaceListActive) { state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr; + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).spaceNum = state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr; state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = state.dataSurface->IntMassObjects(Loop).Name; state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::IntMass; state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListName; state.dataSurfaceGeometry->SurfaceTmp(SurfNum).HeatTransSurf = true; } else { - CheckCreatedZoneItemName( - state, - RoutineName, - cCurrentModuleObject, - state.dataHeatBal - ->Zone(state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1)) - .Name, - state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).MaxZoneNameLength, - state.dataSurface->IntMassObjects(Loop).Name, - state.dataSurfaceGeometry->SurfaceTmp, - SurfNum - 1, - state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name, - errFlag); - - ZoneNum = state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1); + if (state.dataSurface->IntMassObjects(Loop).ZoneListActive) { + CheckCreatedZoneItemName( + state, + RoutineName, + cCurrentModuleObject, + state.dataHeatBal + ->Zone(state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1)) + .Name, + state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).MaxZoneNameLength, + state.dataSurface->IntMassObjects(Loop).Name, + state.dataSurfaceGeometry->SurfaceTmp, + SurfNum - 1, + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name, + errFlag); + + ZoneNum = state.dataHeatBal->ZoneList(state.dataSurface->IntMassObjects(Loop).ZoneOrZoneListPtr).Zone(Item1); + } else if (state.dataSurface->IntMassObjects(Loop).spaceListActive) { + spaceNum = state.dataHeatBal->spaceList(state.dataSurface->IntMassObjects(Loop).spaceOrSpaceListPtr).spaces(Item1); + ZoneNum = state.dataHeatBal->space(spaceNum).zoneNum; + const std::string spaceName = state.dataHeatBal->space(spaceNum).Name; + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Name = spaceName + ' ' + state.dataSurface->IntMassObjects(Loop).Name; + state.dataSurfaceGeometry->SurfaceTmp(SurfNum).spaceNum = spaceNum; + } state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Zone = ZoneNum; state.dataSurfaceGeometry->SurfaceTmp(SurfNum).Class = SurfaceClass::IntMass; state.dataSurfaceGeometry->SurfaceTmp(SurfNum).ZoneName = state.dataHeatBal->Zone(ZoneNum).Name; @@ -7217,10 +7245,25 @@ namespace SurfaceGeometry { if (Item1 == 0 && state.dataHeatBal->NumOfZoneLists > 0) ZLItem = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(3), state.dataHeatBal->ZoneList); if (Item1 > 0) { - ++NumIntMassSurf; + if (state.dataIPShortCut->lAlphaFieldBlanks(4)) { + ++NumIntMassSurf; + } } else if (ZLItem > 0) { NumIntMassSurf += state.dataHeatBal->ZoneList(ZLItem).NumOfZones; } + + if (!state.dataIPShortCut->lAlphaFieldBlanks(4)) { + int Item1 = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataHeatBal->space); + int SLItem = 0; + if (Item1 == 0 && int(state.dataHeatBal->spaceList.size()) > 0) + SLItem = UtilityRoutines::FindItemInList(state.dataIPShortCut->cAlphaArgs(4), state.dataHeatBal->spaceList); + if (Item1 > 0) { + ++NumIntMassSurf; + } else if (SLItem > 0) { + int numOfSpaces = int(state.dataHeatBal->spaceList(SLItem).numListSpaces); + NumIntMassSurf += numOfSpaces; + } + } } NumIntMassSurf = max(NumIntMassSurf, TotIntMass); return NumIntMassSurf; @@ -14923,6 +14966,7 @@ namespace SurfaceGeometry { if (spaceEnclosureNum == 0) { spaceHasOnlyFloors = true; for (int const surfNum : state.dataHeatBal->space(spaceNum).surfaces) { + if (state.dataSurface->Surface(surfNum).Class == SurfaceClass::IntMass) continue; if (state.dataSurface->Surface(surfNum).Class != SurfaceClass::Floor) { spaceHasOnlyFloors = false; break; From 7e6e7585f312e7de45b4891af6b010aad094f5e5 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Oct 2021 15:19:09 -0500 Subject: [PATCH 07/10] Space-Fix 9135 DesignSpecification:OutdoorAir:SpaceList --- src/EnergyPlus/SizingManager.cc | 22 +++++++--------------- src/EnergyPlus/SizingManager.hh | 4 +--- 2 files changed, 8 insertions(+), 18 deletions(-) diff --git a/src/EnergyPlus/SizingManager.cc b/src/EnergyPlus/SizingManager.cc index 9fa1c209356..cdd8578cbaa 100644 --- a/src/EnergyPlus/SizingManager.cc +++ b/src/EnergyPlus/SizingManager.cc @@ -2356,18 +2356,8 @@ void GetOARequirements(EnergyPlusData &state) state.dataSize->OARequirements(OAIndex).Name = Alphas(1); - ProcessInputOARequirements(state, - CurrentModuleObject, - OAIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields, - ErrorsFound); + ProcessInputOARequirements( + state, CurrentModuleObject, OAIndex, Alphas, NumAlphas, Numbers, NumNumbers, lAlphaBlanks, cAlphaFields, ErrorsFound); } Alphas.deallocate(); @@ -2422,6 +2412,10 @@ void GetOARequirements(EnergyPlusData &state) ErrorsFound = true; } } + } else { + ShowSevereError(state, std::string(RoutineName) + cCurrentModuleObject2 + "=" + thisOAReq.Name + " is empty."); + ShowContinueError(state, "At least one pair of Space Name and Space Design Specification Outdoor Air Object Name is required."); + ErrorsFound = true; } } @@ -2439,11 +2433,9 @@ void ProcessInputOARequirements(EnergyPlusData &state, int &NumAlphas, Array1D const &Numbers, int &NumNumbers, - [[maybe_unused]] Array1D_bool const &lNumericBlanks, // Unused Array1D_bool const &lAlphaBlanks, Array1D_string const &cAlphaFields, - [[maybe_unused]] Array1D_string const &cNumericFields, // Unused - bool &ErrorsFound // If errors found in input + bool &ErrorsFound // If errors found in input ) { diff --git a/src/EnergyPlus/SizingManager.hh b/src/EnergyPlus/SizingManager.hh index f3df285d44a..49730ce9299 100644 --- a/src/EnergyPlus/SizingManager.hh +++ b/src/EnergyPlus/SizingManager.hh @@ -96,11 +96,9 @@ namespace SizingManager { int &NumAlphas, Array1D const &rNumericArgs, int &NumNumbers, - Array1D_bool const &lNumericFieldBlanks, // Unused Array1D_bool const &lAlphaFieldBlanks, Array1D_string const &cAlphaFieldNames, - Array1D_string const &cNumericFieldNames, // Unused - bool &ErrorsFound // If errors found in input + bool &ErrorsFound // If errors found in input ); void GetZoneAirDistribution(EnergyPlusData &state); From e4750704722930d7b65977ec6b1f2e41bd2a408d Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Oct 2021 15:20:31 -0500 Subject: [PATCH 08/10] Space-Unit tests --- tst/EnergyPlus/unit/DataSizing.unit.cc | 195 ++++++++++++++++++ .../unit/HeatBalanceManager.unit.cc | 120 +++++++++++ tst/EnergyPlus/unit/SizingManager.unit.cc | 78 +------ 3 files changed, 321 insertions(+), 72 deletions(-) diff --git a/tst/EnergyPlus/unit/DataSizing.unit.cc b/tst/EnergyPlus/unit/DataSizing.unit.cc index f28ebc56515..cf04235f74c 100644 --- a/tst/EnergyPlus/unit/DataSizing.unit.cc +++ b/tst/EnergyPlus/unit/DataSizing.unit.cc @@ -52,7 +52,14 @@ // EnergyPlus Headers #include +#include +#include #include +#include +#include +#include +#include +#include #include "Fixtures/EnergyPlusFixture.hh" @@ -224,3 +231,191 @@ TEST_F(EnergyPlusFixture, DataSizingTest_resetHVACSizingGlobals) DataSizing::resetHVACSizingGlobals(*state, state->dataSize->CurZoneEqNum, 0, FirstPass); EXPECT_FALSE(FirstPass); } + +TEST_F(EnergyPlusFixture, OARequirements_calcDesignSpecificationOutdoorAir) +{ + // Test OARequirements.calcDesignSpecificationOutdoorAir() + + // GetZoneData uses GetObjectItem with ipshortcuts so these need to be allocated + int NumAlphas = 4; + int NumNumbers = 9; + state->dataIPShortCut->lNumericFieldBlanks.allocate(NumNumbers); + state->dataIPShortCut->lAlphaFieldBlanks.allocate(NumAlphas); + state->dataIPShortCut->cAlphaFieldNames.allocate(NumAlphas); + state->dataIPShortCut->cNumericFieldNames.allocate(NumNumbers); + state->dataIPShortCut->cAlphaArgs.allocate(NumAlphas); + state->dataIPShortCut->rNumericArgs.allocate(NumNumbers); + state->dataIPShortCut->lNumericFieldBlanks = false; + state->dataIPShortCut->lAlphaFieldBlanks = false; + state->dataIPShortCut->cAlphaFieldNames = " "; + state->dataIPShortCut->cNumericFieldNames = " "; + state->dataIPShortCut->cAlphaArgs = " "; + state->dataIPShortCut->rNumericArgs = 0.0; + + // Original method of initializing epJSON input objects, but couldn't get this to work for extensible arrays + // state->dataInputProcessing->inputProcessor->epJSON["Zone"]["Zone 1"] = {}; + // state->dataInputProcessing->inputProcessor->epJSON["Zone"]["Zone 2"] = {}; + // state->dataInputProcessing->inputProcessor->epJSON["Space"]["Space 1a"] = {{"zone_name", "Zone 1"}}; + + // Using R_json raw string parsing to get the arrays processed correctly + // Reference https://github.com/nlohmann/json#json-as-first-class-data-type + state->dataInputProcessing->inputProcessor->epJSON = R"( + { + "Zone": { + "Zone 1" : { + "volume": 1200.0, + "floor_area": 400.0 + }, + "Zone 2" : { + "volume": 1200.0, + "floor_area": 400.0 + } + }, + "Space": { + "Space 1a" : { + "zone_name": "Zone 1", + "floor_area": 100.0 + }, + "Space 1b" : { + "zone_name": "Zone 1", + "floor_area": 100.0 + }, + "Space 1c" : { + "zone_name": "Zone 1", + "floor_area": 100.0 + }, + "Space 1d" : { + "zone_name": "Zone 1", + "floor_area": 100.0 + } + }, + "DesignSpecification:OutdoorAir": { + "DSOA Per Person": { + "outdoor_air_flow_per_person": 0.0125, + "outdoor_air_method": "Flow/Person" + }, + "DSOA Per Area": { + "outdoor_air_flow_per_zone_floor_area": 0.001, + "outdoor_air_method": "Flow/Area" + }, + "DSOA Per Zone": { + "outdoor_air_flow_per_zone": 1.0, + "outdoor_air_method": "Flow/Zone" + }, + "DSOA ACH": { + "outdoor_air_flow_air_changes_per_hour": 0.1, + "outdoor_air_method": "AirChanges/Hour" + }, + "DSOA Sum": { + "outdoor_air_method": "Sum", + "outdoor_air_flow_per_person": 0.0125, + "outdoor_air_flow_per_zone_floor_area": 0.00025, + "outdoor_air_flow_per_zone": 1.0, + "outdoor_air_flow_air_changes_per_hour": 0.025 + } + }, + "DesignSpecification:OutdoorAir:SpaceList": { + "DSOA Zone 1 Spaces" : { + "space_specs": [ + { + "space_name": "Space 1a", + "space_design_specification_outdoor_air_object_name": "DSOA Per Person" + }, + { + "space_name": "Space 1b", + "space_design_specification_outdoor_air_object_name": "DSOA Per Area" + }, + { + "space_name": "Space 1c", + "space_design_specification_outdoor_air_object_name": "DSOA Per Zone" + }, + { + "space_name": "Space 1d", + "space_design_specification_outdoor_air_object_name": "DSOA ACH" + } + ] + } + } + } + )"_json; + + state->dataGlobal->isEpJSON = true; + state->dataInputProcessing->inputProcessor->initializeMaps(); + + bool ErrorsFound = false; + HeatBalanceManager::GetZoneData(*state, ErrorsFound); + compare_err_stream(""); + EXPECT_FALSE(ErrorsFound); + + int zoneNum = 1; + EXPECT_EQ("ZONE 1", state->dataHeatBal->Zone(zoneNum).Name); + EXPECT_EQ(4, state->dataHeatBal->Zone(zoneNum).numSpaces); + EXPECT_EQ("SPACE 1A", state->dataHeatBal->space(state->dataHeatBal->Zone(zoneNum).spaceIndexes[0]).Name); + EXPECT_EQ("SPACE 1B", state->dataHeatBal->space(state->dataHeatBal->Zone(zoneNum).spaceIndexes[1]).Name); + EXPECT_EQ("SPACE 1C", state->dataHeatBal->space(state->dataHeatBal->Zone(zoneNum).spaceIndexes[2]).Name); + EXPECT_EQ("SPACE 1D", state->dataHeatBal->space(state->dataHeatBal->Zone(zoneNum).spaceIndexes[3]).Name); + zoneNum = 2; + EXPECT_EQ("ZONE 2", state->dataHeatBal->Zone(zoneNum).Name); + EXPECT_EQ(1, state->dataHeatBal->Zone(zoneNum).numSpaces); + EXPECT_EQ("ZONE 2", state->dataHeatBal->space(state->dataHeatBal->Zone(zoneNum).spaceIndexes[0]).Name); + + SizingManager::GetOARequirements(*state); + state->dataZoneEquip->ZoneEquipConfig.allocate(state->dataGlobal->numSpaces); + ZoneEquipmentManager::SetUpZoneSizingArrays(*state); + compare_err_stream(""); + + std::string thisOAReqName = "DSOA ZONE 1 SPACES"; + int oaNum = UtilityRoutines::FindItemInList(thisOAReqName, state->dataSize->OARequirements); + EXPECT_TRUE(oaNum > 0); + EXPECT_EQ(4, state->dataSize->OARequirements(oaNum).dsoaIndexes.size()); + + // Set zone and space occupants + state->dataHeatBal->spaceIntGain.allocate(state->dataGlobal->numSpaces); + state->dataHeatBal->ZoneIntGain.allocate(state->dataGlobal->NumOfZones); + std::string thisSpaceName = "SPACE 1A"; + int spaceNum = UtilityRoutines::FindItemInList(thisSpaceName, state->dataHeatBal->space); + state->dataHeatBal->space(spaceNum).floorArea = 100.0; + state->dataHeatBal->space(spaceNum).totOccupants = 10; + state->dataHeatBal->spaceIntGain(spaceNum).NOFOCC = 1; + state->dataHeatBal->space(spaceNum).maxOccupants = 12; + + thisSpaceName = "SPACE 1B"; + spaceNum = UtilityRoutines::FindItemInList(thisSpaceName, state->dataHeatBal->space); + state->dataHeatBal->space(spaceNum).floorArea = 100.0; + + thisSpaceName = "SPACE 1C"; + spaceNum = UtilityRoutines::FindItemInList(thisSpaceName, state->dataHeatBal->space); + state->dataHeatBal->space(spaceNum).floorArea = 100.0; + + thisSpaceName = "SPACE 1D"; + spaceNum = UtilityRoutines::FindItemInList(thisSpaceName, state->dataHeatBal->space); + state->dataHeatBal->space(spaceNum).floorArea = 100.0; + + std::string thisZoneName = "ZONE 2"; + zoneNum = UtilityRoutines::FindItemInList(thisZoneName, state->dataHeatBal->Zone); + state->dataHeatBal->Zone(zoneNum).FloorArea = 400.0; + state->dataHeatBal->Zone(zoneNum).TotOccupants = 10; + state->dataHeatBal->ZoneIntGain(zoneNum).NOFOCC = 1; + state->dataHeatBal->Zone(zoneNum).maxOccupants = 12; + + bool UseOccSchFlag = false; + bool UseMinOASchFlag = false; + + thisZoneName = "ZONE 1"; + zoneNum = UtilityRoutines::FindItemInList(thisZoneName, state->dataHeatBal->Zone); + state->dataHeatBal->Zone(zoneNum).FloorArea = 400.0; + thisOAReqName = "DSOA ZONE 1 SPACES"; + oaNum = UtilityRoutines::FindItemInList(thisOAReqName, state->dataSize->OARequirements); + Real64 zone1OA = DataSizing::calcDesignSpecificationOutdoorAir(*state, oaNum, zoneNum, UseOccSchFlag, UseMinOASchFlag); + // 0.0125/person * 10.0 + 0.001/area * 100.0 + 1.0/zone + 0.1ACH * 300.0 / 3600.0; + Real64 expectedOA = 0.0125 * 10.0 + 0.001 * 100.0 + 1.0 + 0.1 * 300.0 / 3600.0; + EXPECT_EQ(expectedOA, zone1OA); + + thisZoneName = "ZONE 2"; + zoneNum = UtilityRoutines::FindItemInList(thisZoneName, state->dataHeatBal->Zone); + state->dataHeatBal->Zone(zoneNum).FloorArea = 400.0; + thisOAReqName = "DSOA SUM"; + oaNum = UtilityRoutines::FindItemInList(thisOAReqName, state->dataSize->OARequirements); + Real64 zone2OA = DataSizing::calcDesignSpecificationOutdoorAir(*state, oaNum, zoneNum, UseOccSchFlag, UseMinOASchFlag); + EXPECT_EQ(expectedOA, zone2OA); +} diff --git a/tst/EnergyPlus/unit/HeatBalanceManager.unit.cc b/tst/EnergyPlus/unit/HeatBalanceManager.unit.cc index cede6a98c14..312c546f768 100644 --- a/tst/EnergyPlus/unit/HeatBalanceManager.unit.cc +++ b/tst/EnergyPlus/unit/HeatBalanceManager.unit.cc @@ -2170,4 +2170,124 @@ TEST_F(EnergyPlusFixture, HeatBalanceManager_EMSConstructionSwitchTest) EXPECT_TRUE(state->dataSurface->SurfEMSConstructionOverrideON(surfNum)); } +TEST_F(EnergyPlusFixture, HeatBalanceManager_GetSpaceData) +{ + // Test input processing of Space object + + // GetZoneData uses GetObjectItem with ipshortcuts so these need to be allocated + int NumAlphas = 4; + int NumNumbers = 9; + state->dataIPShortCut->lNumericFieldBlanks.allocate(NumNumbers); + state->dataIPShortCut->lAlphaFieldBlanks.allocate(NumAlphas); + state->dataIPShortCut->cAlphaFieldNames.allocate(NumAlphas); + state->dataIPShortCut->cNumericFieldNames.allocate(NumNumbers); + state->dataIPShortCut->cAlphaArgs.allocate(NumAlphas); + state->dataIPShortCut->rNumericArgs.allocate(NumNumbers); + state->dataIPShortCut->lNumericFieldBlanks = false; + state->dataIPShortCut->lAlphaFieldBlanks = false; + state->dataIPShortCut->cAlphaFieldNames = " "; + state->dataIPShortCut->cNumericFieldNames = " "; + state->dataIPShortCut->cAlphaArgs = " "; + state->dataIPShortCut->rNumericArgs = 0.0; + + // Original method of initializing epJSON input objects, but couldn't get this to work for extensible arrays + // state->dataInputProcessing->inputProcessor->epJSON["Zone"]["Zone 1"] = {}; + // state->dataInputProcessing->inputProcessor->epJSON["Zone"]["Zone 2"] = {}; + // state->dataInputProcessing->inputProcessor->epJSON["Space"]["Space 1a"] = {{"zone_name", "Zone 1"}}; + + // Using R_json raw string parsing to get the arrays processed correctly + // Reference https://github.com/nlohmann/json#json-as-first-class-data-type + state->dataInputProcessing->inputProcessor->epJSON = R"( + { + "Zone": { + "Zone 1" : { + }, + "Zone 2" : { + } + }, + "Space": { + "Space 1a" : { + "zone_name": "Zone 1" + }, + "Space 1b" : { + "zone_name": "Zone 1", + "floor_area": 100.0, + "space_type": "Office", + "tags": [ + { + "tag": "Tag1" + }, + { + "tag": "Tag2" + } + ] + } + }, + "SpaceList": { + "SomeSpaces" : { + "spaces": [ + { + "space_name": "Space 1a" + }, + { + "space_name": "Space 1b" + } + ] + } + } + } + )"_json; + + state->dataGlobal->isEpJSON = true; + state->dataInputProcessing->inputProcessor->initializeMaps(); + + bool ErrorsFound = false; + GetZoneData(*state, ErrorsFound); + compare_err_stream(""); + EXPECT_FALSE(ErrorsFound); + + int zoneNum = 1; + EXPECT_EQ("ZONE 1", state->dataHeatBal->Zone(zoneNum).Name); + EXPECT_EQ(2, state->dataHeatBal->Zone(zoneNum).numSpaces); + EXPECT_EQ("SPACE 1A", state->dataHeatBal->space(state->dataHeatBal->Zone(zoneNum).spaceIndexes[0]).Name); + EXPECT_EQ("SPACE 1B", state->dataHeatBal->space(state->dataHeatBal->Zone(zoneNum).spaceIndexes[1]).Name); + zoneNum = 2; + EXPECT_EQ("ZONE 2", state->dataHeatBal->Zone(zoneNum).Name); + EXPECT_EQ(1, state->dataHeatBal->Zone(zoneNum).numSpaces); + EXPECT_EQ("ZONE 2", state->dataHeatBal->space(state->dataHeatBal->Zone(zoneNum).spaceIndexes[0]).Name); + + int spaceNum = 1; + EXPECT_EQ("SPACE 1A", state->dataHeatBal->space(spaceNum).Name); + EXPECT_EQ("GENERAL", state->dataHeatBal->space(spaceNum).spaceType); + EXPECT_EQ("GENERAL", state->dataHeatBal->spaceTypes(state->dataHeatBal->space(spaceNum).spaceTypeNum)); + EXPECT_EQ("ZONE 1", state->dataHeatBal->Zone(state->dataHeatBal->space(spaceNum).zoneNum).Name); + // Defaults + EXPECT_EQ(-99999, state->dataHeatBal->space(spaceNum).userEnteredFloorArea); + EXPECT_TRUE(state->dataHeatBal->space(spaceNum).tags.empty()); + + spaceNum = 2; + EXPECT_EQ("SPACE 1B", state->dataHeatBal->space(spaceNum).Name); + EXPECT_EQ("OFFICE", state->dataHeatBal->space(spaceNum).spaceType); + EXPECT_EQ("OFFICE", state->dataHeatBal->spaceTypes(state->dataHeatBal->space(spaceNum).spaceTypeNum)); + EXPECT_EQ("ZONE 1", state->dataHeatBal->Zone(state->dataHeatBal->space(spaceNum).zoneNum).Name); + EXPECT_EQ(100, state->dataHeatBal->space(spaceNum).userEnteredFloorArea); + EXPECT_EQ("TAG1", state->dataHeatBal->space(spaceNum).tags(1)); + EXPECT_EQ("TAG2", state->dataHeatBal->space(spaceNum).tags(2)); + + EXPECT_EQ("SOMESPACES", state->dataHeatBal->spaceList(1).Name); + EXPECT_EQ(2, state->dataHeatBal->spaceList(1).spaces.size()); + EXPECT_EQ("SPACE 1A", state->dataHeatBal->space(state->dataHeatBal->spaceList(1).spaces[0]).Name); + EXPECT_EQ("SPACE 1B", state->dataHeatBal->space(state->dataHeatBal->spaceList(1).spaces[1]).Name); + + // This space is auto-generated + spaceNum = 3; + EXPECT_EQ("ZONE 2", state->dataHeatBal->space(spaceNum).Name); + EXPECT_EQ("GENERAL", state->dataHeatBal->space(spaceNum).spaceType); + EXPECT_EQ("GENERAL", state->dataHeatBal->spaceTypes(state->dataHeatBal->space(spaceNum).spaceTypeNum)); + EXPECT_EQ("ZONE 2", state->dataHeatBal->Zone(state->dataHeatBal->space(spaceNum).zoneNum).Name); + // Defaults + EXPECT_EQ(-99999, state->dataHeatBal->space(spaceNum).userEnteredFloorArea); + EXPECT_TRUE(state->dataHeatBal->space(spaceNum).tags.empty()); +} + } // namespace EnergyPlus diff --git a/tst/EnergyPlus/unit/SizingManager.unit.cc b/tst/EnergyPlus/unit/SizingManager.unit.cc index 0447ffb1b7a..ffa6e132f76 100644 --- a/tst/EnergyPlus/unit/SizingManager.unit.cc +++ b/tst/EnergyPlus/unit/SizingManager.unit.cc @@ -103,18 +103,7 @@ TEST_F(EnergyPlusFixture, GetOARequirementsTest_DSOA1) Numbers(4) = 0.4; // Outdoor Air Flow Air Changes per Hour ErrorsFound = false; - ProcessInputOARequirements(*state, - CurrentModuleObject, - OAIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields, - ErrorsFound); + ProcessInputOARequirements(*state, CurrentModuleObject, OAIndex, Alphas, NumAlphas, Numbers, NumNumbers, lAlphaBlanks, cAlphaFields, ErrorsFound); EXPECT_FALSE(ErrorsFound); @@ -134,18 +123,7 @@ TEST_F(EnergyPlusFixture, GetOARequirementsTest_DSOA1) Numbers(4) = 0.4; // Outdoor Air Flow Air Changes per Hour ErrorsFound = false; - ProcessInputOARequirements(*state, - CurrentModuleObject, - OAIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields, - ErrorsFound); + ProcessInputOARequirements(*state, CurrentModuleObject, OAIndex, Alphas, NumAlphas, Numbers, NumNumbers, lAlphaBlanks, cAlphaFields, ErrorsFound); EXPECT_FALSE(ErrorsFound); @@ -165,18 +143,7 @@ TEST_F(EnergyPlusFixture, GetOARequirementsTest_DSOA1) Numbers(4) = 0.4; // Outdoor Air Flow Air Changes per Hour ErrorsFound = false; - ProcessInputOARequirements(*state, - CurrentModuleObject, - OAIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields, - ErrorsFound); + ProcessInputOARequirements(*state, CurrentModuleObject, OAIndex, Alphas, NumAlphas, Numbers, NumNumbers, lAlphaBlanks, cAlphaFields, ErrorsFound); EXPECT_FALSE(ErrorsFound); @@ -196,18 +163,7 @@ TEST_F(EnergyPlusFixture, GetOARequirementsTest_DSOA1) Numbers(4) = 0.4; // Outdoor Air Flow Air Changes per Hour ErrorsFound = false; - ProcessInputOARequirements(*state, - CurrentModuleObject, - OAIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields, - ErrorsFound); + ProcessInputOARequirements(*state, CurrentModuleObject, OAIndex, Alphas, NumAlphas, Numbers, NumNumbers, lAlphaBlanks, cAlphaFields, ErrorsFound); EXPECT_FALSE(ErrorsFound); @@ -227,18 +183,7 @@ TEST_F(EnergyPlusFixture, GetOARequirementsTest_DSOA1) Numbers(4) = 0.4; // Outdoor Air Flow Air Changes per Hour ErrorsFound = false; - ProcessInputOARequirements(*state, - CurrentModuleObject, - OAIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields, - ErrorsFound); + ProcessInputOARequirements(*state, CurrentModuleObject, OAIndex, Alphas, NumAlphas, Numbers, NumNumbers, lAlphaBlanks, cAlphaFields, ErrorsFound); EXPECT_FALSE(ErrorsFound); @@ -258,18 +203,7 @@ TEST_F(EnergyPlusFixture, GetOARequirementsTest_DSOA1) Numbers(4) = 0.4; // Outdoor Air Flow Air Changes per Hour ErrorsFound = false; - ProcessInputOARequirements(*state, - CurrentModuleObject, - OAIndex, - Alphas, - NumAlphas, - Numbers, - NumNumbers, - lNumericBlanks, - lAlphaBlanks, - cAlphaFields, - cNumericFields, - ErrorsFound); + ProcessInputOARequirements(*state, CurrentModuleObject, OAIndex, Alphas, NumAlphas, Numbers, NumNumbers, lAlphaBlanks, cAlphaFields, ErrorsFound); EXPECT_FALSE(ErrorsFound); From 580cc1f3002040384eb5d5d433ba302171413516 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Oct 2021 15:56:27 -0500 Subject: [PATCH 09/10] Space-UserInputFloorArea default --- src/EnergyPlus/DataHeatBalance.hh | 36 +++++++++++++++---------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/EnergyPlus/DataHeatBalance.hh b/src/EnergyPlus/DataHeatBalance.hh index ef5b8af7c8c..c6282299c95 100644 --- a/src/EnergyPlus/DataHeatBalance.hh +++ b/src/EnergyPlus/DataHeatBalance.hh @@ -338,24 +338,24 @@ namespace DataHeatBalance { struct SpaceData { - std::string Name; // Space name - int zoneNum = 0; // Pointer to Zone wich contains this space - Real64 userEnteredFloorArea = 0.0; // User input floor area for this space - std::string spaceType = "General"; // Space type tag - int spaceTypeNum = 0; // Points to spaceType for this space - EPVector tags; // Optional tags for reporting - EPVector surfaces; // Pointers to surfaces in this space - Real64 calcFloorArea = 0.0; // Calculated floor area used for this space - Real64 floorArea = 0.0; // Floor area used for this space - bool hasFloor = false; // Has "Floor" surface - Real64 extWindowArea = 0.0; // Exterior Window Area for Zone - Real64 totalSurfArea = 0.0; // Total surface area for Zone - int radiantEnclosureNum = 0; // Radiant exchange enclosure this space belongs to - int solarEnclosureNum = 0; // Solar distribution enclosure this space belongs to - Real64 totOccupants = 0.0; // total design occupancy (sum of NumberOfPeople for the space People objects, not multiplied) - Real64 minOccupants = 0.0; // minimum occupancy (sum of NomMinNumberPeople for the space People objects, not multiplied) - Real64 maxOccupants = 0.0; // maximum occupancy (sum of NomMaxNumberPeople for the space People objects, not multiplied) - bool isRemainderSpace = false; // True if this space is auto-generated "-Remainder" space + std::string Name; // Space name + int zoneNum = 0; // Pointer to Zone wich contains this space + Real64 userEnteredFloorArea = DataGlobalConstants::AutoCalculate; // User input floor area for this space + std::string spaceType = "General"; // Space type tag + int spaceTypeNum = 0; // Points to spaceType for this space + EPVector tags; // Optional tags for reporting + EPVector surfaces; // Pointers to surfaces in this space + Real64 calcFloorArea = 0.0; // Calculated floor area used for this space + Real64 floorArea = 0.0; // Floor area used for this space + bool hasFloor = false; // Has "Floor" surface + Real64 extWindowArea = 0.0; // Exterior Window Area for Zone + Real64 totalSurfArea = 0.0; // Total surface area for Zone + int radiantEnclosureNum = 0; // Radiant exchange enclosure this space belongs to + int solarEnclosureNum = 0; // Solar distribution enclosure this space belongs to + Real64 totOccupants = 0.0; // total design occupancy (sum of NumberOfPeople for the space People objects, not multiplied) + Real64 minOccupants = 0.0; // minimum occupancy (sum of NomMinNumberPeople for the space People objects, not multiplied) + Real64 maxOccupants = 0.0; // maximum occupancy (sum of NomMaxNumberPeople for the space People objects, not multiplied) + bool isRemainderSpace = false; // True if this space is auto-generated "-Remainder" space std::vector otherEquipFuelTypeNums; // List of fuel types used by other equipment in this space std::vector otherEquipFuelTypeNames; // List of fuel types used by other equipment in this space }; From a4fcb58377581c608317ae2bdf749e638e272795 Mon Sep 17 00:00:00 2001 From: mjwitte Date: Mon, 18 Oct 2021 15:57:21 -0500 Subject: [PATCH 10/10] Space-Fix 9135 DesignSpecification:OutdoorAir:SpaceList --- src/EnergyPlus/ZoneEquipmentManager.cc | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/EnergyPlus/ZoneEquipmentManager.cc b/src/EnergyPlus/ZoneEquipmentManager.cc index d2aa88974dc..b3a72471706 100644 --- a/src/EnergyPlus/ZoneEquipmentManager.cc +++ b/src/EnergyPlus/ZoneEquipmentManager.cc @@ -1324,6 +1324,7 @@ void SetUpZoneSizingArrays(EnergyPlusData &state) } // Populate DesignSpecification:OutdoorAir:SpaceList spaces + bool dsoaError = false; for (int oaIndex = 1; oaIndex <= state.dataSize->NumOARequirements; ++oaIndex) { auto &thisOAReq = state.dataSize->OARequirements(oaIndex); // If this is a DesignSpecification:OutdoorAir:SpaceList check to make sure spaces are valid and belong to this zone @@ -1336,13 +1337,15 @@ void SetUpZoneSizingArrays(EnergyPlusData &state) } else { ShowSevereError(state, "SetUpZoneSizingArrays: DesignSpecification:OutdoorAir:SpaceList=" + thisOAReq.Name); ShowContinueError(state, "Space Name=" + thisSpaceName + " not found."); + dsoaError = true; ErrorsFound = true; } // Check for duplicate spaces for (int loop = 1; loop <= int(thisOAReq.dsoaSpaceIndexes.size()) - 1; ++loop) { if (thisSpaceNum == thisOAReq.dsoaSpaceIndexes(loop)) { ShowSevereError(state, "SetUpZoneSizingArrays: DesignSpecification:OutdoorAir:SpaceList=" + thisOAReq.Name); - ShowContinueError(state, "Space Name=" + thisSpaceName + " appears more than once in list."); + ShowContinueError(state, "Space Name=" + thisSpaceName + " appears more than once in the list."); + dsoaError = true; ErrorsFound = true; } } @@ -1361,7 +1364,7 @@ void SetUpZoneSizingArrays(EnergyPlusData &state) Real64 ZoneMinOccupancy = 0.; ZoneIndex = state.dataSize->FinalZoneSizing(CtrlZoneNum).ActualZoneNum; int DSOAPtr = state.dataSize->FinalZoneSizing(CtrlZoneNum).ZoneDesignSpecOAIndex; // index to DesignSpecification:OutdoorAir object - if (DSOAPtr > 0) { + if ((DSOAPtr > 0) && !dsoaError) { auto &thisOAReq = state.dataSize->OARequirements(DSOAPtr); // If this is a DesignSpecification:OutdoorAir:SpaceList check to make sure spaces are valid and belong to this zone if (thisOAReq.numDSOA > 0) { @@ -1425,7 +1428,11 @@ void SetUpZoneSizingArrays(EnergyPlusData &state) state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneDesignSpecOAIndex = DSOAPtr; // store for later use state.dataZoneEquip->ZoneEquipConfig(CtrlZoneNum).ZoneAirDistributionIndex = state.dataSize->FinalZoneSizing(CtrlZoneNum).ZoneAirDistributionIndex; // store for later use - OAVolumeFlowRate = DataSizing::calcDesignSpecificationOutdoorAir(state, DSOAPtr, ZoneIndex, UseOccSchFlag, UseMinOASchFlag); + if (!dsoaError) { + OAVolumeFlowRate = DataSizing::calcDesignSpecificationOutdoorAir(state, DSOAPtr, ZoneIndex, UseOccSchFlag, UseMinOASchFlag); + } else { + OAVolumeFlowRate = 0.0; + } // Zone(ZoneIndex)%Multiplier and Zone(ZoneIndex)%ListMultiplier applied in CalcDesignSpecificationOutdoorAir state.dataSize->FinalZoneSizing(CtrlZoneNum).MinOA = OAVolumeFlowRate;