Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : #include <EnergyPlus/IOFiles.hh>
49 :
50 : #include "Data/EnergyPlusData.hh"
51 : #include "DataStringGlobals.hh"
52 : #include "FileSystem.hh"
53 : #include "InputProcessing/InputProcessor.hh"
54 : #include "ResultsFramework.hh"
55 : #include "UtilityRoutines.hh"
56 : #include <embedded/EmbeddedEpJSONSchema.hh>
57 :
58 : #include <algorithm>
59 : #include <fmt/format.h>
60 : #include <memory>
61 : #include <stdexcept>
62 :
63 : namespace EnergyPlus {
64 :
65 813 : InputFile &InputFile::ensure_open(EnergyPlusData &state, const std::string &caller, bool output_to_file)
66 : {
67 813 : if (!good()) {
68 813 : open(false, output_to_file);
69 : }
70 813 : if (!good()) {
71 0 : ShowFatalError(state, fmt::format("{}: Could not open file {} for input (read).", caller, filePath));
72 : }
73 813 : return *this;
74 : }
75 :
76 438200 : bool InputFile::good() const noexcept
77 : {
78 438200 : if (is) {
79 437387 : return is->good();
80 : } else {
81 813 : return false;
82 : }
83 : }
84 :
85 18761 : void InputFile::close()
86 : {
87 18761 : is.reset();
88 18761 : }
89 :
90 2933859 : InputFile::ReadResult<std::string> InputFile::readLine() noexcept
91 : {
92 2933859 : if (!is) {
93 0 : return {"", true, false};
94 : }
95 :
96 2933859 : std::string line;
97 2933859 : if (std::getline(*is, line)) {
98 2933058 : if (!line.empty() && line.back() == '\r') {
99 73 : line.pop_back();
100 : }
101 : // Use operator bool, see ReadResult::good() docstring
102 2933058 : return {std::move(line), is->eof(), bool(is)};
103 : } else {
104 1602 : return {"", is->eof(), false};
105 : }
106 2933859 : }
107 :
108 0 : std::string InputFile::readFile()
109 : {
110 0 : std::string result(file_size, '\0');
111 0 : is->read(result.data(), file_size);
112 0 : return result;
113 0 : }
114 :
115 0 : nlohmann::json InputFile::readJSON()
116 : {
117 0 : FileSystem::FileTypes const ext = FileSystem::getFileType(filePath);
118 0 : switch (ext) {
119 0 : case FileSystem::FileTypes::EpJSON:
120 : case FileSystem::FileTypes::JSON:
121 : case FileSystem::FileTypes::GLHE:
122 0 : return nlohmann::json::parse(*is, nullptr, true, true);
123 0 : case FileSystem::FileTypes::CBOR:
124 0 : return nlohmann::json::from_cbor(*is);
125 0 : case FileSystem::FileTypes::MsgPack:
126 0 : return nlohmann::json::from_msgpack(*is);
127 0 : case FileSystem::FileTypes::UBJSON:
128 0 : return nlohmann::json::from_ubjson(*is);
129 0 : case FileSystem::FileTypes::BSON:
130 0 : return nlohmann::json::from_bson(*is);
131 0 : default:
132 0 : throw FatalError("Invalid file extension. Must be epJSON, JSON, or other experimental extensions");
133 : }
134 : }
135 :
136 3651 : InputFile::InputFile(fs::path FilePath) : filePath(std::move(FilePath))
137 : {
138 3651 : }
139 :
140 0 : std::ostream::pos_type InputFile::position() const noexcept
141 : {
142 0 : return is->tellg();
143 : }
144 :
145 7419 : void InputFile::open(bool, bool)
146 : {
147 7419 : file_size = fs::file_size(filePath);
148 : // basic_fstream is a template, it has no problem with wchar_t (which filePath.c_str() returns on Windows)
149 7419 : is = std::make_unique<std::fstream>(filePath.c_str(), std::ios_base::in | std::ios_base::binary);
150 : // is->imbue(std::locale("C"));
151 7419 : }
152 :
153 0 : std::string InputFile::error_state_to_string() const
154 : {
155 0 : const std::istream::iostate state = rdstate();
156 :
157 0 : if (!is_open()) {
158 0 : return "file not opened'";
159 : }
160 :
161 0 : if (state == std::ios_base::failbit) {
162 0 : return "io operation failed";
163 0 : } else if (state == std::ios_base::badbit) {
164 0 : return "irrecoverable stream error";
165 0 : } else if (state == std::ios_base::eofbit) {
166 0 : return "end of file reached";
167 : } else {
168 0 : return "no error";
169 : }
170 : }
171 :
172 0 : std::istream::iostate InputFile::rdstate() const noexcept
173 : {
174 0 : if (is) {
175 0 : return is->rdstate();
176 : } else {
177 0 : return std::ios_base::badbit;
178 : }
179 : }
180 :
181 2037 : bool InputFile::is_open() const noexcept
182 : {
183 2037 : if (is) {
184 2037 : auto *ss = dynamic_cast<std::ifstream *>(is.get());
185 2037 : if (ss) {
186 0 : return ss->is_open();
187 : } else {
188 2037 : return true;
189 : }
190 : } else {
191 0 : return false;
192 : }
193 : }
194 :
195 1233 : void InputFile::backspace() noexcept
196 : {
197 1233 : if (is) {
198 1233 : is->clear();
199 1233 : std::streamoff g1(is->tellg()); // Current position
200 1233 : is->seekg(0, std::ios::beg); // Beginning of file
201 1233 : std::streampos const g0(is->tellg());
202 1233 : is->seekg(g1, std::ios::beg); // Restore position
203 1233 : if (g1 > g0) {
204 1233 : --g1;
205 : }
206 214866 : while (g1 > g0) {
207 214866 : is->seekg(--g1, std::ios::beg); // Backup by 1
208 214866 : if (is->peek() == '\n') { // Found end of previous record
209 1233 : is->seekg(++g1, std::ios::beg);
210 1233 : break;
211 : }
212 : }
213 : }
214 1233 : }
215 :
216 10324 : InputOutputFile &InputOutputFile::ensure_open(EnergyPlusData &state, const std::string &caller, bool output_to_file)
217 : {
218 10324 : if (!good()) {
219 8664 : open(false, output_to_file);
220 : }
221 10324 : if (!good()) {
222 0 : ShowFatalError(state, fmt::format("{}: Could not open file {} for output (write).", caller, filePath));
223 : }
224 10324 : return *this;
225 : }
226 :
227 17362790 : bool InputOutputFile::good() const
228 : {
229 17362790 : if (os && print_to_dev_null && os->bad()) { // badbit is set
230 17110 : return true;
231 17345680 : } else if (os) {
232 17193128 : return os->good();
233 : } else {
234 152552 : return false;
235 : }
236 : }
237 :
238 6683 : void InputOutputFile::close()
239 : {
240 6683 : os.reset();
241 6683 : }
242 :
243 965 : void InputOutputFile::del()
244 : {
245 965 : if (os) {
246 965 : os.reset();
247 965 : FileSystem::removeFile(filePath);
248 : }
249 965 : }
250 :
251 0 : void InputOutputFile::open_as_stringstream()
252 : {
253 0 : os = std::make_unique<std::stringstream>();
254 0 : }
255 :
256 0 : void InputOutputFile::flush()
257 : {
258 0 : if (os) {
259 0 : os->flush();
260 : }
261 0 : }
262 :
263 0 : std::string InputOutputFile::get_output()
264 : {
265 0 : auto *ss = dynamic_cast<std::stringstream *>(os.get());
266 0 : if (ss) {
267 0 : return ss->str();
268 : } else {
269 0 : return "";
270 : }
271 : }
272 :
273 167800 : InputOutputFile::InputOutputFile(fs::path FilePath, const bool DefaultToStdout) : filePath{std::move(FilePath)}, defaultToStdOut{DefaultToStdout}
274 : {
275 167800 : }
276 :
277 801 : std::ostream::pos_type InputOutputFile::position() const noexcept
278 : {
279 801 : return os->tellg();
280 : }
281 :
282 9465 : void InputOutputFile::open(const bool forAppend, bool output_to_file)
283 : {
284 28395 : auto appendMode = [=]() {
285 9465 : if (forAppend) {
286 0 : return std::ios_base::app;
287 : } else {
288 9465 : return std::ios_base::trunc;
289 : }
290 9465 : }();
291 9465 : if (!output_to_file) {
292 29 : os = std::make_unique<std::iostream>(nullptr);
293 : // os->imbue(std::locale("C"));
294 29 : print_to_dev_null = true;
295 : } else {
296 9436 : os = std::make_unique<std::fstream>(filePath.c_str(), std::ios_base::in | std::ios_base::out | appendMode);
297 : // os->imbue(std::locale("C"));
298 9436 : print_to_dev_null = false;
299 : }
300 9465 : }
301 :
302 687 : std::vector<std::string> InputOutputFile::getLines()
303 : {
304 687 : if (os) {
305 : // avoid saving and reloading the file by simply reading the current input stream
306 687 : os->flush();
307 687 : const size_t last_pos = os->tellg();
308 687 : std::string line;
309 687 : std::vector<std::string> lines;
310 687 : os->seekg(0);
311 :
312 228794 : while (std::getline(*os, line)) {
313 228107 : lines.push_back(line);
314 : }
315 :
316 : // after getline is done, we're at eof/fail bit
317 687 : os->clear();
318 687 : os->seekg(last_pos);
319 687 : return lines;
320 687 : }
321 0 : return std::vector<std::string>();
322 : }
323 :
324 3196 : bool IOFiles::OutputControl::writeTabular(EnergyPlusData &state)
325 : {
326 3196 : bool const htmlTabular = state.files.outputControl.tabular;
327 3196 : bool const jsonTabular = state.files.outputControl.json && state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled();
328 3196 : bool const sqliteTabular = state.files.outputControl.sqlite; // && @JasonGlazer thinks something else maybe?
329 3196 : return (htmlTabular || jsonTabular || sqliteTabular);
330 : }
331 :
332 801 : void IOFiles::OutputControl::getInput(EnergyPlusData &state)
333 : {
334 801 : auto &ip = state.dataInputProcessing->inputProcessor;
335 1602 : auto const instances = ip->epJSON.find("OutputControl:Files");
336 801 : if (instances != ip->epJSON.end()) {
337 :
338 224 : auto find_input = [=, &state](nlohmann::json const &fields, std::string const &field_name) -> std::string {
339 224 : std::string input;
340 224 : auto found = fields.find(field_name);
341 224 : if (found != fields.end()) {
342 78 : input = found.value().get<std::string>();
343 78 : input = Util::makeUPPER(input);
344 : } else {
345 438 : state.dataInputProcessing->inputProcessor->getDefaultValue(state, "OutputControl:Files", field_name, input);
346 : }
347 448 : return input;
348 224 : };
349 :
350 224 : auto boolean_choice = [=, &state](std::string const &input) -> bool {
351 224 : if (input == "YES") {
352 173 : return true;
353 51 : } else if (input == "NO") {
354 51 : return false;
355 : }
356 0 : ShowFatalError(state, "Invalid boolean Yes/No choice input");
357 0 : return true;
358 7 : };
359 :
360 7 : auto &instancesValue = instances.value();
361 14 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
362 7 : auto const &fields = instance.value();
363 :
364 21 : ip->markObjectAsUsed("OutputControl:Files", instance.key());
365 :
366 : { // "output_csv"
367 14 : csv = boolean_choice(find_input(fields, "output_csv"));
368 : }
369 : { // "output_mtr"
370 14 : mtr = boolean_choice(find_input(fields, "output_mtr"));
371 : }
372 : { // "output_eso"
373 14 : eso = boolean_choice(find_input(fields, "output_eso"));
374 : }
375 : { // "output_eio"
376 14 : eio = boolean_choice(find_input(fields, "output_eio"));
377 : }
378 : { // "output_audit"
379 14 : audit = boolean_choice(find_input(fields, "output_audit"));
380 : }
381 : { // "output_space_sizing"
382 14 : spsz = boolean_choice(find_input(fields, "output_space_sizing"));
383 : }
384 : { // "output_zone_sizing"
385 14 : zsz = boolean_choice(find_input(fields, "output_zone_sizing"));
386 : }
387 : { // "output_system_sizing"
388 14 : ssz = boolean_choice(find_input(fields, "output_system_sizing"));
389 : }
390 : { // "output_dxf"
391 14 : dxf = boolean_choice(find_input(fields, "output_dxf"));
392 : }
393 : { // "output_bnd"
394 14 : bnd = boolean_choice(find_input(fields, "output_bnd"));
395 : }
396 : { // "output_rdd"
397 14 : rdd = boolean_choice(find_input(fields, "output_rdd"));
398 : }
399 : { // "output_mdd"
400 14 : mdd = boolean_choice(find_input(fields, "output_mdd"));
401 : }
402 : { // "output_mtd"
403 14 : mtd = boolean_choice(find_input(fields, "output_mtd"));
404 : }
405 : { // "output_end"
406 14 : end = boolean_choice(find_input(fields, "output_end"));
407 : }
408 : { // "output_shd"
409 14 : shd = boolean_choice(find_input(fields, "output_shd"));
410 : }
411 : { // "output_dfs"
412 14 : dfs = boolean_choice(find_input(fields, "output_dfs"));
413 : }
414 : { // "output_glhe"
415 14 : glhe = boolean_choice(find_input(fields, "output_glhe"));
416 : }
417 : { // "output_delightin"
418 14 : delightin = boolean_choice(find_input(fields, "output_delightin"));
419 : }
420 : { // "output_delighteldmp"
421 14 : delighteldmp = boolean_choice(find_input(fields, "output_delighteldmp"));
422 : }
423 : { // "output_delightdfdmp"
424 14 : delightdfdmp = boolean_choice(find_input(fields, "output_delightdfdmp"));
425 : }
426 : { // "output_edd"
427 14 : edd = boolean_choice(find_input(fields, "output_edd"));
428 : }
429 : { // "output_dbg"
430 14 : dbg = boolean_choice(find_input(fields, "output_dbg"));
431 : }
432 : { // "output_perflog"
433 14 : perflog = boolean_choice(find_input(fields, "output_perflog"));
434 : }
435 : { // "output_sln"
436 14 : sln = boolean_choice(find_input(fields, "output_sln"));
437 : }
438 : { // "output_sci"
439 14 : sci = boolean_choice(find_input(fields, "output_sci"));
440 : }
441 : { // "output_wrl"
442 14 : wrl = boolean_choice(find_input(fields, "output_wrl"));
443 : }
444 : { // "output_screen"
445 14 : screen = boolean_choice(find_input(fields, "output_screen"));
446 : }
447 : { // "output_tarcog"
448 14 : tarcog = boolean_choice(find_input(fields, "output_tarcog"));
449 : }
450 : { // "output_extshd"
451 14 : extshd = boolean_choice(find_input(fields, "output_extshd"));
452 : }
453 : { // "json"
454 14 : json = boolean_choice(find_input(fields, "output_json"));
455 : }
456 : { // "tabular"
457 14 : tabular = boolean_choice(find_input(fields, "output_tabular"));
458 : }
459 : { // "sqlite"
460 14 : sqlite = boolean_choice(find_input(fields, "output_sqlite"));
461 : }
462 7 : }
463 : }
464 :
465 1602 : auto const timestamp_instances = ip->epJSON.find("OutputControl:Timestamp");
466 801 : if (timestamp_instances != ip->epJSON.end()) {
467 1 : auto const &instancesValue = timestamp_instances.value();
468 2 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
469 1 : auto const &fields = instance.value();
470 3 : ip->markObjectAsUsed("OutputControl:Timestamp", instance.key());
471 :
472 1 : auto item = fields.find("iso_8601_format");
473 1 : if (item != fields.end()) {
474 1 : state.dataResultsFramework->resultsFramework->setISO8601(item->get<std::string>() == "Yes");
475 : }
476 :
477 1 : item = fields.find("timestamp_at_beginning_of_interval");
478 1 : if (item != fields.end()) {
479 1 : state.dataResultsFramework->resultsFramework->setBeginningOfInterval(item->get<std::string>() == "Yes");
480 : }
481 2 : }
482 : }
483 801 : }
484 :
485 0 : void IOFiles::flushAll()
486 : {
487 :
488 0 : audit.flush();
489 0 : eio.flush();
490 0 : eso.flush();
491 0 : zsz.flush();
492 0 : spsz.flush();
493 0 : ssz.flush();
494 0 : map.flush();
495 0 : mtr.flush();
496 0 : bnd.flush();
497 0 : rdd.flush();
498 0 : mdd.flush();
499 0 : debug.flush();
500 0 : dfs.flush();
501 0 : mtd.flush();
502 0 : edd.flush();
503 0 : shade.flush();
504 0 : csv.flush();
505 :
506 0 : if (err_stream) {
507 0 : err_stream->flush();
508 : }
509 0 : }
510 :
511 : } // namespace EnergyPlus
512 :
513 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int>(std::string_view, int &&);
514 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const char *const &>(std::string_view, const char *const &);
515 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, std::string &>(std::string_view, int &, std::string &);
516 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, std::string &, std::string &, double &>(
517 : std::string_view, std::string &, std::string &, std::string &, double &);
518 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const std::string_view &>(std::string_view, const std::string_view &);
519 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const std::string_view &, std::string &>(std::string_view,
520 : const std::string_view &,
521 : std::string &);
522 : template std::string
523 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, double &, double &>(std::string_view, std::string &, double &, double &);
524 : template std::string
525 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, std::string &, int &>(std::string_view, std::string &, std::string &, int &);
526 : template std::string
527 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &, double &, double &>(std::string_view, double &, double &, double &);
528 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &, std::string &>(std::string_view, double &, std::string &);
529 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &>(std::string_view, std::string &);
530 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const int &, int &>(std::string_view, const int &, int &);
531 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double>(std::string_view, double &&);
532 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, int &>(std::string_view, int &, int &);
533 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const double &>(std::string_view, const double &);
534 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, int &>(std::string_view, std::string &, int &);
535 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, std::string &, double &>(std::string_view,
536 : std::string &,
537 : std::string &,
538 : double &);
539 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, double &, std::string &, double &>(
540 : std::string_view, std::string &, double &, std::string &, double &);
541 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const int &>(std::string_view, const int &);
542 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, const std::string &, std::string &>(std::string_view,
543 : int &,
544 : const std::string &,
545 : std::string &);
546 : template std::string
547 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, int &, const std::string &>(std::string_view, int &, int &, const std::string &);
548 : template std::string
549 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, int &, std::string_view &>(std::string_view, int &, int &, std::string_view &);
550 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, std::string_view &, std::string &>(std::string_view,
551 : int &,
552 : std::string_view &,
553 : std::string &);
554 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &, double &>(std::string_view, double &, double &);
555 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &>(std::string_view, int &);
556 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, double &>(std::string_view, std::string &, double &);
557 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &>(std::string_view, double &);
|