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 : #include <EnergyPlus/IOFiles.hh>
49 :
50 : #include "Data/EnergyPlusData.hh"
51 : #include "DataStringGlobals.hh"
52 : #include "FileSystem.hh"
53 : #include "InputProcessing/EmbeddedEpJSONSchema.hh"
54 : #include "InputProcessing/InputProcessor.hh"
55 : #include "UtilityRoutines.hh"
56 :
57 : #include <algorithm>
58 : #include <fmt/format.h>
59 : #include <memory>
60 : #include <stdexcept>
61 :
62 : namespace EnergyPlus {
63 :
64 781 : InputFile &InputFile::ensure_open(EnergyPlusData &state, const std::string &caller, bool output_to_file)
65 : {
66 781 : if (!good()) {
67 781 : open(false, output_to_file);
68 : }
69 781 : if (!good()) {
70 0 : ShowFatalError(state, fmt::format("{}: Could not open file {} for input (read).", caller, filePath.string()));
71 : }
72 781 : return *this;
73 : }
74 :
75 421303 : bool InputFile::good() const noexcept
76 : {
77 421303 : if (is) {
78 420522 : return is->good();
79 : } else {
80 781 : return false;
81 : }
82 : }
83 :
84 18033 : void InputFile::close()
85 : {
86 18033 : is.reset();
87 18033 : }
88 :
89 2808953 : InputFile::ReadResult<std::string> InputFile::readLine() noexcept
90 : {
91 2808953 : if (is) {
92 5617906 : std::string line;
93 2808953 : std::getline(*is, line);
94 2808953 : if (!line.empty() && line.back() == '\r') {
95 0 : line.pop_back();
96 : }
97 2808953 : return {std::move(line), is->eof(), is->good()};
98 : } else {
99 0 : return {"", true, false};
100 : }
101 : }
102 :
103 0 : std::string InputFile::readFile()
104 : {
105 0 : std::string result(file_size, '\0');
106 0 : is->read(result.data(), file_size);
107 0 : return result;
108 : }
109 :
110 0 : nlohmann::json InputFile::readJSON()
111 : {
112 0 : auto const ext = FileSystem::getFileType(filePath);
113 0 : switch (ext) {
114 0 : case FileSystem::FileTypes::EpJSON:
115 : case FileSystem::FileTypes::JSON:
116 : case FileSystem::FileTypes::GLHE:
117 0 : return nlohmann::json::parse(*is, nullptr, true, true);
118 0 : case FileSystem::FileTypes::CBOR:
119 0 : return nlohmann::json::from_cbor(*is);
120 0 : case FileSystem::FileTypes::MsgPack:
121 0 : return nlohmann::json::from_msgpack(*is);
122 0 : case FileSystem::FileTypes::UBJSON:
123 0 : return nlohmann::json::from_ubjson(*is);
124 0 : case FileSystem::FileTypes::BSON:
125 0 : return nlohmann::json::from_bson(*is);
126 0 : default:
127 0 : throw FatalError("Invalid file extension. Must be epJSON, JSON, or other experimental extensions");
128 : }
129 : }
130 :
131 3589 : InputFile::InputFile(fs::path FilePath) : filePath(std::move(FilePath))
132 : {
133 3589 : }
134 :
135 0 : std::ostream::pos_type InputFile::position() const noexcept
136 : {
137 0 : return is->tellg();
138 : }
139 :
140 7187 : void InputFile::open(bool, bool)
141 : {
142 7187 : file_size = fs::file_size(filePath);
143 : // basic_fstream is a template, it has no problem with wchar_t (which filePath.c_str() returns on Windows)
144 7187 : is = std::make_unique<std::fstream>(filePath.c_str(), std::ios_base::in | std::ios_base::binary);
145 : // is->imbue(std::locale("C"));
146 7187 : }
147 :
148 0 : std::string InputFile::error_state_to_string() const
149 : {
150 0 : const auto state = rdstate();
151 :
152 0 : if (!is_open()) {
153 0 : return "file not opened'";
154 : }
155 :
156 0 : if (state == std::ios_base::failbit) {
157 0 : return "io operation failed";
158 0 : } else if (state == std::ios_base::badbit) {
159 0 : return "irrecoverable stream error";
160 0 : } else if (state == std::ios_base::eofbit) {
161 0 : return "end of file reached";
162 : } else {
163 0 : return "no error";
164 : }
165 : }
166 :
167 0 : std::istream::iostate InputFile::rdstate() const noexcept
168 : {
169 0 : if (is) {
170 0 : return is->rdstate();
171 : } else {
172 0 : return std::ios_base::badbit;
173 : }
174 : }
175 :
176 2037 : bool InputFile::is_open() const noexcept
177 : {
178 2037 : if (is) {
179 2037 : auto *ss = dynamic_cast<std::ifstream *>(is.get());
180 2037 : if (ss) {
181 0 : return ss->is_open();
182 : } else {
183 2037 : return true;
184 : }
185 : } else {
186 0 : return false;
187 : }
188 : }
189 :
190 1186 : void InputFile::backspace() noexcept
191 : {
192 1186 : if (is) {
193 1186 : is->clear();
194 1186 : std::streamoff g1(is->tellg()); // Current position
195 1186 : is->seekg(0, std::ios::beg); // Beginning of file
196 1186 : std::streampos const g0(is->tellg());
197 1186 : is->seekg(g1, std::ios::beg); // Restore position
198 1186 : if (g1 > g0) --g1;
199 412212 : while (g1 > g0) {
200 206699 : is->seekg(--g1, std::ios::beg); // Backup by 1
201 206699 : if (is->peek() == '\n') { // Found end of previous record
202 1186 : is->seekg(++g1, std::ios::beg);
203 1186 : break;
204 : }
205 : }
206 : }
207 1186 : }
208 :
209 9879 : InputOutputFile &InputOutputFile::ensure_open(EnergyPlusData &state, const std::string &caller, bool output_to_file)
210 : {
211 9879 : if (!good()) {
212 8320 : open(false, output_to_file);
213 : }
214 9879 : if (!good()) {
215 0 : ShowFatalError(state, fmt::format("{}: Could not open file {} for output (write).", caller, filePath.string()));
216 : }
217 9879 : return *this;
218 : }
219 :
220 10478610 : bool InputOutputFile::good() const
221 : {
222 10478610 : if (os && print_to_dev_null && os->bad()) { // badbit is set
223 12442 : return true;
224 10466168 : } else if (os) {
225 10313960 : return os->good();
226 : } else {
227 152208 : return false;
228 : }
229 : }
230 :
231 5654 : void InputOutputFile::close()
232 : {
233 5654 : os.reset();
234 5654 : }
235 :
236 921 : void InputOutputFile::del()
237 : {
238 921 : if (os) {
239 921 : os.reset();
240 921 : FileSystem::removeFile(filePath);
241 : }
242 921 : }
243 :
244 0 : void InputOutputFile::open_as_stringstream()
245 : {
246 0 : os = std::make_unique<std::stringstream>();
247 0 : }
248 :
249 0 : void InputOutputFile::flush()
250 : {
251 0 : if (os) {
252 0 : os->flush();
253 : }
254 0 : }
255 :
256 0 : std::string InputOutputFile::get_output()
257 : {
258 0 : auto *ss = dynamic_cast<std::stringstream *>(os.get());
259 0 : if (ss) {
260 0 : return ss->str();
261 : } else {
262 0 : return "";
263 : }
264 : }
265 :
266 166435 : InputOutputFile::InputOutputFile(fs::path FilePath, const bool DefaultToStdout) : filePath{std::move(FilePath)}, defaultToStdOut{DefaultToStdout}
267 : {
268 166435 : }
269 :
270 771 : std::ostream::pos_type InputOutputFile::position() const noexcept
271 : {
272 771 : return os->tellg();
273 : }
274 :
275 9091 : void InputOutputFile::open(const bool forAppend, bool output_to_file)
276 : {
277 9091 : auto appendMode = [=]() {
278 9091 : if (forAppend) {
279 0 : return std::ios_base::app;
280 : } else {
281 9091 : return std::ios_base::trunc;
282 : }
283 9091 : }();
284 9091 : if (!output_to_file) {
285 21 : os = std::make_unique<std::iostream>(nullptr);
286 : // os->imbue(std::locale("C"));
287 21 : print_to_dev_null = true;
288 : } else {
289 9070 : os = std::make_unique<std::fstream>(filePath.c_str(), std::ios_base::in | std::ios_base::out | appendMode);
290 : // os->imbue(std::locale("C"));
291 9070 : print_to_dev_null = false;
292 : }
293 9091 : }
294 :
295 661 : std::vector<std::string> InputOutputFile::getLines()
296 : {
297 661 : if (os) {
298 : // avoid saving and reloading the file by simply reading the current input stream
299 661 : os->flush();
300 661 : const auto last_pos = os->tellg();
301 1322 : std::string line;
302 1322 : std::vector<std::string> lines;
303 661 : os->seekg(0);
304 :
305 415957 : while (std::getline(*os, line)) {
306 207648 : lines.push_back(line);
307 : }
308 :
309 : // after getline is done, we're at eof/fail bit
310 661 : os->clear();
311 661 : os->seekg(last_pos);
312 661 : return lines;
313 : }
314 0 : return std::vector<std::string>();
315 : }
316 :
317 771 : void IOFiles::OutputControl::getInput(EnergyPlusData &state)
318 : {
319 1542 : auto const instances = state.dataInputProcessing->inputProcessor->epJSON.find("OutputControl:Files");
320 771 : if (instances != state.dataInputProcessing->inputProcessor->epJSON.end()) {
321 :
322 286 : auto find_input = [=, &state](nlohmann::json const &fields, std::string const &field_name) -> std::string {
323 124 : std::string input;
324 248 : auto found = fields.find(field_name);
325 124 : if (found != fields.end()) {
326 43 : input = found.value().get<std::string>();
327 43 : input = UtilityRoutines::MakeUPPERCase(input);
328 : } else {
329 162 : state.dataInputProcessing->inputProcessor->getDefaultValue(state, "OutputControl:Files", field_name, input);
330 : }
331 248 : return input;
332 4 : };
333 :
334 124 : auto boolean_choice = [=, &state](std::string const &input) -> bool {
335 124 : if (input == "YES") {
336 86 : return true;
337 38 : } else if (input == "NO") {
338 38 : return false;
339 : }
340 0 : ShowFatalError(state, "Invalid boolean Yes/No choice input");
341 0 : return true;
342 4 : };
343 :
344 4 : auto &instancesValue = instances.value();
345 8 : for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
346 4 : auto const &fields = instance.value();
347 :
348 4 : state.dataInputProcessing->inputProcessor->markObjectAsUsed("OutputControl:Files", instance.key());
349 :
350 : { // "output_csv"
351 4 : csv = boolean_choice(find_input(fields, "output_csv"));
352 : }
353 : { // "output_mtr"
354 4 : mtr = boolean_choice(find_input(fields, "output_mtr"));
355 : }
356 : { // "output_eso"
357 4 : eso = boolean_choice(find_input(fields, "output_eso"));
358 : }
359 : { // "output_eio"
360 4 : eio = boolean_choice(find_input(fields, "output_eio"));
361 : }
362 : { // "output_audit"
363 4 : audit = boolean_choice(find_input(fields, "output_audit"));
364 : }
365 : { // "output_zone_sizing"
366 4 : zsz = boolean_choice(find_input(fields, "output_zone_sizing"));
367 : }
368 : { // "output_system_sizing"
369 4 : ssz = boolean_choice(find_input(fields, "output_system_sizing"));
370 : }
371 : { // "output_dxf"
372 4 : dxf = boolean_choice(find_input(fields, "output_dxf"));
373 : }
374 : { // "output_bnd"
375 4 : bnd = boolean_choice(find_input(fields, "output_bnd"));
376 : }
377 : { // "output_rdd"
378 4 : rdd = boolean_choice(find_input(fields, "output_rdd"));
379 : }
380 : { // "output_mdd"
381 4 : mdd = boolean_choice(find_input(fields, "output_mdd"));
382 : }
383 : { // "output_mtd"
384 4 : mtd = boolean_choice(find_input(fields, "output_mtd"));
385 : }
386 : { // "output_end"
387 4 : end = boolean_choice(find_input(fields, "output_end"));
388 : }
389 : { // "output_shd"
390 4 : shd = boolean_choice(find_input(fields, "output_shd"));
391 : }
392 : { // "output_dfs"
393 4 : dfs = boolean_choice(find_input(fields, "output_dfs"));
394 : }
395 : { // "output_glhe"
396 4 : glhe = boolean_choice(find_input(fields, "output_glhe"));
397 : }
398 : { // "output_delightin"
399 4 : delightin = boolean_choice(find_input(fields, "output_delightin"));
400 : }
401 : { // "output_delighteldmp"
402 4 : delighteldmp = boolean_choice(find_input(fields, "output_delighteldmp"));
403 : }
404 : { // "output_delightdfdmp"
405 4 : delightdfdmp = boolean_choice(find_input(fields, "output_delightdfdmp"));
406 : }
407 : { // "output_edd"
408 4 : edd = boolean_choice(find_input(fields, "output_edd"));
409 : }
410 : { // "output_dbg"
411 4 : dbg = boolean_choice(find_input(fields, "output_dbg"));
412 : }
413 : { // "output_perflog"
414 4 : perflog = boolean_choice(find_input(fields, "output_perflog"));
415 : }
416 : { // "output_sln"
417 4 : sln = boolean_choice(find_input(fields, "output_sln"));
418 : }
419 : { // "output_sci"
420 4 : sci = boolean_choice(find_input(fields, "output_sci"));
421 : }
422 : { // "output_wrl"
423 4 : wrl = boolean_choice(find_input(fields, "output_wrl"));
424 : }
425 : { // "output_screen"
426 4 : screen = boolean_choice(find_input(fields, "output_screen"));
427 : }
428 : { // "output_tarcog"
429 4 : tarcog = boolean_choice(find_input(fields, "output_tarcog"));
430 : }
431 : { // "output_extshd"
432 4 : extshd = boolean_choice(find_input(fields, "output_extshd"));
433 : }
434 : { // "json"
435 4 : json = boolean_choice(find_input(fields, "output_json"));
436 : }
437 : { // "tabular"
438 4 : tabular = boolean_choice(find_input(fields, "output_tabular"));
439 : }
440 : { // "sqlite"
441 4 : sqlite = boolean_choice(find_input(fields, "output_sqlite"));
442 : }
443 : }
444 : }
445 771 : }
446 :
447 0 : void IOFiles::flushAll()
448 : {
449 :
450 0 : audit.flush();
451 0 : eio.flush();
452 0 : eso.flush();
453 0 : zsz.flush();
454 0 : ssz.flush();
455 0 : map.flush();
456 0 : mtr.flush();
457 0 : bnd.flush();
458 0 : rdd.flush();
459 0 : mdd.flush();
460 0 : debug.flush();
461 0 : dfs.flush();
462 0 : mtd.flush();
463 0 : edd.flush();
464 0 : shade.flush();
465 0 : csv.flush();
466 :
467 0 : if (err_stream) {
468 0 : err_stream->flush();
469 : }
470 0 : }
471 :
472 : } // namespace EnergyPlus
473 :
474 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int>(std::string_view, int &&);
475 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const char *const &>(std::string_view, const char *const &);
476 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, std::string &>(std::string_view, int &, std::string &);
477 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, std::string &, std::string &, double &>(
478 : std::string_view, std::string &, std::string &, std::string &, double &);
479 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const std::string_view &>(std::string_view, const std::string_view &);
480 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const std::string_view &, std::string &>(std::string_view,
481 : const std::string_view &,
482 : std::string &);
483 : template std::string
484 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, double &, double &>(std::string_view, std::string &, double &, double &);
485 : template std::string
486 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, std::string &, int &>(std::string_view, std::string &, std::string &, int &);
487 : template std::string
488 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &, double &, double &>(std::string_view, double &, double &, double &);
489 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &, std::string &>(std::string_view, double &, std::string &);
490 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &>(std::string_view, std::string &);
491 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const int &, int &>(std::string_view, const int &, int &);
492 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double>(std::string_view, double &&);
493 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, int &>(std::string_view, int &, int &);
494 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const double &>(std::string_view, const double &);
495 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, int &>(std::string_view, std::string &, int &);
496 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, std::string &, double &>(std::string_view,
497 : std::string &,
498 : std::string &,
499 : double &);
500 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, double &, std::string &, double &>(
501 : std::string_view, std::string &, double &, std::string &, double &);
502 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, const int &>(std::string_view, const int &);
503 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, const std::string &, std::string &>(std::string_view,
504 : int &,
505 : const std::string &,
506 : std::string &);
507 : template std::string
508 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, int &, const std::string &>(std::string_view, int &, int &, const std::string &);
509 : template std::string
510 : EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, int &, std::string_view &>(std::string_view, int &, int &, std::string_view &);
511 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &, std::string_view &, std::string &>(std::string_view,
512 : int &,
513 : std::string_view &,
514 : std::string &);
515 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &, double &>(std::string_view, double &, double &);
516 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, int &>(std::string_view, int &);
517 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, std::string &, double &>(std::string_view, std::string &, double &);
518 2313 : template std::string EnergyPlus::format<EnergyPlus::FormatSyntax::Fortran, double &>(std::string_view, double &);
|