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