Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, 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 : // FMI-Related Headers
49 : extern "C" {
50 : #include <BCVTB/utilSocket.h>
51 : #include <BCVTB/utilXml.h>
52 : #include <FMI/main.h>
53 : }
54 :
55 : // C++ Headers
56 : #include <string>
57 : #include <vector>
58 :
59 : // ObjexxFCL Headers
60 : #include <ObjexxFCL/Array.functions.hh>
61 : #include <ObjexxFCL/string.functions.hh>
62 :
63 : // EnergyPlus Headers
64 : #include <EnergyPlus/Data/EnergyPlusData.hh>
65 : #include <EnergyPlus/DataEnvironment.hh>
66 : #include <EnergyPlus/DataIPShortCuts.hh>
67 : #include <EnergyPlus/DataStringGlobals.hh>
68 : #include <EnergyPlus/DataSystemVariables.hh>
69 : #include <EnergyPlus/DisplayRoutines.hh>
70 : #include <EnergyPlus/EMSManager.hh>
71 : #include <EnergyPlus/ExternalInterface.hh>
72 : #include <EnergyPlus/FileSystem.hh>
73 : #include <EnergyPlus/GlobalNames.hh>
74 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
75 : #include <EnergyPlus/OutputProcessor.hh>
76 : #include <EnergyPlus/RuntimeLanguageProcessor.hh>
77 : #include <EnergyPlus/ScheduleManager.hh>
78 : #include <EnergyPlus/UtilityRoutines.hh>
79 :
80 : namespace EnergyPlus::ExternalInterface {
81 :
82 : // Module containing the routines dealing with the BCVTB interface
83 :
84 : // MODULE INFORMATION:
85 : // AUTHOR Michael Wetter
86 : // DATE WRITTEN 2Dec2007
87 : // MODIFIED Rui Zhang July 2009
88 : // MODIFIED Thierry S. Nouidui 2011
89 :
90 : // PURPOSE OF THIS MODULE:
91 : // To encapsulate the data and routines required to interface
92 : // the Building Controls Virtual Test Bed (BCVTB) and FunctionalMockupUnits (FMU)
93 :
94 : // REFERENCES:
95 : // http://simulationresearch.lbl.gov/bcvtb
96 : // http://www.modelisar.com
97 :
98 1946046 : void ExternalInterfaceExchangeVariables(EnergyPlusData &state)
99 : {
100 :
101 : // SUBROUTINE INFORMATION:
102 : // AUTHOR Michael Wetter
103 : // DATE WRITTEN 2Dec2007
104 :
105 : // PURPOSE OF THIS SUBROUTINE:
106 : // Exchanges variables between EnergyPlus and the BCVTB socket.
107 :
108 1946046 : if (state.dataExternalInterface->GetInputFlag) {
109 795 : GetExternalInterfaceInput(state);
110 795 : state.dataExternalInterface->GetInputFlag = false;
111 : }
112 :
113 1946046 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB || state.dataExternalInterface->haveExternalInterfaceFMUExport) {
114 0 : InitExternalInterface(state);
115 : // Exchange data only after sizing and after warm-up.
116 : // Note that checking for ZoneSizingCalc SysSizingCalc does not work here, hence we
117 : // use the KindOfSim flag
118 0 : if (!state.dataGlobal->WarmupFlag && (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather)) {
119 0 : CalcExternalInterface(state);
120 : }
121 : }
122 :
123 1946046 : if (state.dataExternalInterface->haveExternalInterfaceFMUImport) {
124 143523 : std::string errorMessage; // Error message
125 143523 : errorMessage.reserve(100);
126 143523 : char *errorMessagePtr(errorMessage.data());
127 143523 : const int retValErrMsg = checkOperatingSystem(errorMessagePtr);
128 143523 : if (retValErrMsg != 0) {
129 0 : ShowSevereError(state, format("ExternalInterface/ExternalInterfaceExchangeVariables:{}", errorMessagePtr));
130 0 : state.dataExternalInterface->ErrorsFound = true;
131 0 : StopExternalInterfaceIfError(state);
132 : }
133 : // initialize the FunctionalMockupUnitImport interface
134 143523 : InitExternalInterfaceFMUImport(state);
135 : // No Data exchange during design days
136 : // Data Exchange data during warmup and after warmup
137 143523 : CalcExternalInterfaceFMUImport(state);
138 143523 : }
139 1946046 : }
140 :
141 795 : void GetExternalInterfaceInput(EnergyPlusData &state)
142 : {
143 :
144 : // SUBROUTINE INFORMATION:
145 : // AUTHOR Michael Wetter
146 : // DATE WRITTEN 2Dec2007
147 :
148 : // PURPOSE OF THIS SUBROUTINE:
149 : // Obtains input data for ExternalInterface
150 :
151 : // METHODOLOGY EMPLOYED:
152 : // Uses InputProcessor "Get" routines to obtain data.
153 :
154 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
155 : int NumAlphas; // Number of Alphas for each GetObjectItem call
156 : int NumNumbers; // Number of Numbers for each GetObjectItem call
157 : int IOStatus; // Used in GetObjectItem
158 795 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
159 795 : cCurrentModuleObject = "ExternalInterface";
160 795 : state.dataExternalInterface->NumExternalInterfaces = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
161 :
162 798 : for (int Loop = 1; Loop <= state.dataExternalInterface->NumExternalInterfaces;
163 : ++Loop) { // This loop determines whether the external interface is for FMU or BCVTB
164 9 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
165 : cCurrentModuleObject,
166 : Loop,
167 3 : state.dataIPShortCut->cAlphaArgs,
168 : NumAlphas,
169 3 : state.dataIPShortCut->rNumericArgs,
170 : NumNumbers,
171 : IOStatus,
172 : _,
173 : _,
174 3 : state.dataIPShortCut->cAlphaFieldNames,
175 3 : state.dataIPShortCut->cNumericFieldNames);
176 3 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "PtolemyServer")) { // The BCVTB interface is activated.
177 0 : ++state.dataExternalInterface->NumExternalInterfacesBCVTB;
178 3 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1),
179 : "FunctionalMockupUnitImport")) { // The functional mock up unit import interface is activated.
180 3 : ++state.dataExternalInterface->NumExternalInterfacesFMUImport;
181 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1),
182 : "FunctionalMockupUnitExport")) { // The functional mock up unit export interface is activated.
183 0 : ++state.dataExternalInterface->NumExternalInterfacesFMUExport;
184 : }
185 : }
186 :
187 : // Check if objects are used although BCVTB interface object is not defined
188 795 : if (state.dataExternalInterface->NumExternalInterfacesBCVTB == 0) {
189 795 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:Schedule");
190 795 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:Variable");
191 795 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:Actuator");
192 : }
193 :
194 : // Check if objects are used although FMUExport interface is not defined
195 795 : if (state.dataExternalInterface->NumExternalInterfacesFMUExport == 0) {
196 795 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitExport:To:Schedule");
197 795 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitExport:To:Variable");
198 795 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitExport:To:Actuator");
199 : }
200 :
201 : // Check if objects are used although FMU Import interface is not defined
202 795 : if (state.dataExternalInterface->NumExternalInterfacesFMUImport == 0) {
203 792 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitImport:To:Schedule");
204 792 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitImport:To:Variable");
205 792 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitImport:To:Actuator");
206 : }
207 :
208 795 : if ((state.dataExternalInterface->NumExternalInterfacesBCVTB == 1) && (state.dataExternalInterface->NumExternalInterfacesFMUExport == 0)) {
209 0 : state.dataExternalInterface->haveExternalInterfaceBCVTB = true;
210 0 : DisplayString(state, "Instantiating Building Controls Virtual Test Bed");
211 0 : state.dataExternalInterface->varKeys.allocate(maxVar); // Keys of report variables used for data exchange
212 0 : state.dataExternalInterface->varNames.allocate(maxVar); // Names of report variables used for data exchange
213 0 : state.dataExternalInterface->inpVarTypes.dimension(maxVar, 0); // Names of report variables used for data exchange
214 0 : state.dataExternalInterface->inpVarNames.allocate(maxVar); // Names of report variables used for data exchange
215 0 : VerifyExternalInterfaceObject(state);
216 795 : } else if ((state.dataExternalInterface->NumExternalInterfacesBCVTB == 0) && (state.dataExternalInterface->NumExternalInterfacesFMUExport == 1)) {
217 0 : state.dataExternalInterface->haveExternalInterfaceFMUExport = true;
218 0 : state.dataExternalInterface->FMUExportActivate = 1;
219 0 : DisplayString(state, "Instantiating FunctionalMockupUnitExport interface");
220 0 : state.dataExternalInterface->varKeys.allocate(maxVar); // Keys of report variables used for data exchange
221 0 : state.dataExternalInterface->varNames.allocate(maxVar); // Names of report variables used for data exchange
222 0 : state.dataExternalInterface->inpVarTypes.dimension(maxVar, 0); // Names of report variables used for data exchange
223 0 : state.dataExternalInterface->inpVarNames.allocate(maxVar); // Names of report variables used for data exchange
224 0 : VerifyExternalInterfaceObject(state);
225 795 : } else if ((state.dataExternalInterface->NumExternalInterfacesBCVTB == 1) && (state.dataExternalInterface->NumExternalInterfacesFMUExport != 0)) {
226 0 : ShowSevereError(state, "GetExternalInterfaceInput: Cannot have Ptolemy and FMU-Export interface simultaneously.");
227 0 : state.dataExternalInterface->ErrorsFound = true;
228 : }
229 :
230 795 : if ((state.dataExternalInterface->NumExternalInterfacesFMUImport == 1) && (state.dataExternalInterface->NumExternalInterfacesFMUExport == 0)) {
231 3 : state.dataExternalInterface->haveExternalInterfaceFMUImport = true;
232 3 : DisplayString(state, "Instantiating FunctionalMockupUnitImport interface");
233 3 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport";
234 3 : state.dataExternalInterface->NumFMUObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
235 3 : VerifyExternalInterfaceObject(state);
236 792 : } else if ((state.dataExternalInterface->NumExternalInterfacesFMUImport == 1) &&
237 0 : (state.dataExternalInterface->NumExternalInterfacesFMUExport != 0)) {
238 0 : ShowSevereError(state, "GetExternalInterfaceInput: Cannot have FMU-Import and FMU-Export interface simultaneously.");
239 0 : state.dataExternalInterface->ErrorsFound = true;
240 : }
241 :
242 795 : if (state.dataExternalInterface->NumExternalInterfacesBCVTB > 1) {
243 0 : ShowSevereError(state, "GetExternalInterfaceInput: Cannot have more than one Ptolemy interface.");
244 0 : ShowContinueError(state, "GetExternalInterfaceInput: Errors found in input.");
245 0 : state.dataExternalInterface->ErrorsFound = true;
246 : }
247 :
248 795 : if (state.dataExternalInterface->NumExternalInterfacesFMUExport > 1) {
249 0 : ShowSevereError(state, "GetExternalInterfaceInput: Cannot have more than one FMU-Export interface.");
250 0 : ShowContinueError(state, "Errors found in input.");
251 0 : state.dataExternalInterface->ErrorsFound = true;
252 : }
253 :
254 795 : if (state.dataExternalInterface->NumExternalInterfacesFMUImport > 1) {
255 0 : ShowSevereError(state, "GetExternalInterfaceInput: Cannot have more than one FMU-Import interface.");
256 0 : ShowContinueError(state, "Errors found in input.");
257 0 : state.dataExternalInterface->ErrorsFound = true;
258 : }
259 :
260 795 : if (state.dataExternalInterface->ErrorsFound) {
261 0 : ShowFatalError(state, "GetExternalInterfaceInput: preceding conditions cause termination.");
262 : }
263 :
264 795 : StopExternalInterfaceIfError(state);
265 795 : }
266 :
267 824 : void StopExternalInterfaceIfError(EnergyPlusData &state)
268 : {
269 : // SUBROUTINE INFORMATION:
270 : // AUTHOR Michael Wetter
271 : // DATE WRITTEN 9Jan2008
272 :
273 : // PURPOSE OF THIS SUBROUTINE:
274 : // This subroutine gracefully stops the ExternalInterface if an error has been found.
275 : // It sends an appropriate message to the ExternalInterface
276 : // and then calls a fatal error to stop EnergyPlus.
277 :
278 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
279 824 : int constexpr flag1(-10);
280 824 : int constexpr flag2(-20);
281 :
282 824 : if ((state.dataExternalInterface->NumExternalInterfacesBCVTB != 0) || (state.dataExternalInterface->NumExternalInterfacesFMUExport != 0)) {
283 0 : if (state.dataExternalInterface->ErrorsFound) {
284 : // Check if the socket is open
285 0 : if (state.dataExternalInterface->socketFD >= 0) {
286 : int retVal; // Return value, needed to catch return value of function call
287 : // Socket is open
288 0 : if (state.dataExternalInterface->simulationStatus == 1) {
289 0 : retVal = sendclientmessage(&state.dataExternalInterface->socketFD, &flag1);
290 : } else {
291 0 : retVal = sendclientmessage(&state.dataExternalInterface->socketFD, &flag2);
292 : }
293 0 : if (retVal == 0) {
294 0 : ShowSevereError(state, "External Interface not found.");
295 : }
296 : }
297 0 : ShowFatalError(state, "Error in ExternalInterface: Check EnergyPlus *.err file.");
298 : }
299 : }
300 824 : if (state.dataExternalInterface->NumExternalInterfacesFMUImport != 0) {
301 32 : if (state.dataExternalInterface->ErrorsFound) {
302 0 : ShowFatalError(state, "ExternalInterface/StopExternalInterfaceIfError: Error in ExternalInterface: Check EnergyPlus *.err file.");
303 : }
304 : }
305 824 : }
306 :
307 0 : void CloseSocket(EnergyPlusData &state, int const FlagToWriteToSocket)
308 : {
309 : // SUBROUTINE INFORMATION:
310 : // AUTHOR Michael Wetter
311 : // DATE WRITTEN December 2008
312 :
313 : // PURPOSE OF THIS SUBROUTINE:
314 : // This subroutine tries to write the optional error code to the
315 : // socket and then closes the socket
316 :
317 : // SUBROUTINE ARGUMENT DEFINITIONS:
318 : // +1: E+ reached final time
319 : // -1: E+ had some error
320 :
321 : // Try to establish socket connection. This is needed if Ptolemy started E+,
322 : // but E+ had an error before the call to InitExternalInterface.
323 :
324 0 : bool fileExist = FileSystem::fileExists(state.dataExternalInterface->socCfgFilPath);
325 :
326 0 : if ((state.dataExternalInterface->socketFD == -1) && fileExist) {
327 0 : state.dataExternalInterface->socketFD = establishclientsocket(FileSystem::toString(state.dataExternalInterface->socCfgFilPath).c_str());
328 : }
329 :
330 0 : if (state.dataExternalInterface->socketFD >= 0) {
331 : // TODO: use return value from this function?
332 0 : sendclientmessage(&state.dataExternalInterface->socketFD, &FlagToWriteToSocket);
333 : // Don't close socket as this may give sometimes an IOException in Windows
334 : // This problem seems to affect only Windows but not Mac
335 : // close(state.dataExternalInterface->socketFD)
336 : }
337 0 : }
338 :
339 0 : void ParseString(std::string const &str, // The string, with all elements separated by ';'
340 : Array1D_string &ele, // The elements
341 : int const nEle // The number of elements
342 : )
343 : {
344 : // SUBROUTINE INFORMATION:
345 : // AUTHOR Michael Wetter
346 : // DATE WRITTEN 8Jan2008
347 :
348 : // PURPOSE OF THIS SUBROUTINE:
349 : // This subroutine parses the semicolon separated string xmlStr
350 : // and assigns each element to ele
351 :
352 : // SUBROUTINE VARIABLE DEFINITIONS:
353 : std::string::size_type iSta; // Start of substring
354 : std::string::size_type iCol; // Index of ;
355 :
356 0 : std::string::size_type lenStr = len(str);
357 0 : std::string::size_type iEnd = 0;
358 0 : for (int i = 1; i <= nEle; ++i) {
359 0 : iSta = iEnd; // add one to skip ';'
360 0 : iCol = str.find(';', iSta);
361 0 : if (iCol != std::string::npos) {
362 0 : iEnd = iCol + 1;
363 : } else { // Use rest of string
364 0 : iEnd = lenStr;
365 : }
366 0 : ele(i) = Util::makeUPPER(str.substr(iSta, iEnd - iSta - 1));
367 : }
368 0 : }
369 :
370 0 : void InitExternalInterface(EnergyPlusData &state)
371 : {
372 : // SUBROUTINE INFORMATION:
373 : // AUTHOR Michael Wetter
374 : // DATE WRITTEN 2Dec2007
375 : // MODIFIED Rui Zhang Aug 2009
376 :
377 : // PURPOSE OF THIS SUBROUTINE:
378 : // This subroutine is for initializations of the ExternalInterface
379 :
380 : // SUBROUTINE PARAMETER DEFINITIONS:
381 :
382 0 : std::string const simCfgFilNam("variables.cfg"); // Configuration file
383 0 : std::string const xmlStrInKey("schedule,variable,actuator\0"); // xml values in string, separated by ','
384 :
385 0 : if (state.dataExternalInterface->InitExternalInterfacefirstCall) {
386 0 : DisplayString(state, "ExternalInterface initializes.");
387 : // do one time initializations
388 :
389 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB) {
390 : // Check version number
391 0 : int mainVersion = getmainversionnumber();
392 0 : if (mainVersion < 0) {
393 0 : ShowSevereError(state, "ExternalInterface: BCVTB is not installed in this version.");
394 0 : state.dataExternalInterface->ErrorsFound = true;
395 0 : StopExternalInterfaceIfError(state);
396 : }
397 : }
398 :
399 : // Get port number
400 0 : if (FileSystem::fileExists(state.dataExternalInterface->socCfgFilPath)) {
401 0 : state.dataExternalInterface->socketFD = establishclientsocket(FileSystem::toString(state.dataExternalInterface->socCfgFilPath).c_str());
402 0 : if (state.dataExternalInterface->socketFD < 0) {
403 0 : ShowSevereError(state,
404 0 : format("ExternalInterface: Could not open socket. File descriptor = {}.", state.dataExternalInterface->socketFD));
405 0 : state.dataExternalInterface->ErrorsFound = true;
406 : }
407 : } else {
408 0 : ShowSevereError(state, format("ExternalInterface: Did not find file \"{}\".", state.dataExternalInterface->socCfgFilPath));
409 0 : ShowContinueError(state, "This file needs to be in same directory as in.idf.");
410 0 : ShowContinueError(state, "Check the documentation for the ExternalInterface.");
411 0 : state.dataExternalInterface->ErrorsFound = true;
412 : }
413 :
414 : // Make sure that idf file specified a run period other than
415 : // design day and system sizing.
416 0 : ValidateRunControl(state);
417 :
418 0 : StopExternalInterfaceIfError(state);
419 :
420 : // make a single length here for all strings to be passed to getepvariables
421 0 : size_t lenXmlStr(maxVar * Constant::MaxNameLength); // Length of strings being passed to getepvariables
422 :
423 : // initialize all the strings to this length with blanks
424 0 : std::string xmlStrOut = std::string(lenXmlStr, ' ');
425 0 : std::string xmlStrOutTyp = std::string(lenXmlStr, ' ');
426 0 : std::string xmlStrIn = std::string(lenXmlStr, ' ');
427 :
428 : // Get input and output variables for EnergyPlus in sequence
429 : // Check if simCfgFilNam exists.
430 0 : if (FileSystem::fileExists(simCfgFilNam)) {
431 : int retVal; // Return value of function call, used for error handling
432 :
433 : // preprocess the strings into char vectors before making the library call
434 0 : std::vector<char> xmlStrOutTypArr(getCharArrayFromString(xmlStrOutTyp));
435 0 : std::vector<char> xmlStrOutArr(getCharArrayFromString(xmlStrOut));
436 0 : std::vector<char> xmlStrInArr(getCharArrayFromString(xmlStrIn));
437 :
438 : // now make the library call
439 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB) {
440 0 : retVal = getepvariables(simCfgFilNam.c_str(),
441 0 : &xmlStrOutTypArr[0],
442 0 : &xmlStrOutArr[0],
443 0 : &state.dataExternalInterface->nOutVal,
444 : xmlStrInKey.c_str(),
445 0 : &state.dataExternalInterface->nInKeys,
446 0 : &xmlStrInArr[0],
447 0 : &state.dataExternalInterface->nInpVar,
448 0 : state.dataExternalInterface->inpVarTypes.data(),
449 : &lenXmlStr);
450 0 : } else if (state.dataExternalInterface->haveExternalInterfaceFMUExport) {
451 0 : retVal = getepvariablesFMU(simCfgFilNam.c_str(),
452 0 : &xmlStrOutTypArr[0],
453 0 : &xmlStrOutArr[0],
454 0 : &state.dataExternalInterface->nOutVal,
455 : xmlStrInKey.c_str(),
456 0 : &state.dataExternalInterface->nInKeys,
457 0 : &xmlStrInArr[0],
458 0 : &state.dataExternalInterface->nInpVar,
459 0 : state.dataExternalInterface->inpVarTypes.data(),
460 : &lenXmlStr);
461 : } else {
462 : // there should be no else condition at this point, however we'll still assign the error value for completeness
463 0 : retVal = -1;
464 : }
465 :
466 : // then postprocess the char vectors in case they are used after the fact
467 0 : xmlStrOutTyp = getStringFromCharArray(xmlStrOutTypArr);
468 0 : xmlStrOut = getStringFromCharArray(xmlStrOutArr);
469 0 : xmlStrIn = getStringFromCharArray(xmlStrInArr);
470 :
471 0 : xmlStrOutTypArr.clear();
472 0 : xmlStrOutArr.clear();
473 0 : xmlStrInArr.clear();
474 :
475 : // handle errors when reading variables.cfg file
476 0 : if (retVal < 0) {
477 0 : ShowSevereError(state, "ExternalInterface: Error when getting input and output variables for EnergyPlus,");
478 0 : ShowContinueError(state, "check simulation.log for error message.");
479 0 : state.dataExternalInterface->ErrorsFound = true;
480 : }
481 :
482 0 : } else {
483 :
484 0 : ShowSevereError(state, format("ExternalInterface: Did not find file \"{}\".", simCfgFilNam));
485 0 : ShowContinueError(state, "This file needs to be in same directory as in.idf.");
486 0 : ShowContinueError(state, "Check the documentation for the ExternalInterface.");
487 0 : state.dataExternalInterface->ErrorsFound = true;
488 : }
489 0 : StopExternalInterfaceIfError(state);
490 :
491 0 : if (state.dataExternalInterface->nOutVal + state.dataExternalInterface->nInpVar > maxVar) {
492 0 : ShowSevereError(state, "ExternalInterface: Too many variables to be exchanged.");
493 0 : ShowContinueError(state, format("Attempted to exchange {} outputs", state.dataExternalInterface->nOutVal));
494 0 : ShowContinueError(state, format("plus {} inputs.", state.dataExternalInterface->nOutVal));
495 0 : ShowContinueError(state, format("Maximum allowed is sum is {}.", maxVar));
496 0 : ShowContinueError(state, "To fix, increase maxVar in ExternalInterface.cc");
497 0 : state.dataExternalInterface->ErrorsFound = true;
498 : }
499 0 : StopExternalInterfaceIfError(state);
500 :
501 0 : if (state.dataExternalInterface->nOutVal < 0) {
502 0 : ShowSevereError(state, "ExternalInterface: Error when getting number of xml values for outputs.");
503 0 : state.dataExternalInterface->ErrorsFound = true;
504 : } else {
505 0 : ParseString(xmlStrOut, state.dataExternalInterface->varNames, state.dataExternalInterface->nOutVal);
506 0 : ParseString(xmlStrOutTyp, state.dataExternalInterface->varKeys, state.dataExternalInterface->nOutVal);
507 : }
508 0 : StopExternalInterfaceIfError(state);
509 :
510 0 : if (state.dataExternalInterface->nInpVar < 0) {
511 0 : ShowSevereError(state, "ExternalInterface: Error when getting number of xml values for inputs.");
512 0 : state.dataExternalInterface->ErrorsFound = true;
513 : } else {
514 0 : ParseString(xmlStrIn, state.dataExternalInterface->inpVarNames, state.dataExternalInterface->nInpVar);
515 : }
516 0 : StopExternalInterfaceIfError(state);
517 :
518 0 : DisplayString(state, format("Number of outputs in ExternalInterface = {}", state.dataExternalInterface->nOutVal));
519 0 : DisplayString(state, format("Number of inputs in ExternalInterface = {}", state.dataExternalInterface->nInpVar));
520 :
521 0 : state.dataExternalInterface->InitExternalInterfacefirstCall = false;
522 :
523 0 : } else if (!state.dataExternalInterface->configuredControlPoints) {
524 0 : state.dataExternalInterface->keyVarIndexes.allocate(state.dataExternalInterface->nOutVal);
525 0 : state.dataExternalInterface->varTypes.allocate(state.dataExternalInterface->nOutVal);
526 0 : GetReportVariableKey(state,
527 0 : state.dataExternalInterface->varKeys,
528 0 : state.dataExternalInterface->nOutVal,
529 0 : state.dataExternalInterface->varNames,
530 0 : state.dataExternalInterface->keyVarIndexes,
531 0 : state.dataExternalInterface->varTypes);
532 0 : state.dataExternalInterface->varInd.allocate(state.dataExternalInterface->nInpVar);
533 0 : for (int i = 1; i <= state.dataExternalInterface->nInpVar; ++i) {
534 0 : if (state.dataExternalInterface->inpVarTypes(i) == indexSchedule) {
535 0 : state.dataExternalInterface->varInd(i) = ScheduleManager::GetDayScheduleIndex(state, state.dataExternalInterface->inpVarNames(i));
536 0 : } else if (state.dataExternalInterface->inpVarTypes(i) == indexVariable) {
537 0 : state.dataExternalInterface->varInd(i) =
538 0 : RuntimeLanguageProcessor::FindEMSVariable(state, state.dataExternalInterface->inpVarNames(i), 0);
539 0 : } else if (state.dataExternalInterface->inpVarTypes(i) == indexActuator) {
540 0 : state.dataExternalInterface->varInd(i) =
541 0 : RuntimeLanguageProcessor::FindEMSVariable(state, state.dataExternalInterface->inpVarNames(i), 0);
542 : }
543 0 : if (state.dataExternalInterface->varInd(i) <= 0) {
544 0 : ShowSevereError(state,
545 0 : format("ExternalInterface: Error, xml file \"{}\" declares variable \"{}\",",
546 : simCfgFilNam,
547 0 : state.dataExternalInterface->inpVarNames(i)));
548 0 : ShowContinueError(state, "but variable was not found in idf file.");
549 0 : state.dataExternalInterface->ErrorsFound = true;
550 : }
551 : }
552 0 : StopExternalInterfaceIfError(state);
553 : // Configure Erl variables
554 0 : for (int i = 1; i <= state.dataExternalInterface->nInpVar; ++i) {
555 0 : if (state.dataExternalInterface->inpVarTypes(i) == indexVariable) { // ems-globalvariable
556 0 : state.dataExternalInterface->useEMS = true;
557 0 : if (!RuntimeLanguageProcessor::isExternalInterfaceErlVariable(state, state.dataExternalInterface->varInd(i))) {
558 0 : ShowSevereError(state,
559 0 : format("ExternalInterface: Error, xml file \"{}\" declares variable \"{}\",",
560 : simCfgFilNam,
561 0 : state.dataExternalInterface->inpVarNames(i)));
562 0 : ShowContinueError(state, "But this variable is an ordinary Erl variable, not an ExternalInterface variable.");
563 0 : ShowContinueError(state, "You must specify a variable of type \"ExternalInterface:Variable\".");
564 0 : state.dataExternalInterface->ErrorsFound = true;
565 : }
566 0 : } else if (state.dataExternalInterface->inpVarTypes(i) == indexActuator) { // ems-actuator
567 0 : state.dataExternalInterface->useEMS = true;
568 0 : if (!RuntimeLanguageProcessor::isExternalInterfaceErlVariable(state, state.dataExternalInterface->varInd(i))) {
569 0 : ShowSevereError(state,
570 0 : format("ExternalInterface: Error, xml file \"{}\" declares variable \"{}\",",
571 : simCfgFilNam,
572 0 : state.dataExternalInterface->inpVarNames(i)));
573 0 : ShowContinueError(state, "But this variable is an ordinary Erl actuator, not an ExternalInterface actuator.");
574 0 : ShowContinueError(state, "You must specify a variable of type \"ExternalInterface:Actuator\".");
575 0 : state.dataExternalInterface->ErrorsFound = true;
576 : }
577 : }
578 : }
579 0 : state.dataExternalInterface->configuredControlPoints = true;
580 : }
581 0 : StopExternalInterfaceIfError(state);
582 0 : }
583 :
584 143520 : void GetSetVariablesAndDoStepFMUImport(EnergyPlusData &state)
585 : {
586 : // SUBROUTINE INFORMATION:
587 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
588 : // DATE WRITTEN 08Aug2011
589 :
590 : // PURPOSE OF THIS SUBROUTINE:
591 : // This routine gets, sets and does the time integration in FMUs.
592 :
593 287040 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
594 287040 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
595 143520 : if (state.dataExternalInterface->FlagReIni) {
596 : // Get from FMUs, values that will be set in EnergyPlus (Schedule)
597 63 : for (int k = 1; k <= state.dataExternalInterface->FMUTemp(i).Instance(j).NumOutputVariablesSchedule; ++k) {
598 34 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).RealVarValue =
599 34 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableSchedule(k).RealVarValue;
600 : }
601 :
602 : // Get from FMUs, values that will be set in EnergyPlus (Variable)
603 35 : for (int k = 1; k <= state.dataExternalInterface->FMUTemp(i).Instance(j).NumOutputVariablesVariable; ++k) {
604 6 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).RealVarValue =
605 6 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableVariable(k).RealVarValue;
606 : }
607 :
608 : // Get from FMUs, values that will be set in EnergyPlus (Actuator)
609 35 : for (int k = 1; k <= state.dataExternalInterface->FMUTemp(i).Instance(j).NumOutputVariablesActuator; ++k) {
610 6 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).RealVarValue =
611 6 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableActuator(k).RealVarValue;
612 : }
613 : } else {
614 : // Get from FMUs, values that will be set in EnergyPlus (Schedule)
615 :
616 143491 : if (size(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule) > 0) {
617 :
618 : // generate vectors here first
619 36655 : std::vector<unsigned int> valueReferenceVec;
620 36655 : std::vector<Real64> realVarValueVec;
621 109965 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule); ++x) {
622 73310 : valueReferenceVec.push_back(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(x).ValueReference);
623 73310 : realVarValueVec.push_back(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(x).RealVarValue);
624 : }
625 :
626 : // pass in the vectors as pointers to the first member of the vector
627 36655 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus =
628 36655 : fmiEPlusGetReal(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
629 36655 : &valueReferenceVec[0],
630 36655 : &realVarValueVec[0],
631 36655 : &state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesSchedule,
632 36655 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
633 :
634 109965 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule); ++x) {
635 73310 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(x).ValueReference = valueReferenceVec[x - 1];
636 73310 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(x).RealVarValue = realVarValueVec[x - 1];
637 : }
638 :
639 36655 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiOK) {
640 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to get outputs");
641 0 : ShowContinueError(state,
642 0 : format("in instance \"{}\" of FMU \"{}\"",
643 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
644 0 : state.dataExternalInterface->FMU(i).Name));
645 0 : ShowContinueError(state, format("Error Code = \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).fmistatus));
646 0 : state.dataExternalInterface->ErrorsFound = true;
647 0 : StopExternalInterfaceIfError(state);
648 : }
649 36655 : }
650 :
651 : // generate vectors here first
652 143491 : if (size(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable) > 0) {
653 :
654 53418 : std::vector<unsigned int> valueReferenceVec2;
655 53418 : std::vector<Real64> realVarValueVec2;
656 106836 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable); ++x) {
657 53418 : valueReferenceVec2.push_back(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(x).ValueReference);
658 53418 : realVarValueVec2.push_back(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(x).RealVarValue);
659 : }
660 :
661 : // pass in the vectors as pointers to the first member of the vector
662 53418 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus =
663 53418 : fmiEPlusGetReal(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
664 53418 : &valueReferenceVec2[0],
665 53418 : &realVarValueVec2[0],
666 53418 : &state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesVariable,
667 53418 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
668 :
669 106836 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable); ++x) {
670 53418 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(x).ValueReference = valueReferenceVec2[x - 1];
671 53418 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(x).RealVarValue = realVarValueVec2[x - 1];
672 : }
673 :
674 53418 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiOK) {
675 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to get outputs");
676 0 : ShowContinueError(state,
677 0 : format("in instance \"{}\" of FMU \"{}\"",
678 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
679 0 : state.dataExternalInterface->FMU(i).Name));
680 0 : ShowContinueError(state, format("Error Code = \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).fmistatus));
681 0 : state.dataExternalInterface->ErrorsFound = true;
682 0 : StopExternalInterfaceIfError(state);
683 : }
684 53418 : }
685 :
686 143491 : if (size(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator) > 0) {
687 :
688 : // generate vectors here first
689 53418 : std::vector<unsigned int> valueReferenceVec3;
690 53418 : std::vector<Real64> realVarValueVec3;
691 106836 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator); ++x) {
692 53418 : valueReferenceVec3.push_back(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(x).ValueReference);
693 53418 : realVarValueVec3.push_back(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(x).RealVarValue);
694 : }
695 :
696 : // pass in the vectors as pointers to the first member of the vector
697 53418 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus =
698 53418 : fmiEPlusGetReal(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
699 53418 : &valueReferenceVec3[0],
700 53418 : &realVarValueVec3[0],
701 53418 : &state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesActuator,
702 53418 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
703 :
704 106836 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator); ++x) {
705 53418 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(x).ValueReference = valueReferenceVec3[x - 1];
706 53418 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(x).RealVarValue = realVarValueVec3[x - 1];
707 : }
708 :
709 53418 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiOK) {
710 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to get outputs");
711 0 : ShowContinueError(state,
712 0 : format("in instance \"{}\" of FMU \"{}\"",
713 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
714 0 : state.dataExternalInterface->FMU(i).Name));
715 0 : ShowContinueError(state, format("Error Code = \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).fmistatus));
716 0 : state.dataExternalInterface->ErrorsFound = true;
717 0 : StopExternalInterfaceIfError(state);
718 : }
719 53418 : }
720 : }
721 :
722 : // Set in EnergyPlus the values of the schedules
723 216864 : for (int k = 1; k <= state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesSchedule; ++k) {
724 73344 : ScheduleManager::ExternalInterfaceSetSchedule(
725 : state,
726 73344 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableSchedule(k).VarIndex,
727 73344 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).RealVarValue);
728 : }
729 :
730 : // Set in EnergyPlus the values of the variables
731 196944 : for (int k = 1; k <= state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesVariable; ++k) {
732 106848 : RuntimeLanguageProcessor::ExternalInterfaceSetErlVariable(
733 : state,
734 53424 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableVariable(k).VarIndex,
735 53424 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).RealVarValue);
736 : }
737 :
738 : // Set in EnergyPlus the values of the actuators
739 196944 : for (int k = 1; k <= state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesActuator; ++k) {
740 106848 : RuntimeLanguageProcessor::ExternalInterfaceSetErlVariable(
741 : state,
742 53424 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableActuator(k).VarIndex,
743 53424 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).RealVarValue);
744 : }
745 :
746 143520 : if (state.dataExternalInterface->FirstCallGetSetDoStep) {
747 : // Get from EnergyPlus, values that will be set in fmus
748 11 : for (int k = 1; k <= state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF; ++k) {
749 : // This make sure that the variables are updated at the Zone Time Step
750 8 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).RTSValue =
751 8 : GetInternalVariableValue(state,
752 8 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarType,
753 8 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarIndex);
754 : }
755 : } else {
756 : // Get from EnergyPlus, values that will be set in fmus
757 503893 : for (int k = 1; k <= state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF; ++k) {
758 : // This make sure that the variables are updated at the Zone Time Step
759 360376 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).RTSValue =
760 360376 : GetInternalVariableValueExternalInterface(state,
761 360376 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarType,
762 360376 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarIndex);
763 : }
764 : }
765 :
766 143520 : if (!state.dataExternalInterface->FlagReIni) {
767 :
768 : // generate vectors here first
769 143491 : std::vector<unsigned int> valueReferenceVec4;
770 503783 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable); ++x) {
771 360292 : valueReferenceVec4.push_back(state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(x).ValueReference);
772 : }
773 :
774 143491 : std::vector<Real64> rtsValueVec4;
775 503783 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable); ++x) {
776 360292 : rtsValueVec4.push_back(state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(x).RTSValue);
777 : }
778 :
779 143491 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus =
780 143491 : fmiEPlusSetReal(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
781 143491 : &valueReferenceVec4[0],
782 143491 : &rtsValueVec4[0],
783 143491 : &state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF,
784 143491 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
785 :
786 143491 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiOK) {
787 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to set inputs");
788 0 : ShowContinueError(state,
789 0 : format("in instance \"{}\" of FMU \"{}\"",
790 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
791 0 : state.dataExternalInterface->FMU(i).Name));
792 0 : ShowContinueError(state, format("Error Code = \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).fmistatus));
793 0 : state.dataExternalInterface->ErrorsFound = true;
794 0 : StopExternalInterfaceIfError(state);
795 : }
796 143491 : }
797 143520 : int localfmitrue(fmiTrue);
798 : // Call and simulate the FMUs to get values at the corresponding timestep.
799 143520 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus = fmiEPlusDoStep(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
800 143520 : &state.dataExternalInterface->tComm,
801 143520 : &state.dataExternalInterface->hStep,
802 : &localfmitrue,
803 143520 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
804 143520 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiOK) {
805 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to");
806 0 : ShowContinueError(state, format("do the coSimulation with instance \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).Name));
807 0 : ShowContinueError(state, format("of FMU \"{}\"", state.dataExternalInterface->FMU(i).Name));
808 0 : ShowContinueError(state, format("Error Code = \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).fmistatus));
809 0 : state.dataExternalInterface->ErrorsFound = true;
810 0 : StopExternalInterfaceIfError(state);
811 : }
812 : }
813 : }
814 :
815 : // If we have Erl variables, we need to call ManageEMS so that they get updated in the Erl data structure
816 143520 : if (state.dataExternalInterface->useEMS) {
817 : bool anyRan;
818 106848 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::ExternalInterface, anyRan, ObjexxFCL::Optional_int_const());
819 : }
820 :
821 143520 : state.dataExternalInterface->FirstCallGetSetDoStep = false;
822 143520 : }
823 :
824 32 : void InstantiateInitializeFMUImport(EnergyPlusData &state)
825 : {
826 : // SUBROUTINE INFORMATION:
827 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
828 : // DATE WRITTEN 08Aug2011
829 :
830 : // PURPOSE OF THIS SUBROUTINE:
831 : // This routine instantiates and initializes FMUs.
832 :
833 : // Instantiate FMUs
834 64 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
835 64 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
836 32 : std::string const folderStr = FileSystem::toString(state.dataExternalInterface->FMU(i).Instance(j).WorkingFolder);
837 32 : state.dataExternalInterface->FMU(i).Instance(j).fmicomponent =
838 32 : fmiEPlusInstantiateSlave((char *)folderStr.c_str(),
839 32 : &state.dataExternalInterface->FMU(i).Instance(j).LenWorkingFolder,
840 32 : &state.dataExternalInterface->FMU(i).TimeOut,
841 32 : &state.dataExternalInterface->FMU(i).Visible,
842 32 : &state.dataExternalInterface->FMU(i).Interactive,
843 32 : &state.dataExternalInterface->FMU(i).LoggingOn,
844 32 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
845 : // TODO: This is doing a null pointer check; OK?
846 32 : if (!state.dataExternalInterface->FMU(i).Instance(j).fmicomponent) {
847 0 : ShowSevereError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: Error when trying to instantiate");
848 0 : ShowContinueError(state,
849 0 : format("instance \"{}\" of FMU \"{}\"",
850 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
851 0 : state.dataExternalInterface->FMU(i).Name));
852 0 : state.dataExternalInterface->ErrorsFound = true;
853 0 : StopExternalInterfaceIfError(state);
854 : }
855 32 : }
856 : }
857 :
858 : // Initialize FMUs
859 32 : int localfmiTrue(fmiTrue);
860 64 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
861 64 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
862 32 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus =
863 32 : fmiEPlusInitializeSlave(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
864 32 : &state.dataExternalInterface->tStart,
865 : &localfmiTrue,
866 32 : &state.dataExternalInterface->tStop,
867 32 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
868 32 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiOK) {
869 0 : ShowSevereError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: Error when trying to initialize");
870 0 : ShowContinueError(state,
871 0 : format("instance \"{}\" of FMU \"{}\"",
872 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
873 0 : state.dataExternalInterface->FMU(i).Name));
874 0 : ShowContinueError(state, format("Error Code = \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).fmistatus));
875 0 : state.dataExternalInterface->ErrorsFound = true;
876 0 : StopExternalInterfaceIfError(state);
877 : }
878 : }
879 : }
880 32 : }
881 :
882 0 : void InitializeFMU(EnergyPlusData &state)
883 : {
884 : // SUBROUTINE INFORMATION:
885 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
886 : // DATE WRITTEN 08Aug2011
887 :
888 : // PURPOSE OF THIS SUBROUTINE:
889 : // This routine reinitializes FMUs.
890 :
891 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
892 0 : int localfmiTrue(fmiTrue);
893 :
894 : // Initialize FMUs
895 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
896 0 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
897 0 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus =
898 0 : fmiEPlusInitializeSlave(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
899 0 : &state.dataExternalInterface->tStart,
900 : &localfmiTrue,
901 0 : &state.dataExternalInterface->tStop,
902 0 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
903 0 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiOK) {
904 0 : ShowSevereError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: Error when trying to initialize");
905 0 : ShowContinueError(state,
906 0 : format("instance \"{}\" of FMU \"{}\"",
907 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
908 0 : state.dataExternalInterface->FMU(i).Name));
909 0 : ShowContinueError(state, format("Error Code = \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).fmistatus));
910 0 : state.dataExternalInterface->ErrorsFound = true;
911 0 : StopExternalInterfaceIfError(state);
912 : }
913 : }
914 : }
915 0 : }
916 :
917 32 : void TerminateResetFreeFMUImport(EnergyPlusData &state, int fmiEndSimulation)
918 : {
919 : // SUBROUTINE INFORMATION:
920 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
921 : // DATE WRITTEN 08Aug2011
922 :
923 : // PURPOSE OF THIS SUBROUTINE:
924 : // This routine terminates the FMUs instances
925 :
926 : //----Needs to have function that allows to terminates FMU. Was not defined in version 1.0 -- fixme
927 64 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
928 64 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
929 32 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiFatal) {
930 : // Cleanup slaves
931 32 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus =
932 32 : fmiEPlusFreeSlave(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
933 32 : &state.dataExternalInterface->FMU(i).Instance(j).Index,
934 : &fmiEndSimulation);
935 : }
936 : // check if fmiComponent has been freed
937 32 : if (!state.dataExternalInterface->FMU(i).Instance(j).fmicomponent) {
938 0 : ShowSevereError(state, "ExternalInterface/TerminateResetFreeFMUImport: Error when trying to terminate");
939 0 : ShowContinueError(state,
940 0 : format("instance \"{}\" of FMU \"{}\"",
941 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
942 0 : state.dataExternalInterface->FMU(i).Name));
943 0 : state.dataExternalInterface->ErrorsFound = true;
944 0 : StopExternalInterfaceIfError(state);
945 : }
946 : }
947 : }
948 32 : }
949 :
950 143523 : void InitExternalInterfaceFMUImport(EnergyPlusData &state)
951 : {
952 :
953 : // SUBROUTINE INFORMATION:
954 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
955 : // DATE WRITTEN 08Aug2011
956 :
957 : // PURPOSE OF THIS SUBROUTINE:
958 : // This routine initializes the input and outputs variables used for the co-simulation with FMUs.
959 :
960 : // Locals
961 143523 : Array1D_int keyIndexes(1); // Array index for
962 143523 : Array1D<OutputProcessor::VariableType> varTypes(1); // Array index for
963 143523 : Array1D_string NamesOfKeys(1); // Specific key name
964 143523 : Array1D_string NameListInstances(5);
965 143523 : fs::path tempFullFilePath;
966 :
967 143523 : Array1D_string strippedFileName; // remove path from entered file name
968 143523 : Array1D_string fullFileName; // entered file name/found
969 :
970 143523 : if (state.dataExternalInterface->FirstCallIni) {
971 3 : DisplayString(state, "Initializing FunctionalMockupUnitImport interface");
972 : // do one time initializations
973 3 : ValidateRunControl(state);
974 3 : state.dataExternalInterface->FMU.allocate(state.dataExternalInterface->NumFMUObjects);
975 :
976 : // there used to be code in here to apply the root working folder to create an absolute path
977 : // however, this wasn't working, as the root working folder was coming back empty
978 : // in any case, the relative paths work fine here
979 :
980 : // post process as needed in case these are used later
981 3 : state.dataExternalInterface->FMURootWorkingFolder = fs::path("tmp-fmus"); // getStringFromCharArray( FMUWorkingFolderCharArr );
982 :
983 : // Get and store the names of all FMUs in EnergyPlus data structure
984 3 : strippedFileName.allocate(state.dataExternalInterface->NumFMUObjects);
985 3 : fullFileName.allocate(state.dataExternalInterface->NumFMUObjects);
986 :
987 3 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
988 3 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport";
989 3 : int NumAlphas = 0; // Number of Alphas for each GetObjectItem call
990 3 : int NumNumbers = 0; // Number of Numbers for each GetObjectItem call
991 3 : int IOStatus = 0; // Used in GetObjectItem
992 6 : for (int Loop = 1; Loop <= state.dataExternalInterface->NumFMUObjects; ++Loop) {
993 9 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
994 : cCurrentModuleObject,
995 : Loop,
996 3 : state.dataIPShortCut->cAlphaArgs,
997 : NumAlphas,
998 3 : state.dataIPShortCut->rNumericArgs,
999 : NumNumbers,
1000 : IOStatus,
1001 : _,
1002 : _,
1003 3 : state.dataIPShortCut->cAlphaFieldNames,
1004 3 : state.dataIPShortCut->cNumericFieldNames);
1005 : // Get the FMU name
1006 3 : state.dataExternalInterface->FMU(Loop).Name = state.dataIPShortCut->cAlphaArgs(1);
1007 :
1008 3 : fs::path inputPath = FileSystem::makeNativePath(state.dataExternalInterface->FMU(Loop).Name);
1009 :
1010 6 : std::string contextString = cCurrentModuleObject + ", " + state.dataIPShortCut->cAlphaFieldNames(1) + ": ";
1011 :
1012 3 : tempFullFilePath = DataSystemVariables::CheckForActualFilePath(state, inputPath, contextString);
1013 3 : if (!tempFullFilePath.empty()) {
1014 :
1015 : // TODO: eliminate this old block once confident
1016 3 : std::string::size_type pos = index(state.dataExternalInterface->FMU(Loop).Name, DataStringGlobals::pathChar, true); // look backwards
1017 3 : if (pos != std::string::npos) {
1018 0 : strippedFileName(Loop) = state.dataExternalInterface->FMU(Loop).Name.substr(pos + 1);
1019 : } else { // pos == 0, look for alt path char
1020 3 : pos = index(state.dataExternalInterface->FMU(Loop).Name, DataStringGlobals::altpathChar, true); // look backwards
1021 3 : if (pos != std::string::npos) {
1022 3 : strippedFileName(Loop) = state.dataExternalInterface->FMU(Loop).Name.substr(pos + 1);
1023 : } else {
1024 0 : strippedFileName(Loop) = state.dataExternalInterface->FMU(Loop).Name;
1025 : }
1026 : }
1027 3 : fullFileName(Loop) = FileSystem::toString(tempFullFilePath);
1028 : } else {
1029 0 : state.dataExternalInterface->ErrorsFound = true;
1030 : }
1031 : // Get fmu time out
1032 3 : state.dataExternalInterface->FMU(Loop).TimeOut = state.dataIPShortCut->rNumericArgs(1);
1033 : // Get fmu logging on
1034 3 : state.dataExternalInterface->FMU(Loop).LoggingOn = state.dataIPShortCut->rNumericArgs(2);
1035 3 : }
1036 :
1037 : // check for dups that aren't the same file
1038 : // this is windows code...
1039 : // So this check that if I entered two different things and get the same end filename, then it's wrong?
1040 6 : for (int j = 1; j <= state.dataExternalInterface->NumFMUObjects; ++j) {
1041 3 : for (int k = 2; k <= state.dataExternalInterface->NumFMUObjects; ++k) {
1042 0 : if (!Util::SameString(strippedFileName(j), strippedFileName(k))) continue;
1043 : // base file names are the same
1044 0 : if (Util::SameString(fullFileName(j), fullFileName(k))) continue;
1045 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport:");
1046 0 : ShowContinueError(state, "duplicate file names (but not same file) entered.");
1047 0 : ShowContinueError(state, format("...entered file name=\"{}\"", state.dataExternalInterface->FMU(j).Name));
1048 0 : ShowContinueError(state, format("... full file name=\"{}\"", fullFileName(j)));
1049 0 : ShowContinueError(state, format("...entered file name=\"{}\"", state.dataExternalInterface->FMU(k).Name));
1050 0 : ShowContinueError(state, format("... full file name=\"{}\"", fullFileName(k)));
1051 0 : ShowContinueError(state, "...name collision but not same file name.");
1052 0 : state.dataExternalInterface->ErrorsFound = true;
1053 : }
1054 : }
1055 :
1056 3 : if (state.dataExternalInterface->ErrorsFound) {
1057 0 : strippedFileName.deallocate();
1058 0 : fullFileName.deallocate();
1059 0 : StopExternalInterfaceIfError(state);
1060 : }
1061 :
1062 : // get the names of the input variables each state.dataExternalInterface->FMU(and the names of the
1063 : // corresponding output variables in EnergyPlus --).
1064 3 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:From:Variable";
1065 3 : int NumFMUInputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1066 : // Determine the number of instances for each FMUs
1067 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1068 3 : std::string Name_OLD = "";
1069 3 : int j = 1;
1070 3 : int k = 1;
1071 3 : state.dataExternalInterface->FMU(i).Instance.allocate(NumFMUInputVariables);
1072 3 : state.dataExternalInterface->checkInstanceName.allocate(NumFMUInputVariables);
1073 11 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1074 24 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1075 : cCurrentModuleObject,
1076 : l,
1077 8 : state.dataIPShortCut->cAlphaArgs,
1078 : NumAlphas,
1079 8 : state.dataIPShortCut->rNumericArgs,
1080 : NumNumbers,
1081 : IOStatus,
1082 : _,
1083 : _,
1084 8 : state.dataIPShortCut->cAlphaFieldNames,
1085 8 : state.dataIPShortCut->cNumericFieldNames);
1086 8 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), state.dataExternalInterface->FMU(i).Name)) {
1087 8 : std::string Name_NEW = state.dataIPShortCut->cAlphaArgs(4);
1088 8 : if (!Util::SameString(Name_OLD, Name_NEW)) {
1089 3 : int FOUND = Util::FindItem(Name_NEW, state.dataExternalInterface->checkInstanceName);
1090 3 : if (FOUND == 0) {
1091 3 : state.dataExternalInterface->checkInstanceName(l).Name = Name_NEW;
1092 3 : state.dataExternalInterface->FMU(i).NumInstances = j;
1093 3 : state.dataExternalInterface->FMU(i).Instance(j).Name = Name_NEW;
1094 3 : ++j;
1095 3 : Name_OLD = Name_NEW;
1096 : }
1097 : }
1098 8 : state.dataExternalInterface->FMU(i).TotNumInputVariablesInIDF = k;
1099 8 : ++k;
1100 8 : }
1101 : }
1102 3 : state.dataExternalInterface->checkInstanceName.deallocate();
1103 3 : }
1104 :
1105 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1106 3 : if (state.dataExternalInterface->FMU(i).NumInstances == 0) {
1107 0 : ShowSevereError(
1108 0 : state, format("ExternalInterface/InitExternalInterfaceFMUImport: The FMU \"{}\" does", state.dataExternalInterface->FMU(i).Name));
1109 0 : ShowContinueError(state, "not have any instances or any input variable. An FMU should have at least one instance");
1110 0 : ShowContinueError(state, "or one input variable defined in input file. Check FMU object in the input file.");
1111 0 : state.dataExternalInterface->ErrorsFound = true;
1112 0 : StopExternalInterfaceIfError(state);
1113 : }
1114 3 : if (NumFMUInputVariables > 0 && state.dataExternalInterface->FMU(i).TotNumInputVariablesInIDF == 0) {
1115 0 : ShowWarningError(state, format("InitExternalInterfaceFMUImport: The FMU \"{}\"", state.dataExternalInterface->FMU(i).Name));
1116 0 : ShowContinueError(state, "is defined but has no input variables.");
1117 0 : ShowContinueError(state, "Check the input field of the corresponding object");
1118 0 : ShowContinueError(state, "ExternalInterface:FunctionalMockupUnitImport:From:Variable.");
1119 : }
1120 : }
1121 :
1122 : // write output folder where FMUs will be unpacked later on.
1123 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1124 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1125 3 : state.dataExternalInterface->FMU(i).Instance(j).WorkingFolder =
1126 6 : state.dataExternalInterface->FMURootWorkingFolder /
1127 9 : fs::path(strippedFileName(i) + '_' + state.dataExternalInterface->FMU(i).Instance(j).Name);
1128 : }
1129 : }
1130 :
1131 : // parse the fmu defined in the idf using the fmuUnpack.
1132 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1133 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1134 : // get the length of working folder trimmed
1135 3 : std::string const workingFolderStr = FileSystem::toString(state.dataExternalInterface->FMU(i).Instance(j).WorkingFolder);
1136 3 : state.dataExternalInterface->FMU(i).Instance(j).LenWorkingFolder = workingFolderStr.length();
1137 : // unpack fmus
1138 : // preprocess arguments for library call
1139 : {
1140 3 : std::vector<char> fullFileNameArr(getCharArrayFromString(fullFileName(i)));
1141 3 : std::vector<char> workingFolderArr(getCharArrayFromString(workingFolderStr));
1142 3 : int lenFileName(len(fullFileName(i)));
1143 :
1144 : // make the library call
1145 3 : int retVal = fmiEPlusUnpack(
1146 3 : &fullFileNameArr[0], &workingFolderArr[0], &lenFileName, &state.dataExternalInterface->FMU(i).Instance(j).LenWorkingFolder);
1147 :
1148 3 : if (retVal != 0) {
1149 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1150 0 : ShowContinueError(state, format("unpack the FMU \"{}\".", state.dataExternalInterface->FMU(i).Name));
1151 0 : ShowContinueError(state, "Check if the FMU exists. Also check if the FMU folder is not write protected.");
1152 0 : state.dataExternalInterface->ErrorsFound = true;
1153 0 : StopExternalInterfaceIfError(state);
1154 : }
1155 3 : }
1156 :
1157 : {
1158 : // determine modelID and modelGUID of all FMU instances
1159 : // preprocess arguments for library call
1160 3 : std::vector<char> workingFolderArr(getCharArrayFromString(workingFolderStr));
1161 :
1162 : // make the library call
1163 3 : state.dataExternalInterface->FMU(i).Instance(j).Index =
1164 3 : model_ID_GUID((char *)state.dataExternalInterface->FMU(i).Instance(j).Name.c_str(),
1165 3 : &workingFolderArr[0],
1166 3 : &state.dataExternalInterface->FMU(i).Instance(j).LenWorkingFolder,
1167 3 : &state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInFMU,
1168 3 : &state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInFMU);
1169 :
1170 3 : if (state.dataExternalInterface->FMU(i).Instance(j).Index < 0) {
1171 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1172 0 : ShowContinueError(state, "get the model ID and model GUID");
1173 0 : ShowContinueError(state,
1174 0 : format("of instance \"{}\" of FMU \"{}\".",
1175 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1176 0 : state.dataExternalInterface->FMU(i).Name));
1177 0 : ShowContinueError(state, "Check if modelDescription.xml exists in the folder where the FMU has been unpacked.");
1178 0 : state.dataExternalInterface->ErrorsFound = true;
1179 0 : StopExternalInterfaceIfError(state);
1180 : }
1181 3 : }
1182 :
1183 : {
1184 : // get the path to the binaries
1185 : // preprocess args for library call
1186 3 : std::vector<char> workingFolderArr(getCharArrayFromString(workingFolderStr));
1187 : // Reserve some space in the string, becasue addLibPathCurrentWorkflowFolder doesn't allocate memory for the
1188 : // workingFolderWithLibArr Note: you can't call str.resize(str.length() + 91) because the conversion to std::vector<char> will
1189 : // find the null terminator and so it will have no effect
1190 : std::string reservedString =
1191 3 : workingFolderStr + " ";
1192 3 : std::vector<char> workingFolderWithLibArr(getCharArrayFromString(reservedString));
1193 :
1194 : // make the library call
1195 3 : int retValfmiPathLib = addLibPathCurrentWorkingFolder(&workingFolderWithLibArr[0],
1196 3 : &workingFolderArr[0],
1197 3 : &state.dataExternalInterface->FMU(i).Instance(j).LenWorkingFolder,
1198 3 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
1199 :
1200 : // post process args in case they are used later
1201 3 : state.dataExternalInterface->FMU(i).Instance(j).WorkingFolder_wLib =
1202 6 : fs::path(trim(getStringFromCharArray(workingFolderWithLibArr)));
1203 :
1204 3 : if (retValfmiPathLib != 0) {
1205 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1206 0 : ShowContinueError(state, "get the path to the binaries of instance");
1207 0 : ShowContinueError(state,
1208 0 : format("\"{}\" of FMU \"{}\".",
1209 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1210 0 : state.dataExternalInterface->FMU(i).Name));
1211 0 : ShowContinueError(state, "Check if binaries folder exists where the FMU has been unpacked.");
1212 0 : state.dataExternalInterface->ErrorsFound = true;
1213 0 : StopExternalInterfaceIfError(state);
1214 : }
1215 :
1216 : // get the length of the working folder with libraries
1217 3 : state.dataExternalInterface->FMU(i).Instance(j).LenWorkingFolder_wLib =
1218 6 : FileSystem::toString(state.dataExternalInterface->FMU(i).Instance(j).WorkingFolder_wLib).length();
1219 3 : }
1220 :
1221 : {
1222 : // determine the FMI version
1223 : // preprocess args for library call
1224 : std::vector<char> workingFolderWithLibArr(
1225 3 : getCharArrayFromString(FileSystem::toString(state.dataExternalInterface->FMU(i).Instance(j).WorkingFolder_wLib)));
1226 : std::vector<char> VersionNumArr(
1227 6 : getCharArrayFromString(" ")); // the version should only be 3 characters long, since for now we only handle "1.0"
1228 :
1229 : // make the library call
1230 3 : int retValfmiVersion = getfmiEPlusVersion(&workingFolderWithLibArr[0],
1231 3 : &state.dataExternalInterface->FMU(i).Instance(j).LenWorkingFolder_wLib,
1232 3 : &VersionNumArr[0],
1233 3 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
1234 :
1235 : // post process in case args are used later
1236 3 : state.dataExternalInterface->FMU(i).Instance(j).fmiVersionNumber = getStringFromCharArray(VersionNumArr);
1237 :
1238 3 : if (retValfmiVersion != 0) {
1239 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1240 0 : ShowContinueError(state, "load FMI functions library of instance");
1241 0 : ShowContinueError(state,
1242 0 : format("\"{}\" of FMU \"{}\".",
1243 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1244 0 : state.dataExternalInterface->FMU(i).Name));
1245 0 : ShowContinueError(state, format("\"{}\".", state.dataExternalInterface->FMU(i).Instance(j).fmiVersionNumber));
1246 0 : state.dataExternalInterface->ErrorsFound = true;
1247 0 : StopExternalInterfaceIfError(state);
1248 : }
1249 :
1250 3 : if (state.dataExternalInterface->FMU(i).Instance(j).fmiVersionNumber.substr(0, 3) != "1.0") {
1251 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when getting version");
1252 0 : ShowContinueError(state, format("number of instance \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).Name));
1253 0 : ShowContinueError(state, format("of FMU \"{}\".", state.dataExternalInterface->FMU(i).Name));
1254 0 : ShowContinueError(state,
1255 0 : format("The version number found (\"{}\")",
1256 0 : state.dataExternalInterface->FMU(i).Instance(j).fmiVersionNumber.substr(0, 3)));
1257 0 : ShowContinueError(state, "differs from version 1.0 which is currently supported.");
1258 0 : state.dataExternalInterface->ErrorsFound = true;
1259 0 : StopExternalInterfaceIfError(state);
1260 : }
1261 3 : }
1262 3 : }
1263 : }
1264 :
1265 3 : strippedFileName.deallocate();
1266 3 : fullFileName.deallocate();
1267 :
1268 3 : state.dataExternalInterface->UniqueFMUInputVarNames.reserve(static_cast<unsigned>(NumFMUInputVariables));
1269 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1270 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1271 3 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable.allocate(NumFMUInputVariables);
1272 3 : state.dataExternalInterface->FMU(i).Instance(j).checkfmuInputVariable.allocate(NumFMUInputVariables);
1273 3 : state.dataExternalInterface->UniqueFMUInputVarNames.clear();
1274 3 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable.allocate(NumFMUInputVariables);
1275 3 : int k = 1;
1276 11 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1277 24 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1278 : cCurrentModuleObject,
1279 : l,
1280 8 : state.dataIPShortCut->cAlphaArgs,
1281 : NumAlphas,
1282 8 : state.dataIPShortCut->rNumericArgs,
1283 : NumNumbers,
1284 : IOStatus,
1285 : _,
1286 : _,
1287 8 : state.dataIPShortCut->cAlphaFieldNames,
1288 8 : state.dataIPShortCut->cNumericFieldNames);
1289 16 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), state.dataExternalInterface->FMU(i).Name) &&
1290 8 : Util::SameString(state.dataIPShortCut->cAlphaArgs(4), state.dataExternalInterface->FMU(i).Instance(j).Name)) {
1291 8 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).Name = state.dataIPShortCut->cAlphaArgs(5);
1292 8 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarKey = state.dataIPShortCut->cAlphaArgs(1);
1293 8 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).Name = state.dataIPShortCut->cAlphaArgs(2);
1294 : // verify whether we have duplicate FMU input variables in the idf
1295 8 : GlobalNames::VerifyUniqueInterObjectName(state,
1296 8 : state.dataExternalInterface->UniqueFMUInputVarNames,
1297 8 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).Name,
1298 : cCurrentModuleObject,
1299 8 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1300 8 : state.dataExternalInterface->ErrorsFound);
1301 : // Util::VerifyName( state.dataExternalInterface->FMU( i ).Instance( j
1302 : // ).fmuInputVariable(
1303 : // k
1304 : //).Name, state.dataExternalInterface->FMU(
1305 : // i
1306 : //).Instance(
1307 : // j
1308 : //).checkfmuInputVariable, NumFMUInputVariables, IsNotOK, IsBlank, "The FMU input variable \"" +
1309 : // state.dataExternalInterface->FMU( i ).Instance( j
1310 : //).fmuInputVariable( k ).Name + "\" of instance \"" + state.dataExternalInterface->FMU( i ).Instance( j ).Name + "\" of FMU
1311 : //\"" + state.dataExternalInterface->FMU( i ).Name + "\"
1312 : // has duplicates. Please check the input file again and delete duplicated entries." );
1313 8 : if (state.dataExternalInterface->ErrorsFound) {
1314 0 : StopExternalInterfaceIfError(state);
1315 : } else {
1316 8 : state.dataExternalInterface->FMU(i).Instance(j).checkfmuInputVariable(k).Name =
1317 16 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).Name;
1318 : }
1319 :
1320 : // preprocess args for library call
1321 : std::vector<char> inputVarNameArr(
1322 8 : getCharArrayFromString(state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).Name));
1323 8 : int inputVarNameLen(len(state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).Name));
1324 :
1325 : // make the library call
1326 8 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).ValueReference = getValueReferenceByNameFMUInputVariables(
1327 8 : &inputVarNameArr[0], &inputVarNameLen, &state.dataExternalInterface->FMU(i).Instance(j).Index);
1328 :
1329 : // postprocess args in case they are used later
1330 8 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).Name = getStringFromCharArray(inputVarNameArr);
1331 :
1332 8 : if (state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).ValueReference == -999) {
1333 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1334 0 : ShowContinueError(state, "get the value reference of FMU input variable");
1335 0 : ShowContinueError(state,
1336 0 : format("\"{}\" of instance \"{}\" of FMU",
1337 0 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).Name,
1338 0 : state.dataExternalInterface->FMU(i).Instance(j).Name));
1339 0 : ShowContinueError(
1340 0 : state, format("of FMU \"{}\". Please check the name of input variable", state.dataExternalInterface->FMU(i).Name));
1341 0 : ShowContinueError(state, "in the input file and in the modelDescription file.");
1342 0 : state.dataExternalInterface->ErrorsFound = true;
1343 0 : StopExternalInterfaceIfError(state);
1344 : }
1345 :
1346 8 : if (state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).ValueReference == -1) {
1347 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1348 0 : ShowContinueError(state, "get the value reference of FMU input variable");
1349 0 : ShowContinueError(state,
1350 0 : format("\"{}\" of instance \"{}\" of FMU",
1351 0 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).Name,
1352 0 : state.dataExternalInterface->FMU(i).Instance(j).Name));
1353 0 : ShowContinueError(
1354 0 : state, format("\"{}\". This variable is not an FMU input variable.", state.dataExternalInterface->FMU(i).Name));
1355 0 : ShowContinueError(state, "Please check the causality of the variable in the modelDescription file.");
1356 0 : state.dataExternalInterface->ErrorsFound = true;
1357 0 : StopExternalInterfaceIfError(state);
1358 : }
1359 :
1360 : // The next call expects an array, but a single item is passed
1361 : // Therefore create a single item array here first
1362 8 : Array1D_string tempSingleStringA(1, state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarKey);
1363 8 : Array1D_string tempSingleStringB(1, state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).Name);
1364 :
1365 : // Make the call with arrays
1366 8 : GetReportVariableKey(state, tempSingleStringA, 1, tempSingleStringB, keyIndexes, varTypes);
1367 :
1368 : // Then postprocess the array items back in case they changed
1369 8 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarKey = tempSingleStringA(1);
1370 8 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).Name = tempSingleStringB(1);
1371 :
1372 8 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarIndex = keyIndexes(1);
1373 8 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarType = varTypes(1);
1374 8 : state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF = k;
1375 8 : ++k;
1376 8 : }
1377 : }
1378 :
1379 3 : if (NumFMUInputVariables > 0 && state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF == 0) {
1380 0 : ShowWarningError(state,
1381 0 : format("InitExternalInterfaceFMUImport: The instance \"{}\" of FMU \"{}\"",
1382 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1383 0 : state.dataExternalInterface->FMU(i).Name));
1384 0 : ShowContinueError(state, "is defined but has no input variables. Check the input field of the");
1385 0 : ShowContinueError(state, "corresponding object: ExternalInterface:FunctionalMockupUnitImport:From:Variable.");
1386 : }
1387 : }
1388 : }
1389 :
1390 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1391 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1392 : // check whether the number of input variables in fmu is bigger than in the idf
1393 3 : if (state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInFMU >
1394 3 : state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF) {
1395 0 : ShowWarningError(state,
1396 0 : format("InitExternalInterfaceFMUImport: The number of input variables defined in input file ({})",
1397 0 : state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF));
1398 0 : ShowContinueError(state,
1399 0 : format("of instance \"{}\" of FMU \"{}\" is less than the number of input variables",
1400 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1401 0 : state.dataExternalInterface->FMU(i).Name));
1402 0 : ShowContinueError(
1403 0 : state, format("in the modelDescription file ({}).", state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInFMU));
1404 0 : ShowContinueError(state, "Check the input file and the modelDescription file again.");
1405 : }
1406 : // check whether the number of input variables in fmu is less than in the idf
1407 3 : if (state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInFMU <
1408 3 : state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF) {
1409 0 : ShowWarningError(state,
1410 0 : format("InitExternalInterfaceFMUImport: The number of input variables defined in input file ({})",
1411 0 : state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF));
1412 0 : ShowContinueError(state,
1413 0 : format("of instance \"{}\" of FMU \"{}\" is bigger than the number of input variables",
1414 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1415 0 : state.dataExternalInterface->FMU(i).Name));
1416 0 : ShowContinueError(
1417 0 : state, format("in the modelDescription file ({}).", state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInFMU));
1418 0 : ShowContinueError(state, "Check the input file and the modelDescription file again.");
1419 : }
1420 : }
1421 : }
1422 :
1423 : // get the names of the output variables each fmu (and the names of the
1424 : // corresponding input variables in EnergyPlus -- schedule).
1425 3 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Schedule";
1426 3 : NumFMUInputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1427 :
1428 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1429 3 : int j = 1;
1430 5 : for (int k = 1; k <= NumFMUInputVariables; ++k) {
1431 6 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1432 : cCurrentModuleObject,
1433 : k,
1434 2 : state.dataIPShortCut->cAlphaArgs,
1435 : NumAlphas,
1436 2 : state.dataIPShortCut->rNumericArgs,
1437 : NumNumbers,
1438 : IOStatus,
1439 : _,
1440 : _,
1441 2 : state.dataIPShortCut->cAlphaFieldNames,
1442 2 : state.dataIPShortCut->cNumericFieldNames);
1443 2 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), state.dataExternalInterface->FMU(i).Name)) {
1444 2 : state.dataExternalInterface->FMU(i).TotNumOutputVariablesSchedule = j;
1445 2 : ++j;
1446 : }
1447 : }
1448 : }
1449 :
1450 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1451 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1452 3 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule.allocate(NumFMUInputVariables);
1453 3 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableSchedule.allocate(NumFMUInputVariables);
1454 3 : int k = 1;
1455 5 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1456 6 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1457 : cCurrentModuleObject,
1458 : l,
1459 2 : state.dataIPShortCut->cAlphaArgs,
1460 : NumAlphas,
1461 2 : state.dataIPShortCut->rNumericArgs,
1462 : NumNumbers,
1463 : IOStatus,
1464 : _,
1465 : _,
1466 2 : state.dataIPShortCut->cAlphaFieldNames,
1467 2 : state.dataIPShortCut->cNumericFieldNames);
1468 4 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), state.dataExternalInterface->FMU(i).Name) &&
1469 2 : Util::SameString(state.dataIPShortCut->cAlphaArgs(4), state.dataExternalInterface->FMU(i).Instance(j).Name)) {
1470 2 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).Name = state.dataIPShortCut->cAlphaArgs(5);
1471 2 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableSchedule(k).Name = state.dataIPShortCut->cAlphaArgs(1);
1472 2 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableSchedule(k).InitialValue =
1473 2 : state.dataIPShortCut->rNumericArgs(1);
1474 :
1475 : // get the value reference by using the FMU name and the variable name.
1476 :
1477 : // preprocess the arguments before the following library call
1478 : std::vector<char> NameCharArr(
1479 2 : getCharArrayFromString(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).Name));
1480 2 : int lengthVar(len(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).Name));
1481 :
1482 : // make the library call
1483 2 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).ValueReference =
1484 2 : getValueReferenceByNameFMUOutputVariables(
1485 2 : &NameCharArr[0], &lengthVar, &state.dataExternalInterface->FMU(i).Instance(j).Index);
1486 :
1487 : // postprocess the arguments after the library call in case they are changed and used later
1488 2 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).Name = getStringFromCharArray(NameCharArr);
1489 :
1490 2 : if (state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).ValueReference == -999) {
1491 0 : ShowSevereError(state,
1492 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1493 : "the FMU output variable");
1494 0 : ShowContinueError(state,
1495 0 : format("\"{}\" of instance \"{}\"",
1496 0 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).Name,
1497 0 : state.dataExternalInterface->FMU(i).Instance(j).Name));
1498 0 : ShowContinueError(state,
1499 0 : format("of FMU \"{}\" that will be mapped to a schedule.", state.dataExternalInterface->FMU(i).Name));
1500 0 : ShowContinueError(state, "Please check the name of output variables in the input file and");
1501 0 : ShowContinueError(state, "in the modelDescription file.");
1502 0 : state.dataExternalInterface->ErrorsFound = true;
1503 0 : StopExternalInterfaceIfError(state);
1504 : }
1505 :
1506 2 : if (state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).ValueReference == -1) {
1507 0 : ShowSevereError(state,
1508 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1509 : "the FMU output variable");
1510 0 : ShowContinueError(state,
1511 0 : format("\"{}\" of instance \"{}\"",
1512 0 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).Name,
1513 0 : state.dataExternalInterface->FMU(i).Instance(j).Name));
1514 0 : ShowContinueError(state,
1515 0 : format("of FMU \"{}\" that will be mapped to a schedule.", state.dataExternalInterface->FMU(i).Name));
1516 0 : ShowContinueError(state, "This variable is not an FMU output variable.");
1517 0 : ShowContinueError(state, "Please check the causality of the variable in the modelDescription file.");
1518 0 : state.dataExternalInterface->ErrorsFound = true;
1519 0 : StopExternalInterfaceIfError(state);
1520 : }
1521 :
1522 2 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableSchedule(k).VarIndex = ScheduleManager::GetDayScheduleIndex(
1523 2 : state, state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableSchedule(k).Name);
1524 2 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesSchedule = k;
1525 2 : if (state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableSchedule(k).VarIndex <= 0) {
1526 0 : ShowSevereError(state,
1527 0 : format("ExternalInterface/InitExternalInterfaceFMUImport:declares variable \"{}\",",
1528 0 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableSchedule(k).Name));
1529 0 : ShowContinueError(state, "but variable is not a schedule variable.");
1530 0 : state.dataExternalInterface->ErrorsFound = true;
1531 0 : StopExternalInterfaceIfError(state);
1532 : }
1533 2 : ++k;
1534 2 : }
1535 : }
1536 : }
1537 : }
1538 :
1539 : // get the names of the output variables each fmu (and the names of the
1540 : // corresponding input variables in EnergyPlus -- variable).
1541 3 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
1542 3 : NumFMUInputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1543 :
1544 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1545 3 : int j = 1;
1546 4 : for (int k = 1; k <= NumFMUInputVariables; ++k) {
1547 3 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1548 : cCurrentModuleObject,
1549 : k,
1550 1 : state.dataIPShortCut->cAlphaArgs,
1551 : NumAlphas,
1552 1 : state.dataIPShortCut->rNumericArgs,
1553 : NumNumbers,
1554 : IOStatus,
1555 : _,
1556 : _,
1557 1 : state.dataIPShortCut->cAlphaFieldNames,
1558 1 : state.dataIPShortCut->cNumericFieldNames);
1559 1 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), state.dataExternalInterface->FMU(i).Name)) {
1560 1 : state.dataExternalInterface->FMU(i).TotNumOutputVariablesVariable = j;
1561 1 : ++j;
1562 : }
1563 : }
1564 : }
1565 :
1566 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1567 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1568 3 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable.allocate(NumFMUInputVariables);
1569 3 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableVariable.allocate(NumFMUInputVariables);
1570 3 : int k = 1;
1571 4 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1572 3 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1573 : cCurrentModuleObject,
1574 : l,
1575 1 : state.dataIPShortCut->cAlphaArgs,
1576 : NumAlphas,
1577 1 : state.dataIPShortCut->rNumericArgs,
1578 : NumNumbers,
1579 : IOStatus,
1580 : _,
1581 : _,
1582 1 : state.dataIPShortCut->cAlphaFieldNames,
1583 1 : state.dataIPShortCut->cNumericFieldNames);
1584 2 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), state.dataExternalInterface->FMU(i).Name) &&
1585 1 : Util::SameString(state.dataIPShortCut->cAlphaArgs(3), state.dataExternalInterface->FMU(i).Instance(j).Name)) {
1586 1 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).Name = state.dataIPShortCut->cAlphaArgs(4);
1587 1 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableVariable(k).Name = state.dataIPShortCut->cAlphaArgs(1);
1588 :
1589 : // get the value reference by using the FMU name and the variable name.
1590 : std::vector<char> NameCharArr(
1591 1 : getCharArrayFromString(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).Name));
1592 1 : int tempLength(len(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).Name));
1593 1 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).ValueReference =
1594 1 : getValueReferenceByNameFMUOutputVariables(
1595 1 : &NameCharArr[0], &tempLength, &state.dataExternalInterface->FMU(i).Instance(j).Index);
1596 : // state.dataExternalInterface->FMU( i ).Instance( j ).fmuOutputVariableVariable( k ).Name = getStringFromCharArray(
1597 : // NameCharArr );
1598 :
1599 1 : if (state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).ValueReference == -999) {
1600 0 : ShowSevereError(state,
1601 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1602 : "the FMU output variable");
1603 0 : ShowContinueError(state,
1604 0 : format("\"{}\" of instance \"{}\"",
1605 0 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).Name,
1606 0 : state.dataExternalInterface->FMU(i).Instance(j).Name));
1607 0 : ShowContinueError(state,
1608 0 : format("of FMU \"{}\" that will be mapped to a variable.", state.dataExternalInterface->FMU(i).Name));
1609 0 : ShowContinueError(state, "Please check the name of output variables in the input file and in the modelDescription file.");
1610 0 : state.dataExternalInterface->ErrorsFound = true;
1611 0 : StopExternalInterfaceIfError(state);
1612 : }
1613 :
1614 1 : if (state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).ValueReference == -1) {
1615 0 : ShowSevereError(state,
1616 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1617 : "the FMU output variable");
1618 0 : ShowContinueError(state,
1619 0 : format("\"{}\" of instance \"{}\"",
1620 0 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).Name,
1621 0 : state.dataExternalInterface->FMU(i).Instance(j).Name));
1622 0 : ShowContinueError(state,
1623 0 : format("of FMU \"{}\" that will be mapped to a variable.", state.dataExternalInterface->FMU(i).Name));
1624 0 : ShowContinueError(state,
1625 : "This variable is not an FMU output variable. Please check the causality of the variable in the "
1626 : "modelDescription file.");
1627 0 : state.dataExternalInterface->ErrorsFound = true;
1628 0 : StopExternalInterfaceIfError(state);
1629 : }
1630 :
1631 1 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableVariable(k).VarIndex =
1632 1 : RuntimeLanguageProcessor::FindEMSVariable(
1633 1 : state, state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableVariable(k).Name, 0);
1634 1 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesVariable = k;
1635 1 : if (state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableVariable(k).VarIndex <= 0) {
1636 0 : ShowSevereError(state,
1637 0 : format("ExternalInterface/InitExternalInterfaceFMUImport:declares variable \"{}\",",
1638 0 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableVariable(k).Name));
1639 0 : ShowContinueError(state, "but variable is not an EMS variable.");
1640 0 : state.dataExternalInterface->ErrorsFound = true;
1641 0 : StopExternalInterfaceIfError(state);
1642 : }
1643 1 : ++k;
1644 1 : }
1645 : }
1646 3 : if (state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesVariable >= 1) {
1647 1 : state.dataExternalInterface->useEMS = true;
1648 : }
1649 : }
1650 : }
1651 :
1652 : // get the names of the output variables each fmu (and the names of the
1653 : // corresponding input variables in EnergyPlus -- actuator).
1654 3 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
1655 3 : NumFMUInputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1656 :
1657 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1658 3 : int j = 1;
1659 4 : for (int k = 1; k <= NumFMUInputVariables; ++k) {
1660 3 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1661 : cCurrentModuleObject,
1662 : k,
1663 1 : state.dataIPShortCut->cAlphaArgs,
1664 : NumAlphas,
1665 1 : state.dataIPShortCut->rNumericArgs,
1666 : NumNumbers,
1667 : IOStatus,
1668 : _,
1669 : _,
1670 1 : state.dataIPShortCut->cAlphaFieldNames,
1671 1 : state.dataIPShortCut->cNumericFieldNames);
1672 1 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(5), state.dataExternalInterface->FMU(i).Name)) {
1673 1 : state.dataExternalInterface->FMU(i).TotNumOutputVariablesActuator = j;
1674 1 : ++j;
1675 : }
1676 : }
1677 : }
1678 :
1679 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1680 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1681 3 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator.allocate(NumFMUInputVariables);
1682 3 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableActuator.allocate(NumFMUInputVariables);
1683 3 : int k = 1;
1684 4 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1685 3 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1686 : cCurrentModuleObject,
1687 : l,
1688 1 : state.dataIPShortCut->cAlphaArgs,
1689 : NumAlphas,
1690 1 : state.dataIPShortCut->rNumericArgs,
1691 : NumNumbers,
1692 : IOStatus,
1693 : _,
1694 : _,
1695 1 : state.dataIPShortCut->cAlphaFieldNames,
1696 1 : state.dataIPShortCut->cNumericFieldNames);
1697 2 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(5), state.dataExternalInterface->FMU(i).Name) &&
1698 1 : Util::SameString(state.dataIPShortCut->cAlphaArgs(6), state.dataExternalInterface->FMU(i).Instance(j).Name)) {
1699 1 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).Name = state.dataIPShortCut->cAlphaArgs(7);
1700 1 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableActuator(k).Name = state.dataIPShortCut->cAlphaArgs(1);
1701 :
1702 : // get the value reference by using the FMU name and the variable name.
1703 : std::vector<char> tempNameArr(
1704 1 : getCharArrayFromString(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).Name));
1705 1 : int tempLength(len(state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).Name));
1706 1 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).ValueReference =
1707 1 : getValueReferenceByNameFMUOutputVariables(
1708 1 : &tempNameArr[0], &tempLength, &state.dataExternalInterface->FMU(i).Instance(j).Index);
1709 : // state.dataExternalInterface->FMU( i ).Instance( j ).fmuOutputVariableActuator( k ).Name = getStringFromCharArray(
1710 : // tempNameArr );
1711 :
1712 1 : if (state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).ValueReference == -999) {
1713 0 : ShowSevereError(state,
1714 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1715 : "the FMU output variable");
1716 0 : ShowContinueError(state,
1717 0 : format("\"{}\" of instance \"{}\"",
1718 0 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).Name,
1719 0 : state.dataExternalInterface->FMU(i).Instance(j).Name));
1720 0 : ShowContinueError(state,
1721 0 : format("of FMU \"{}\" that will be mapped to an actuator.", state.dataExternalInterface->FMU(i).Name));
1722 0 : ShowContinueError(state, "Please check the name of output variables in the input file and in the modelDescription file.");
1723 0 : state.dataExternalInterface->ErrorsFound = true;
1724 0 : StopExternalInterfaceIfError(state);
1725 : }
1726 :
1727 1 : if (state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).ValueReference == -1) {
1728 0 : ShowSevereError(state,
1729 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1730 : "the FMU output variable");
1731 0 : ShowContinueError(state,
1732 0 : format("\"{}\" of instance \"{}\"",
1733 0 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).Name,
1734 0 : state.dataExternalInterface->FMU(i).Instance(j).Name));
1735 0 : ShowContinueError(state,
1736 0 : format("of FMU \"{}\" that will be mapped to an actuator.", state.dataExternalInterface->FMU(i).Name));
1737 0 : ShowContinueError(state,
1738 : "This variable is not an FMU output variable. Please check the causality of the variable in the "
1739 : "modelDescription file.");
1740 0 : state.dataExternalInterface->ErrorsFound = true;
1741 0 : StopExternalInterfaceIfError(state);
1742 : }
1743 :
1744 1 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableActuator(k).VarIndex =
1745 1 : RuntimeLanguageProcessor::FindEMSVariable(
1746 1 : state, state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableActuator(k).Name, 0);
1747 1 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesActuator = k;
1748 1 : if (state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableActuator(k).VarIndex <= 0) {
1749 0 : ShowSevereError(state,
1750 0 : format("ExternalInterface/InitExternalInterfaceFMUImport:declares variable \"{}\",",
1751 0 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableActuator(k).Name));
1752 0 : ShowContinueError(state, "but variable is not an EMS variable.");
1753 0 : state.dataExternalInterface->ErrorsFound = true;
1754 0 : StopExternalInterfaceIfError(state);
1755 : }
1756 1 : ++k;
1757 1 : }
1758 : }
1759 : // set the flag state.dataExternalInterface->useEMS to true. This will be used then to update the erl variables in erl data structure
1760 3 : if (state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesActuator >= 1) {
1761 1 : state.dataExternalInterface->useEMS = true;
1762 : }
1763 : }
1764 : }
1765 :
1766 : // parse the fmu defined in the idf using the fmuUnpack with the flag --unpack.
1767 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1768 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1769 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInIDF =
1770 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesSchedule +
1771 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesVariable +
1772 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesActuator;
1773 : // check whether the number of output variables in fmu is bigger than in the idf
1774 3 : if (state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInFMU >
1775 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInIDF) {
1776 0 : ShowWarningError(state,
1777 0 : format("InitExternalInterfaceFMUImport: The number of output variables defined in input file ({})",
1778 0 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInIDF));
1779 0 : ShowContinueError(state,
1780 0 : format("of instance \"{}\" of FMU \"{}\" is less than the number of output variables",
1781 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1782 0 : state.dataExternalInterface->FMU(i).Name));
1783 0 : ShowContinueError(
1784 0 : state, format("in the modelDescription file ({}).", state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInFMU));
1785 0 : ShowContinueError(state, "Check the input file and the modelDescription file again.");
1786 : }
1787 : // check whether the number of output variables in fmu is less than in the idf
1788 3 : if (state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInFMU <
1789 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInIDF) {
1790 0 : ShowWarningError(state,
1791 0 : format("InitExternalInterfaceFMUImport: The number of output variables defined in input file ({})",
1792 0 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInIDF));
1793 0 : ShowContinueError(state,
1794 0 : format("of instance \"{}\" of FMU \"{}\" is bigger than the number of output variables",
1795 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1796 0 : state.dataExternalInterface->FMU(i).Name));
1797 0 : ShowContinueError(
1798 0 : state, format("in the modelDescription file ({}).", state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInFMU));
1799 0 : ShowContinueError(state, "Check the input file and the modelDescription file again.");
1800 : }
1801 :
1802 3 : DisplayString(state,
1803 6 : format("Number of inputs in instance \"{}\" of FMU \"{}\" = \"{}\".",
1804 3 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1805 3 : state.dataExternalInterface->FMU(i).Name,
1806 3 : state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF));
1807 3 : DisplayString(state,
1808 6 : format("Number of outputs in instance \"{}\" of FMU \"{}\" = \"{}\".",
1809 3 : state.dataExternalInterface->FMU(i).Instance(j).Name,
1810 3 : state.dataExternalInterface->FMU(i).Name,
1811 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesInIDF));
1812 : }
1813 : }
1814 3 : StopExternalInterfaceIfError(state);
1815 3 : state.dataExternalInterface->FirstCallIni = false;
1816 : }
1817 143523 : }
1818 :
1819 3 : std::string trim(std::string const &str)
1820 : {
1821 3 : std::size_t first = str.find_first_not_of(' ');
1822 3 : std::size_t last = str.find_last_not_of(' ');
1823 3 : return str.substr(first, last - first + 1);
1824 : }
1825 :
1826 6 : Real64 GetCurSimStartTimeSeconds(const EnergyPlusData &state)
1827 : {
1828 : // FUNCTION INFORMATION:
1829 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
1830 : // DATE WRITTEN August 2011
1831 :
1832 : // PURPOSE OF THIS FUNCTION:
1833 : // Get the current month and day in the runperiod and convert
1834 : // it into seconds.
1835 :
1836 : // Locals
1837 : Real64 simtime;
1838 :
1839 6 : if (!state.dataEnvrn->CurrentYearIsLeapYear) {
1840 6 : switch (state.dataEnvrn->Month) {
1841 6 : case 1:
1842 6 : simtime = 0;
1843 6 : break;
1844 0 : case 2:
1845 0 : simtime = 31;
1846 0 : break;
1847 0 : case 3:
1848 0 : simtime = 59;
1849 0 : break;
1850 0 : case 4:
1851 0 : simtime = 90;
1852 0 : break;
1853 0 : case 5:
1854 0 : simtime = 120;
1855 0 : break;
1856 0 : case 6:
1857 0 : simtime = 151;
1858 0 : break;
1859 0 : case 7:
1860 0 : simtime = 181;
1861 0 : break;
1862 0 : case 8:
1863 0 : simtime = 212;
1864 0 : break;
1865 0 : case 9:
1866 0 : simtime = 243;
1867 0 : break;
1868 0 : case 10:
1869 0 : simtime = 273;
1870 0 : break;
1871 0 : case 11:
1872 0 : simtime = 304;
1873 0 : break;
1874 0 : case 12:
1875 0 : simtime = 334;
1876 0 : break;
1877 0 : default:
1878 0 : simtime = 0;
1879 : }
1880 : } else {
1881 0 : switch (state.dataEnvrn->Month) {
1882 0 : case 1:
1883 0 : simtime = 0;
1884 0 : break;
1885 0 : case 2:
1886 0 : simtime = 31;
1887 0 : break;
1888 0 : case 3:
1889 0 : simtime = 59 + 1;
1890 0 : break;
1891 0 : case 4:
1892 0 : simtime = 90 + 1;
1893 0 : break;
1894 0 : case 5:
1895 0 : simtime = 120 + 1;
1896 0 : break;
1897 0 : case 6:
1898 0 : simtime = 151 + 1;
1899 0 : break;
1900 0 : case 7:
1901 0 : simtime = 181 + 1;
1902 0 : break;
1903 0 : case 8:
1904 0 : simtime = 212 + 1;
1905 0 : break;
1906 0 : case 9:
1907 0 : simtime = 243 + 1;
1908 0 : break;
1909 0 : case 10:
1910 0 : simtime = 273 + 1;
1911 0 : break;
1912 0 : case 11:
1913 0 : simtime = 304 + 1;
1914 0 : break;
1915 0 : case 12:
1916 0 : simtime = 334 + 1;
1917 0 : break;
1918 0 : default:
1919 0 : simtime = 0;
1920 : }
1921 : }
1922 :
1923 6 : simtime = 24 * (simtime + (state.dataEnvrn->DayOfMonth - 1)); // day of month does not need to be stubtracted??
1924 6 : simtime = 60 * (simtime + (state.dataGlobal->HourOfDay - 1)); // hours to minutes
1925 6 : simtime = 60 * (simtime); // minutes to seconds
1926 :
1927 6 : return simtime;
1928 : }
1929 :
1930 143523 : void CalcExternalInterfaceFMUImport(EnergyPlusData &state)
1931 : {
1932 :
1933 : // SUBROUTINE INFORMATION:
1934 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
1935 : // DATE WRITTEN 08Aug2011
1936 :
1937 : // PURPOSE OF THIS SUBROUTINE:
1938 : // This subroutine organizes the data exchange between FMU and EnergyPlus.
1939 :
1940 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1941 143523 : Array1D_string Alphas(5);
1942 143523 : Array1D_int keyIndexes(1); // Array index for
1943 143523 : Array1D_string NamesOfKeys(1); // Specific key name
1944 :
1945 146883 : if (state.dataGlobal->WarmupFlag &&
1946 3360 : (state.dataGlobal->KindOfSim != Constant::KindOfSim::RunPeriodWeather)) { // No data exchange during design days
1947 0 : if (state.dataExternalInterface->FirstCallDesignDays) {
1948 0 : ShowWarningError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: ExternalInterface does not exchange data during design days.");
1949 : }
1950 0 : state.dataExternalInterface->FirstCallDesignDays = false;
1951 : }
1952 143523 : if (state.dataGlobal->WarmupFlag && (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather)) { // Data exchange after design days
1953 3360 : if (state.dataExternalInterface->FirstCallWUp) {
1954 : // set the report during warmup to true so that variables are also updated during the warmup
1955 3 : state.dataSysVars->UpdateDataDuringWarmupExternalInterface = true;
1956 3 : state.dataExternalInterface->hStep = (60.0 * state.dataGlobal->TimeStepZone) * 60.0;
1957 3 : state.dataExternalInterface->tStart = GetCurSimStartTimeSeconds(state);
1958 3 : state.dataExternalInterface->tStop = state.dataExternalInterface->tStart + 24.0 * 3600.0;
1959 3 : state.dataExternalInterface->tComm = state.dataExternalInterface->tStart;
1960 :
1961 : // instantiate and initialize the unpack fmus
1962 3 : InstantiateInitializeFMUImport(state);
1963 :
1964 : // allocate memory for a temporary FMU that will be used at the end of the warmup
1965 3 : state.dataExternalInterface->FMUTemp.allocate(state.dataExternalInterface->NumFMUObjects);
1966 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1967 3 : state.dataExternalInterface->FMUTemp(i).Instance.allocate(state.dataExternalInterface->FMU(i).NumInstances);
1968 : }
1969 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1970 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1971 6 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuInputVariable.allocate(
1972 3 : state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF);
1973 6 : state.dataExternalInterface->FMUTemp(i).Instance(j).eplusOutputVariable.allocate(
1974 3 : state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF);
1975 6 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableSchedule.allocate(
1976 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesSchedule);
1977 6 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableVariable.allocate(
1978 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesVariable);
1979 6 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableActuator.allocate(
1980 3 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesActuator);
1981 : }
1982 : }
1983 :
1984 3 : GetSetVariablesAndDoStepFMUImport(state);
1985 3 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
1986 3 : state.dataExternalInterface->FirstCallWUp = false;
1987 :
1988 : } else {
1989 3357 : if (state.dataExternalInterface->tComm < state.dataExternalInterface->tStop) {
1990 3331 : GetSetVariablesAndDoStepFMUImport(state);
1991 : // Advance the communication time step
1992 3331 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
1993 : } else {
1994 52 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1995 52 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
1996 :
1997 26 : state.dataExternalInterface->FMUTemp(i).Instance(j).NumInputVariablesInIDF =
1998 26 : state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF;
1999 110 : for (int k = 1; k <= state.dataExternalInterface->FMU(i).Instance(j).NumInputVariablesInIDF; ++k) {
2000 84 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuInputVariable(k).ValueReference =
2001 84 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(k).ValueReference;
2002 84 : state.dataExternalInterface->FMUTemp(i).Instance(j).eplusOutputVariable(k).RTSValue =
2003 84 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).RTSValue;
2004 84 : state.dataExternalInterface->FMUTemp(i).Instance(j).eplusOutputVariable(k).ITSValue =
2005 84 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).ITSValue;
2006 84 : state.dataExternalInterface->FMUTemp(i).Instance(j).eplusOutputVariable(k).VarType =
2007 84 : state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(k).VarType;
2008 : }
2009 :
2010 : // save values that will be set in EnergyPlus (Schedule)
2011 26 : state.dataExternalInterface->FMUTemp(i).Instance(j).NumOutputVariablesSchedule =
2012 26 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesSchedule;
2013 58 : for (int k = 1; k <= state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesSchedule; ++k) {
2014 32 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableSchedule(k).RealVarValue =
2015 32 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule(k).RealVarValue;
2016 : }
2017 :
2018 : // save values that will be set in EnergyPlus (Variable)
2019 26 : state.dataExternalInterface->FMUTemp(i).Instance(j).NumOutputVariablesVariable =
2020 26 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesVariable;
2021 31 : for (int k = 1; k <= state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesVariable; ++k) {
2022 5 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableVariable(k).RealVarValue =
2023 5 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable(k).RealVarValue;
2024 : }
2025 :
2026 : // save values that will be set in EnergyPlus (Actuator)
2027 26 : state.dataExternalInterface->FMUTemp(i).Instance(j).NumOutputVariablesActuator =
2028 26 : state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesActuator;
2029 31 : for (int k = 1; k <= state.dataExternalInterface->FMU(i).Instance(j).NumOutputVariablesActuator; ++k) {
2030 5 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableActuator(k).RealVarValue =
2031 5 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator(k).RealVarValue;
2032 : }
2033 : }
2034 : }
2035 :
2036 26 : StopExternalInterfaceIfError(state);
2037 :
2038 : // Terminate all FMUs
2039 26 : TerminateResetFreeFMUImport(state, state.dataExternalInterface->fmiEndSimulation);
2040 :
2041 : // Reset the communication time step
2042 26 : state.dataExternalInterface->tComm = state.dataExternalInterface->tStart;
2043 :
2044 : // Reinstantiate and reinitialize the FMUs
2045 26 : InstantiateInitializeFMUImport(state);
2046 :
2047 : // Set the values that have been saved in the FMUs-- saveFMUStateVariables ()
2048 52 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2049 52 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
2050 :
2051 26 : std::vector<unsigned int> valRefVec;
2052 110 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable); ++x) {
2053 84 : valRefVec.push_back(state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable(x).ValueReference);
2054 : }
2055 :
2056 26 : std::vector<Real64> rtsValVec;
2057 110 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable); ++x) {
2058 84 : rtsValVec.push_back(state.dataExternalInterface->FMU(i).Instance(j).eplusOutputVariable(x).RTSValue);
2059 : }
2060 :
2061 : // make the library call
2062 26 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus =
2063 26 : fmiEPlusSetReal(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
2064 26 : &valRefVec[0],
2065 26 : &rtsValVec[0],
2066 26 : &state.dataExternalInterface->FMUTemp(i).Instance(j).NumInputVariablesInIDF,
2067 26 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
2068 :
2069 26 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiOK) {
2070 0 : ShowSevereError(
2071 : state,
2072 0 : format("ExternalInterface/CalcExternalInterfaceFMUImport: Error when trying to set an input value in instance \"{}\"",
2073 0 : state.dataExternalInterface->FMU(i).Instance(j).Name));
2074 0 : ShowContinueError(state,
2075 0 : format("of FMU \"{}\"; Error Code = \"{}\"",
2076 0 : state.dataExternalInterface->FMU(i).Name,
2077 0 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus));
2078 0 : state.dataExternalInterface->ErrorsFound = true;
2079 0 : StopExternalInterfaceIfError(state);
2080 : }
2081 26 : }
2082 : }
2083 : // set the flag to reinitialize states to be true
2084 26 : state.dataExternalInterface->FlagReIni = true;
2085 26 : GetSetVariablesAndDoStepFMUImport(state);
2086 26 : state.dataExternalInterface->FlagReIni = false;
2087 : // advance one time step ahead for the next calculation
2088 26 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
2089 : }
2090 : }
2091 : }
2092 : // BeginSimulation
2093 143523 : if (!state.dataGlobal->WarmupFlag && (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather)) {
2094 :
2095 140163 : if (state.dataExternalInterface->FirstCallTStep) {
2096 : // reset the UpdateDataDuringWarmupExternalInterface to be false.
2097 3 : state.dataSysVars->UpdateDataDuringWarmupExternalInterface = false;
2098 : // The time is computed in seconds for FMU
2099 3 : state.dataExternalInterface->tStart = GetCurSimStartTimeSeconds(state);
2100 6 : state.dataExternalInterface->tStop =
2101 3 : state.dataExternalInterface->tStart + (state.dataEnvrn->TotalOverallSimDays - state.dataEnvrn->TotDesDays) * 24.0 * 3600.0;
2102 3 : state.dataExternalInterface->tComm = state.dataExternalInterface->tStart;
2103 :
2104 : // Terminate all FMUs
2105 3 : TerminateResetFreeFMUImport(state, state.dataExternalInterface->fmiEndSimulation);
2106 :
2107 : // Reinstantiate and reinitialize the FMUs
2108 3 : InstantiateInitializeFMUImport(state);
2109 :
2110 : // Set the values that have been saved in the FMUs-- saveFMUStateVariables ()
2111 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2112 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
2113 :
2114 : // make vectors first
2115 3 : std::vector<unsigned int> valRefVec;
2116 11 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMUTemp(i).Instance(j).fmuInputVariable); ++x) {
2117 8 : valRefVec.push_back(state.dataExternalInterface->FMUTemp(i).Instance(j).fmuInputVariable(x).ValueReference);
2118 : }
2119 3 : std::vector<Real64> rtsValVec;
2120 11 : for (unsigned long x = 1; x <= size(state.dataExternalInterface->FMUTemp(i).Instance(j).eplusOutputVariable); ++x) {
2121 8 : rtsValVec.push_back(state.dataExternalInterface->FMUTemp(i).Instance(j).eplusOutputVariable(x).RTSValue);
2122 : }
2123 :
2124 : // make the library call
2125 3 : state.dataExternalInterface->FMU(i).Instance(j).fmistatus =
2126 3 : fmiEPlusSetReal(&state.dataExternalInterface->FMU(i).Instance(j).fmicomponent,
2127 3 : &valRefVec[0],
2128 3 : &rtsValVec[0],
2129 3 : &state.dataExternalInterface->FMUTemp(i).Instance(j).NumInputVariablesInIDF,
2130 3 : &state.dataExternalInterface->FMU(i).Instance(j).Index);
2131 :
2132 3 : if (state.dataExternalInterface->FMU(i).Instance(j).fmistatus != fmiOK) {
2133 0 : ShowSevereError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: ");
2134 0 : ShowContinueError(state, "Error when trying to set inputs in instance");
2135 0 : ShowContinueError(state,
2136 0 : format("\"{}\" of FMU \"{}\"",
2137 0 : state.dataExternalInterface->FMU(i).Instance(j).Name,
2138 0 : state.dataExternalInterface->FMU(i).Name));
2139 0 : ShowContinueError(state, format("Error Code = \"{}\"", state.dataExternalInterface->FMU(i).Instance(j).fmistatus));
2140 0 : state.dataExternalInterface->ErrorsFound = true;
2141 0 : StopExternalInterfaceIfError(state);
2142 : }
2143 3 : }
2144 : }
2145 : // set the flag to reinitialize states to be true
2146 3 : state.dataExternalInterface->FlagReIni = true;
2147 3 : GetSetVariablesAndDoStepFMUImport(state);
2148 3 : state.dataExternalInterface->FlagReIni = false;
2149 : // advance one time step ahead for the next calculation
2150 3 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
2151 3 : state.dataExternalInterface->FirstCallTStep = false;
2152 : } else {
2153 140160 : if (state.dataExternalInterface->tComm != state.dataExternalInterface->tStop) {
2154 140157 : GetSetVariablesAndDoStepFMUImport(state);
2155 140157 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
2156 : } else {
2157 : // Terminate reset and free Slaves
2158 3 : state.dataExternalInterface->fmiEndSimulation = 1;
2159 3 : TerminateResetFreeFMUImport(state, state.dataExternalInterface->fmiEndSimulation);
2160 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2161 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
2162 : // Deallocate used objects
2163 3 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuInputVariable.deallocate();
2164 3 : state.dataExternalInterface->FMUTemp(i).Instance(j).eplusOutputVariable.deallocate();
2165 3 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableSchedule.deallocate();
2166 3 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableVariable.deallocate();
2167 3 : state.dataExternalInterface->FMUTemp(i).Instance(j).fmuOutputVariableActuator.deallocate();
2168 : }
2169 : }
2170 :
2171 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2172 3 : state.dataExternalInterface->FMUTemp(i).Instance.deallocate();
2173 : }
2174 :
2175 3 : state.dataExternalInterface->FMUTemp.deallocate();
2176 :
2177 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2178 6 : for (int j = 1; j <= state.dataExternalInterface->FMU(i).NumInstances; ++j) {
2179 3 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableSchedule.deallocate();
2180 3 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableSchedule.deallocate();
2181 3 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableVariable.deallocate();
2182 3 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableVariable.deallocate();
2183 3 : state.dataExternalInterface->FMU(i).Instance(j).eplusInputVariableActuator.deallocate();
2184 3 : state.dataExternalInterface->FMU(i).Instance(j).fmuOutputVariableActuator.deallocate();
2185 3 : state.dataExternalInterface->FMU(i).Instance(j).fmuInputVariable.deallocate();
2186 3 : state.dataExternalInterface->FMU(i).Instance(j).checkfmuInputVariable.deallocate();
2187 : }
2188 : }
2189 :
2190 6 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2191 3 : state.dataExternalInterface->FMU(i).Instance.deallocate();
2192 : }
2193 3 : state.dataExternalInterface->FMU.deallocate();
2194 : }
2195 : }
2196 : }
2197 143523 : }
2198 :
2199 3 : void ValidateRunControl(EnergyPlusData &state)
2200 : {
2201 : // SUBROUTINE INFORMATION:
2202 : // AUTHOR Michael Wetter
2203 : // DATE WRITTEN December 2009
2204 :
2205 : // PURPOSE OF THIS SUBROUTINE:
2206 : // This subroutine ensures that the RunControl object is valid.
2207 :
2208 : // METHODOLOGY EMPLOYED:
2209 : // Use GetObjectItem from the Input Processor
2210 :
2211 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2212 3 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
2213 :
2214 3 : cCurrentModuleObject = "SimulationControl";
2215 3 : int const NumRunControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
2216 3 : if (NumRunControl > 0) {
2217 2 : int NumAlphas = 0; // Number of Alphas for each GetObjectItem call
2218 2 : int NumNumbers = 0; // Number of Numbers for each GetObjectItem call
2219 2 : int IOStatus = 0; // Used in GetObjectItem
2220 6 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2221 : cCurrentModuleObject,
2222 : 1,
2223 2 : state.dataIPShortCut->cAlphaArgs,
2224 : NumAlphas,
2225 2 : state.dataIPShortCut->rNumericArgs,
2226 : NumNumbers,
2227 : IOStatus,
2228 : _,
2229 : _,
2230 2 : state.dataIPShortCut->cAlphaFieldNames,
2231 2 : state.dataIPShortCut->cNumericFieldNames);
2232 2 : if (state.dataIPShortCut->cAlphaArgs(5) == "NO") { // This run does not have a weather file simulation.
2233 0 : ShowSevereError(state, "ExternalInterface: Error in idf file, section SimulationControl:");
2234 0 : ShowContinueError(state, "When using the ExternalInterface, a run period from the weather file must be specified");
2235 0 : ShowContinueError(state, "in the idf file, because the ExternalInterface interface is not active during");
2236 0 : ShowContinueError(state, "warm-up and during sizing.");
2237 0 : state.dataExternalInterface->ErrorsFound = true;
2238 : }
2239 : }
2240 3 : }
2241 :
2242 0 : void CalcExternalInterface(EnergyPlusData &state)
2243 : {
2244 : // SUBROUTINE INFORMATION:
2245 : // AUTHOR Michael Wetter
2246 : // DATE WRITTEN 2Dec2007
2247 :
2248 : // SUBROUTINE PARAMETER DEFINITIONS:
2249 0 : int constexpr nDblMax(1024); // Maximum number of doubles
2250 :
2251 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2252 : Real64 curSimTim; // current simulation time
2253 : Real64 preSimTim; // previous time step's simulation time
2254 :
2255 0 : Array1D<Real64> dblValWri(nDblMax);
2256 0 : Array1D<Real64> dblValRea(nDblMax);
2257 :
2258 0 : if (state.dataExternalInterface->firstCall) {
2259 0 : DisplayString(state, "ExternalInterface starts first data exchange.");
2260 0 : state.dataExternalInterface->simulationStatus = 2;
2261 0 : preSimTim = 0; // In the first call, E+ did not reset SimTimeSteps to zero
2262 : } else {
2263 0 : preSimTim = state.dataGlobal->SimTimeSteps * state.dataGlobal->MinutesPerTimeStep * 60.0;
2264 : }
2265 :
2266 : // Socket asked to terminate simulation, but simulation continues
2267 0 : if (state.dataExternalInterface->noMoreValues && state.dataExternalInterface->showContinuationWithoutUpdate) {
2268 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB) {
2269 0 : ShowWarningError(
2270 0 : state, format("ExternalInterface: Continue simulation without updated values from server at t ={:.2T} hours", preSimTim / 3600.0));
2271 : }
2272 0 : state.dataExternalInterface->showContinuationWithoutUpdate = false;
2273 : }
2274 :
2275 : // Usual branch, control is configured and simulation should continue
2276 0 : if (state.dataExternalInterface->configuredControlPoints && (!state.dataExternalInterface->noMoreValues)) {
2277 : // Data to be exchanged
2278 0 : int nDblWri = size(state.dataExternalInterface->varTypes); // number of doubles to write to socket
2279 0 : int nDblRea = 0; // number of doubles to read from socket
2280 0 : int flaWri = 0; // flag to write to the socket
2281 :
2282 : // Get EnergyPlus variables
2283 0 : if (state.dataExternalInterface->firstCall) { // bug fix causing external interface to send zero at the beginning of sim, Thierry Nouidui
2284 0 : for (int i = 1; i <= nDblWri; ++i) {
2285 0 : dblValWri(i) =
2286 0 : GetInternalVariableValue(state, state.dataExternalInterface->varTypes(i), state.dataExternalInterface->keyVarIndexes(i));
2287 : }
2288 : } else {
2289 0 : for (int i = 1; i <= nDblWri; ++i) {
2290 0 : dblValWri(i) = GetInternalVariableValueExternalInterface(
2291 0 : state, state.dataExternalInterface->varTypes(i), state.dataExternalInterface->keyVarIndexes(i));
2292 : }
2293 : }
2294 :
2295 : // Exchange data with socket
2296 0 : int retVal = 0;
2297 0 : int flaRea = 0; // flag read from the socket
2298 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB) {
2299 0 : retVal = exchangedoubleswithsocket(&state.dataExternalInterface->socketFD,
2300 : &flaWri,
2301 : &flaRea,
2302 : &nDblWri,
2303 : &nDblRea,
2304 : &preSimTim,
2305 : dblValWri.data(),
2306 : &curSimTim,
2307 : dblValRea.data());
2308 0 : } else if (state.dataExternalInterface->haveExternalInterfaceFMUExport) {
2309 0 : retVal = exchangedoubleswithsocketFMU(&state.dataExternalInterface->socketFD,
2310 : &flaWri,
2311 : &flaRea,
2312 : &nDblWri,
2313 : &nDblRea,
2314 : &preSimTim,
2315 : dblValWri.data(),
2316 : &curSimTim,
2317 : dblValRea.data(),
2318 0 : &state.dataExternalInterface->FMUExportActivate);
2319 : }
2320 0 : bool continueSimulation = true;
2321 :
2322 : // Check for errors, in which case we terminate the simulation loop
2323 : // Added a check since the FMUExport is terminated with the flaRea set to 1.
2324 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB ||
2325 0 : (state.dataExternalInterface->haveExternalInterfaceFMUExport && (flaRea == 0))) {
2326 0 : if (retVal != 0) {
2327 0 : continueSimulation = false;
2328 0 : ShowSevereError(state,
2329 0 : format("ExternalInterface: Socket communication received error value \"{:2}\" at time = {:.2T} hours.",
2330 : retVal,
2331 0 : preSimTim / 3600));
2332 0 : ShowContinueError(state, format("ExternalInterface: Flag from server \"{:2}\".", flaRea));
2333 0 : state.dataExternalInterface->ErrorsFound = true;
2334 0 : StopExternalInterfaceIfError(state);
2335 : }
2336 : }
2337 :
2338 : // Check communication flag
2339 0 : if (flaRea != 0) {
2340 : // No more values will be received in future steps
2341 : // Added a check since the FMUExport is terminated with the flaRea set to 1.
2342 0 : state.dataExternalInterface->noMoreValues = true;
2343 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB) {
2344 0 : ShowSevereError(state, format("ExternalInterface: Received end of simulation flag at time = {:.2T} hours.", preSimTim / 3600));
2345 0 : StopExternalInterfaceIfError(state);
2346 : }
2347 : }
2348 :
2349 : // Make sure we get the right number of double values, unless retVal != 0
2350 0 : if ((flaRea == 0) && (!state.dataExternalInterface->ErrorsFound) && continueSimulation &&
2351 0 : (nDblRea != isize(state.dataExternalInterface->varInd))) {
2352 0 : ShowSevereError(
2353 : state,
2354 0 : format("ExternalInterface: Received \"{}\" double values, expected \"{}\".", nDblRea, size(state.dataExternalInterface->varInd)));
2355 0 : state.dataExternalInterface->ErrorsFound = true;
2356 0 : StopExternalInterfaceIfError(state);
2357 : }
2358 :
2359 : // No errors found. Assign exchanged variables
2360 0 : if ((flaRea == 0) && continueSimulation) {
2361 0 : for (int i = 1; i <= isize(state.dataExternalInterface->varInd); ++i) {
2362 0 : if (state.dataExternalInterface->inpVarTypes(i) == indexSchedule) {
2363 0 : ScheduleManager::ExternalInterfaceSetSchedule(state, state.dataExternalInterface->varInd(i), dblValRea(i));
2364 0 : } else if ((state.dataExternalInterface->inpVarTypes(i) == indexVariable) ||
2365 0 : (state.dataExternalInterface->inpVarTypes(i) == indexActuator)) {
2366 0 : RuntimeLanguageProcessor::ExternalInterfaceSetErlVariable(state, state.dataExternalInterface->varInd(i), dblValRea(i));
2367 : } else {
2368 0 : ShowContinueError(state, "ExternalInterface: Error in finding the type of the input variable for EnergyPlus");
2369 0 : ShowContinueError(state, format("variable index: {}. Variable will not be updated.", i));
2370 : }
2371 : }
2372 : }
2373 : }
2374 :
2375 : // If we have Erl variables, we need to call ManageEMS so that they get updated in the Erl data structure
2376 0 : if (state.dataExternalInterface->useEMS) {
2377 : bool anyRan;
2378 0 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::ExternalInterface, anyRan, ObjexxFCL::Optional_int_const());
2379 : }
2380 :
2381 0 : state.dataExternalInterface->firstCall = false; // bug fix causing external interface to send zero at the beginning of sim, Thierry Nouidui
2382 0 : }
2383 :
2384 8 : void GetReportVariableKey(
2385 : EnergyPlusData &state,
2386 : const Array1D_string &varKeys, // Standard variable name
2387 : int const numberOfKeys, // Number of keys=size(state.dataExternalInterface->varKeys)
2388 : const Array1D_string &VarNames, // Standard variable name
2389 : Array1D_int &keyVarIndexes, // Array index
2390 : Array1D<OutputProcessor::VariableType> &varTypes // Types of variables in state.dataExternalInterface->keystate.dataExternalInterface->varIndexes
2391 : )
2392 : {
2393 : // SUBROUTINE INFORMATION:
2394 : // AUTHOR Michael Wetter
2395 : // DATE WRITTEN 2Dec2007
2396 :
2397 : // PURPOSE OF THIS SUBROUTINE:
2398 : // Gets the sensor key index and type for the specified variable key and name
2399 :
2400 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2401 8 : OutputProcessor::VariableType varType(OutputProcessor::VariableType::Invalid); // 0=not found, 1=integer, 2=real, 3=meter
2402 8 : int numKeys(0); // Number of keys found
2403 8 : OutputProcessor::StoreType varAvgSum(OutputProcessor::StoreType::Average); // Variable is Averaged=1 or Summed=2
2404 8 : OutputProcessor::TimeStepType varStepType(OutputProcessor::TimeStepType::Zone); // Variable time step is Zone=1 or HVAC=2
2405 8 : Constant::Units varUnits(Constant::Units::None); // Units sting, may be blank
2406 8 : Array1D_string keyNames;
2407 8 : Array1D_int keyIndexes; // Array index for
2408 : int Loop, iKey; // Loop counters
2409 :
2410 : // Get pointers for variables to be sent to Ptolemy
2411 16 : for (Loop = 1; Loop <= numberOfKeys; ++Loop) {
2412 8 : GetVariableKeyCountandType(state, VarNames(Loop), numKeys, varType, varAvgSum, varStepType, varUnits);
2413 8 : if (varType != OutputProcessor::VariableType::Invalid) {
2414 8 : keyIndexes.allocate(numKeys);
2415 8 : keyNames.allocate(numKeys);
2416 8 : GetVariableKeys(state, VarNames(Loop), varType, keyNames, keyIndexes);
2417 : // Find key index whose keyName is equal to keyNames(Loop)
2418 8 : int max(keyIndexes.size());
2419 8 : for (iKey = 1; iKey <= max; ++iKey) {
2420 8 : if (keyNames(iKey) == varKeys(Loop)) {
2421 8 : keyVarIndexes(Loop) = keyIndexes(iKey);
2422 8 : varTypes(Loop) = varType;
2423 8 : break;
2424 : }
2425 : }
2426 8 : keyIndexes.deallocate();
2427 8 : keyNames.deallocate();
2428 : }
2429 8 : if ((varType == OutputProcessor::VariableType::Invalid) || (iKey > numKeys)) {
2430 0 : ShowSevereError(state,
2431 0 : format("ExternalInterface: Simulation model has no variable \"{}\" with key \"{}\".", VarNames(Loop), varKeys(Loop)));
2432 0 : state.dataExternalInterface->ErrorsFound = true;
2433 : }
2434 : }
2435 8 : }
2436 :
2437 7146 : void WarnIfExternalInterfaceObjectsAreUsed(EnergyPlusData &state, std::string const &ObjectWord)
2438 : {
2439 : // SUBROUTINE INFORMATION:
2440 : // AUTHOR Michael Wetter
2441 : // DATE WRITTEN December 2009
2442 :
2443 : // PURPOSE OF THIS SUBROUTINE:
2444 : // This subroutine writes a warning if ExternalInterface objects are used in the
2445 : // idf file, but the ExternalInterface link is not specified.
2446 :
2447 7146 : int const NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjectWord);
2448 7146 : if (NumObjects > 0) {
2449 0 : ShowWarningError(state, format("IDF file contains object \"{}\",", ObjectWord));
2450 0 : ShowContinueError(state, "but object \"ExternalInterface\" with appropriate key entry is not specified. Values will not be updated.");
2451 : }
2452 7146 : }
2453 :
2454 3 : void VerifyExternalInterfaceObject(EnergyPlusData &state)
2455 : {
2456 : // SUBROUTINE INFORMATION:
2457 : // AUTHOR Michael Wetter
2458 : // DATE WRITTEN 12Dec2009
2459 :
2460 : // PURPOSE OF THIS SUBROUTINE:
2461 : // This subroutine verifies the correctness of the fields of
2462 : // the ExternalInterface object in the idf file
2463 :
2464 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2465 3 : int NumAlphas(0); // Number of Alphas for each GetObjectItem call
2466 3 : int NumNumbers(0); // Number of Numbers for each GetObjectItem call
2467 3 : int IOStatus(0); // Used in GetObjectItem
2468 3 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
2469 :
2470 3 : cCurrentModuleObject = "ExternalInterface";
2471 9 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2472 : cCurrentModuleObject,
2473 : 1,
2474 3 : state.dataIPShortCut->cAlphaArgs,
2475 : NumAlphas,
2476 3 : state.dataIPShortCut->rNumericArgs,
2477 : NumNumbers,
2478 : IOStatus,
2479 : _,
2480 : _,
2481 3 : state.dataIPShortCut->cAlphaFieldNames,
2482 3 : state.dataIPShortCut->cNumericFieldNames);
2483 3 : if ((!Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "PtolemyServer")) &&
2484 3 : (!Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "FunctionalMockupUnitImport")) &&
2485 3 : (!Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "FunctionalMockupUnitExport"))) {
2486 0 : ShowSevereError(state,
2487 0 : format("VerifyExternalInterfaceObject: {}, invalid {}=\"{}\".",
2488 : cCurrentModuleObject,
2489 0 : state.dataIPShortCut->cAlphaFieldNames(1),
2490 0 : state.dataIPShortCut->cAlphaArgs(1)));
2491 0 : ShowContinueError(state, "only \"PtolemyServer or FunctionalMockupUnitImport or FunctionalMockupUnitExport\" allowed.");
2492 0 : state.dataExternalInterface->ErrorsFound = true;
2493 : }
2494 3 : }
2495 :
2496 33 : std::vector<char> getCharArrayFromString(std::string const &originalString)
2497 : {
2498 : // c_str returns null terminated, so we don't need a +1?
2499 33 : return std::vector<char>(originalString.c_str(), originalString.c_str() + originalString.size());
2500 : }
2501 :
2502 16 : std::string getStringFromCharArray(std::vector<char> originalCharArray)
2503 : {
2504 16 : originalCharArray.push_back('\0');
2505 16 : return std::string(&originalCharArray.front());
2506 : }
2507 :
2508 : } // namespace EnergyPlus::ExternalInterface
|