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