Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <algorithm>
50 : #include <cmath>
51 : #include <fstream>
52 : #include <ostream>
53 :
54 : // ObjexxFCL Headers
55 : #include <ObjexxFCL/Array1D.hh>
56 : #include <ObjexxFCL/string.functions.hh>
57 :
58 : // EnergyPlus Headers
59 : #include <EnergyPlus/Construction.hh>
60 : #include <EnergyPlus/DElightManagerF.hh>
61 : #include <EnergyPlus/Data/EnergyPlusData.hh>
62 : #include <EnergyPlus/DataDElight.hh>
63 : #include <EnergyPlus/DataDaylighting.hh>
64 : #include <EnergyPlus/DataEnvironment.hh>
65 : #include <EnergyPlus/DataGlobals.hh>
66 : #include <EnergyPlus/DataHeatBalance.hh>
67 : #include <EnergyPlus/DataIPShortCuts.hh>
68 : #include <EnergyPlus/DataStringGlobals.hh>
69 : #include <EnergyPlus/DataSurfaces.hh>
70 : #include <EnergyPlus/General.hh>
71 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
72 : #include <EnergyPlus/InternalHeatGains.hh>
73 : #include <EnergyPlus/Material.hh>
74 : #include <EnergyPlus/OutputProcessor.hh>
75 : #include <EnergyPlus/UtilityRoutines.hh>
76 :
77 : extern "C" {
78 : #include <DElight/DElightManagerC.h>
79 : }
80 :
81 : namespace EnergyPlus {
82 :
83 : namespace DElightManagerF {
84 :
85 : // MODULE INFORMATION
86 : // AUTHOR Robert J. Hitchcock
87 : // DATE WRITTEN August 2003
88 : // MODIFIED January 2004
89 : // RE-ENGINEERED na
90 :
91 : // PURPOSE OF THIS MODULE:
92 :
93 : // Defines INTERFACE Statements for Fortran calls to the DElightManagerC.cpp module.
94 : // The DElightManager.cpp module in turn defines the C/C++ calls to the DElight DLL.
95 : // Also, contains subroutines for performing associated operations.
96 :
97 : // METHODOLOGY EMPLOYED:
98 :
99 : // C Language Implementation of DOE2.1d and Superlite 3.0
100 : // Daylighting Algorithms with new Complex Fenestration System
101 : // analysis algorithms.
102 : // The original DOE2 daylighting algorithms and implementation
103 : // in FORTRAN were developed by F.C. Winkelmann at the
104 : // Lawrence Berkeley National Laboratory.
105 : // The original Superlite algorithms and implementation in FORTRAN
106 : // were developed by Michael Modest and Jong-Jin Kim
107 : // under contract with Lawrence Berkeley National Laboratory.
108 : // REFERENCES:
109 :
110 : // "Daylighting Calculation in DOE-2," F.C.Winkelmann, LBL-11353, May 1983
111 : // "Daylighting Simulation in the DOE-2 Building Energy Analysis Program,"
112 : // F.C. Winkelmann and S. Selkowitz, Energy and Buildings 8(1985)271-286
113 :
114 : // USE STATEMENTS:
115 : using namespace DataDElight;
116 :
117 3 : void DElightInputGenerator(EnergyPlusData &state)
118 : {
119 :
120 : // SUBROUTINE INFORMATION:
121 : // AUTHOR Robert J. Hitchcock
122 : // DATE WRITTEN August 2003
123 : // MODIFIED February 2004 - Changes to accommodate mods in DElight IDD
124 : // RE-ENGINEERED na
125 :
126 : // PURPOSE OF THIS SUBROUTINE:
127 : // This subroutine creates a DElight input file from EnergyPlus processed input.
128 :
129 : // USE STATEMENTS:
130 : using namespace DataHeatBalance; // Gives access to Building, Zone and Lights data
131 : using namespace DataEnvironment; // Gives access to Site data
132 : using namespace DataSurfaces; // Gives access to Surface data
133 : using namespace DataStringGlobals; // Gives access to Program Path and Current Time/Date
134 : using InternalHeatGains::CheckLightsReplaceableMinMaxForZone;
135 : using InternalHeatGains::GetDesignLightingLevelForZone;
136 :
137 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
138 : int iNumDElightZones; // Counter for Thermal Zones with hosted Daylighting:DElight objects
139 : int iNumOpaqueSurfs; // Counter for opaque surfaces in each zone
140 : int iNumWindows; // Counter for windows hosted in each surface
141 : int iconstruct; // Index for construction type of surfaces
142 : int iMatlLayer; // Index for the outside (i.e., 1st) Material Layer for a Construction
143 : Real64 rExtVisRefl; // Exterior visible reflectance of a material
144 : Real64 rLightLevel; // installed lighting level for current zone
145 : Real64 CosBldgRelNorth; // Cosine of Building rotation
146 : Real64 SinBldgRelNorth; // Sine of Building rotation
147 : Real64 CosZoneRelNorth; // Cosine of Zone rotation
148 : Real64 SinZoneRelNorth; // Sine of Zone rotation
149 : Real64 Xb; // temp var for transformation calc
150 : Real64 Yb; // temp var for transformation calc
151 6 : Array1D<Real64> RefPt_WCS_Coord(3);
152 6 : Array1D_int iWndoConstIndexes(100);
153 : bool lWndoConstFound; // Flag for non-unique window const index
154 6 : std::string cNameWOBlanks; // Name without blanks
155 : bool ErrorsFound;
156 : int iHostedCFS;
157 : bool lWndoIsDoppelganger; // Flag for doppelganger window test
158 : int iDoppelganger;
159 : bool ldoTransform;
160 : Real64 roldAspectRatio;
161 : Real64 rnewAspectRatio;
162 : Real64 Xo;
163 : Real64 XnoRot;
164 : Real64 Xtrans;
165 : Real64 Yo;
166 : Real64 YnoRot;
167 : Real64 Ytrans;
168 :
169 : // Formats
170 : static constexpr std::string_view Format_901("Version EPlus : DElight input generated from EnergyPlus processed input {}\n");
171 : static constexpr std::string_view Format_902(
172 : "\nBuilding_Name {}\nSite_Latitude {:12.4F}\nSite_Longitude {:12.4F}\nSite_Altitude {:12.4F}\nBldg_Azimuth {:12.4F}\nSite_Time_Zone "
173 : "{:12.4F}\nAtm_Moisture 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07 0.07\nAtm_Turbidity 0.12 0.12 0.12 0.12 0.12 0.12 0.12 "
174 : "0.12 0.12 0.12 0.12 0.12\n");
175 : static constexpr std::string_view Format_903("\nZONES\nN_Zones {:4}\n");
176 : static constexpr std::string_view Format_904(
177 : "\nZONE DATA\nZone {}\nBldgSystem_Zone_Origin {:12.4F}{:12.4F}{:12.4F}\nZone_Azimuth {:12.4F}\nZone_Multiplier {:5}\nZone_Floor_Area "
178 : "{:12.4F}\nZone_Volume {:12.4F}\nZone_Installed_Lighting {:12.4F}\nMin_Input_Power {:12.4F}\nMin_Light_Fraction "
179 : "{:12.4F}\nLight_Ctrl_Steps {:3}\nLight_Ctrl_Prob {:12.4F}\nView_Azimuth 0.0\nMax_Grid_Node_Area {:12.4F}\n");
180 : static constexpr std::string_view Format_905("\nZONE LIGHTING SCHEDULES\nN_Lt_Scheds 0\n");
181 : static constexpr std::string_view Format_906("\nZONE SURFACES\nN_Surfaces {:4}\n");
182 : static constexpr std::string_view Format_907("\nZONE SURFACE DATA\nSurface {}\nWCS_Azimuth {:12.4F}\nWCS_Tilt {:12.4F}\nVis_Refl "
183 : "{:12.4F}\nExt_Refl {:12.4F}\nGnd_Refl 0.2\nN_WCS_Vertices {:6}\n");
184 : static constexpr std::string_view Format_908("Vertex {:12.4F}{:12.4F}{:12.4F}\n");
185 : static constexpr std::string_view Format_909("\nSURFACE WINDOWS\nN_Windows {:6}\n");
186 : static constexpr std::string_view Format_910(
187 : "\nSURFACE WINDOW DATA\nWindow {}\nGlass_Type {:8}\nShade_Flag 0\nOverhang_Fin_Depth 0.0 0.0 "
188 : "0.0\nOverhang_Fin_Distance 0.0 0.0 0.0\nN_WCS_Vertices {:4}\n");
189 : static constexpr std::string_view Format_911("\nSURFACE CFS\nN_CFS {:6}\n");
190 : static constexpr std::string_view Format_915(
191 : "\nCOMPLEX FENESTRATION DATA\nCFS_Name {}\nCFS_Type {}\nFenestration_Rotation {:12.4F}\nN_WCS_Vertices {:4}\n");
192 : static constexpr std::string_view Format_912("\nZONE REFERENCE POINTS\nN_Ref_Pts {:4}\n");
193 : static constexpr std::string_view Format_913(
194 : "\nZONE REFERENCE POINT DATA\nReference_Point {}\nRefPt_WCS_Coords {:12.4F}{:12.4F}{:12.4F}\nZone_Fraction "
195 : "{:12.4F}\nLight_Set_Pt {:12.4F}\nLight_Ctrl_Type {:4}\n");
196 : static constexpr std::string_view Format_914("\nBUILDING SHADES\nN_BShades 0\n");
197 : static constexpr std::string_view Format_920("\nLIBRARY DATA\nGLASS TYPES\nN_Glass_Types {:4}\n");
198 : static constexpr std::string_view Format_921(
199 : "\nGLASS TYPE DATA\nName {:6}\nEPlusDiffuse_Transmittance {:12.4F}\nEPlusDiffuse_Int_Reflectance "
200 : "{:12.4F}\nEPlus_Vis_Trans_Coeff_1 {:17.9F}\nEPlus_Vis_Trans_Coeff_2 {:17.9F}\nEPlus_Vis_Trans_Coeff_3 "
201 : "{:17.9F}\nEPlus_Vis_Trans_Coeff_4 {:17.9F}\nEPlus_Vis_Trans_Coeff_5 {:17.9F}\nEPlus_Vis_Trans_Coeff_6 {:17.9F}\n");
202 :
203 : // Init the ErrorsFound flag
204 3 : ErrorsFound = false;
205 :
206 3 : GetInputDElightComplexFenestration(state, ErrorsFound);
207 :
208 3 : CheckForGeometricTransform(state, ldoTransform, roldAspectRatio, rnewAspectRatio);
209 :
210 : // Init the counter for Thermal Zones with hosted Daylighting:DElight objects
211 3 : iNumDElightZones = 0;
212 :
213 : // Init the counter for Window Construction types for writing to Library Data section of DElight input file
214 3 : int iNumWndoConsts = 0;
215 :
216 : // Open a file for writing DElight input from EnergyPlus data
217 6 : auto delightInFile = state.files.delightIn.open(state, "DElightInputGenerator", state.files.outputControl.delightin);
218 :
219 : // Start of DElight input file
220 3 : print(delightInFile, Format_901, state.dataStrGlobals->CurrentDateTime);
221 :
222 : // Building Data Section retrieved from DataHeatBalance and DataEnvironment modules
223 : // Remove any blanks from the Building Name for ease of input to DElight
224 3 : cNameWOBlanks = ReplaceBlanksWithUnderscores(state.dataHeatBal->BuildingName);
225 12 : print(delightInFile,
226 : Format_902,
227 : cNameWOBlanks,
228 3 : state.dataEnvrn->Latitude,
229 3 : state.dataEnvrn->Longitude,
230 6 : state.dataEnvrn->Elevation * M2FT,
231 3 : state.dataHeatBal->BuildingAzimuth,
232 3 : state.dataEnvrn->TimeZoneNumber);
233 :
234 : // Calc cos and sin of Building Relative North values for later use in transforming Reference Point coordinates
235 3 : CosBldgRelNorth = std::cos(-state.dataHeatBal->BuildingAzimuth * DataGlobalConstants::DegToRadians);
236 3 : SinBldgRelNorth = std::sin(-state.dataHeatBal->BuildingAzimuth * DataGlobalConstants::DegToRadians);
237 :
238 : // Loop through the Daylighting:Controls objects that use DElight checking for a host Zone
239 9 : for (auto &znDayl : state.dataDaylightingData->daylightControl) {
240 6 : if (znDayl.DaylightMethod == DataDaylighting::DaylightingMethod::DElight) {
241 :
242 : // Register Error if 0 DElight RefPts have been input for valid DElight object
243 3 : if (znDayl.TotalDaylRefPoints == 0) {
244 0 : ShowSevereError(state, "No Reference Points input for daylighting zone using DElight =" + znDayl.Name);
245 0 : ErrorsFound = true;
246 : }
247 :
248 : // Register Warning if more than 100 DElight RefPts have been input for valid DElight object
249 3 : if (znDayl.TotalDaylRefPoints > 100) {
250 : // Restrict to 100 Ref Pt maximum
251 0 : znDayl.TotalDaylRefPoints = 100;
252 0 : ShowWarningError(state, "Maximum of 100 Reference Points exceeded for daylighting zone using DElight =" + znDayl.Name);
253 0 : ShowWarningError(state, " Only first 100 Reference Points included in DElight analysis");
254 : }
255 3 : znDayl.DaylRefPtAbsCoord.allocate(3, znDayl.TotalDaylRefPoints);
256 3 : znDayl.DaylRefPtAbsCoord = 0.0;
257 :
258 : // RJH 2008-03-07: Allocate and Init DaylIllumAtRefPt array for this DElight zone
259 3 : znDayl.DaylIllumAtRefPt.allocate(znDayl.TotalDaylRefPoints);
260 3 : znDayl.DaylIllumAtRefPt = 0.0;
261 : // following not used in DElight but allocated for convenience
262 3 : znDayl.GlareIndexAtRefPt.allocate(znDayl.TotalDaylRefPoints);
263 3 : znDayl.GlareIndexAtRefPt = 0.0;
264 :
265 : // Increment counter of Thermal Zones with valid hosted DElight object
266 3 : ++iNumDElightZones;
267 : }
268 : } // traverse ZoneDaylight array
269 :
270 : // Zone Data Section
271 3 : print(delightInFile, Format_903, iNumDElightZones);
272 :
273 : // Loop through the Daylighting:DElight objects searching for a match to the current Zone
274 :
275 9 : for (auto &znDayl : state.dataDaylightingData->daylightControl) {
276 6 : if (znDayl.DaylightMethod == DataDaylighting::DaylightingMethod::DElight) {
277 3 : int const izone = UtilityRoutines::FindItemInList(znDayl.ZoneName, state.dataHeatBal->Zone);
278 3 : if (izone != 0) {
279 :
280 3 : rLightLevel = GetDesignLightingLevelForZone(state, izone);
281 3 : CheckLightsReplaceableMinMaxForZone(state, izone);
282 3 : auto &zn(state.dataHeatBal->Zone(izone));
283 :
284 : // Write this Zone to the DElight input file
285 : // Remove any blanks from the Zone Name for ease of input to DElight
286 3 : cNameWOBlanks = ReplaceBlanksWithUnderscores(zn.Name);
287 9 : print(delightInFile,
288 : Format_904,
289 : cNameWOBlanks,
290 6 : zn.OriginX * M2FT,
291 6 : zn.OriginY * M2FT,
292 6 : zn.OriginZ * M2FT,
293 : zn.RelNorth,
294 6 : zn.Multiplier * zn.ListMultiplier,
295 6 : zn.FloorArea * M22FT2,
296 6 : zn.Volume * M32FT3,
297 6 : rLightLevel / (zn.FloorArea * M22FT2 + 0.00001),
298 : znDayl.MinPowerFraction,
299 : znDayl.MinLightFraction,
300 : znDayl.LightControlSteps,
301 : znDayl.LightControlProbability,
302 6 : znDayl.DElightGriddingResolution * M22FT2);
303 :
304 : // Calc cos and sin of Zone Relative North values for later use in transforming Reference Point coordinates
305 3 : CosZoneRelNorth = std::cos(-zn.RelNorth * DataGlobalConstants::DegToRadians);
306 3 : SinZoneRelNorth = std::sin(-zn.RelNorth * DataGlobalConstants::DegToRadians);
307 :
308 : // Zone Lighting Schedule Data Section
309 : // NOTE: Schedules are not required since hourly values are retrieved from EnergyPlus as needed
310 3 : print(delightInFile, Format_905);
311 :
312 : // Zone Surface Data Section
313 : // Count the number of opaque surfaces bounding the current zone
314 3 : iNumOpaqueSurfs = 0;
315 6 : for (int spaceNum : zn.spaceIndexes) {
316 3 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
317 24 : for (int isurf = thisSpace.HTSurfaceFirst; isurf <= thisSpace.HTSurfaceLast; ++isurf) {
318 21 : auto &surf(state.dataSurface->Surface(isurf));
319 21 : if (surf.Class == SurfaceClass::Wall) ++iNumOpaqueSurfs;
320 21 : if (surf.Class == SurfaceClass::Roof) ++iNumOpaqueSurfs;
321 21 : if (surf.Class == SurfaceClass::Floor) ++iNumOpaqueSurfs;
322 : }
323 : } // Zone Opaque Surface loop
324 :
325 3 : print(delightInFile, Format_906, iNumOpaqueSurfs);
326 :
327 : // Write each opaque bounding Surface to the DElight input file
328 6 : for (int spaceNum : zn.spaceIndexes) {
329 3 : auto &thisSpace = state.dataHeatBal->space(spaceNum);
330 3 : int const iSurfaceFirst = thisSpace.HTSurfaceFirst;
331 3 : int const iSurfaceLast = thisSpace.HTSurfaceLast;
332 24 : for (int isurf = iSurfaceFirst; isurf <= iSurfaceLast; ++isurf) {
333 :
334 21 : auto &surf(state.dataSurface->Surface(isurf));
335 :
336 : // Only process "opaque bounding" surface types
337 21 : if ((surf.Class == SurfaceClass::Wall) || (surf.Class == SurfaceClass::Roof) || (surf.Class == SurfaceClass::Floor)) {
338 :
339 : // Get the Construction index for this Surface
340 18 : iconstruct = surf.Construction;
341 :
342 : // Is this Surface exposed to the exterior?
343 18 : if (surf.ExtSolar) {
344 : // Get the index for the outside (i.e., 1st) Material Layer for this Construction
345 12 : iMatlLayer = state.dataConstruction->Construct(iconstruct).LayerPoint(1);
346 : // Get the outside visible reflectance of this material layer
347 : // (since Construct(iconstruct)%ReflectVisDiffFront always appears to == 0.0)
348 12 : rExtVisRefl = 1.0 - state.dataMaterial->Material(iMatlLayer).AbsorpVisible;
349 : } else {
350 6 : rExtVisRefl = 0.0;
351 : }
352 :
353 : // Remove any blanks from the Surface Name for ease of input to DElight
354 18 : cNameWOBlanks = ReplaceBlanksWithUnderscores(surf.Name);
355 36 : print(delightInFile,
356 : Format_907,
357 : cNameWOBlanks,
358 : surf.Azimuth,
359 : surf.Tilt,
360 18 : state.dataConstruction->Construct(iconstruct).ReflectVisDiffBack,
361 : rExtVisRefl,
362 : surf.Sides);
363 :
364 : // Write out the vertex coordinates for each vertex
365 18 : int const iNumVertices = surf.Sides; // Counter for surface vertices
366 90 : for (int ivert = 1; ivert <= iNumVertices; ++ivert) {
367 72 : print(delightInFile,
368 : Format_908,
369 144 : surf.Vertex(ivert).x * M2FT,
370 144 : surf.Vertex(ivert).y * M2FT,
371 144 : surf.Vertex(ivert).z * M2FT);
372 : }
373 :
374 : // Count each Window hosted by the current opaque bounding Surface
375 18 : iNumWindows = 0;
376 144 : for (int iwndo = iSurfaceFirst; iwndo <= iSurfaceLast; ++iwndo) {
377 126 : if (state.dataSurface->Surface(iwndo).Class == SurfaceClass::Window) {
378 18 : auto &wndo(state.dataSurface->Surface(iwndo));
379 18 : if (wndo.BaseSurfName == surf.Name) {
380 :
381 : // Error if window has multiplier > 1 since this causes incorrect illuminance calc
382 3 : if (wndo.Multiplier > 1.0) {
383 0 : ShowSevereError(state,
384 0 : "Multiplier > 1.0 for window " + wndo.Name +
385 : " not allowed since it is in a zone with DElight daylighting.");
386 0 : ErrorsFound = true;
387 : }
388 :
389 : // Error if window has a shading device (blind/shade/screen) since
390 : // DElight cannot perform dynamic shading device deployment
391 3 : if (wndo.HasShadeControl) {
392 0 : ShowSevereError(state,
393 0 : "Shading Device on window " + wndo.Name +
394 : " dynamic control is not supported in a zone with DElight daylighting.");
395 0 : ErrorsFound = true;
396 : }
397 :
398 : // Loop through all Doppelganger Surface Names to ignore these Windows
399 3 : lWndoIsDoppelganger = false;
400 5 : for (auto &cfs : state.dataDaylightingData->DElightComplexFene) {
401 :
402 : // Is the current Window Surface a Doppelganger?
403 2 : if (wndo.Name == cfs.wndwName) {
404 : // Ignore this Doppelganger Window
405 2 : lWndoIsDoppelganger = true;
406 : }
407 :
408 : } // CFS object loop A
409 :
410 3 : if (!lWndoIsDoppelganger) {
411 1 : ++iNumWindows;
412 : }
413 :
414 : } // Surface hosts Window test
415 : } // Window test
416 : } // Window loop
417 :
418 18 : print(delightInFile, Format_909, iNumWindows);
419 :
420 : // If the current opaque bounding Surface hosts Windows,
421 : // then write each hosted Window to the DElight input file
422 : // and track the Window Construction type for later writing
423 18 : if (iNumWindows > 0) {
424 8 : for (int iwndo2 = iSurfaceFirst; iwndo2 <= iSurfaceLast; ++iwndo2) {
425 7 : if (state.dataSurface->Surface(iwndo2).Class == SurfaceClass::Window) {
426 :
427 1 : auto &wndo2(state.dataSurface->Surface(iwndo2));
428 :
429 1 : if (wndo2.BaseSurfName == surf.Name) {
430 :
431 : // Loop through all Doppelganger Surface Names to ignore these Windows
432 1 : lWndoIsDoppelganger = false;
433 :
434 1 : for (auto &cfs : state.dataDaylightingData->DElightComplexFene) {
435 :
436 : // Is the current Window Surface a Doppelganger?
437 0 : if (wndo2.Name == cfs.wndwName) {
438 : // Ignore this Doppelganger Window
439 0 : lWndoIsDoppelganger = true;
440 : }
441 :
442 : } // CFS object loop A
443 :
444 1 : if (!lWndoIsDoppelganger) {
445 :
446 : // Track unique window construction types here for later writing to
447 : // the library section of DElight input file
448 :
449 : // Get the Construction index for this Window Surface
450 1 : iconstruct = wndo2.Construction;
451 :
452 : // Has the current Construction index been encountered before?
453 1 : lWndoConstFound = false;
454 1 : for (int iconst = 1; iconst <= iNumWndoConsts; ++iconst) {
455 0 : if (iconstruct == iWndoConstIndexes(iconst)) lWndoConstFound = true;
456 : }
457 1 : if (!lWndoConstFound) {
458 1 : ++iNumWndoConsts;
459 1 : iWndoConstIndexes(iNumWndoConsts) = iconstruct;
460 : }
461 :
462 : // Write this Window to the DElight input file
463 : // Remove any blanks from the Window Surface Name for ease of input to DElight
464 1 : cNameWOBlanks = ReplaceBlanksWithUnderscores(wndo2.Name);
465 1 : print(delightInFile, Format_910, cNameWOBlanks, iconstruct + 10000, wndo2.Sides);
466 : // Use WndoConstIndex + 10000 as the Glass Type Name
467 : // to differentiate EPlus glass types within DElight
468 :
469 : // Write out the vertex coordinates for each vertex
470 1 : int const iNumVertices = wndo2.Sides; // Counter for surface vertices
471 5 : for (int ivert = 1; ivert <= iNumVertices; ++ivert) {
472 4 : print(delightInFile,
473 : Format_908,
474 8 : wndo2.Vertex(ivert).x * M2FT,
475 8 : wndo2.Vertex(ivert).y * M2FT,
476 8 : wndo2.Vertex(ivert).z * M2FT);
477 : }
478 : } //! lWndoIsDoppelganger
479 : } // Surface hosts Window2 test
480 : } // Window2 Class test
481 : } // Window2 loop
482 : } // Hosted Windows test
483 :
484 : // Write the number of CFS hosted by the current Opaque Bounding Surface
485 18 : iHostedCFS = 0;
486 :
487 : // Loop through the input CFS objects searching for a match to the current Opaque Bounding Surface
488 30 : for (auto &cfs : state.dataDaylightingData->DElightComplexFene) {
489 :
490 : // Does the current Opaque Bounding Surface host the current CFS object?
491 12 : if (surf.Name == cfs.surfName) {
492 : // Count this hosted CFS
493 2 : ++iHostedCFS;
494 : }
495 : } // CFS object loop 1
496 :
497 18 : print(delightInFile, Format_911, iHostedCFS);
498 :
499 : // Now write each of the hosted CFS data
500 : // Loop through the input CFS objects searching for a match to the current Opaque Bounding Surface
501 30 : for (auto &cfs : state.dataDaylightingData->DElightComplexFene) {
502 :
503 : // Does the current Opaque Bounding Surface host the current CFS object?
504 12 : if (surf.Name == cfs.surfName) {
505 :
506 : // Get the Doppelganger surface for this CFS
507 2 : iDoppelganger = 0;
508 16 : for (int iwndo3 = iSurfaceFirst; iwndo3 <= iSurfaceLast; ++iwndo3) {
509 :
510 14 : auto &wndo3(state.dataSurface->Surface(iwndo3));
511 :
512 14 : if (wndo3.Class == SurfaceClass::Window) {
513 :
514 : // Is the current Window Surface the Doppelganger for the current CFS?
515 2 : if (wndo3.Name == cfs.wndwName) {
516 : // Store the window surface index for future reference
517 2 : iDoppelganger = iwndo3;
518 : }
519 : }
520 : }
521 :
522 : // Make sure that a valid Doppelganger surface exists
523 2 : if (iDoppelganger > 0) {
524 :
525 : // Write the data for this hosted CFS
526 2 : auto &doppelgangerSurf(state.dataSurface->Surface(iDoppelganger));
527 :
528 : // Remove any blanks from the CFS Name for ease of input to DElight
529 2 : cNameWOBlanks = ReplaceBlanksWithUnderscores(cfs.Name);
530 2 : int const iNumVertices = doppelgangerSurf.Sides; // Counter for surface vertices
531 2 : print(delightInFile, Format_915, cNameWOBlanks, cfs.ComplexFeneType, cfs.feneRota, iNumVertices);
532 :
533 : // Write out the vertex coordinates for each vertex
534 10 : for (int ivert = 1; ivert <= iNumVertices; ++ivert) {
535 8 : print(delightInFile,
536 : Format_908,
537 16 : doppelgangerSurf.Vertex(ivert).x * M2FT,
538 16 : doppelgangerSurf.Vertex(ivert).y * M2FT,
539 16 : doppelgangerSurf.Vertex(ivert).z * M2FT);
540 : }
541 : }
542 : // Register Error if there is no valid Doppelganger for current Complex Fenestration
543 2 : if (iDoppelganger == 0) {
544 0 : ShowSevereError(state, "No Doppelganger Window Surface found for Complex Fenestration =" + cfs.Name);
545 0 : ErrorsFound = true;
546 : }
547 : } // The current Opaque Bounding Surface hosts the current CFS object?
548 : } // CFS object loop 2
549 : } // Opaque Bounding Surface test
550 : }
551 : } // Zone Surface loop
552 :
553 : // Write ZONE REFERENCE POINTS
554 3 : print(delightInFile, Format_912, znDayl.TotalDaylRefPoints);
555 :
556 : // Loop through the Daylighting:DElight:Reference Point objects checking for the current DElight Zone host
557 15 : for (auto &refPt : state.dataDaylightingData->DaylRefPt) {
558 :
559 : // Is this RefPt hosted by current DElight Zone?
560 12 : if (izone == refPt.ZoneNum) {
561 6 : auto &zn(state.dataHeatBal->Zone(izone));
562 :
563 : // Limit to maximum of 100 RefPts
564 6 : if (znDayl.TotalDaylRefPoints <= 100) {
565 :
566 6 : if (state.dataSurface->DaylRefWorldCoordSystem) {
567 0 : RefPt_WCS_Coord(1) = refPt.x;
568 0 : RefPt_WCS_Coord(2) = refPt.y;
569 0 : RefPt_WCS_Coord(3) = refPt.z;
570 : } else {
571 : // Transform reference point coordinates into building coordinate system
572 6 : Xb = refPt.x * CosZoneRelNorth - refPt.y * SinZoneRelNorth + zn.OriginX;
573 6 : Yb = refPt.x * SinZoneRelNorth + refPt.y * CosZoneRelNorth + zn.OriginY;
574 : // Transform into World Coordinate System
575 6 : RefPt_WCS_Coord(1) = Xb * CosBldgRelNorth - Yb * SinBldgRelNorth;
576 6 : RefPt_WCS_Coord(2) = Xb * SinBldgRelNorth + Yb * CosBldgRelNorth;
577 6 : RefPt_WCS_Coord(3) = refPt.z + zn.OriginZ;
578 6 : if (ldoTransform) { // Geometry transform
579 0 : Xo = RefPt_WCS_Coord(1); // world coordinates.... shifted by relative north angle...
580 0 : Yo = RefPt_WCS_Coord(2);
581 : // next derotate the building
582 0 : XnoRot = Xo * CosBldgRelNorth + Yo * SinBldgRelNorth;
583 0 : YnoRot = Yo * CosBldgRelNorth - Xo * SinBldgRelNorth;
584 : // translate
585 0 : Xtrans = XnoRot * std::sqrt(rnewAspectRatio / roldAspectRatio);
586 0 : Ytrans = YnoRot * std::sqrt(roldAspectRatio / rnewAspectRatio);
587 : // rerotate
588 0 : RefPt_WCS_Coord(1) = Xtrans * CosBldgRelNorth - Ytrans * SinBldgRelNorth;
589 :
590 0 : RefPt_WCS_Coord(2) = Xtrans * SinBldgRelNorth + Ytrans * CosBldgRelNorth;
591 : }
592 : }
593 6 : znDayl.DaylRefPtAbsCoord({1, 3}, refPt.indexToFracAndIllum) = RefPt_WCS_Coord({1, 3});
594 :
595 : // Validate that Reference Point coordinates are within the host Zone
596 6 : if (RefPt_WCS_Coord(1) < zn.MinimumX || RefPt_WCS_Coord(1) > zn.MaximumX) {
597 0 : ShowWarningError(state, "DElightInputGenerator:Reference point X Value outside Zone Min/Max X, Zone=" + zn.Name);
598 0 : ShowSevereError(state,
599 0 : format("...X Reference Point= {:.2R}, Zone Minimum X= {:.2R}, Zone Maximum X= {:.2R}",
600 : zn.MinimumX,
601 : RefPt_WCS_Coord(1),
602 0 : zn.MaximumX));
603 0 : ErrorsFound = true;
604 : }
605 6 : if (RefPt_WCS_Coord(2) < zn.MinimumY || RefPt_WCS_Coord(2) > zn.MaximumY) {
606 0 : ShowWarningError(state, "DElightInputGenerator:Reference point Y Value outside Zone Min/Max Y, Zone=" + zn.Name);
607 0 : ShowSevereError(state,
608 0 : format("...Y Reference Point= {:.2R}, Zone Minimum Y= {:.2R}, Zone Maximum Y= {:.2R}",
609 : zn.MinimumY,
610 : RefPt_WCS_Coord(2),
611 0 : zn.MaximumY));
612 0 : ErrorsFound = true;
613 : }
614 6 : if (RefPt_WCS_Coord(3) < state.dataHeatBal->Zone(izone).MinimumZ || RefPt_WCS_Coord(3) > zn.MaximumZ) {
615 0 : ShowWarningError(state, "DElightInputGenerator:Reference point Z Value outside Zone Min/Max Z, Zone=" + zn.Name);
616 0 : ShowSevereError(state,
617 0 : format("...Z Reference Point= {:.2R}, Zone Minimum Z= {:.2R}, Zone Maximum Z= {:.2R}",
618 : zn.MinimumZ,
619 : RefPt_WCS_Coord(3),
620 0 : zn.MaximumZ));
621 0 : ErrorsFound = true;
622 : }
623 :
624 : // Write this RefPt to the DElight input file
625 :
626 : // Remove any blanks from the RefPt Name for ease of input to DElight
627 6 : cNameWOBlanks = ReplaceBlanksWithUnderscores(refPt.Name);
628 6 : if (refPt.indexToFracAndIllum != 0) {
629 18 : print(delightInFile,
630 : Format_913,
631 : cNameWOBlanks,
632 12 : RefPt_WCS_Coord(1) * M2FT,
633 12 : RefPt_WCS_Coord(2) * M2FT,
634 12 : RefPt_WCS_Coord(3) * M2FT,
635 : znDayl.FracZoneDaylit(refPt.indexToFracAndIllum),
636 12 : znDayl.IllumSetPoint(refPt.indexToFracAndIllum) * LUX2FC,
637 : znDayl.LightControlType);
638 : // RJH 2008-03-07: Set up DaylIllumAtRefPt for output for this DElight zone RefPt
639 12 : SetupOutputVariable(state,
640 : "Daylighting Reference Point Illuminance",
641 : OutputProcessor::Unit::lux,
642 6 : znDayl.DaylIllumAtRefPt(refPt.indexToFracAndIllum),
643 : OutputProcessor::SOVTimeStepType::Zone,
644 : OutputProcessor::SOVStoreType::Average,
645 6 : refPt.Name);
646 : } else {
647 0 : print(delightInFile,
648 : Format_913,
649 : cNameWOBlanks,
650 0 : RefPt_WCS_Coord(1) * M2FT,
651 0 : RefPt_WCS_Coord(2) * M2FT,
652 0 : RefPt_WCS_Coord(3) * M2FT,
653 : 0.0,
654 0 : 0.0 * LUX2FC,
655 : znDayl.LightControlType); // should never happen but just in case send zero fraction and illuminance
656 : }
657 : } // Max 100 RefPt test
658 : } // RefPt in current DElight Zone test
659 : } // traverse reference points loop
660 : } // if in a zone
661 : } // Zone hosts DElight object test
662 : } // traverse ZoneDayLight object loop
663 :
664 : // Write BUILDING SHADES
665 3 : print(delightInFile, Format_914);
666 :
667 : // Write LIBRARY DATA
668 3 : print(delightInFile, Format_920, iNumWndoConsts);
669 :
670 : // Write GLASS TYPES
671 : // VisBeamCoeffs are processed in EPlus by POLYF() function
672 : // Use WndoConstIndex + 10000 as the Glass Type Name to differentiate EPlus glass types within DElight
673 4 : for (int iconst = 1; iconst <= iNumWndoConsts; ++iconst) {
674 9 : print(delightInFile,
675 : Format_921,
676 2 : iWndoConstIndexes(iconst) + 10000,
677 1 : state.dataConstruction->Construct(iWndoConstIndexes(iconst)).TransDiffVis,
678 1 : state.dataConstruction->Construct(iWndoConstIndexes(iconst)).ReflectVisDiffBack,
679 1 : state.dataConstruction->Construct(iWndoConstIndexes(iconst)).TransVisBeamCoef(1),
680 1 : state.dataConstruction->Construct(iWndoConstIndexes(iconst)).TransVisBeamCoef(2),
681 1 : state.dataConstruction->Construct(iWndoConstIndexes(iconst)).TransVisBeamCoef(3),
682 1 : state.dataConstruction->Construct(iWndoConstIndexes(iconst)).TransVisBeamCoef(4),
683 1 : state.dataConstruction->Construct(iWndoConstIndexes(iconst)).TransVisBeamCoef(5),
684 1 : state.dataConstruction->Construct(iWndoConstIndexes(iconst)).TransVisBeamCoef(6));
685 :
686 : } // Glass Type loop
687 :
688 3 : if (ErrorsFound) ShowFatalError(state, "Problems with Daylighting:DElight input, see previous error messages");
689 3 : }
690 :
691 3 : void GenerateDElightDaylightCoefficients(Real64 &dLatitude, int &iErrorFlag)
692 : {
693 :
694 : // SUBROUTINE INFORMATION:
695 : // AUTHOR Linda Lawrie
696 : // DATE WRITTEN September 2012
697 : // MODIFIED na
698 : // RE-ENGINEERED na
699 :
700 : // PURPOSE OF THIS SUBROUTINE:
701 : // The purpose of this subroutine is to provide an envelop to the DElightDaylightCoefficients routine
702 :
703 3 : delightdaylightcoefficients(dLatitude, &iErrorFlag);
704 3 : }
705 :
706 3 : void GetInputDElightComplexFenestration(EnergyPlusData &state, bool &ErrorsFound)
707 : {
708 : // Perform GetInput function for the Daylighting:DELight:ComplexFenestration object
709 : // Glazer - July 2016
710 :
711 : int NumAlpha;
712 : int NumNumber;
713 : int IOStat;
714 3 : int CFSNum = 0;
715 :
716 3 : constexpr auto cCurrentModuleObject("Daylighting:DELight:ComplexFenestration");
717 :
718 3 : int TotDElightCFS = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
719 3 : state.dataDaylightingData->DElightComplexFene.allocate(TotDElightCFS);
720 5 : for (auto &cfs : state.dataDaylightingData->DElightComplexFene) {
721 16 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
722 : cCurrentModuleObject,
723 : ++CFSNum,
724 2 : state.dataIPShortCut->cAlphaArgs,
725 : NumAlpha,
726 2 : state.dataIPShortCut->rNumericArgs,
727 : NumNumber,
728 : IOStat,
729 2 : state.dataIPShortCut->lNumericFieldBlanks,
730 2 : state.dataIPShortCut->lAlphaFieldBlanks,
731 2 : state.dataIPShortCut->cAlphaFieldNames,
732 4 : state.dataIPShortCut->cNumericFieldNames);
733 2 : cfs.Name = state.dataIPShortCut->cAlphaArgs(1);
734 2 : cfs.ComplexFeneType = state.dataIPShortCut->cAlphaArgs(2);
735 2 : cfs.surfName = state.dataIPShortCut->cAlphaArgs(3);
736 2 : if (UtilityRoutines::FindItemInList(cfs.surfName, state.dataSurface->Surface) == 0) {
737 0 : ShowSevereError(state,
738 0 : format("{}{}",
739 : cCurrentModuleObject,
740 0 : ": " + cfs.Name + ", invalid " + state.dataIPShortCut->cAlphaFieldNames(3) + "=\"" + cfs.surfName + "\"."));
741 0 : ErrorsFound = true;
742 : }
743 2 : cfs.wndwName = state.dataIPShortCut->cAlphaArgs(4);
744 2 : if (UtilityRoutines::FindItemInList(cfs.surfName, state.dataSurface->Surface) == 0) {
745 0 : ShowSevereError(state,
746 0 : format("{}{}",
747 : cCurrentModuleObject,
748 0 : ": " + cfs.Name + ", invalid " + state.dataIPShortCut->cAlphaFieldNames(4) + "=\"" + cfs.wndwName + "\"."));
749 0 : ErrorsFound = true;
750 : }
751 2 : cfs.feneRota = state.dataIPShortCut->rNumericArgs(1);
752 2 : if (cfs.feneRota < 0. || cfs.feneRota > 360.) {
753 0 : ShowSevereError(state,
754 0 : format("{}{}",
755 : cCurrentModuleObject,
756 0 : ": " + cfs.Name + ", invalid " + state.dataIPShortCut->cNumericFieldNames(1) + " outside of range 0 to 360."));
757 0 : ErrorsFound = true;
758 : }
759 : }
760 3 : }
761 :
762 3 : void CheckForGeometricTransform(EnergyPlusData &state, bool &doTransform, Real64 &OldAspectRatio, Real64 &NewAspectRatio)
763 : {
764 :
765 : // SUBROUTINE INFORMATION:
766 : // AUTHOR Linda Lawrie
767 : // DATE WRITTEN February 2009
768 : // MODIFIED na
769 : // RE-ENGINEERED na
770 :
771 : // PURPOSE OF THIS SUBROUTINE:
772 : // check for geometrytransform in the daylighting access for reference points
773 :
774 : // METHODOLOGY EMPLOYED:
775 : // once reference points have been converted to WCS,
776 : // change them to reflect a different aspect
777 : // ratio for the entire building based on user input.
778 :
779 : // SUBROUTINE PARAMETER DEFINITIONS:
780 3 : constexpr auto CurrentModuleObject("GeometryTransform");
781 :
782 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
783 6 : Array1D_string cAlphas(1);
784 6 : Array1D<Real64> rNumerics(2);
785 : int NAlphas;
786 : int NNum;
787 : int IOStat;
788 :
789 : // begin execution
790 : // get user input...
791 3 : doTransform = false;
792 3 : OldAspectRatio = 1.0;
793 3 : NewAspectRatio = 1.0;
794 :
795 3 : if (state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject) == 1) {
796 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
797 : CurrentModuleObject,
798 : 1,
799 : cAlphas,
800 : NAlphas,
801 : rNumerics,
802 : NNum,
803 : IOStat,
804 0 : state.dataIPShortCut->lNumericFieldBlanks,
805 0 : state.dataIPShortCut->lAlphaFieldBlanks,
806 0 : state.dataIPShortCut->cAlphaFieldNames,
807 0 : state.dataIPShortCut->cNumericFieldNames);
808 0 : OldAspectRatio = rNumerics(1);
809 0 : NewAspectRatio = rNumerics(2);
810 0 : if (cAlphas(1) != "XY") {
811 0 : ShowWarningError(
812 : state,
813 0 : format("{}{}", CurrentModuleObject, ": invalid " + state.dataIPShortCut->cAlphaFieldNames(1) + "=" + cAlphas(1) + "...ignored."));
814 : }
815 0 : doTransform = true;
816 0 : state.dataSurface->AspectTransform = true;
817 : }
818 3 : if (state.dataSurface->WorldCoordSystem) {
819 3 : doTransform = false;
820 3 : state.dataSurface->AspectTransform = false;
821 : }
822 3 : }
823 :
824 33 : std::string ReplaceBlanksWithUnderscores(std::string const &InputString) // Input String
825 : {
826 :
827 : // FUNCTION INFORMATION:
828 : // AUTHOR Robert J. Hitchcock
829 : // DATE WRITTEN August 2003
830 : // MODIFIED From UtilityRoutines::MakeUPPERCase( function by Linda K. Lawrie
831 : // RE-ENGINEERED na
832 :
833 : // PURPOSE OF THIS SUBROUTINE:
834 : // This function returns a representation of the InputString with blanks replaced with underscores.
835 :
836 : // METHODOLOGY EMPLOYED:
837 : // Uses the std::replace function from the C++ library
838 :
839 : // FUNCTION LOCAL VARIABLE DECLARATIONS:
840 :
841 33 : std::string ResultString(trimmed(InputString));
842 33 : std::replace(ResultString.begin(), ResultString.end(), ' ', '_');
843 33 : return ResultString;
844 : }
845 :
846 2037 : void DElightElecLtgCtrl(int iNameLength,
847 : std::string cZoneName,
848 : Real64 dBldgLat,
849 : Real64 dHISKF,
850 : Real64 dHISUNF,
851 : Real64 dCloudFraction,
852 : Real64 dSOLCOSX,
853 : Real64 dSOLCOSY,
854 : Real64 dSOLCOSZ,
855 : Real64 &pdPowerReducFac,
856 : int piErrorFlag)
857 : {
858 4074 : auto zoneNameArr(getCharArrayFromString(cZoneName));
859 2037 : delightelecltgctrl(
860 2037 : iNameLength, &zoneNameArr[0], dBldgLat, dHISKF, dHISUNF, dCloudFraction, dSOLCOSX, dSOLCOSY, dSOLCOSZ, &pdPowerReducFac, &piErrorFlag);
861 2037 : }
862 :
863 2037 : std::vector<char> getCharArrayFromString(std::string const &originalString)
864 : {
865 2037 : std::vector<char> returnVal(originalString.begin(), originalString.end());
866 2037 : returnVal.push_back('\0'); // get null terminated string of chars
867 2037 : return returnVal;
868 : }
869 :
870 0 : std::string getStringFromCharArray(std::vector<char> const &originalCharArray)
871 : {
872 0 : return std::string(originalCharArray.begin(), originalCharArray.end());
873 : }
874 :
875 : } // namespace DElightManagerF
876 :
877 2313 : } // namespace EnergyPlus
|