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