Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, 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 165881 : 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 165881 : if (state.dataExternalInterface->GetInputFlag) {
109 65 : GetExternalInterfaceInput(state);
110 65 : state.dataExternalInterface->GetInputFlag = false;
111 : }
112 :
113 165881 : 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 165881 : if (state.dataExternalInterface->haveExternalInterfaceFMUImport) {
124 0 : std::string errorMessage; // Error message
125 0 : errorMessage.reserve(100);
126 0 : char *errorMessagePtr(errorMessage.data());
127 0 : const int retValErrMsg = checkOperatingSystem(errorMessagePtr);
128 0 : 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 0 : InitExternalInterfaceFMUImport(state);
135 : // No Data exchange during design days
136 : // Data Exchange data during warmup and after warmup
137 0 : CalcExternalInterfaceFMUImport(state);
138 0 : }
139 165881 : }
140 :
141 65 : 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 65 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
159 65 : cCurrentModuleObject = "ExternalInterface";
160 65 : state.dataExternalInterface->NumExternalInterfaces = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
161 :
162 65 : for (int Loop = 1; Loop <= state.dataExternalInterface->NumExternalInterfaces;
163 : ++Loop) { // This loop determines whether the external interface is for FMU or BCVTB
164 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
165 : cCurrentModuleObject,
166 : Loop,
167 0 : state.dataIPShortCut->cAlphaArgs,
168 : NumAlphas,
169 0 : state.dataIPShortCut->rNumericArgs,
170 : NumNumbers,
171 : IOStatus,
172 : _,
173 : _,
174 0 : state.dataIPShortCut->cAlphaFieldNames,
175 0 : state.dataIPShortCut->cNumericFieldNames);
176 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "PtolemyServer")) { // The BCVTB interface is activated.
177 0 : ++state.dataExternalInterface->NumExternalInterfacesBCVTB;
178 0 : } else if (Util::SameString(state.dataIPShortCut->cAlphaArgs(1),
179 : "FunctionalMockupUnitImport")) { // The functional mock up unit import interface is activated.
180 0 : ++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 65 : if (state.dataExternalInterface->NumExternalInterfacesBCVTB == 0) {
189 130 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:Schedule");
190 130 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:Variable");
191 130 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:Actuator");
192 : }
193 :
194 : // Check if objects are used although FMUExport interface is not defined
195 65 : if (state.dataExternalInterface->NumExternalInterfacesFMUExport == 0) {
196 130 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitExport:To:Schedule");
197 130 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitExport:To:Variable");
198 130 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitExport:To:Actuator");
199 : }
200 :
201 : // Check if objects are used although FMU Import interface is not defined
202 65 : if (state.dataExternalInterface->NumExternalInterfacesFMUImport == 0) {
203 130 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitImport:To:Schedule");
204 130 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitImport:To:Variable");
205 130 : WarnIfExternalInterfaceObjectsAreUsed(state, "ExternalInterface:FunctionalMockupUnitImport:To:Actuator");
206 : }
207 :
208 65 : 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 65 : } 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 65 : } 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 65 : if ((state.dataExternalInterface->NumExternalInterfacesFMUImport == 1) && (state.dataExternalInterface->NumExternalInterfacesFMUExport == 0)) {
231 0 : state.dataExternalInterface->haveExternalInterfaceFMUImport = true;
232 0 : DisplayString(state, "Instantiating FunctionalMockupUnitImport interface");
233 0 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport";
234 0 : state.dataExternalInterface->NumFMUObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
235 0 : VerifyExternalInterfaceObject(state);
236 65 : } 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 65 : 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 65 : 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 65 : 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 65 : if (state.dataExternalInterface->ErrorsFound) {
261 0 : ShowFatalError(state, "GetExternalInterfaceInput: preceding conditions cause termination.");
262 : }
263 :
264 65 : StopExternalInterfaceIfError(state);
265 65 : }
266 :
267 65 : 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 65 : int constexpr flag1(-10);
280 65 : int constexpr flag2(-20);
281 :
282 65 : 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 65 : if (state.dataExternalInterface->NumExternalInterfacesFMUImport != 0) {
301 0 : if (state.dataExternalInterface->ErrorsFound) {
302 0 : ShowFatalError(state, "ExternalInterface/StopExternalInterfaceIfError: Error in ExternalInterface: Check EnergyPlus *.err file.");
303 : }
304 : }
305 65 : }
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) = Sched::GetDayScheduleNum(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 0 : 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 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
594 0 : auto &fmu = state.dataExternalInterface->FMU(i);
595 0 : auto &fmuTemp = state.dataExternalInterface->FMUTemp(i);
596 :
597 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
598 0 : auto &fmuInst = fmu.Instance(j);
599 0 : auto &fmuTempInst = fmuTemp.Instance(j);
600 :
601 0 : if (state.dataExternalInterface->FlagReIni) {
602 : // Get from FMUs, values that will be set in EnergyPlus (Schedule)
603 0 : for (int k = 1; k <= fmuTempInst.NumOutputVariablesSchedule; ++k) {
604 0 : fmuInst.fmuOutputVariableSchedule(k).RealVarValue = fmuTempInst.fmuOutputVariableSchedule(k).RealVarValue;
605 : }
606 :
607 : // Get from FMUs, values that will be set in EnergyPlus (Variable)
608 0 : for (int k = 1; k <= fmuTempInst.NumOutputVariablesVariable; ++k) {
609 0 : fmuInst.fmuOutputVariableVariable(k).RealVarValue = fmuTempInst.fmuOutputVariableVariable(k).RealVarValue;
610 : }
611 :
612 : // Get from FMUs, values that will be set in EnergyPlus (Actuator)
613 0 : for (int k = 1; k <= fmuTempInst.NumOutputVariablesActuator; ++k) {
614 0 : fmuInst.fmuOutputVariableActuator(k).RealVarValue = fmuTempInst.fmuOutputVariableActuator(k).RealVarValue;
615 : }
616 : } else {
617 : // Get from FMUs, values that will be set in EnergyPlus (Schedule)
618 :
619 0 : if (size(fmuInst.fmuOutputVariableSchedule) > 0) {
620 :
621 : // generate vectors here first
622 0 : std::vector<unsigned int> valueReferenceVec;
623 0 : std::vector<Real64> realVarValueVec;
624 0 : for (unsigned long x = 1; x <= size(fmuInst.fmuOutputVariableSchedule); ++x) {
625 0 : valueReferenceVec.push_back(fmuInst.fmuOutputVariableSchedule(x).ValueReference);
626 0 : realVarValueVec.push_back(fmuInst.fmuOutputVariableSchedule(x).RealVarValue);
627 : }
628 :
629 : // pass in the vectors as pointers to the first member of the vector
630 0 : fmuInst.fmistatus = fmiEPlusGetReal(
631 0 : &fmuInst.fmicomponent, &valueReferenceVec[0], &realVarValueVec[0], &fmuInst.NumOutputVariablesSchedule, &fmuInst.Index);
632 :
633 0 : for (unsigned long x = 1; x <= size(fmuInst.fmuOutputVariableSchedule); ++x) {
634 0 : fmuInst.fmuOutputVariableSchedule(x).ValueReference = valueReferenceVec[x - 1];
635 0 : fmuInst.fmuOutputVariableSchedule(x).RealVarValue = realVarValueVec[x - 1];
636 : }
637 :
638 0 : if (fmuInst.fmistatus != fmiOK) {
639 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to get outputs");
640 0 : ShowContinueError(state, format("in instance \"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
641 0 : ShowContinueError(state, format("Error Code = \"{}\"", fmuInst.fmistatus));
642 0 : state.dataExternalInterface->ErrorsFound = true;
643 0 : StopExternalInterfaceIfError(state);
644 : }
645 0 : }
646 :
647 : // generate vectors here first
648 0 : if (size(fmuInst.fmuOutputVariableVariable) > 0) {
649 :
650 0 : std::vector<unsigned int> valueReferenceVec2;
651 0 : std::vector<Real64> realVarValueVec2;
652 0 : for (unsigned long x = 1; x <= size(fmuInst.fmuOutputVariableVariable); ++x) {
653 0 : valueReferenceVec2.push_back(fmuInst.fmuOutputVariableVariable(x).ValueReference);
654 0 : realVarValueVec2.push_back(fmuInst.fmuOutputVariableVariable(x).RealVarValue);
655 : }
656 :
657 : // pass in the vectors as pointers to the first member of the vector
658 0 : fmuInst.fmistatus = fmiEPlusGetReal(
659 0 : &fmuInst.fmicomponent, &valueReferenceVec2[0], &realVarValueVec2[0], &fmuInst.NumOutputVariablesVariable, &fmuInst.Index);
660 :
661 0 : for (unsigned long x = 1; x <= size(fmuInst.fmuOutputVariableVariable); ++x) {
662 0 : fmuInst.fmuOutputVariableVariable(x).ValueReference = valueReferenceVec2[x - 1];
663 0 : fmuInst.fmuOutputVariableVariable(x).RealVarValue = realVarValueVec2[x - 1];
664 : }
665 :
666 0 : if (fmuInst.fmistatus != fmiOK) {
667 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to get outputs");
668 0 : ShowContinueError(state, format("in instance \"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
669 0 : ShowContinueError(state, format("Error Code = \"{}\"", fmuInst.fmistatus));
670 0 : state.dataExternalInterface->ErrorsFound = true;
671 0 : StopExternalInterfaceIfError(state);
672 : }
673 0 : }
674 :
675 0 : if (size(fmuInst.fmuOutputVariableActuator) > 0) {
676 :
677 : // generate vectors here first
678 0 : std::vector<unsigned int> valueReferenceVec3;
679 0 : std::vector<Real64> realVarValueVec3;
680 0 : for (unsigned long x = 1; x <= size(fmuInst.fmuOutputVariableActuator); ++x) {
681 0 : valueReferenceVec3.push_back(fmuInst.fmuOutputVariableActuator(x).ValueReference);
682 0 : realVarValueVec3.push_back(fmuInst.fmuOutputVariableActuator(x).RealVarValue);
683 : }
684 :
685 : // pass in the vectors as pointers to the first member of the vector
686 0 : fmuInst.fmistatus = fmiEPlusGetReal(
687 0 : &fmuInst.fmicomponent, &valueReferenceVec3[0], &realVarValueVec3[0], &fmuInst.NumOutputVariablesActuator, &fmuInst.Index);
688 :
689 0 : for (unsigned long x = 1; x <= size(fmuInst.fmuOutputVariableActuator); ++x) {
690 0 : fmuInst.fmuOutputVariableActuator(x).ValueReference = valueReferenceVec3[x - 1];
691 0 : fmuInst.fmuOutputVariableActuator(x).RealVarValue = realVarValueVec3[x - 1];
692 : }
693 :
694 0 : if (fmuInst.fmistatus != fmiOK) {
695 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to get outputs");
696 0 : ShowContinueError(state, format("in instance \"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
697 0 : ShowContinueError(state, format("Error Code = \"{}\"", fmuInst.fmistatus));
698 0 : state.dataExternalInterface->ErrorsFound = true;
699 0 : StopExternalInterfaceIfError(state);
700 : }
701 0 : }
702 : }
703 :
704 : // Set in EnergyPlus the values of the schedules
705 0 : for (int k = 1; k <= fmuInst.NumOutputVariablesSchedule; ++k) {
706 0 : Sched::ExternalInterfaceSetSchedule(
707 0 : state, fmuInst.eplusInputVariableSchedule(k).VarIndex, fmuInst.fmuOutputVariableSchedule(k).RealVarValue);
708 : }
709 :
710 : // Set in EnergyPlus the values of the variables
711 0 : for (int k = 1; k <= fmuInst.NumOutputVariablesVariable; ++k) {
712 0 : RuntimeLanguageProcessor::ExternalInterfaceSetErlVariable(
713 0 : state, fmuInst.eplusInputVariableVariable(k).VarIndex, fmuInst.fmuOutputVariableVariable(k).RealVarValue);
714 : }
715 :
716 : // Set in EnergyPlus the values of the actuators
717 0 : for (int k = 1; k <= fmuInst.NumOutputVariablesActuator; ++k) {
718 0 : RuntimeLanguageProcessor::ExternalInterfaceSetErlVariable(
719 0 : state, fmuInst.eplusInputVariableActuator(k).VarIndex, fmuInst.fmuOutputVariableActuator(k).RealVarValue);
720 : }
721 :
722 0 : if (state.dataExternalInterface->FirstCallGetSetDoStep) {
723 : // Get from EnergyPlus, values that will be set in fmus
724 0 : for (int k = 1; k <= fmuInst.NumInputVariablesInIDF; ++k) {
725 : // This make sure that the variables are updated at the Zone Time Step
726 0 : fmuInst.eplusOutputVariable(k).RTSValue =
727 0 : GetInternalVariableValue(state, fmuInst.eplusOutputVariable(k).VarType, fmuInst.eplusOutputVariable(k).VarIndex);
728 : }
729 : } else {
730 : // Get from EnergyPlus, values that will be set in fmus
731 0 : for (int k = 1; k <= fmuInst.NumInputVariablesInIDF; ++k) {
732 : // This make sure that the variables are updated at the Zone Time Step
733 0 : fmuInst.eplusOutputVariable(k).RTSValue = GetInternalVariableValueExternalInterface(
734 0 : state, fmuInst.eplusOutputVariable(k).VarType, fmuInst.eplusOutputVariable(k).VarIndex);
735 : }
736 : }
737 :
738 0 : if (!state.dataExternalInterface->FlagReIni) {
739 :
740 : // generate vectors here first
741 0 : std::vector<unsigned int> valueReferenceVec4;
742 0 : for (unsigned long x = 1; x <= size(fmuInst.fmuInputVariable); ++x) {
743 0 : valueReferenceVec4.push_back(fmuInst.fmuInputVariable(x).ValueReference);
744 : }
745 :
746 0 : std::vector<Real64> rtsValueVec4;
747 0 : for (unsigned long x = 1; x <= size(fmuInst.eplusOutputVariable); ++x) {
748 0 : rtsValueVec4.push_back(fmuInst.eplusOutputVariable(x).RTSValue);
749 : }
750 :
751 0 : fmuInst.fmistatus =
752 0 : fmiEPlusSetReal(&fmuInst.fmicomponent, &valueReferenceVec4[0], &rtsValueVec4[0], &fmuInst.NumInputVariablesInIDF, &fmuInst.Index);
753 :
754 0 : if (fmuInst.fmistatus != fmiOK) {
755 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to set inputs");
756 0 : ShowContinueError(state, format("in instance \"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
757 0 : ShowContinueError(state, format("Error Code = \"{}\"", fmuInst.fmistatus));
758 0 : state.dataExternalInterface->ErrorsFound = true;
759 0 : StopExternalInterfaceIfError(state);
760 : }
761 0 : }
762 0 : int localfmitrue(fmiTrue);
763 : // Call and simulate the FMUs to get values at the corresponding timestep.
764 0 : fmuInst.fmistatus = fmiEPlusDoStep(
765 0 : &fmuInst.fmicomponent, &state.dataExternalInterface->tComm, &state.dataExternalInterface->hStep, &localfmitrue, &fmuInst.Index);
766 0 : if (fmuInst.fmistatus != fmiOK) {
767 0 : ShowSevereError(state, "ExternalInterface/GetSetVariablesAndDoStepFMUImport: Error when trying to");
768 0 : ShowContinueError(state, format("do the coSimulation with instance \"{}\"", fmuInst.Name));
769 0 : ShowContinueError(state, format("of FMU \"{}\"", fmu.Name));
770 0 : ShowContinueError(state, format("Error Code = \"{}\"", fmuInst.fmistatus));
771 0 : state.dataExternalInterface->ErrorsFound = true;
772 0 : StopExternalInterfaceIfError(state);
773 : }
774 : }
775 : }
776 :
777 : // If we have Erl variables, we need to call ManageEMS so that they get updated in the Erl data structure
778 0 : if (state.dataExternalInterface->useEMS) {
779 : bool anyRan;
780 0 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::ExternalInterface, anyRan, ObjexxFCL::Optional_int_const());
781 : }
782 :
783 0 : state.dataExternalInterface->FirstCallGetSetDoStep = false;
784 0 : }
785 :
786 0 : void InstantiateInitializeFMUImport(EnergyPlusData &state)
787 : {
788 : // SUBROUTINE INFORMATION:
789 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
790 : // DATE WRITTEN 08Aug2011
791 :
792 : // PURPOSE OF THIS SUBROUTINE:
793 : // This routine instantiates and initializes FMUs.
794 :
795 : // Instantiate FMUs
796 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
797 0 : auto &fmu = state.dataExternalInterface->FMU(i);
798 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
799 0 : auto &fmuInst = fmu.Instance(j);
800 0 : std::string const folderStr = FileSystem::toString(fmuInst.WorkingFolder);
801 0 : fmuInst.fmicomponent = fmiEPlusInstantiateSlave(
802 0 : (char *)folderStr.c_str(), &fmuInst.LenWorkingFolder, &fmu.TimeOut, &fmu.Visible, &fmu.Interactive, &fmu.LoggingOn, &fmuInst.Index);
803 : // TODO: This is doing a null pointer check; OK?
804 0 : if (!fmuInst.fmicomponent) {
805 0 : ShowSevereError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: Error when trying to instantiate");
806 0 : ShowContinueError(state, format("instance \"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
807 0 : state.dataExternalInterface->ErrorsFound = true;
808 0 : StopExternalInterfaceIfError(state);
809 : }
810 0 : }
811 : }
812 :
813 : // Initialize FMUs
814 0 : int localfmiTrue(fmiTrue);
815 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
816 0 : auto &fmu = state.dataExternalInterface->FMU(i);
817 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
818 0 : auto &fmuInst = fmu.Instance(j);
819 0 : fmuInst.fmistatus = fmiEPlusInitializeSlave(
820 0 : &fmuInst.fmicomponent, &state.dataExternalInterface->tStart, &localfmiTrue, &state.dataExternalInterface->tStop, &fmuInst.Index);
821 0 : if (fmuInst.fmistatus != fmiOK) {
822 0 : ShowSevereError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: Error when trying to initialize");
823 0 : ShowContinueError(state, format("instance \"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
824 0 : ShowContinueError(state, format("Error Code = \"{}\"", fmuInst.fmistatus));
825 0 : state.dataExternalInterface->ErrorsFound = true;
826 0 : StopExternalInterfaceIfError(state);
827 : }
828 : }
829 : }
830 0 : }
831 :
832 0 : void InitializeFMU(EnergyPlusData &state)
833 : {
834 : // SUBROUTINE INFORMATION:
835 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
836 : // DATE WRITTEN 08Aug2011
837 :
838 : // PURPOSE OF THIS SUBROUTINE:
839 : // This routine reinitializes FMUs.
840 :
841 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
842 0 : int localfmiTrue(fmiTrue);
843 :
844 : // Initialize FMUs
845 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
846 0 : auto &fmu = state.dataExternalInterface->FMU(i);
847 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
848 0 : auto &fmuInst = fmu.Instance(j);
849 0 : fmuInst.fmistatus = fmiEPlusInitializeSlave(
850 0 : &fmuInst.fmicomponent, &state.dataExternalInterface->tStart, &localfmiTrue, &state.dataExternalInterface->tStop, &fmuInst.Index);
851 0 : if (fmuInst.fmistatus != fmiOK) {
852 0 : ShowSevereError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: Error when trying to initialize");
853 0 : ShowContinueError(state, format("instance \"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
854 0 : ShowContinueError(state, format("Error Code = \"{}\"", fmuInst.fmistatus));
855 0 : state.dataExternalInterface->ErrorsFound = true;
856 0 : StopExternalInterfaceIfError(state);
857 : }
858 : }
859 : }
860 0 : }
861 :
862 0 : void TerminateResetFreeFMUImport(EnergyPlusData &state, int fmiEndSimulation)
863 : {
864 : // SUBROUTINE INFORMATION:
865 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
866 : // DATE WRITTEN 08Aug2011
867 :
868 : // PURPOSE OF THIS SUBROUTINE:
869 : // This routine terminates the FMUs instances
870 :
871 : //----Needs to have function that allows to terminates FMU. Was not defined in version 1.0 -- fixme
872 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
873 0 : auto &fmu = state.dataExternalInterface->FMU(i);
874 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
875 0 : auto &fmuInst = fmu.Instance(j);
876 0 : if (fmuInst.fmistatus != fmiFatal) {
877 : // Cleanup slaves
878 0 : fmuInst.fmistatus = fmiEPlusFreeSlave(&fmuInst.fmicomponent, &fmuInst.Index, &fmiEndSimulation);
879 : }
880 : // check if fmiComponent has been freed
881 0 : if (!fmuInst.fmicomponent) {
882 0 : ShowSevereError(state, "ExternalInterface/TerminateResetFreeFMUImport: Error when trying to terminate");
883 0 : ShowContinueError(state, format("instance \"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
884 0 : state.dataExternalInterface->ErrorsFound = true;
885 0 : StopExternalInterfaceIfError(state);
886 : }
887 : }
888 : }
889 0 : }
890 :
891 0 : void InitExternalInterfaceFMUImport(EnergyPlusData &state)
892 : {
893 :
894 : // SUBROUTINE INFORMATION:
895 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
896 : // DATE WRITTEN 08Aug2011
897 :
898 : // PURPOSE OF THIS SUBROUTINE:
899 : // This routine initializes the input and outputs variables used for the co-simulation with FMUs.
900 :
901 : // Locals
902 0 : Array1D_int keyIndexes(1); // Array index for
903 0 : Array1D<OutputProcessor::VariableType> varTypes(1); // Array index for
904 0 : Array1D_string NamesOfKeys(1); // Specific key name
905 0 : Array1D_string NameListInstances(5);
906 0 : fs::path tempFullFilePath;
907 :
908 0 : Array1D_string strippedFileName; // remove path from entered file name
909 0 : Array1D_string fullFileName; // entered file name/found
910 :
911 0 : if (state.dataExternalInterface->FirstCallIni) {
912 0 : DisplayString(state, "Initializing FunctionalMockupUnitImport interface");
913 : // do one time initializations
914 0 : ValidateRunControl(state);
915 0 : state.dataExternalInterface->FMU.allocate(state.dataExternalInterface->NumFMUObjects);
916 :
917 : // there used to be code in here to apply the root working folder to create an absolute path
918 : // however, this wasn't working, as the root working folder was coming back empty
919 : // in any case, the relative paths work fine here
920 :
921 : // post process as needed in case these are used later
922 0 : state.dataExternalInterface->FMURootWorkingFolder = fs::path("tmp-fmus"); // getStringFromCharArray( FMUWorkingFolderCharArr );
923 :
924 : // Get and store the names of all FMUs in EnergyPlus data structure
925 0 : strippedFileName.allocate(state.dataExternalInterface->NumFMUObjects);
926 0 : fullFileName.allocate(state.dataExternalInterface->NumFMUObjects);
927 :
928 0 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
929 0 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport";
930 0 : int NumAlphas = 0; // Number of Alphas for each GetObjectItem call
931 0 : int NumNumbers = 0; // Number of Numbers for each GetObjectItem call
932 0 : int IOStatus = 0; // Used in GetObjectItem
933 0 : for (int Loop = 1; Loop <= state.dataExternalInterface->NumFMUObjects; ++Loop) {
934 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
935 : cCurrentModuleObject,
936 : Loop,
937 0 : state.dataIPShortCut->cAlphaArgs,
938 : NumAlphas,
939 0 : state.dataIPShortCut->rNumericArgs,
940 : NumNumbers,
941 : IOStatus,
942 : _,
943 : _,
944 0 : state.dataIPShortCut->cAlphaFieldNames,
945 0 : state.dataIPShortCut->cNumericFieldNames);
946 : // Get the FMU name
947 0 : state.dataExternalInterface->FMU(Loop).Name = state.dataIPShortCut->cAlphaArgs(1);
948 :
949 0 : fs::path inputPath = FileSystem::makeNativePath(state.dataExternalInterface->FMU(Loop).Name);
950 :
951 0 : std::string contextString = cCurrentModuleObject + ", " + state.dataIPShortCut->cAlphaFieldNames(1) + ": ";
952 :
953 0 : tempFullFilePath = DataSystemVariables::CheckForActualFilePath(state, inputPath, contextString);
954 0 : if (!tempFullFilePath.empty()) {
955 :
956 : // TODO: eliminate this old block once confident
957 0 : std::string::size_type pos = index(state.dataExternalInterface->FMU(Loop).Name, DataStringGlobals::pathChar, true); // look backwards
958 0 : if (pos != std::string::npos) {
959 0 : strippedFileName(Loop) = state.dataExternalInterface->FMU(Loop).Name.substr(pos + 1);
960 : } else { // pos == 0, look for alt path char
961 0 : pos = index(state.dataExternalInterface->FMU(Loop).Name, DataStringGlobals::altpathChar, true); // look backwards
962 0 : if (pos != std::string::npos) {
963 0 : strippedFileName(Loop) = state.dataExternalInterface->FMU(Loop).Name.substr(pos + 1);
964 : } else {
965 0 : strippedFileName(Loop) = state.dataExternalInterface->FMU(Loop).Name;
966 : }
967 : }
968 0 : fullFileName(Loop) = FileSystem::toString(tempFullFilePath);
969 : } else {
970 0 : state.dataExternalInterface->ErrorsFound = true;
971 : }
972 : // Get fmu time out
973 0 : state.dataExternalInterface->FMU(Loop).TimeOut = state.dataIPShortCut->rNumericArgs(1);
974 : // Get fmu logging on
975 0 : state.dataExternalInterface->FMU(Loop).LoggingOn = state.dataIPShortCut->rNumericArgs(2);
976 0 : }
977 :
978 : // check for dups that aren't the same file
979 : // this is windows code...
980 : // So this check that if I entered two different things and get the same end filename, then it's wrong?
981 0 : for (int j = 1; j <= state.dataExternalInterface->NumFMUObjects; ++j) {
982 0 : for (int k = 2; k <= state.dataExternalInterface->NumFMUObjects; ++k) {
983 0 : if (!Util::SameString(strippedFileName(j), strippedFileName(k))) continue;
984 : // base file names are the same
985 0 : if (Util::SameString(fullFileName(j), fullFileName(k))) continue;
986 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport:");
987 0 : ShowContinueError(state, "duplicate file names (but not same file) entered.");
988 0 : ShowContinueError(state, format("...entered file name=\"{}\"", state.dataExternalInterface->FMU(j).Name));
989 0 : ShowContinueError(state, format("... full file name=\"{}\"", fullFileName(j)));
990 0 : ShowContinueError(state, format("...entered file name=\"{}\"", state.dataExternalInterface->FMU(k).Name));
991 0 : ShowContinueError(state, format("... full file name=\"{}\"", fullFileName(k)));
992 0 : ShowContinueError(state, "...name collision but not same file name.");
993 0 : state.dataExternalInterface->ErrorsFound = true;
994 : }
995 : }
996 :
997 0 : if (state.dataExternalInterface->ErrorsFound) {
998 0 : strippedFileName.deallocate();
999 0 : fullFileName.deallocate();
1000 0 : StopExternalInterfaceIfError(state);
1001 : }
1002 :
1003 : // get the names of the input variables each state.dataExternalInterface->FMU(and the names of the
1004 : // corresponding output variables in EnergyPlus --).
1005 0 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:From:Variable";
1006 0 : int NumFMUInputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1007 : // Determine the number of instances for each FMUs
1008 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1009 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1010 :
1011 0 : std::string Name_OLD = "";
1012 0 : int j = 1;
1013 0 : int k = 1;
1014 0 : fmu.Instance.allocate(NumFMUInputVariables);
1015 0 : state.dataExternalInterface->checkInstanceName.allocate(NumFMUInputVariables);
1016 0 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1017 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1018 : cCurrentModuleObject,
1019 : l,
1020 0 : state.dataIPShortCut->cAlphaArgs,
1021 : NumAlphas,
1022 0 : state.dataIPShortCut->rNumericArgs,
1023 : NumNumbers,
1024 : IOStatus,
1025 : _,
1026 : _,
1027 0 : state.dataIPShortCut->cAlphaFieldNames,
1028 0 : state.dataIPShortCut->cNumericFieldNames);
1029 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), fmu.Name)) {
1030 0 : std::string Name_NEW = state.dataIPShortCut->cAlphaArgs(4);
1031 0 : if (!Util::SameString(Name_OLD, Name_NEW)) {
1032 0 : int FOUND = Util::FindItem(Name_NEW, state.dataExternalInterface->checkInstanceName);
1033 0 : if (FOUND == 0) {
1034 0 : state.dataExternalInterface->checkInstanceName(l).Name = Name_NEW;
1035 0 : fmu.NumInstances = j;
1036 0 : fmu.Instance(j).Name = Name_NEW;
1037 0 : ++j;
1038 0 : Name_OLD = Name_NEW;
1039 : }
1040 : }
1041 0 : fmu.TotNumInputVariablesInIDF = k;
1042 0 : ++k;
1043 0 : }
1044 : }
1045 0 : state.dataExternalInterface->checkInstanceName.deallocate();
1046 0 : }
1047 :
1048 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1049 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1050 0 : if (fmu.NumInstances == 0) {
1051 0 : ShowSevereError(state, format("ExternalInterface/InitExternalInterfaceFMUImport: The FMU \"{}\" does", fmu.Name));
1052 0 : ShowContinueError(state, "not have any instances or any input variable. An FMU should have at least one instance");
1053 0 : ShowContinueError(state, "or one input variable defined in input file. Check FMU object in the input file.");
1054 0 : state.dataExternalInterface->ErrorsFound = true;
1055 0 : StopExternalInterfaceIfError(state);
1056 : }
1057 0 : if (NumFMUInputVariables > 0 && fmu.TotNumInputVariablesInIDF == 0) {
1058 0 : ShowWarningError(state, format("InitExternalInterfaceFMUImport: The FMU \"{}\"", fmu.Name));
1059 0 : ShowContinueError(state, "is defined but has no input variables.");
1060 0 : ShowContinueError(state, "Check the input field of the corresponding object");
1061 0 : ShowContinueError(state, "ExternalInterface:FunctionalMockupUnitImport:From:Variable.");
1062 : }
1063 : }
1064 :
1065 : // write output folder where FMUs will be unpacked later on.
1066 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1067 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1068 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1069 0 : auto &fmuInst = fmu.Instance(j);
1070 0 : fmuInst.WorkingFolder = state.dataExternalInterface->FMURootWorkingFolder / fs::path(strippedFileName(i) + '_' + fmuInst.Name);
1071 : }
1072 : }
1073 :
1074 : // parse the fmu defined in the idf using the fmuUnpack.
1075 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1076 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1077 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1078 0 : auto &fmuInst = fmu.Instance(j);
1079 : // get the length of working folder trimmed
1080 0 : std::string const workingFolderStr = FileSystem::toString(fmuInst.WorkingFolder);
1081 0 : fmuInst.LenWorkingFolder = workingFolderStr.length();
1082 : // unpack fmus
1083 : // preprocess arguments for library call
1084 : {
1085 0 : std::vector<char> fullFileNameArr(getCharArrayFromString(fullFileName(i)));
1086 0 : std::vector<char> workingFolderArr(getCharArrayFromString(workingFolderStr));
1087 0 : int lenFileName(len(fullFileName(i)));
1088 :
1089 : // make the library call
1090 0 : int retVal = fmiEPlusUnpack(&fullFileNameArr[0], &workingFolderArr[0], &lenFileName, &fmuInst.LenWorkingFolder);
1091 :
1092 0 : if (retVal != 0) {
1093 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1094 0 : ShowContinueError(state, format("unpack the FMU \"{}\".", fmu.Name));
1095 0 : ShowContinueError(state, "Check if the FMU exists. Also check if the FMU folder is not write protected.");
1096 0 : state.dataExternalInterface->ErrorsFound = true;
1097 0 : StopExternalInterfaceIfError(state);
1098 : }
1099 0 : }
1100 :
1101 : {
1102 : // determine modelID and modelGUID of all FMU instances
1103 : // preprocess arguments for library call
1104 0 : std::vector<char> workingFolderArr(getCharArrayFromString(workingFolderStr));
1105 :
1106 : // make the library call
1107 0 : fmuInst.Index = model_ID_GUID((char *)fmuInst.Name.c_str(),
1108 0 : &workingFolderArr[0],
1109 : &fmuInst.LenWorkingFolder,
1110 : &fmuInst.NumInputVariablesInFMU,
1111 : &fmuInst.NumOutputVariablesInFMU);
1112 :
1113 0 : if (fmuInst.Index < 0) {
1114 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1115 0 : ShowContinueError(state, "get the model ID and model GUID");
1116 0 : ShowContinueError(state, format("of instance \"{}\" of FMU \"{}\".", fmuInst.Name, fmu.Name));
1117 0 : ShowContinueError(state, "Check if modelDescription.xml exists in the folder where the FMU has been unpacked.");
1118 0 : state.dataExternalInterface->ErrorsFound = true;
1119 0 : StopExternalInterfaceIfError(state);
1120 : }
1121 0 : }
1122 :
1123 : {
1124 : // get the path to the binaries
1125 : // preprocess args for library call
1126 0 : std::vector<char> workingFolderArr(getCharArrayFromString(workingFolderStr));
1127 : // Reserve some space in the string, becasue addLibPathCurrentWorkflowFolder doesn't allocate memory for the
1128 : // workingFolderWithLibArr Note: you can't call str.resize(str.length() + 91) because the conversion to std::vector<char> will
1129 : // find the null terminator and so it will have no effect
1130 : std::string reservedString =
1131 0 : workingFolderStr + " ";
1132 0 : std::vector<char> workingFolderWithLibArr(getCharArrayFromString(reservedString));
1133 :
1134 : // make the library call
1135 : int retValfmiPathLib =
1136 0 : addLibPathCurrentWorkingFolder(&workingFolderWithLibArr[0], &workingFolderArr[0], &fmuInst.LenWorkingFolder, &fmuInst.Index);
1137 :
1138 : // post process args in case they are used later
1139 0 : fmuInst.WorkingFolder_wLib = fs::path(trim(getStringFromCharArray(workingFolderWithLibArr)));
1140 :
1141 0 : if (retValfmiPathLib != 0) {
1142 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1143 0 : ShowContinueError(state, "get the path to the binaries of instance");
1144 0 : ShowContinueError(state, format("\"{}\" of FMU \"{}\".", fmuInst.Name, fmu.Name));
1145 0 : ShowContinueError(state, "Check if binaries folder exists where the FMU has been unpacked.");
1146 0 : state.dataExternalInterface->ErrorsFound = true;
1147 0 : StopExternalInterfaceIfError(state);
1148 : }
1149 :
1150 : // get the length of the working folder with libraries
1151 0 : fmuInst.LenWorkingFolder_wLib = FileSystem::toString(fmuInst.WorkingFolder_wLib).length();
1152 0 : }
1153 :
1154 : {
1155 : // determine the FMI version
1156 : // preprocess args for library call
1157 0 : std::vector<char> workingFolderWithLibArr(getCharArrayFromString(FileSystem::toString(fmuInst.WorkingFolder_wLib)));
1158 : std::vector<char> VersionNumArr(
1159 0 : getCharArrayFromString(" ")); // the version should only be 3 characters long, since for now we only handle "1.0"
1160 :
1161 : // make the library call
1162 : int retValfmiVersion =
1163 0 : getfmiEPlusVersion(&workingFolderWithLibArr[0], &fmuInst.LenWorkingFolder_wLib, &VersionNumArr[0], &fmuInst.Index);
1164 :
1165 : // post process in case args are used later
1166 0 : fmuInst.fmiVersionNumber = getStringFromCharArray(VersionNumArr);
1167 :
1168 0 : if (retValfmiVersion != 0) {
1169 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1170 0 : ShowContinueError(state, "load FMI functions library of instance");
1171 0 : ShowContinueError(state, format("\"{}\" of FMU \"{}\".", fmuInst.Name, fmu.Name));
1172 0 : ShowContinueError(state, format("\"{}\".", fmuInst.fmiVersionNumber));
1173 0 : state.dataExternalInterface->ErrorsFound = true;
1174 0 : StopExternalInterfaceIfError(state);
1175 : }
1176 :
1177 0 : if (fmuInst.fmiVersionNumber.substr(0, 3) != "1.0") {
1178 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when getting version");
1179 0 : ShowContinueError(state, format("number of instance \"{}\"", fmuInst.Name));
1180 0 : ShowContinueError(state, format("of FMU \"{}\".", fmu.Name));
1181 0 : ShowContinueError(state, format("The version number found (\"{}\")", fmuInst.fmiVersionNumber.substr(0, 3)));
1182 0 : ShowContinueError(state, "differs from version 1.0 which is currently supported.");
1183 0 : state.dataExternalInterface->ErrorsFound = true;
1184 0 : StopExternalInterfaceIfError(state);
1185 : }
1186 0 : }
1187 0 : }
1188 : }
1189 :
1190 0 : strippedFileName.deallocate();
1191 0 : fullFileName.deallocate();
1192 :
1193 0 : state.dataExternalInterface->UniqueFMUInputVarNames.reserve(static_cast<unsigned>(NumFMUInputVariables));
1194 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1195 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1196 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1197 0 : auto &fmuInst = fmu.Instance(j);
1198 0 : fmuInst.fmuInputVariable.allocate(NumFMUInputVariables);
1199 0 : fmuInst.checkfmuInputVariable.allocate(NumFMUInputVariables);
1200 0 : state.dataExternalInterface->UniqueFMUInputVarNames.clear();
1201 0 : fmuInst.eplusOutputVariable.allocate(NumFMUInputVariables);
1202 0 : int k = 1;
1203 0 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1204 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1205 : cCurrentModuleObject,
1206 : l,
1207 0 : state.dataIPShortCut->cAlphaArgs,
1208 : NumAlphas,
1209 0 : state.dataIPShortCut->rNumericArgs,
1210 : NumNumbers,
1211 : IOStatus,
1212 : _,
1213 : _,
1214 0 : state.dataIPShortCut->cAlphaFieldNames,
1215 0 : state.dataIPShortCut->cNumericFieldNames);
1216 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), fmu.Name) &&
1217 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(4), fmuInst.Name)) {
1218 0 : fmuInst.fmuInputVariable(k).Name = state.dataIPShortCut->cAlphaArgs(5);
1219 0 : fmuInst.eplusOutputVariable(k).VarKey = state.dataIPShortCut->cAlphaArgs(1);
1220 0 : fmuInst.eplusOutputVariable(k).Name = state.dataIPShortCut->cAlphaArgs(2);
1221 : // verify whether we have duplicate FMU input variables in the idf
1222 0 : GlobalNames::VerifyUniqueInterObjectName(state,
1223 0 : state.dataExternalInterface->UniqueFMUInputVarNames,
1224 0 : fmuInst.fmuInputVariable(k).Name,
1225 : cCurrentModuleObject,
1226 : fmuInst.Name,
1227 0 : state.dataExternalInterface->ErrorsFound);
1228 : // Util::VerifyName( state.dataExternalInterface->FMU( i ).Instance( j
1229 : // ).fmuInputVariable(
1230 : // k
1231 : //).Name, state.dataExternalInterface->FMU(
1232 : // i
1233 : //).Instance(
1234 : // j
1235 : //).checkfmuInputVariable, NumFMUInputVariables, IsNotOK, IsBlank, "The FMU input variable \"" +
1236 : // state.dataExternalInterface->FMU( i ).Instance( j
1237 : //).fmuInputVariable( k ).Name + "\" of instance \"" + state.dataExternalInterface->FMU( i ).Instance( j ).Name + "\" of FMU
1238 : //\"" + state.dataExternalInterface->FMU( i ).Name + "\"
1239 : // has duplicates. Please check the input file again and delete duplicated entries." );
1240 0 : if (state.dataExternalInterface->ErrorsFound) {
1241 0 : StopExternalInterfaceIfError(state);
1242 : } else {
1243 0 : fmuInst.checkfmuInputVariable(k).Name = fmuInst.fmuInputVariable(k).Name;
1244 : }
1245 :
1246 : // preprocess args for library call
1247 0 : std::vector<char> inputVarNameArr(getCharArrayFromString(fmuInst.fmuInputVariable(k).Name));
1248 0 : int inputVarNameLen(len(fmuInst.fmuInputVariable(k).Name));
1249 :
1250 : // make the library call
1251 0 : fmuInst.fmuInputVariable(k).ValueReference =
1252 0 : getValueReferenceByNameFMUInputVariables(&inputVarNameArr[0], &inputVarNameLen, &fmuInst.Index);
1253 :
1254 : // postprocess args in case they are used later
1255 0 : fmuInst.fmuInputVariable(k).Name = getStringFromCharArray(inputVarNameArr);
1256 :
1257 0 : if (fmuInst.fmuInputVariable(k).ValueReference == -999) {
1258 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1259 0 : ShowContinueError(state, "get the value reference of FMU input variable");
1260 0 : ShowContinueError(state, format("\"{}\" of instance \"{}\" of FMU", fmuInst.fmuInputVariable(k).Name, fmuInst.Name));
1261 0 : ShowContinueError(state, format("of FMU \"{}\". Please check the name of input variable", fmu.Name));
1262 0 : ShowContinueError(state, "in the input file and in the modelDescription file.");
1263 0 : state.dataExternalInterface->ErrorsFound = true;
1264 0 : StopExternalInterfaceIfError(state);
1265 : }
1266 :
1267 0 : if (fmuInst.fmuInputVariable(k).ValueReference == -1) {
1268 0 : ShowSevereError(state, "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to");
1269 0 : ShowContinueError(state, "get the value reference of FMU input variable");
1270 0 : ShowContinueError(state, format("\"{}\" of instance \"{}\" of FMU", fmuInst.fmuInputVariable(k).Name, fmuInst.Name));
1271 0 : ShowContinueError(state, format("\"{}\". This variable is not an FMU input variable.", fmu.Name));
1272 0 : ShowContinueError(state, "Please check the causality of the variable in the modelDescription file.");
1273 0 : state.dataExternalInterface->ErrorsFound = true;
1274 0 : StopExternalInterfaceIfError(state);
1275 : }
1276 :
1277 : // The next call expects an array, but a single item is passed
1278 : // Therefore create a single item array here first
1279 0 : Array1D_string tempSingleStringA(1, fmuInst.eplusOutputVariable(k).VarKey);
1280 0 : Array1D_string tempSingleStringB(1, fmuInst.eplusOutputVariable(k).Name);
1281 :
1282 : // Make the call with arrays
1283 0 : GetReportVariableKey(state, tempSingleStringA, 1, tempSingleStringB, keyIndexes, varTypes);
1284 :
1285 : // Then postprocess the array items back in case they changed
1286 0 : fmuInst.eplusOutputVariable(k).VarKey = tempSingleStringA(1);
1287 0 : fmuInst.eplusOutputVariable(k).Name = tempSingleStringB(1);
1288 :
1289 0 : fmuInst.eplusOutputVariable(k).VarIndex = keyIndexes(1);
1290 0 : fmuInst.eplusOutputVariable(k).VarType = varTypes(1);
1291 0 : fmuInst.NumInputVariablesInIDF = k;
1292 0 : ++k;
1293 0 : }
1294 : }
1295 :
1296 0 : if (NumFMUInputVariables > 0 && fmuInst.NumInputVariablesInIDF == 0) {
1297 0 : ShowWarningError(state, format("InitExternalInterfaceFMUImport: The instance \"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
1298 0 : ShowContinueError(state, "is defined but has no input variables. Check the input field of the");
1299 0 : ShowContinueError(state, "corresponding object: ExternalInterface:FunctionalMockupUnitImport:From:Variable.");
1300 : }
1301 : }
1302 : }
1303 :
1304 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1305 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1306 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1307 0 : auto &fmuInst = fmu.Instance(j);
1308 : // check whether the number of input variables in fmu is bigger than in the idf
1309 0 : if (fmuInst.NumInputVariablesInFMU > fmuInst.NumInputVariablesInIDF) {
1310 0 : ShowWarningError(state,
1311 0 : format("InitExternalInterfaceFMUImport: The number of input variables defined in input file ({})",
1312 0 : fmuInst.NumInputVariablesInIDF));
1313 0 : ShowContinueError(state,
1314 0 : format("of instance \"{}\" of FMU \"{}\" is less than the number of input variables", fmuInst.Name, fmu.Name));
1315 0 : ShowContinueError(state, format("in the modelDescription file ({}).", fmuInst.NumInputVariablesInFMU));
1316 0 : ShowContinueError(state, "Check the input file and the modelDescription file again.");
1317 : }
1318 : // check whether the number of input variables in fmu is less than in the idf
1319 0 : if (fmuInst.NumInputVariablesInFMU < fmuInst.NumInputVariablesInIDF) {
1320 0 : ShowWarningError(state,
1321 0 : format("InitExternalInterfaceFMUImport: The number of input variables defined in input file ({})",
1322 0 : fmuInst.NumInputVariablesInIDF));
1323 0 : ShowContinueError(
1324 0 : state, format("of instance \"{}\" of FMU \"{}\" is bigger than the number of input variables", fmuInst.Name, fmu.Name));
1325 0 : ShowContinueError(state, format("in the modelDescription file ({}).", fmuInst.NumInputVariablesInFMU));
1326 0 : ShowContinueError(state, "Check the input file and the modelDescription file again.");
1327 : }
1328 : }
1329 : }
1330 :
1331 : // get the names of the output variables each fmu (and the names of the
1332 : // corresponding input variables in EnergyPlus -- schedule).
1333 0 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Schedule";
1334 0 : NumFMUInputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1335 :
1336 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1337 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1338 0 : int j = 1;
1339 0 : for (int k = 1; k <= NumFMUInputVariables; ++k) {
1340 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1341 : cCurrentModuleObject,
1342 : k,
1343 0 : state.dataIPShortCut->cAlphaArgs,
1344 : NumAlphas,
1345 0 : state.dataIPShortCut->rNumericArgs,
1346 : NumNumbers,
1347 : IOStatus,
1348 : _,
1349 : _,
1350 0 : state.dataIPShortCut->cAlphaFieldNames,
1351 0 : state.dataIPShortCut->cNumericFieldNames);
1352 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), fmu.Name)) {
1353 0 : fmu.TotNumOutputVariablesSchedule = j;
1354 0 : ++j;
1355 : }
1356 : }
1357 : }
1358 :
1359 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1360 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1361 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1362 0 : auto &fmuInst = fmu.Instance(j);
1363 0 : fmuInst.fmuOutputVariableSchedule.allocate(NumFMUInputVariables);
1364 0 : fmuInst.eplusInputVariableSchedule.allocate(NumFMUInputVariables);
1365 0 : int k = 1;
1366 0 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1367 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1368 : cCurrentModuleObject,
1369 : l,
1370 0 : state.dataIPShortCut->cAlphaArgs,
1371 : NumAlphas,
1372 0 : state.dataIPShortCut->rNumericArgs,
1373 : NumNumbers,
1374 : IOStatus,
1375 : _,
1376 : _,
1377 0 : state.dataIPShortCut->cAlphaFieldNames,
1378 0 : state.dataIPShortCut->cNumericFieldNames);
1379 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(3), fmu.Name) &&
1380 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(4), fmuInst.Name)) {
1381 0 : fmuInst.fmuOutputVariableSchedule(k).Name = state.dataIPShortCut->cAlphaArgs(5);
1382 0 : fmuInst.eplusInputVariableSchedule(k).Name = state.dataIPShortCut->cAlphaArgs(1);
1383 0 : fmuInst.eplusInputVariableSchedule(k).InitialValue = state.dataIPShortCut->rNumericArgs(1);
1384 :
1385 : // get the value reference by using the FMU name and the variable name.
1386 :
1387 : // preprocess the arguments before the following library call
1388 0 : std::vector<char> NameCharArr(getCharArrayFromString(fmuInst.fmuOutputVariableSchedule(k).Name));
1389 0 : int lengthVar(len(fmuInst.fmuOutputVariableSchedule(k).Name));
1390 :
1391 : // make the library call
1392 0 : fmuInst.fmuOutputVariableSchedule(k).ValueReference =
1393 0 : getValueReferenceByNameFMUOutputVariables(&NameCharArr[0], &lengthVar, &fmuInst.Index);
1394 :
1395 : // postprocess the arguments after the library call in case they are changed and used later
1396 0 : fmuInst.fmuOutputVariableSchedule(k).Name = getStringFromCharArray(NameCharArr);
1397 :
1398 0 : if (fmuInst.fmuOutputVariableSchedule(k).ValueReference == -999) {
1399 0 : ShowSevereError(state,
1400 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1401 : "the FMU output variable");
1402 0 : ShowContinueError(state, format("\"{}\" of instance \"{}\"", fmuInst.fmuOutputVariableSchedule(k).Name, fmuInst.Name));
1403 0 : ShowContinueError(state, format("of FMU \"{}\" that will be mapped to a schedule.", fmu.Name));
1404 0 : ShowContinueError(state, "Please check the name of output variables in the input file and");
1405 0 : ShowContinueError(state, "in the modelDescription file.");
1406 0 : state.dataExternalInterface->ErrorsFound = true;
1407 0 : StopExternalInterfaceIfError(state);
1408 : }
1409 :
1410 0 : if (fmuInst.fmuOutputVariableSchedule(k).ValueReference == -1) {
1411 0 : ShowSevereError(state,
1412 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1413 : "the FMU output variable");
1414 0 : ShowContinueError(state, format("\"{}\" of instance \"{}\"", fmuInst.fmuOutputVariableSchedule(k).Name, fmuInst.Name));
1415 0 : ShowContinueError(state, format("of FMU \"{}\" that will be mapped to a schedule.", fmu.Name));
1416 0 : ShowContinueError(state, "This variable is not an FMU output variable.");
1417 0 : ShowContinueError(state, "Please check the causality of the variable in the modelDescription file.");
1418 0 : state.dataExternalInterface->ErrorsFound = true;
1419 0 : StopExternalInterfaceIfError(state);
1420 : }
1421 :
1422 0 : fmuInst.eplusInputVariableSchedule(k).VarIndex = Sched::GetScheduleNum(state, fmuInst.eplusInputVariableSchedule(k).Name);
1423 0 : fmuInst.NumOutputVariablesSchedule = k;
1424 0 : if (fmuInst.eplusInputVariableSchedule(k).VarIndex <= 0) {
1425 0 : ShowSevereError(state,
1426 0 : format("ExternalInterface/InitExternalInterfaceFMUImport:declares variable \"{}\",",
1427 0 : fmuInst.eplusInputVariableSchedule(k).Name));
1428 0 : ShowContinueError(state, "but variable is not a schedule variable.");
1429 0 : state.dataExternalInterface->ErrorsFound = true;
1430 0 : StopExternalInterfaceIfError(state);
1431 : }
1432 0 : ++k;
1433 0 : }
1434 : }
1435 : }
1436 : }
1437 :
1438 : // get the names of the output variables each fmu (and the names of the
1439 : // corresponding input variables in EnergyPlus -- variable).
1440 0 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Variable";
1441 0 : NumFMUInputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1442 :
1443 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1444 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1445 0 : int j = 1;
1446 0 : for (int k = 1; k <= NumFMUInputVariables; ++k) {
1447 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1448 : cCurrentModuleObject,
1449 : k,
1450 0 : state.dataIPShortCut->cAlphaArgs,
1451 : NumAlphas,
1452 0 : state.dataIPShortCut->rNumericArgs,
1453 : NumNumbers,
1454 : IOStatus,
1455 : _,
1456 : _,
1457 0 : state.dataIPShortCut->cAlphaFieldNames,
1458 0 : state.dataIPShortCut->cNumericFieldNames);
1459 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), fmu.Name)) {
1460 0 : fmu.TotNumOutputVariablesVariable = j;
1461 0 : ++j;
1462 : }
1463 : }
1464 : }
1465 :
1466 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1467 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1468 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1469 0 : auto &fmuInst = fmu.Instance(j);
1470 0 : fmuInst.fmuOutputVariableVariable.allocate(NumFMUInputVariables);
1471 0 : fmuInst.eplusInputVariableVariable.allocate(NumFMUInputVariables);
1472 0 : int k = 1;
1473 0 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1474 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1475 : cCurrentModuleObject,
1476 : l,
1477 0 : state.dataIPShortCut->cAlphaArgs,
1478 : NumAlphas,
1479 0 : state.dataIPShortCut->rNumericArgs,
1480 : NumNumbers,
1481 : IOStatus,
1482 : _,
1483 : _,
1484 0 : state.dataIPShortCut->cAlphaFieldNames,
1485 0 : state.dataIPShortCut->cNumericFieldNames);
1486 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(2), fmu.Name) &&
1487 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(3), fmuInst.Name)) {
1488 0 : fmuInst.fmuOutputVariableVariable(k).Name = state.dataIPShortCut->cAlphaArgs(4);
1489 0 : fmuInst.eplusInputVariableVariable(k).Name = state.dataIPShortCut->cAlphaArgs(1);
1490 :
1491 : // get the value reference by using the FMU name and the variable name.
1492 0 : std::vector<char> NameCharArr(getCharArrayFromString(fmuInst.fmuOutputVariableVariable(k).Name));
1493 0 : int tempLength(len(fmuInst.fmuOutputVariableVariable(k).Name));
1494 0 : fmuInst.fmuOutputVariableVariable(k).ValueReference =
1495 0 : getValueReferenceByNameFMUOutputVariables(&NameCharArr[0], &tempLength, &fmuInst.Index);
1496 : // state.dataExternalInterface->FMU( i ).Instance( j ).fmuOutputVariableVariable( k ).Name = getStringFromCharArray(
1497 : // NameCharArr );
1498 :
1499 0 : if (fmuInst.fmuOutputVariableVariable(k).ValueReference == -999) {
1500 0 : ShowSevereError(state,
1501 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1502 : "the FMU output variable");
1503 0 : ShowContinueError(state, format("\"{}\" of instance \"{}\"", fmuInst.fmuOutputVariableVariable(k).Name, fmuInst.Name));
1504 0 : ShowContinueError(state, format("of FMU \"{}\" that will be mapped to a variable.", fmu.Name));
1505 0 : ShowContinueError(state, "Please check the name of output variables in the input file and in the modelDescription file.");
1506 0 : state.dataExternalInterface->ErrorsFound = true;
1507 0 : StopExternalInterfaceIfError(state);
1508 : }
1509 :
1510 0 : if (fmuInst.fmuOutputVariableVariable(k).ValueReference == -1) {
1511 0 : ShowSevereError(state,
1512 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1513 : "the FMU output variable");
1514 0 : ShowContinueError(state, format("\"{}\" of instance \"{}\"", fmuInst.fmuOutputVariableVariable(k).Name, fmuInst.Name));
1515 0 : ShowContinueError(state, format("of FMU \"{}\" that will be mapped to a variable.", fmu.Name));
1516 0 : ShowContinueError(state,
1517 : "This variable is not an FMU output variable. Please check the causality of the variable in the "
1518 : "modelDescription file.");
1519 0 : state.dataExternalInterface->ErrorsFound = true;
1520 0 : StopExternalInterfaceIfError(state);
1521 : }
1522 :
1523 0 : fmuInst.eplusInputVariableVariable(k).VarIndex =
1524 0 : RuntimeLanguageProcessor::FindEMSVariable(state, fmuInst.eplusInputVariableVariable(k).Name, 0);
1525 0 : fmuInst.NumOutputVariablesVariable = k;
1526 0 : if (fmuInst.eplusInputVariableVariable(k).VarIndex <= 0) {
1527 0 : ShowSevereError(state,
1528 0 : format("ExternalInterface/InitExternalInterfaceFMUImport:declares variable \"{}\",",
1529 0 : fmuInst.eplusInputVariableVariable(k).Name));
1530 0 : ShowContinueError(state, "but variable is not an EMS variable.");
1531 0 : state.dataExternalInterface->ErrorsFound = true;
1532 0 : StopExternalInterfaceIfError(state);
1533 : }
1534 0 : ++k;
1535 0 : }
1536 : }
1537 0 : if (fmuInst.NumOutputVariablesVariable >= 1) {
1538 0 : state.dataExternalInterface->useEMS = true;
1539 : }
1540 : }
1541 : }
1542 :
1543 : // get the names of the output variables each fmu (and the names of the
1544 : // corresponding input variables in EnergyPlus -- actuator).
1545 0 : cCurrentModuleObject = "ExternalInterface:FunctionalMockupUnitImport:To:Actuator";
1546 0 : NumFMUInputVariables = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
1547 :
1548 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1549 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1550 0 : int j = 1;
1551 0 : for (int k = 1; k <= NumFMUInputVariables; ++k) {
1552 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1553 : cCurrentModuleObject,
1554 : k,
1555 0 : state.dataIPShortCut->cAlphaArgs,
1556 : NumAlphas,
1557 0 : state.dataIPShortCut->rNumericArgs,
1558 : NumNumbers,
1559 : IOStatus,
1560 : _,
1561 : _,
1562 0 : state.dataIPShortCut->cAlphaFieldNames,
1563 0 : state.dataIPShortCut->cNumericFieldNames);
1564 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(5), fmu.Name)) {
1565 0 : fmu.TotNumOutputVariablesActuator = j;
1566 0 : ++j;
1567 : }
1568 : }
1569 : }
1570 :
1571 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1572 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1573 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1574 0 : auto &fmuInst = fmu.Instance(j);
1575 0 : fmuInst.fmuOutputVariableActuator.allocate(NumFMUInputVariables);
1576 0 : fmuInst.eplusInputVariableActuator.allocate(NumFMUInputVariables);
1577 0 : int k = 1;
1578 0 : for (int l = 1; l <= NumFMUInputVariables; ++l) {
1579 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1580 : cCurrentModuleObject,
1581 : l,
1582 0 : state.dataIPShortCut->cAlphaArgs,
1583 : NumAlphas,
1584 0 : state.dataIPShortCut->rNumericArgs,
1585 : NumNumbers,
1586 : IOStatus,
1587 : _,
1588 : _,
1589 0 : state.dataIPShortCut->cAlphaFieldNames,
1590 0 : state.dataIPShortCut->cNumericFieldNames);
1591 0 : if (Util::SameString(state.dataIPShortCut->cAlphaArgs(5), fmu.Name) &&
1592 0 : Util::SameString(state.dataIPShortCut->cAlphaArgs(6), fmuInst.Name)) {
1593 0 : fmuInst.fmuOutputVariableActuator(k).Name = state.dataIPShortCut->cAlphaArgs(7);
1594 0 : fmuInst.eplusInputVariableActuator(k).Name = state.dataIPShortCut->cAlphaArgs(1);
1595 :
1596 : // get the value reference by using the FMU name and the variable name.
1597 0 : std::vector<char> tempNameArr(getCharArrayFromString(fmuInst.fmuOutputVariableActuator(k).Name));
1598 0 : int tempLength(len(fmuInst.fmuOutputVariableActuator(k).Name));
1599 0 : fmuInst.fmuOutputVariableActuator(k).ValueReference =
1600 0 : getValueReferenceByNameFMUOutputVariables(&tempNameArr[0], &tempLength, &fmuInst.Index);
1601 : // state.dataExternalInterface->FMU( i ).Instance( j ).fmuOutputVariableActuator( k ).Name = getStringFromCharArray(
1602 : // tempNameArr );
1603 :
1604 0 : if (fmuInst.fmuOutputVariableActuator(k).ValueReference == -999) {
1605 0 : ShowSevereError(state,
1606 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1607 : "the FMU output variable");
1608 0 : ShowContinueError(state, format("\"{}\" of instance \"{}\"", fmuInst.fmuOutputVariableActuator(k).Name, fmuInst.Name));
1609 0 : ShowContinueError(state, format("of FMU \"{}\" that will be mapped to an actuator.", fmu.Name));
1610 0 : ShowContinueError(state, "Please check the name of output variables in the input file and in the modelDescription file.");
1611 0 : state.dataExternalInterface->ErrorsFound = true;
1612 0 : StopExternalInterfaceIfError(state);
1613 : }
1614 :
1615 0 : if (fmuInst.fmuOutputVariableActuator(k).ValueReference == -1) {
1616 0 : ShowSevereError(state,
1617 : "ExternalInterface/InitExternalInterfaceFMUImport: Error when trying to get the value reference of "
1618 : "the FMU output variable");
1619 0 : ShowContinueError(state, format("\"{}\" of instance \"{}\"", fmuInst.fmuOutputVariableActuator(k).Name, fmuInst.Name));
1620 0 : ShowContinueError(state, format("of FMU \"{}\" that will be mapped to an actuator.", fmu.Name));
1621 0 : ShowContinueError(state,
1622 : "This variable is not an FMU output variable. Please check the causality of the variable in the "
1623 : "modelDescription file.");
1624 0 : state.dataExternalInterface->ErrorsFound = true;
1625 0 : StopExternalInterfaceIfError(state);
1626 : }
1627 :
1628 0 : fmuInst.eplusInputVariableActuator(k).VarIndex =
1629 0 : RuntimeLanguageProcessor::FindEMSVariable(state, fmuInst.eplusInputVariableActuator(k).Name, 0);
1630 0 : fmuInst.NumOutputVariablesActuator = k;
1631 0 : if (fmuInst.eplusInputVariableActuator(k).VarIndex <= 0) {
1632 0 : ShowSevereError(state,
1633 0 : format("ExternalInterface/InitExternalInterfaceFMUImport:declares variable \"{}\",",
1634 0 : fmuInst.eplusInputVariableActuator(k).Name));
1635 0 : ShowContinueError(state, "but variable is not an EMS variable.");
1636 0 : state.dataExternalInterface->ErrorsFound = true;
1637 0 : StopExternalInterfaceIfError(state);
1638 : }
1639 0 : ++k;
1640 0 : }
1641 : }
1642 : // set the flag state.dataExternalInterface->useEMS to true. This will be used then to update the erl variables in erl data structure
1643 0 : if (fmuInst.NumOutputVariablesActuator >= 1) {
1644 0 : state.dataExternalInterface->useEMS = true;
1645 : }
1646 : }
1647 : }
1648 :
1649 : // parse the fmu defined in the idf using the fmuUnpack with the flag --unpack.
1650 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1651 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1652 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1653 0 : auto &fmuInst = fmu.Instance(j);
1654 0 : fmuInst.NumOutputVariablesInIDF =
1655 0 : fmuInst.NumOutputVariablesSchedule + fmuInst.NumOutputVariablesVariable + fmuInst.NumOutputVariablesActuator;
1656 : // check whether the number of output variables in fmu is bigger than in the idf
1657 0 : if (fmuInst.NumOutputVariablesInFMU > fmuInst.NumOutputVariablesInIDF) {
1658 0 : ShowWarningError(state,
1659 0 : format("InitExternalInterfaceFMUImport: The number of output variables defined in input file ({})",
1660 0 : fmuInst.NumOutputVariablesInIDF));
1661 0 : ShowContinueError(state,
1662 0 : format("of instance \"{}\" of FMU \"{}\" is less than the number of output variables", fmuInst.Name, fmu.Name));
1663 0 : ShowContinueError(state, format("in the modelDescription file ({}).", fmuInst.NumOutputVariablesInFMU));
1664 0 : ShowContinueError(state, "Check the input file and the modelDescription file again.");
1665 : }
1666 : // check whether the number of output variables in fmu is less than in the idf
1667 0 : if (fmuInst.NumOutputVariablesInFMU < fmuInst.NumOutputVariablesInIDF) {
1668 0 : ShowWarningError(state,
1669 0 : format("InitExternalInterfaceFMUImport: The number of output variables defined in input file ({})",
1670 0 : fmuInst.NumOutputVariablesInIDF));
1671 0 : ShowContinueError(
1672 0 : state, format("of instance \"{}\" of FMU \"{}\" is bigger than the number of output variables", fmuInst.Name, fmu.Name));
1673 0 : ShowContinueError(state, format("in the modelDescription file ({}).", fmuInst.NumOutputVariablesInFMU));
1674 0 : ShowContinueError(state, "Check the input file and the modelDescription file again.");
1675 : }
1676 :
1677 0 : DisplayString(
1678 : state,
1679 0 : format("Number of inputs in instance \"{}\" of FMU \"{}\" = \"{}\".", fmuInst.Name, fmu.Name, fmuInst.NumInputVariablesInIDF));
1680 0 : DisplayString(
1681 : state,
1682 0 : format("Number of outputs in instance \"{}\" of FMU \"{}\" = \"{}\".", fmuInst.Name, fmu.Name, fmuInst.NumOutputVariablesInIDF));
1683 : }
1684 : }
1685 0 : StopExternalInterfaceIfError(state);
1686 0 : state.dataExternalInterface->FirstCallIni = false;
1687 : }
1688 0 : }
1689 :
1690 0 : std::string trim(std::string const &str)
1691 : {
1692 0 : std::size_t first = str.find_first_not_of(' ');
1693 0 : std::size_t last = str.find_last_not_of(' ');
1694 0 : return str.substr(first, last - first + 1);
1695 : }
1696 :
1697 0 : Real64 GetCurSimStartTimeSeconds(const EnergyPlusData &state)
1698 : {
1699 : // FUNCTION INFORMATION:
1700 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
1701 : // DATE WRITTEN August 2011
1702 :
1703 : // PURPOSE OF THIS FUNCTION:
1704 : // Get the current month and day in the runperiod and convert
1705 : // it into seconds.
1706 :
1707 : // Locals
1708 : Real64 simtime;
1709 :
1710 0 : if (!state.dataEnvrn->CurrentYearIsLeapYear) {
1711 0 : switch (state.dataEnvrn->Month) {
1712 0 : case 1:
1713 0 : simtime = 0;
1714 0 : break;
1715 0 : case 2:
1716 0 : simtime = 31;
1717 0 : break;
1718 0 : case 3:
1719 0 : simtime = 59;
1720 0 : break;
1721 0 : case 4:
1722 0 : simtime = 90;
1723 0 : break;
1724 0 : case 5:
1725 0 : simtime = 120;
1726 0 : break;
1727 0 : case 6:
1728 0 : simtime = 151;
1729 0 : break;
1730 0 : case 7:
1731 0 : simtime = 181;
1732 0 : break;
1733 0 : case 8:
1734 0 : simtime = 212;
1735 0 : break;
1736 0 : case 9:
1737 0 : simtime = 243;
1738 0 : break;
1739 0 : case 10:
1740 0 : simtime = 273;
1741 0 : break;
1742 0 : case 11:
1743 0 : simtime = 304;
1744 0 : break;
1745 0 : case 12:
1746 0 : simtime = 334;
1747 0 : break;
1748 0 : default:
1749 0 : simtime = 0;
1750 : }
1751 : } else {
1752 0 : switch (state.dataEnvrn->Month) {
1753 0 : case 1:
1754 0 : simtime = 0;
1755 0 : break;
1756 0 : case 2:
1757 0 : simtime = 31;
1758 0 : break;
1759 0 : case 3:
1760 0 : simtime = 59 + 1;
1761 0 : break;
1762 0 : case 4:
1763 0 : simtime = 90 + 1;
1764 0 : break;
1765 0 : case 5:
1766 0 : simtime = 120 + 1;
1767 0 : break;
1768 0 : case 6:
1769 0 : simtime = 151 + 1;
1770 0 : break;
1771 0 : case 7:
1772 0 : simtime = 181 + 1;
1773 0 : break;
1774 0 : case 8:
1775 0 : simtime = 212 + 1;
1776 0 : break;
1777 0 : case 9:
1778 0 : simtime = 243 + 1;
1779 0 : break;
1780 0 : case 10:
1781 0 : simtime = 273 + 1;
1782 0 : break;
1783 0 : case 11:
1784 0 : simtime = 304 + 1;
1785 0 : break;
1786 0 : case 12:
1787 0 : simtime = 334 + 1;
1788 0 : break;
1789 0 : default:
1790 0 : simtime = 0;
1791 : }
1792 : }
1793 :
1794 0 : simtime = 24 * (simtime + (state.dataEnvrn->DayOfMonth - 1)); // day of month does not need to be stubtracted??
1795 0 : simtime = 60 * (simtime + (state.dataGlobal->HourOfDay - 1)); // hours to minutes
1796 0 : simtime = 60 * (simtime); // minutes to seconds
1797 :
1798 0 : return simtime;
1799 : }
1800 :
1801 0 : void CalcExternalInterfaceFMUImport(EnergyPlusData &state)
1802 : {
1803 :
1804 : // SUBROUTINE INFORMATION:
1805 : // AUTHOR Thierry S. Nouidui, Michael Wetter, Wangda Zuo
1806 : // DATE WRITTEN 08Aug2011
1807 :
1808 : // PURPOSE OF THIS SUBROUTINE:
1809 : // This subroutine organizes the data exchange between FMU and EnergyPlus.
1810 :
1811 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
1812 0 : Array1D_string Alphas(5);
1813 0 : Array1D_int keyIndexes(1); // Array index for
1814 0 : Array1D_string NamesOfKeys(1); // Specific key name
1815 :
1816 0 : if (state.dataGlobal->WarmupFlag &&
1817 0 : (state.dataGlobal->KindOfSim != Constant::KindOfSim::RunPeriodWeather)) { // No data exchange during design days
1818 0 : if (state.dataExternalInterface->FirstCallDesignDays) {
1819 0 : ShowWarningError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: ExternalInterface does not exchange data during design days.");
1820 : }
1821 0 : state.dataExternalInterface->FirstCallDesignDays = false;
1822 : }
1823 0 : if (state.dataGlobal->WarmupFlag && (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather)) { // Data exchange after design days
1824 0 : if (state.dataExternalInterface->FirstCallWUp) {
1825 : // set the report during warmup to true so that variables are also updated during the warmup
1826 0 : state.dataSysVars->UpdateDataDuringWarmupExternalInterface = true;
1827 0 : state.dataExternalInterface->hStep = (60.0 * state.dataGlobal->TimeStepZone) * 60.0;
1828 0 : state.dataExternalInterface->tStart = GetCurSimStartTimeSeconds(state);
1829 0 : state.dataExternalInterface->tStop = state.dataExternalInterface->tStart + 24.0 * 3600.0;
1830 0 : state.dataExternalInterface->tComm = state.dataExternalInterface->tStart;
1831 :
1832 : // instantiate and initialize the unpack fmus
1833 0 : InstantiateInitializeFMUImport(state);
1834 :
1835 : // allocate memory for a temporary FMU that will be used at the end of the warmup
1836 0 : state.dataExternalInterface->FMUTemp.allocate(state.dataExternalInterface->NumFMUObjects);
1837 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1838 0 : auto const &fmu = state.dataExternalInterface->FMU(i);
1839 0 : auto &fmuTemp = state.dataExternalInterface->FMUTemp(i);
1840 0 : fmuTemp.Instance.allocate(fmu.NumInstances);
1841 : }
1842 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1843 0 : auto const &fmu = state.dataExternalInterface->FMU(i);
1844 0 : auto &fmuTemp = state.dataExternalInterface->FMUTemp(i);
1845 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1846 0 : auto const &fmuInst = fmu.Instance(j);
1847 0 : auto &fmuTempInst = fmuTemp.Instance(j);
1848 :
1849 0 : fmuTempInst.fmuInputVariable.allocate(fmuInst.NumInputVariablesInIDF);
1850 0 : fmuTempInst.eplusOutputVariable.allocate(fmuInst.NumInputVariablesInIDF);
1851 0 : fmuTempInst.fmuOutputVariableSchedule.allocate(fmuInst.NumOutputVariablesSchedule);
1852 0 : fmuTempInst.fmuOutputVariableVariable.allocate(fmuInst.NumOutputVariablesVariable);
1853 0 : fmuTempInst.fmuOutputVariableActuator.allocate(fmuInst.NumOutputVariablesActuator);
1854 : }
1855 : }
1856 :
1857 0 : GetSetVariablesAndDoStepFMUImport(state);
1858 0 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
1859 0 : state.dataExternalInterface->FirstCallWUp = false;
1860 :
1861 : } else {
1862 0 : if (state.dataExternalInterface->tComm < state.dataExternalInterface->tStop) {
1863 0 : GetSetVariablesAndDoStepFMUImport(state);
1864 : // Advance the communication time step
1865 0 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
1866 : } else {
1867 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1868 0 : auto const &fmu = state.dataExternalInterface->FMU(i);
1869 0 : auto &fmuTemp = state.dataExternalInterface->FMUTemp(i);
1870 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1871 0 : auto const &fmuInst = fmu.Instance(j);
1872 0 : auto &fmuTempInst = fmuTemp.Instance(j);
1873 :
1874 0 : fmuTempInst.NumInputVariablesInIDF = fmuInst.NumInputVariablesInIDF;
1875 0 : for (int k = 1; k <= fmuInst.NumInputVariablesInIDF; ++k) {
1876 0 : fmuTempInst.fmuInputVariable(k).ValueReference = fmuInst.fmuInputVariable(k).ValueReference;
1877 0 : fmuTempInst.eplusOutputVariable(k).RTSValue = fmuInst.eplusOutputVariable(k).RTSValue;
1878 0 : fmuTempInst.eplusOutputVariable(k).ITSValue = fmuInst.eplusOutputVariable(k).ITSValue;
1879 0 : fmuTempInst.eplusOutputVariable(k).VarType = fmuInst.eplusOutputVariable(k).VarType;
1880 : }
1881 :
1882 : // save values that will be set in EnergyPlus (Schedule)
1883 0 : fmuTempInst.NumOutputVariablesSchedule = fmuInst.NumOutputVariablesSchedule;
1884 0 : for (int k = 1; k <= fmuInst.NumOutputVariablesSchedule; ++k) {
1885 0 : fmuTempInst.fmuOutputVariableSchedule(k).RealVarValue = fmuInst.fmuOutputVariableSchedule(k).RealVarValue;
1886 : }
1887 :
1888 : // save values that will be set in EnergyPlus (Variable)
1889 0 : fmuTempInst.NumOutputVariablesVariable = fmuInst.NumOutputVariablesVariable;
1890 0 : for (int k = 1; k <= fmuInst.NumOutputVariablesVariable; ++k) {
1891 0 : fmuTempInst.fmuOutputVariableVariable(k).RealVarValue = fmuInst.fmuOutputVariableVariable(k).RealVarValue;
1892 : }
1893 :
1894 : // save values that will be set in EnergyPlus (Actuator)
1895 0 : fmuTempInst.NumOutputVariablesActuator = fmuInst.NumOutputVariablesActuator;
1896 0 : for (int k = 1; k <= fmuInst.NumOutputVariablesActuator; ++k) {
1897 0 : fmuTempInst.fmuOutputVariableActuator(k).RealVarValue = fmuInst.fmuOutputVariableActuator(k).RealVarValue;
1898 : }
1899 : }
1900 : }
1901 :
1902 0 : StopExternalInterfaceIfError(state);
1903 :
1904 : // Terminate all FMUs
1905 0 : TerminateResetFreeFMUImport(state, state.dataExternalInterface->fmiEndSimulation);
1906 :
1907 : // Reset the communication time step
1908 0 : state.dataExternalInterface->tComm = state.dataExternalInterface->tStart;
1909 :
1910 : // Reinstantiate and reinitialize the FMUs
1911 0 : InstantiateInitializeFMUImport(state);
1912 :
1913 : // Set the values that have been saved in the FMUs-- saveFMUStateVariables ()
1914 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1915 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1916 0 : auto &fmuTemp = state.dataExternalInterface->FMUTemp(i);
1917 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1918 0 : auto &fmuInst = fmu.Instance(j);
1919 0 : auto &fmuTempInst = fmuTemp.Instance(j);
1920 :
1921 0 : std::vector<unsigned int> valRefVec;
1922 0 : for (unsigned long x = 1; x <= size(fmuInst.fmuInputVariable); ++x) {
1923 0 : valRefVec.push_back(fmuInst.fmuInputVariable(x).ValueReference);
1924 : }
1925 :
1926 0 : std::vector<Real64> rtsValVec;
1927 0 : for (unsigned long x = 1; x <= size(fmuInst.eplusOutputVariable); ++x) {
1928 0 : rtsValVec.push_back(fmuInst.eplusOutputVariable(x).RTSValue);
1929 : }
1930 :
1931 : // make the library call
1932 0 : fmuInst.fmistatus =
1933 0 : fmiEPlusSetReal(&fmuInst.fmicomponent, &valRefVec[0], &rtsValVec[0], &fmuTempInst.NumInputVariablesInIDF, &fmuInst.Index);
1934 :
1935 0 : if (fmuInst.fmistatus != fmiOK) {
1936 0 : ShowSevereError(
1937 : state,
1938 0 : format("ExternalInterface/CalcExternalInterfaceFMUImport: Error when trying to set an input value in instance \"{}\"",
1939 0 : fmuInst.Name));
1940 0 : ShowContinueError(state, format("of FMU \"{}\"; Error Code = \"{}\"", fmu.Name, fmuInst.fmistatus));
1941 0 : state.dataExternalInterface->ErrorsFound = true;
1942 0 : StopExternalInterfaceIfError(state);
1943 : }
1944 0 : }
1945 : }
1946 : // set the flag to reinitialize states to be true
1947 0 : state.dataExternalInterface->FlagReIni = true;
1948 0 : GetSetVariablesAndDoStepFMUImport(state);
1949 0 : state.dataExternalInterface->FlagReIni = false;
1950 : // advance one time step ahead for the next calculation
1951 0 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
1952 : }
1953 : }
1954 : }
1955 : // BeginSimulation
1956 0 : if (!state.dataGlobal->WarmupFlag && (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather)) {
1957 :
1958 0 : if (state.dataExternalInterface->FirstCallTStep) {
1959 : // reset the UpdateDataDuringWarmupExternalInterface to be false.
1960 0 : state.dataSysVars->UpdateDataDuringWarmupExternalInterface = false;
1961 : // The time is computed in seconds for FMU
1962 0 : state.dataExternalInterface->tStart = GetCurSimStartTimeSeconds(state);
1963 0 : state.dataExternalInterface->tStop =
1964 0 : state.dataExternalInterface->tStart + (state.dataEnvrn->TotalOverallSimDays - state.dataEnvrn->TotDesDays) * 24.0 * 3600.0;
1965 0 : state.dataExternalInterface->tComm = state.dataExternalInterface->tStart;
1966 :
1967 : // Terminate all FMUs
1968 0 : TerminateResetFreeFMUImport(state, state.dataExternalInterface->fmiEndSimulation);
1969 :
1970 : // Reinstantiate and reinitialize the FMUs
1971 0 : InstantiateInitializeFMUImport(state);
1972 :
1973 : // Set the values that have been saved in the FMUs-- saveFMUStateVariables ()
1974 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
1975 0 : auto &fmu = state.dataExternalInterface->FMU(i);
1976 0 : auto &fmuTemp = state.dataExternalInterface->FMUTemp(i);
1977 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
1978 0 : auto &fmuInst = fmu.Instance(j);
1979 0 : auto &fmuTempInst = fmuTemp.Instance(j);
1980 :
1981 : // make vectors first
1982 0 : std::vector<unsigned int> valRefVec;
1983 0 : for (unsigned long x = 1; x <= size(fmuTempInst.fmuInputVariable); ++x) {
1984 0 : valRefVec.push_back(fmuTempInst.fmuInputVariable(x).ValueReference);
1985 : }
1986 0 : std::vector<Real64> rtsValVec;
1987 0 : for (unsigned long x = 1; x <= size(fmuTempInst.eplusOutputVariable); ++x) {
1988 0 : rtsValVec.push_back(fmuTempInst.eplusOutputVariable(x).RTSValue);
1989 : }
1990 :
1991 : // make the library call
1992 0 : fmuInst.fmistatus =
1993 0 : fmiEPlusSetReal(&fmuInst.fmicomponent, &valRefVec[0], &rtsValVec[0], &fmuTempInst.NumInputVariablesInIDF, &fmuInst.Index);
1994 :
1995 0 : if (fmuInst.fmistatus != fmiOK) {
1996 0 : ShowSevereError(state, "ExternalInterface/CalcExternalInterfaceFMUImport: ");
1997 0 : ShowContinueError(state, "Error when trying to set inputs in instance");
1998 0 : ShowContinueError(state, format("\"{}\" of FMU \"{}\"", fmuInst.Name, fmu.Name));
1999 0 : ShowContinueError(state, format("Error Code = \"{}\"", fmuInst.fmistatus));
2000 0 : state.dataExternalInterface->ErrorsFound = true;
2001 0 : StopExternalInterfaceIfError(state);
2002 : }
2003 0 : }
2004 : }
2005 : // set the flag to reinitialize states to be true
2006 0 : state.dataExternalInterface->FlagReIni = true;
2007 0 : GetSetVariablesAndDoStepFMUImport(state);
2008 0 : state.dataExternalInterface->FlagReIni = false;
2009 : // advance one time step ahead for the next calculation
2010 0 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
2011 0 : state.dataExternalInterface->FirstCallTStep = false;
2012 : } else {
2013 0 : if (state.dataExternalInterface->tComm != state.dataExternalInterface->tStop) {
2014 0 : GetSetVariablesAndDoStepFMUImport(state);
2015 0 : state.dataExternalInterface->tComm += state.dataExternalInterface->hStep;
2016 : } else {
2017 : // Terminate reset and free Slaves
2018 0 : state.dataExternalInterface->fmiEndSimulation = 1;
2019 0 : TerminateResetFreeFMUImport(state, state.dataExternalInterface->fmiEndSimulation);
2020 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2021 0 : auto &fmu = state.dataExternalInterface->FMU(i);
2022 0 : auto &fmuTemp = state.dataExternalInterface->FMUTemp(i);
2023 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
2024 0 : auto &fmuTempInst = fmuTemp.Instance(j);
2025 : // Deallocate used objects
2026 0 : fmuTempInst.fmuInputVariable.deallocate();
2027 0 : fmuTempInst.eplusOutputVariable.deallocate();
2028 0 : fmuTempInst.fmuOutputVariableSchedule.deallocate();
2029 0 : fmuTempInst.fmuOutputVariableVariable.deallocate();
2030 0 : fmuTempInst.fmuOutputVariableActuator.deallocate();
2031 : }
2032 : }
2033 :
2034 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2035 0 : auto &fmuTemp = state.dataExternalInterface->FMUTemp(i);
2036 0 : fmuTemp.Instance.deallocate();
2037 : }
2038 :
2039 0 : state.dataExternalInterface->FMUTemp.deallocate();
2040 :
2041 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2042 0 : auto &fmu = state.dataExternalInterface->FMU(i);
2043 0 : for (int j = 1; j <= fmu.NumInstances; ++j) {
2044 0 : auto &fmuInst = fmu.Instance(j);
2045 0 : fmuInst.eplusInputVariableSchedule.deallocate();
2046 0 : fmuInst.fmuOutputVariableSchedule.deallocate();
2047 0 : fmuInst.eplusInputVariableVariable.deallocate();
2048 0 : fmuInst.fmuOutputVariableVariable.deallocate();
2049 0 : fmuInst.eplusInputVariableActuator.deallocate();
2050 0 : fmuInst.fmuOutputVariableActuator.deallocate();
2051 0 : fmuInst.fmuInputVariable.deallocate();
2052 0 : fmuInst.checkfmuInputVariable.deallocate();
2053 : }
2054 : }
2055 :
2056 0 : for (int i = 1; i <= state.dataExternalInterface->NumFMUObjects; ++i) {
2057 0 : auto &fmu = state.dataExternalInterface->FMU(i);
2058 0 : fmu.Instance.deallocate();
2059 : }
2060 0 : state.dataExternalInterface->FMU.deallocate();
2061 : }
2062 : }
2063 : }
2064 0 : }
2065 :
2066 0 : void ValidateRunControl(EnergyPlusData &state)
2067 : {
2068 : // SUBROUTINE INFORMATION:
2069 : // AUTHOR Michael Wetter
2070 : // DATE WRITTEN December 2009
2071 :
2072 : // PURPOSE OF THIS SUBROUTINE:
2073 : // This subroutine ensures that the RunControl object is valid.
2074 :
2075 : // METHODOLOGY EMPLOYED:
2076 : // Use GetObjectItem from the Input Processor
2077 :
2078 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2079 0 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
2080 :
2081 0 : cCurrentModuleObject = "SimulationControl";
2082 0 : int const NumRunControl = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, cCurrentModuleObject);
2083 0 : if (NumRunControl > 0) {
2084 0 : int NumAlphas = 0; // Number of Alphas for each GetObjectItem call
2085 0 : int NumNumbers = 0; // Number of Numbers for each GetObjectItem call
2086 0 : int IOStatus = 0; // Used in GetObjectItem
2087 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2088 : cCurrentModuleObject,
2089 : 1,
2090 0 : state.dataIPShortCut->cAlphaArgs,
2091 : NumAlphas,
2092 0 : state.dataIPShortCut->rNumericArgs,
2093 : NumNumbers,
2094 : IOStatus,
2095 : _,
2096 : _,
2097 0 : state.dataIPShortCut->cAlphaFieldNames,
2098 0 : state.dataIPShortCut->cNumericFieldNames);
2099 0 : if (state.dataIPShortCut->cAlphaArgs(5) == "NO") { // This run does not have a weather file simulation.
2100 0 : ShowSevereError(state, "ExternalInterface: Error in idf file, section SimulationControl:");
2101 0 : ShowContinueError(state, "When using the ExternalInterface, a run period from the weather file must be specified");
2102 0 : ShowContinueError(state, "in the idf file, because the ExternalInterface interface is not active during");
2103 0 : ShowContinueError(state, "warm-up and during sizing.");
2104 0 : state.dataExternalInterface->ErrorsFound = true;
2105 : }
2106 : }
2107 0 : }
2108 :
2109 0 : void CalcExternalInterface(EnergyPlusData &state)
2110 : {
2111 : // SUBROUTINE INFORMATION:
2112 : // AUTHOR Michael Wetter
2113 : // DATE WRITTEN 2Dec2007
2114 :
2115 : // SUBROUTINE PARAMETER DEFINITIONS:
2116 0 : int constexpr nDblMax(1024); // Maximum number of doubles
2117 :
2118 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2119 : Real64 curSimTim; // current simulation time
2120 : Real64 preSimTim; // previous time step's simulation time
2121 :
2122 0 : Array1D<Real64> dblValWri(nDblMax);
2123 0 : Array1D<Real64> dblValRea(nDblMax);
2124 :
2125 0 : if (state.dataExternalInterface->firstCall) {
2126 0 : DisplayString(state, "ExternalInterface starts first data exchange.");
2127 0 : state.dataExternalInterface->simulationStatus = 2;
2128 0 : preSimTim = 0; // In the first call, E+ did not reset SimTimeSteps to zero
2129 : } else {
2130 0 : preSimTim = state.dataGlobal->SimTimeSteps * state.dataGlobal->MinutesInTimeStep * 60.0;
2131 : }
2132 :
2133 : // Socket asked to terminate simulation, but simulation continues
2134 0 : if (state.dataExternalInterface->noMoreValues && state.dataExternalInterface->showContinuationWithoutUpdate) {
2135 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB) {
2136 0 : ShowWarningError(
2137 0 : state, format("ExternalInterface: Continue simulation without updated values from server at t ={:.2T} hours", preSimTim / 3600.0));
2138 : }
2139 0 : state.dataExternalInterface->showContinuationWithoutUpdate = false;
2140 : }
2141 :
2142 : // Usual branch, control is configured and simulation should continue
2143 0 : if (state.dataExternalInterface->configuredControlPoints && (!state.dataExternalInterface->noMoreValues)) {
2144 : // Data to be exchanged
2145 0 : int nDblWri = size(state.dataExternalInterface->varTypes); // number of doubles to write to socket
2146 0 : int nDblRea = 0; // number of doubles to read from socket
2147 0 : int flaWri = 0; // flag to write to the socket
2148 :
2149 : // Get EnergyPlus variables
2150 0 : if (state.dataExternalInterface->firstCall) { // bug fix causing external interface to send zero at the beginning of sim, Thierry Nouidui
2151 0 : for (int i = 1; i <= nDblWri; ++i) {
2152 0 : dblValWri(i) =
2153 0 : GetInternalVariableValue(state, state.dataExternalInterface->varTypes(i), state.dataExternalInterface->keyVarIndexes(i));
2154 : }
2155 : } else {
2156 0 : for (int i = 1; i <= nDblWri; ++i) {
2157 0 : dblValWri(i) = GetInternalVariableValueExternalInterface(
2158 0 : state, state.dataExternalInterface->varTypes(i), state.dataExternalInterface->keyVarIndexes(i));
2159 : }
2160 : }
2161 :
2162 : // Exchange data with socket
2163 0 : int retVal = 0;
2164 0 : int flaRea = 0; // flag read from the socket
2165 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB) {
2166 0 : retVal = exchangedoubleswithsocket(&state.dataExternalInterface->socketFD,
2167 : &flaWri,
2168 : &flaRea,
2169 : &nDblWri,
2170 : &nDblRea,
2171 : &preSimTim,
2172 : dblValWri.data(),
2173 : &curSimTim,
2174 : dblValRea.data());
2175 0 : } else if (state.dataExternalInterface->haveExternalInterfaceFMUExport) {
2176 0 : retVal = exchangedoubleswithsocketFMU(&state.dataExternalInterface->socketFD,
2177 : &flaWri,
2178 : &flaRea,
2179 : &nDblWri,
2180 : &nDblRea,
2181 : &preSimTim,
2182 : dblValWri.data(),
2183 : &curSimTim,
2184 : dblValRea.data(),
2185 0 : &state.dataExternalInterface->FMUExportActivate);
2186 : }
2187 0 : bool continueSimulation = true;
2188 :
2189 : // Check for errors, in which case we terminate the simulation loop
2190 : // Added a check since the FMUExport is terminated with the flaRea set to 1.
2191 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB ||
2192 0 : (state.dataExternalInterface->haveExternalInterfaceFMUExport && (flaRea == 0))) {
2193 0 : if (retVal != 0) {
2194 0 : continueSimulation = false;
2195 0 : ShowSevereError(state,
2196 0 : format("ExternalInterface: Socket communication received error value \"{:2}\" at time = {:.2T} hours.",
2197 : retVal,
2198 0 : preSimTim / 3600));
2199 0 : ShowContinueError(state, format("ExternalInterface: Flag from server \"{:2}\".", flaRea));
2200 0 : state.dataExternalInterface->ErrorsFound = true;
2201 0 : StopExternalInterfaceIfError(state);
2202 : }
2203 : }
2204 :
2205 : // Check communication flag
2206 0 : if (flaRea != 0) {
2207 : // No more values will be received in future steps
2208 : // Added a check since the FMUExport is terminated with the flaRea set to 1.
2209 0 : state.dataExternalInterface->noMoreValues = true;
2210 0 : if (state.dataExternalInterface->haveExternalInterfaceBCVTB) {
2211 0 : ShowSevereError(state, format("ExternalInterface: Received end of simulation flag at time = {:.2T} hours.", preSimTim / 3600));
2212 0 : StopExternalInterfaceIfError(state);
2213 : }
2214 : }
2215 :
2216 : // Make sure we get the right number of double values, unless retVal != 0
2217 0 : if ((flaRea == 0) && (!state.dataExternalInterface->ErrorsFound) && continueSimulation &&
2218 0 : (nDblRea != isize(state.dataExternalInterface->varInd))) {
2219 0 : ShowSevereError(
2220 : state,
2221 0 : format("ExternalInterface: Received \"{}\" double values, expected \"{}\".", nDblRea, size(state.dataExternalInterface->varInd)));
2222 0 : state.dataExternalInterface->ErrorsFound = true;
2223 0 : StopExternalInterfaceIfError(state);
2224 : }
2225 :
2226 : // No errors found. Assign exchanged variables
2227 0 : if ((flaRea == 0) && continueSimulation) {
2228 0 : for (int i = 1; i <= isize(state.dataExternalInterface->varInd); ++i) {
2229 0 : if (state.dataExternalInterface->inpVarTypes(i) == indexSchedule) {
2230 0 : Sched::ExternalInterfaceSetSchedule(state, state.dataExternalInterface->varInd(i), dblValRea(i));
2231 0 : } else if ((state.dataExternalInterface->inpVarTypes(i) == indexVariable) ||
2232 0 : (state.dataExternalInterface->inpVarTypes(i) == indexActuator)) {
2233 0 : RuntimeLanguageProcessor::ExternalInterfaceSetErlVariable(state, state.dataExternalInterface->varInd(i), dblValRea(i));
2234 : } else {
2235 0 : ShowContinueError(state, "ExternalInterface: Error in finding the type of the input variable for EnergyPlus");
2236 0 : ShowContinueError(state, format("variable index: {}. Variable will not be updated.", i));
2237 : }
2238 : }
2239 : }
2240 : }
2241 :
2242 : // If we have Erl variables, we need to call ManageEMS so that they get updated in the Erl data structure
2243 0 : if (state.dataExternalInterface->useEMS) {
2244 : bool anyRan;
2245 0 : EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::ExternalInterface, anyRan, ObjexxFCL::Optional_int_const());
2246 : }
2247 :
2248 0 : state.dataExternalInterface->firstCall = false; // bug fix causing external interface to send zero at the beginning of sim, Thierry Nouidui
2249 0 : }
2250 :
2251 0 : void GetReportVariableKey(
2252 : EnergyPlusData &state,
2253 : const Array1D_string &varKeys, // Standard variable name
2254 : int const numberOfKeys, // Number of keys=size(state.dataExternalInterface->varKeys)
2255 : const Array1D_string &VarNames, // Standard variable name
2256 : Array1D_int &keyVarIndexes, // Array index
2257 : Array1D<OutputProcessor::VariableType> &varTypes // Types of variables in state.dataExternalInterface->keystate.dataExternalInterface->varIndexes
2258 : )
2259 : {
2260 : // SUBROUTINE INFORMATION:
2261 : // AUTHOR Michael Wetter
2262 : // DATE WRITTEN 2Dec2007
2263 :
2264 : // PURPOSE OF THIS SUBROUTINE:
2265 : // Gets the sensor key index and type for the specified variable key and name
2266 :
2267 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2268 0 : OutputProcessor::VariableType varType(OutputProcessor::VariableType::Invalid); // 0=not found, 1=integer, 2=real, 3=meter
2269 0 : int numKeys(0); // Number of keys found
2270 0 : OutputProcessor::StoreType varAvgSum(OutputProcessor::StoreType::Average); // Variable is Averaged=1 or Summed=2
2271 0 : OutputProcessor::TimeStepType varStepType(OutputProcessor::TimeStepType::Zone); // Variable time step is Zone=1 or HVAC=2
2272 0 : Constant::Units varUnits(Constant::Units::None); // Units sting, may be blank
2273 0 : Array1D_string keyNames;
2274 0 : Array1D_int keyIndexes; // Array index for
2275 : int Loop, iKey; // Loop counters
2276 :
2277 : // Get pointers for variables to be sent to Ptolemy
2278 0 : for (Loop = 1; Loop <= numberOfKeys; ++Loop) {
2279 0 : GetVariableKeyCountandType(state, VarNames(Loop), numKeys, varType, varAvgSum, varStepType, varUnits);
2280 0 : if (varType != OutputProcessor::VariableType::Invalid) {
2281 0 : keyIndexes.allocate(numKeys);
2282 0 : keyNames.allocate(numKeys);
2283 0 : GetVariableKeys(state, VarNames(Loop), varType, keyNames, keyIndexes);
2284 : // Find key index whose keyName is equal to keyNames(Loop)
2285 0 : int max(keyIndexes.size());
2286 0 : for (iKey = 1; iKey <= max; ++iKey) {
2287 0 : if (keyNames(iKey) == varKeys(Loop)) {
2288 0 : keyVarIndexes(Loop) = keyIndexes(iKey);
2289 0 : varTypes(Loop) = varType;
2290 0 : break;
2291 : }
2292 : }
2293 0 : keyIndexes.deallocate();
2294 0 : keyNames.deallocate();
2295 : }
2296 0 : if ((varType == OutputProcessor::VariableType::Invalid) || (iKey > numKeys)) {
2297 0 : ShowSevereError(state,
2298 0 : format("ExternalInterface: Simulation model has no variable \"{}\" with key \"{}\".", VarNames(Loop), varKeys(Loop)));
2299 0 : state.dataExternalInterface->ErrorsFound = true;
2300 : }
2301 : }
2302 0 : }
2303 :
2304 585 : void WarnIfExternalInterfaceObjectsAreUsed(EnergyPlusData &state, std::string const &ObjectWord)
2305 : {
2306 : // SUBROUTINE INFORMATION:
2307 : // AUTHOR Michael Wetter
2308 : // DATE WRITTEN December 2009
2309 :
2310 : // PURPOSE OF THIS SUBROUTINE:
2311 : // This subroutine writes a warning if ExternalInterface objects are used in the
2312 : // idf file, but the ExternalInterface link is not specified.
2313 :
2314 585 : int const NumObjects = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, ObjectWord);
2315 585 : if (NumObjects > 0) {
2316 0 : ShowWarningError(state, format("IDF file contains object \"{}\",", ObjectWord));
2317 0 : ShowContinueError(state, "but object \"ExternalInterface\" with appropriate key entry is not specified. Values will not be updated.");
2318 : }
2319 585 : }
2320 :
2321 0 : void VerifyExternalInterfaceObject(EnergyPlusData &state)
2322 : {
2323 : // SUBROUTINE INFORMATION:
2324 : // AUTHOR Michael Wetter
2325 : // DATE WRITTEN 12Dec2009
2326 :
2327 : // PURPOSE OF THIS SUBROUTINE:
2328 : // This subroutine verifies the correctness of the fields of
2329 : // the ExternalInterface object in the idf file
2330 :
2331 : // SUBROUTINE LOCAL VARIABLE DECLARATIONS:
2332 0 : int NumAlphas(0); // Number of Alphas for each GetObjectItem call
2333 0 : int NumNumbers(0); // Number of Numbers for each GetObjectItem call
2334 0 : int IOStatus(0); // Used in GetObjectItem
2335 0 : auto &cCurrentModuleObject = state.dataIPShortCut->cCurrentModuleObject;
2336 :
2337 0 : cCurrentModuleObject = "ExternalInterface";
2338 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
2339 : cCurrentModuleObject,
2340 : 1,
2341 0 : state.dataIPShortCut->cAlphaArgs,
2342 : NumAlphas,
2343 0 : state.dataIPShortCut->rNumericArgs,
2344 : NumNumbers,
2345 : IOStatus,
2346 : _,
2347 : _,
2348 0 : state.dataIPShortCut->cAlphaFieldNames,
2349 0 : state.dataIPShortCut->cNumericFieldNames);
2350 0 : if ((!Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "PtolemyServer")) &&
2351 0 : (!Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "FunctionalMockupUnitImport")) &&
2352 0 : (!Util::SameString(state.dataIPShortCut->cAlphaArgs(1), "FunctionalMockupUnitExport"))) {
2353 0 : ShowSevereError(state,
2354 0 : format("VerifyExternalInterfaceObject: {}, invalid {}=\"{}\".",
2355 : cCurrentModuleObject,
2356 0 : state.dataIPShortCut->cAlphaFieldNames(1),
2357 0 : state.dataIPShortCut->cAlphaArgs(1)));
2358 0 : ShowContinueError(state, "only \"PtolemyServer or FunctionalMockupUnitImport or FunctionalMockupUnitExport\" allowed.");
2359 0 : state.dataExternalInterface->ErrorsFound = true;
2360 : }
2361 0 : }
2362 :
2363 0 : std::vector<char> getCharArrayFromString(std::string const &originalString)
2364 : {
2365 : // c_str returns null terminated, so we don't need a +1?
2366 0 : return std::vector<char>(originalString.c_str(), originalString.c_str() + originalString.size());
2367 : }
2368 :
2369 0 : std::string getStringFromCharArray(std::vector<char> originalCharArray)
2370 : {
2371 0 : originalCharArray.push_back('\0');
2372 0 : return std::string(&originalCharArray.front());
2373 : }
2374 :
2375 : } // namespace EnergyPlus::ExternalInterface
|