OGS
SWMMInterface.cpp
Go to the documentation of this file.
1
10#include "SwmmInterface.h"
11
12#include <swmm5_iface.h>
13
14#include <boost/algorithm/string/predicate.hpp>
15#include <cctype>
16#include <fstream>
17#include <utility>
18
20#include "BaseLib/FileTools.h"
21#include "BaseLib/StringTools.h"
22#include "GeoLib/GEOObjects.h"
23#include "GeoLib/Point.h"
24#include "GeoLib/PointVec.h"
25#include "GeoLib/Polygon.h"
26#include "GeoLib/Polyline.h"
28#include "MeshLib/Mesh.h"
29#include "MeshLib/Node.h"
30#include "MeshLib/Properties.h"
32
33namespace FileIO
34{
36const std::array<std::string, 9> subcatchment_vars = {
37 "rainfall",
38 "snow depth",
39 "evaporation loss",
40 "infiltration losses",
41 "runoff rate",
42 "groundwater outflow",
43 "groundwater head",
44 "moisture content",
45 "concentration of pollutant"};
46
48const std::array<std::string, 7> node_vars = {"water depth",
49 "hydraulic head",
50 "volume of stored water",
51 "lateral inflow",
52 "total inflow",
53 "flow lost to flooding",
54 "concentration of pollutant"};
55
57const std::array<std::string, 6> link_vars = {"flow rate",
58 "flow depth",
59 "flow velocity",
60 "flow volume",
61 "fraction conduit/non-conduit",
62 "concentration of pollutant"};
63
65const std::array<std::string, 15> system_vars = {
66 "air temperature",
67 "rainfall",
68 "snow depth",
69 "evaporation + infiltration loss",
70 "runoff flow",
71 "dry weather inflow",
72 "groundwater inflow",
73 "RDII inflow",
74 "direct inflow",
75 "total lateral inflow",
76 "flow lost to flooding",
77 "flow leaving through outfalls",
78 "volume of stored water",
79 "actual evaporation rate",
80 "potential evaporation rate"};
81
84std::array<std::size_t, 4> const n_obj_params = {8, 6, 5, 15};
85
86std::unique_ptr<SwmmInterface> SwmmInterface::create(
87 std::string const& file_name)
88{
89 // The input/output methods take a base name and check if the corresponding
90 // i/o file for that base name exists. This check takes any swmm project
91 // file, i.e. [base name].[extension] which needs to be at least 5 chars
92 // because the extension is always 3 chars.
93 if (file_name.length() < 5)
94 return nullptr;
95
96 if (!SwmmInterface::isSwmmInputFile(file_name))
97 return nullptr;
98
99 std::string const base_name(file_name.substr(0, file_name.length() - 4));
100 SwmmInterface* swmm = new SwmmInterface(base_name);
101 if (swmm->readSwmmInputToLineMesh())
102 return std::unique_ptr<SwmmInterface>(swmm);
103
104 ERR("Error creating mesh from SWMM file.");
105 delete swmm;
106 return nullptr;
107}
108
109SwmmInterface::SwmmInterface(std::string const& swmm_base_name)
110 : _base_name(swmm_base_name), _mesh(nullptr)
111{
112}
113
115{
116 for (Subcatchment& sc : _subcatchments)
117 delete sc.outline;
118
120 delete pnt;
121}
122
123bool SwmmInterface::isSwmmInputFile(std::string const& inp_file_name)
124{
125 if (!boost::iequals(BaseLib::getFileExtension(inp_file_name), ".inp"))
126 {
127 ERR("SWMMInterface: {:s} is not a SWMM input file.", inp_file_name);
128 return false;
129 }
130
131 std::ifstream in(inp_file_name.c_str());
132 if (!in.is_open())
133 {
134 ERR("SWMMInterface: Could not open input file {:s}.", inp_file_name);
135 return false;
136 }
137
138 std::string line;
139 bool header_found(false);
140 std::size_t pos_end(0);
141 while (!header_found)
142 {
143 if (!std::getline(in, line))
144 return false;
145
146 std::size_t const pos_beg = line.find_first_not_of(' ', pos_end);
147 pos_end = line.find_first_of(" \n", pos_beg);
148
149 // skip empty or comment lines at the beginning of the file
150 if (line.empty() || pos_beg == pos_end || isCommentLine(line))
151 continue;
152
153 if (line == "[TITLE]")
154 header_found = true;
155 else
156 {
157 INFO("SWMMInterface: input file type {:s} not recognised.",
158 BaseLib::getFileExtension(inp_file_name));
159 return false;
160 }
161 }
162
163 in.close();
164 return true;
165}
166
168{
169 std::string const outfile(_base_name + ".out");
170 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
171 return false;
172 return true;
173}
174
175template <typename T>
176bool SwmmInterface::readCoordinates(std::ifstream& in, std::vector<T*>& points,
177 std::vector<std::string>& names)
178{
179 std::size_t id(points.size());
180 std::string line;
181
182 while (std::getline(in, line))
183 {
184 if (isSectionFinished(line))
185 return true;
186
187 if (isCommentLine(line))
188 continue;
189
190 std::vector<std::string> split_str(BaseLib::splitString(line));
191 if (split_str.size() != 3)
192 {
193 ERR("Format not recognised.");
194 return false;
195 }
196 names.push_back(split_str[0]);
197
198 double const x = BaseLib::str2number<double>(split_str[1]);
199 double const y = BaseLib::str2number<double>(split_str[2]);
200 T* pnt = new T(x, y, 0, id);
201 points.push_back(pnt);
202 id++;
203 }
204 return true;
205}
206
207bool SwmmInterface::readPolygons(std::ifstream& in,
208 std::vector<GeoLib::Polyline*>& lines,
209 std::vector<std::string>& ply_names,
210 std::vector<GeoLib::Point*>& points,
211 std::vector<std::string>& pnt_names)
212{
213 bool finished(false);
214 std::size_t id(points.size());
215 std::string line;
216 std::string polygon_name("");
217 GeoLib::Polyline* p(nullptr);
218 while (std::getline(in, line))
219 {
220 if (isSectionFinished(line))
221 break;
222
223 if (isCommentLine(line))
224 continue;
225
226 std::vector<std::string> split_str(BaseLib::splitString(line));
227 if (split_str.size() != 3)
228 {
229 ERR("Polygon format not recognised.");
230 delete p;
231 return false;
232 }
233
234 // if a new polygon starts, add the old one to the vector
235 if (split_str[0] != polygon_name)
236 {
237 if (p != nullptr)
238 {
239 p->addPoint(p->getPointID(0));
240 lines.push_back(p);
241 }
242
243 polygon_name = split_str[0];
244 p = new GeoLib::Polyline(points);
245 ply_names.push_back(polygon_name);
246 }
247
248 double const x = BaseLib::str2number<double>(split_str[1]);
249 double const y = BaseLib::str2number<double>(split_str[2]);
250 points.push_back(new GeoLib::Point(x, y, 0, id));
251 p->addPoint(points.size() - 1);
252 pnt_names.push_back("");
253 id++;
254 }
255
256 // when the section is finished, add the last polygon
257 if (p != nullptr)
258 {
259 p->addPoint(p->getPointID(0));
260 lines.push_back(p);
261 }
262
263 return true;
264}
265
267 std::ifstream& in, std::vector<GeoLib::Point*>& points,
268 std::map<std::string, std::size_t> const& name_id_map)
269{
270 std::string line;
271 while (std::getline(in, line))
272 {
273 if (isSectionFinished(line))
274 return true;
275
276 if (isCommentLine(line))
277 continue;
278
279 std::vector<std::string> const split_str(BaseLib::splitString(line));
280 // Junctions = 6, Outfalls = 4, Storage = 8
281 if (split_str.size() < 4)
282 {
283 ERR("Format not recognised.");
284 return false;
285 }
286 std::string const current_name(split_str[0]);
287 auto const it = name_id_map.find(current_name);
288 if (it == name_id_map.end())
289 {
290 ERR("SwmmInterface::addPointElevation(): Name {:s} not found in "
291 "coordinates map.",
292 current_name);
293 return false;
294 }
295 std::size_t const id = it->second;
296 (*points[id])[2] = BaseLib::str2number<double>(split_str[1]);
297 }
298 return true;
299}
300
302 std::ifstream& in, std::vector<GeoLib::Polyline*>& lines,
303 std::vector<std::string>& line_names,
304 std::vector<GeoLib::Point*> const& points,
305 std::map<std::string, std::size_t> const& point_names)
306{
307 std::string line;
308 while (std::getline(in, line))
309 {
310 if (isSectionFinished(line))
311 return true;
312
313 if (isCommentLine(line))
314 continue;
315
316 std::vector<std::string> const split_str(BaseLib::splitString(line));
317 // Conduits = 9, Pumps = 7, Weirs = 8
318 if (split_str.size() < 7)
319 {
320 ERR("Conduit format not recognised.");
321 return false;
322 }
323
324 std::string const inlet(split_str[1]);
325 auto const i_it = point_names.find(inlet);
326 if (i_it == point_names.end())
327 {
328 ERR("SwmmInterface::readLineElements(): Inlet node {:s} not found "
329 "in coordinates map.",
330 inlet);
331 return false;
332 }
333
334 std::string const outlet(split_str[2]);
335 auto const o_it = point_names.find(outlet);
336 if (o_it == point_names.end())
337 {
338 ERR("SwmmInterface::readLineElements(): Outlet node {:s} not found "
339 "in coordinates map.",
340 outlet);
341 return false;
342 }
343 GeoLib::Polyline* ply = new GeoLib::Polyline(points);
344 std::size_t a(i_it->second);
345 ply->addPoint(i_it->second);
346 ply->addPoint(o_it->second);
347 lines.push_back(ply);
348 line_names.push_back(split_str[0]);
349 }
350 return true;
351}
352
353bool SwmmInterface::convertSwmmInputToGeometry(std::string const& inp_file_name,
354 GeoLib::GEOObjects& geo_objects,
355 bool add_subcatchments)
356{
357 if (!isSwmmInputFile(inp_file_name))
358 return false;
359
360 std::ifstream in(inp_file_name.c_str());
361 if (!in.is_open())
362 {
363 ERR("SWMMInterface: Could not open input file {:s}.", inp_file_name);
364 return false;
365 }
366
367 std::vector<GeoLib::Point*> points;
368 std::vector<GeoLib::Polyline*> lines;
369 std::vector<std::string> pnt_names;
370 std::vector<std::string> line_names;
371
372 std::string geo_name =
374 std::string line;
375 while (std::getline(in, line))
376 {
377 if (line == "[COORDINATES]" || line == "[VERTICES]" ||
378 line == "[SYMBOLS]")
379 {
380 INFO("Reading {:s}...", line);
381 if (!readCoordinates<GeoLib::Point>(in, points, pnt_names))
382 {
383 BaseLib::cleanupVectorElements(points, lines);
384 return false;
385 }
386 }
387 if (line == "[Polygons]" && add_subcatchments)
388 {
389 INFO("Reading {:s}...", line);
390 if (!readPolygons(in, lines, line_names, points, pnt_names))
391 {
392 BaseLib::cleanupVectorElements(points, lines);
393 return false;
394 }
395 }
396 }
397
398 if (points.empty())
399 {
400 ERR("No points found in file");
401 return false;
402 }
403 if (points.size() != pnt_names.size())
404 {
405 ERR("Length of point vector and point name vector do not match.");
406 BaseLib::cleanupVectorElements(points, lines);
407 return false;
408 }
409
410 GeoLib::PointVec::NameIdMap name_id_map;
411 {
412 std::size_t const n_names(pnt_names.size());
413 for (std::size_t i = 0; i < n_names; ++i)
414 {
415 if (!pnt_names[i].empty())
416 name_id_map.insert(std::make_pair(pnt_names[i], i));
417 }
418 }
419
420 // rewind stream and read links between junctions
421 in.clear();
422 in.seekg(0, in.beg);
423
424 while (std::getline(in, line))
425 {
426 if (line == "[JUNCTIONS]" || line == "[OUTFALLS]" ||
427 line == "[STORAGE]")
428 {
429 INFO("Reading {:s} elevation...", line);
430 if (!addPointElevation(in, points, name_id_map))
431 {
432 BaseLib::cleanupVectorElements(points, lines);
433 return false;
434 }
435 }
436 if (line == "[CONDUITS]")
437 {
438 INFO("Reading conduits...");
439 if (!readLinksAsPolylines(in, lines, line_names, points,
440 name_id_map))
441 {
442 BaseLib::cleanupVectorElements(points, lines);
443 return false;
444 }
445 }
446 else if (line == "[PUMPS]")
447 {
448 INFO("Reading pumps...");
449 if (!readLinksAsPolylines(in, lines, line_names, points,
450 name_id_map))
451 {
452 BaseLib::cleanupVectorElements(points, lines);
453 return false;
454 }
455 }
456 else if (line == "[WEIRS]")
457 {
458 INFO("Reading weirs...");
459 if (!readLinksAsPolylines(in, lines, line_names, points,
460 name_id_map))
461 {
462 BaseLib::cleanupVectorElements(points, lines);
463 return false;
464 }
465 }
466 }
467
468 geo_objects.addPointVec(std::move(points), geo_name,
469 std::move(name_id_map));
470 if (!lines.empty())
471 {
472 if (lines.size() != line_names.size())
473 {
474 ERR("Length of line vector and line name vector do not match.");
475 geo_objects.removePointVec(geo_name);
476 for (auto ply : lines)
477 delete ply;
478 return false;
479 }
481 {
482 std::size_t const n_names(line_names.size());
483 for (std::size_t i = 0; i < n_names; ++i)
484 {
485 line_id_map.insert(std::make_pair(line_names[i], i));
486 }
487 }
488 std::vector<std::size_t> const& pnt_id_map(
489 geo_objects.getPointVecObj(geo_name)->getIDMap());
490 for (GeoLib::Polyline* polyline : lines)
491 {
492 for (std::size_t i = 0; i < polyline->getNumberOfPoints(); ++i)
493 {
494 polyline->setPointID(i, pnt_id_map[polyline->getPointID(i)]);
495 if (i > 0 &&
496 polyline->getPointID(i - 1) == polyline->getPointID(i))
497 {
498 polyline->removePoint(i);
499 i--;
500 }
501 }
502 if (polyline->getPointID(0) ==
503 polyline->getPointID(polyline->getNumberOfPoints() - 1))
504 {
505 polyline->removePoint(polyline->getNumberOfPoints() - 1);
506 polyline->addPoint(polyline->getPointID(0));
507 }
508 }
509 geo_objects.addPolylineVec(std::move(lines), geo_name,
510 std::move(line_id_map));
511 }
512 return true;
513}
514
516 std::ifstream& in, std::vector<MeshLib::Node*>& nodes,
517 std::map<std::string, std::size_t> const& name_id_map,
518 std::vector<double>& max_depth, bool read_max_depth)
519{
520 std::string line;
521 while (std::getline(in, line))
522 {
523 if (isSectionFinished(line))
524 return true;
525
526 if (isCommentLine(line))
527 continue;
528
529 std::vector<std::string> const split_str(BaseLib::splitString(line));
530 // Junctions = 6, Outfalls = 4, Storage = 8
531 if (split_str.size() < 3)
532 {
533 ERR("Format not recognised.");
534 return false;
535 }
536 std::string const current_name(split_str[0]);
537 auto const it = name_id_map.find(current_name);
538 if (it == name_id_map.end())
539 {
540 ERR("SwmmInterface::readNodeData(): Name {:s} not found in "
541 "coordinates map.",
542 current_name);
543 return false;
544 }
545 std::size_t const id = it->second;
546 (*nodes[id])[2] = BaseLib::str2number<double>(split_str[1]);
547
548 if (read_max_depth)
549 max_depth[id] = BaseLib::str2number<double>(split_str[2]);
550 else
551 max_depth[id] = 0;
552 }
553 return true;
554}
555
557 std::ifstream& in, std::vector<MeshLib::Element*>& elements,
558 std::vector<MeshLib::Node*> const& nodes,
559 std::map<std::string, std::size_t> const& name_id_map)
560{
561 std::string line;
562 while (std::getline(in, line))
563 {
564 if (isSectionFinished(line))
565 return true;
566
567 if (isCommentLine(line))
568 continue;
569
570 std::vector<std::string> const split_str(BaseLib::splitString(line));
571 // Conduits = 9, Pumps = 7, Weirs = 8
572 if (split_str.size() < 7)
573 {
574 ERR("Conduit format not recognised.");
575 return false;
576 }
577
578 std::string const inlet(split_str[1]);
579 auto const i_it = name_id_map.find(inlet);
580 if (i_it == name_id_map.end())
581 {
582 ERR("SwmmInterface::readLineElements(): Inlet node {:s} not found "
583 "in coordinates map.",
584 inlet);
585 return false;
586 }
587
588 std::string const outlet(split_str[2]);
589 auto const o_it = name_id_map.find(outlet);
590 if (o_it == name_id_map.end())
591 {
592 ERR("SwmmInterface::readLineElements(): Outlet node {:s} not found "
593 "in coordinates map.",
594 outlet);
595 return false;
596 }
597
598 std::array<MeshLib::Node*, 2> const line_nodes = {nodes[i_it->second],
599 nodes[o_it->second]};
600 elements.push_back(new MeshLib::Line(line_nodes));
601 _id_linkname_map.push_back(split_str[0]);
602 }
603 return true;
604}
605
607 std::ifstream& in, std::map<std::string, std::size_t> const& name_id_map)
608{
609 std::string line;
610 while (std::getline(in, line))
611 {
612 if (isSectionFinished(line))
613 return true;
614
615 if (isCommentLine(line))
616 continue;
617
618 std::vector<std::string> const split_str(BaseLib::splitString(line));
619 if (split_str.size() < 8)
620 {
621 ERR("Subcatchment format not recognised.");
622 return false;
623 }
624
625 Subcatchment sc;
626 sc.name = split_str[0];
627 sc.rain_gauge = std::numeric_limits<std::size_t>::max();
628 std::size_t const n_gauges(_rain_gauges.size());
629 for (std::size_t i = 0; i < n_gauges; ++i)
630 {
631 if (_rain_gauges[i].first.getName() == split_str[1])
632 {
633 sc.rain_gauge = i;
634 break;
635 }
636 }
637 if (sc.rain_gauge == std::numeric_limits<std::size_t>::max())
638 {
639 ERR("Rain gauge for subcatchment '{:s}' not found.", split_str[0]);
640 return false;
641 }
642
643 auto const it = name_id_map.find(split_str[2]);
644 if (it == name_id_map.end())
645 {
646 ERR("Outlet node for subcatchment '{:s}' not found.", split_str[0]);
647 return false;
648 }
649 sc.outlet = it->second;
650 sc.area = BaseLib::str2number<double>(split_str[3]);
651 _subcatchments.push_back(sc);
652 }
653
654 return true;
655}
656
658{
659 if (_mesh != nullptr)
660 {
661 ERR("Mesh already exists.");
662 return false;
663 }
664
665 std::string const inp_file_name(_base_name + ".inp");
666 if (!isSwmmInputFile(inp_file_name))
667 return false;
668
669 std::ifstream in(inp_file_name.c_str());
670 if (!in.is_open())
671 {
672 ERR("SWMMInterface: Could not open input file {:s}.", inp_file_name);
673 return false;
674 }
675
676 _id_nodename_map.clear();
677 std::vector<MeshLib::Node*> nodes;
678 std::string line;
679 while (std::getline(in, line))
680 {
681 if (line == "[COORDINATES]")
682 {
683 INFO("Reading coordinates...");
685 return false;
686 }
687 /* TODO: check if needed
688 else if (line == "[VERTICES]")
689 {
690 INFO ("Reading vertices...");
691 if (!readCoordinates(in, nodes, _id_nodename_map))
692 return false;
693 }
694 */
695 else if (line == "[SYMBOLS]")
696 {
697 INFO("Reading symbols...");
698 std::vector<GeoLib::Point*> points;
699 std::vector<std::string> names;
700 if (!readCoordinates(in, points, names))
701 return false;
702 for (std::size_t i = 0; i < points.size(); ++i)
703 {
704 GeoLib::Station stn(points[i], names[i]);
705 _rain_gauges.push_back(
706 std::pair<GeoLib::Station, std::string>(stn, ""));
707 }
708 }
709 }
710
711 if (nodes.empty())
712 return false;
713
714 // After end of file is reached, create name-id-map and
715 // start reading again to get line elements and node data.
716 std::map<std::string, std::size_t> name_id_map;
717 std::size_t const n_nodes(nodes.size());
718 for (std::size_t i = 0; i < n_nodes; ++i)
719 name_id_map[_id_nodename_map[i]] = i;
720 in.clear();
721 in.seekg(0, in.beg);
722
723 std::vector<MeshLib::Element*> elements;
724 std::vector<double> max_depth(n_nodes);
725 std::size_t const n_types = 3;
726 std::array<std::size_t, n_types> n_elem_types{{0, 0, 0}};
727 while (std::getline(in, line))
728 {
729 if (line == "[RAINGAGES]")
730 {
731 if (!_rain_gauges.empty())
733 }
734 else if (line == "[SUBCATCHMENTS]")
735 {
736 INFO("Reading subcatchment information...");
737 if (!readSubcatchments(in, name_id_map))
738 return false;
739 }
740 else if (line == "[SUBAREAS]")
741 {
742 // more subcatchment variables, not yet implemented
743 }
744 else if (line == "[INFILTRATION]")
745 {
746 // more subcatchment variables, not yet implemented
747 }
748 else if (line == "[JUNCTIONS]")
749 {
750 INFO("Reading junctions...");
751 if (!readNodeData(in, nodes, name_id_map, max_depth, true))
752 return false;
753 }
754 else if (line == "[OUTFALLS]")
755 {
756 INFO("Reading outfalls...");
757 if (!readNodeData(in, nodes, name_id_map, max_depth, false))
758 return false;
759 }
760 else if (line == "[STORAGE]")
761 {
762 INFO("Reading storages...");
763 if (!readNodeData(in, nodes, name_id_map, max_depth, true))
764 return false;
765 }
766 else if (line == "[CONDUITS]")
767 {
768 INFO("Reading conduits...");
769 if (!readLineElements(in, elements, nodes, name_id_map))
770 return false;
771 n_elem_types[0] = elements.size();
772 }
773 else if (line == "[PUMPS]")
774 {
775 INFO("Reading pumps...");
776 if (!readLineElements(in, elements, nodes, name_id_map))
777 return false;
778 n_elem_types[1] = elements.size();
779 }
780 else if (line == "[WEIRS]")
781 {
782 INFO("Reading weirs...");
783 if (!readLineElements(in, elements, nodes, name_id_map))
784 return false;
785 n_elem_types[2] = elements.size();
786 }
787 else if (line == "[POLLUTANTS]")
788 {
789 if (!readPollutants(in))
790 return false;
791 }
792 else if (line == "[Polygons]")
793 {
794 INFO("Reading subcatchments...");
795 std::vector<GeoLib::Polyline*> lines;
796 std::vector<std::string> line_names;
797 std::vector<std::string>
798 tmp_names; // polygon points are nameless but the method
799 // requires a vector
800 if (!readPolygons(in, lines, line_names, _subcatchment_points,
801 tmp_names))
802 return false;
803
804 if (!matchSubcatchmentsWithPolygons(lines, line_names))
805 return false;
806 }
807 }
808
809 if (elements.empty())
810 {
811 for (MeshLib::Node* node : nodes)
812 delete node;
813 return false;
814 }
815
817 auto* const mat_ids = props.createNewPropertyVector<int>(
818 "MaterialIDs", MeshLib::MeshItemType::Cell, 1);
819 mat_ids->resize(elements.size(), 0);
820 for (std::size_t i = 1; i < n_types; ++i)
821 {
822 if (n_elem_types[i] > 0)
823 std::fill(mat_ids->begin() + n_elem_types[i - 1],
824 mat_ids->begin() + n_elem_types[i], i);
825 }
826
827 if (nodes.size() == max_depth.size())
828 {
829 auto* const depth = props.createNewPropertyVector<double>(
830 "Max Depth", MeshLib::MeshItemType::Node, 1);
831 depth->assign(max_depth);
832 assert(depth.size() == max_depth.size());
833 }
834 else
835 ERR("Size of max depth array does not fit number of elements. Skipping "
836 "array.");
837
838 _mesh.reset(new MeshLib::Mesh(_base_name, nodes, elements,
839 false /* compute_element_neighbors */,
840 props));
841 return true;
842}
843
845 std::vector<GeoLib::Polyline*> const& lines,
846 std::vector<std::string> const& names)
847{
848 std::size_t const n_lines(lines.size());
849 std::size_t const n_subcatchments(_subcatchments.size());
850
851 if (n_lines != n_subcatchments)
852 {
853 ERR("Number of subcatchments does not match number of outlines.");
854 return false;
855 }
856 for (std::size_t i = 0; i < n_lines; ++i)
857 {
858 bool found = false;
859 for (std::size_t j = 0; j < n_subcatchments; ++j)
860 {
861 if (names[i] == _subcatchments[j].name)
862 {
863 _subcatchments[j].outline = lines[i];
864 found = true;
865 break;
866 }
867 }
868 if (found == false)
869 {
870 ERR("No match in subcatcments for outline '{:s}'.", names[i]);
871 return false;
872 }
873 }
874 return true;
875}
876
877std::vector<std::string> SwmmInterface::getSubcatchmentNameMap() const
878{
879 std::vector<std::string> names;
880 names.reserve(_subcatchments.size());
881 std::transform(_subcatchments.begin(), _subcatchments.end(),
882 std::back_inserter(names),
883 [](auto const& sc) { return sc.name; });
884 return names;
885}
886
887std::vector<std::string> SwmmInterface::getNames(SwmmObject obj_type) const
888{
889 switch (obj_type)
890 {
891 case SwmmObject::NODE:
892 return _id_nodename_map;
893 case SwmmObject::LINK:
894 return _id_linkname_map;
896 return getSubcatchmentNameMap();
898 std::vector<std::string> system_name{"System"};
899 return system_name;
900 }
901 ERR("Object type has no name map");
902 std::vector<std::string> empty_vec;
903 return empty_vec;
904}
905
906std::string SwmmInterface::getName(SwmmObject obj_type, std::size_t idx) const
907{
908 switch (obj_type)
909 {
910 case SwmmObject::NODE:
911 if (idx < _id_nodename_map.size())
912 return _id_nodename_map[idx];
913 case SwmmObject::LINK:
914 if (idx < _id_linkname_map.size())
915 return _id_linkname_map[idx];
917 if (idx < _subcatchments.size())
918 return _subcatchments[idx].name;
920 if (idx == 0)
921 return std::string("System");
922 }
923 ERR("Index out of bounds.");
924 return std::string("");
925}
926
928{
929 std::string const outfile(_base_name + ".out");
930 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
931 return 0;
932
933 switch (obj_type)
934 {
936 return SWMM_Nsubcatch;
937 case SwmmObject::NODE:
938 return SWMM_Nnodes;
939 case SwmmObject::LINK:
940 return SWMM_Nlinks;
942 return 1;
943 default:
944 ERR("Object type not recognised.");
945 }
946 CloseSwmmOutFile();
947 return 0;
948}
949
951{
952 std::string const outfile(_base_name + ".out");
953 std::size_t n_time_steps(std::numeric_limits<std::size_t>::max());
954 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
955 return 0;
956
957 std::size_t n_params(0);
958 switch (obj_type)
959 {
961 n_params = n_obj_params[0] + SWMM_Npolluts;
962 break;
963 case SwmmObject::NODE:
964 n_params = n_obj_params[1] + SWMM_Npolluts;
965 break;
966 case SwmmObject::LINK:
967 n_params = n_obj_params[2] + SWMM_Npolluts;
968 break;
970 n_params = n_obj_params[3];
971 break;
972 default:
973 ERR("Object type not recognised.");
974 }
975 CloseSwmmOutFile();
976 return n_params;
977}
978
980{
981 std::string const outfile(_base_name + ".out");
982 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
983 return std::numeric_limits<std::size_t>::max();
984 std::size_t const n_time_steps(static_cast<std::size_t>(SWMM_Nperiods));
985 CloseSwmmOutFile();
986 return n_time_steps;
987}
988
990 SwmmObject const swmm_type,
991 std::string const& vec_name,
992 std::vector<double> const& data)
993{
994 if (!(swmm_type == SwmmObject::NODE || swmm_type == SwmmObject::LINK))
995 {
996 ERR("Information of this object type cannot be added to mesh.");
997 return false;
998 }
999
1000 if (data.empty())
1001 {
1002 ERR("Data array is empty and cannot be added to mesh.");
1003 return false;
1004 }
1005
1006 if (swmm_type == SwmmObject::NODE && data.size() != mesh.getNumberOfNodes())
1007 {
1008 ERR("Number of mesh nodes ({:d}) does not match length of array "
1009 "({:d}).",
1010 mesh.getNumberOfNodes(), data.size());
1011 return false;
1012 }
1013
1014 if (swmm_type == SwmmObject::LINK &&
1015 data.size() != mesh.getNumberOfElements())
1016 {
1017 ERR("Number of mesh elements ({:d}) does not match length of array "
1018 "({:d}).",
1019 mesh.getNumberOfElements(), data.size());
1020 return false;
1021 }
1022
1023 MeshLib::MeshItemType const item_type = (swmm_type == SwmmObject::NODE)
1027 MeshLib::getOrCreateMeshProperty<double>(mesh, vec_name, item_type, 1);
1028 if (!prop)
1029 {
1030 ERR("Error fetching array '{:s}'.", vec_name);
1031 return false;
1032 }
1033 std::copy(data.cbegin(), data.cend(), prop->begin());
1034 return true;
1035}
1036
1038 std::size_t time_step,
1039 std::size_t var_idx) const
1040{
1041 std::vector<double> data;
1042 std::string const outfile(_base_name + ".out");
1043 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
1044 return data;
1045
1046 if (time_step >= SWMM_Nperiods)
1047 {
1048 ERR("Time step {:d} not available, file contains only {:d} periods.",
1049 time_step, SWMM_Nperiods);
1050 return data;
1051 }
1052
1053 bool is_var_idx_okay = true;
1054 int obj_type_id;
1055 std::size_t n_objects;
1056 switch (obj_type)
1057 {
1059 obj_type_id = 0;
1060 n_objects = SWMM_Nsubcatch;
1061 if (var_idx > (n_obj_params[obj_type_id] - 1 + SWMM_Npolluts))
1062 is_var_idx_okay = false;
1063 break;
1064 case SwmmObject::NODE:
1065 obj_type_id = 1;
1066 n_objects = SWMM_Nnodes;
1067 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1068 is_var_idx_okay = false;
1069 break;
1070 case SwmmObject::LINK:
1071 obj_type_id = 2;
1072 n_objects = SWMM_Nlinks;
1073 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1074 is_var_idx_okay = false;
1075 break;
1076 case SwmmObject::SYSTEM:
1077 obj_type_id = 3;
1078 n_objects = 1;
1079 if (var_idx > n_obj_params[obj_type_id])
1080 is_var_idx_okay = false;
1081 break;
1082 default:
1083 ERR("Object type not recognised.");
1084 CloseSwmmOutFile();
1085 return data;
1086 }
1087
1088 if (!is_var_idx_okay)
1089 {
1090 ERR("Requested variable does not exist.");
1091 CloseSwmmOutFile();
1092 return data;
1093 }
1094
1095 INFO("Fetching '{:s}'-data for time step {:d}...",
1096 getArrayName(obj_type, var_idx, SWMM_Npolluts), time_step);
1097
1098 for (std::size_t i = 0; i < n_objects; ++i)
1099 {
1100 float val;
1101 GetSwmmResult(obj_type_id, i, var_idx, time_step, &val);
1102 data.push_back(static_cast<double>(val));
1103 }
1104
1105 CloseSwmmOutFile();
1106 return data;
1107}
1108
1110 std::size_t obj_idx,
1111 std::size_t var_idx) const
1112{
1113 std::vector<double> data;
1114 std::string const outfile(_base_name + ".out");
1115 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
1116 return data;
1117
1118 bool is_var_idx_okay = true;
1119 bool is_obj_idx_okay = true;
1120 int obj_type_id;
1121 switch (obj_type)
1122 {
1124 obj_type_id = 0;
1125 if (obj_idx >= SWMM_Nsubcatch)
1126 is_obj_idx_okay = false;
1127 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1128 is_var_idx_okay = false;
1129 break;
1130 case SwmmObject::NODE:
1131 obj_type_id = 1;
1132 if (obj_idx >= SWMM_Nnodes)
1133 is_obj_idx_okay = false;
1134 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1135 is_var_idx_okay = false;
1136 break;
1137 case SwmmObject::LINK:
1138 obj_type_id = 2;
1139 if (obj_idx >= SWMM_Nlinks)
1140 is_obj_idx_okay = false;
1141 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1142 is_var_idx_okay = false;
1143 break;
1144 case SwmmObject::SYSTEM:
1145 obj_type_id = 3;
1146 if (obj_idx >= 1)
1147 is_obj_idx_okay = false;
1148 if (var_idx > n_obj_params[obj_type_id])
1149 is_var_idx_okay = false;
1150 break;
1151 default:
1152 ERR("Object type not recognised.");
1153 CloseSwmmOutFile();
1154 return data;
1155 }
1156
1157 if (!is_obj_idx_okay)
1158 {
1159 ERR("Requested object index does not exist.");
1160 CloseSwmmOutFile();
1161 return data;
1162 }
1163
1164 if (!is_var_idx_okay)
1165 {
1166 ERR("Requested variable does not exist.");
1167 CloseSwmmOutFile();
1168 return data;
1169 }
1170
1171 std::size_t const n_time_steps(static_cast<std::size_t>(SWMM_Nperiods));
1172 for (std::size_t i = 0; i < n_time_steps; ++i)
1173 {
1174 float val;
1175 GetSwmmResult(obj_type_id, obj_idx, var_idx, i, &val);
1176 data.push_back(static_cast<double>(val));
1177 }
1178
1179 CloseSwmmOutFile();
1180 return data;
1181}
1182
1184 std::size_t var_idx) const
1185{
1186 std::string const outfile(_base_name + ".out");
1187 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
1188 return std::string("");
1189
1190 std::string const name = getArrayName(obj_type, var_idx, SWMM_Npolluts);
1191 CloseSwmmOutFile();
1192 return name;
1193}
1194
1196 std::size_t var_idx,
1197 std::size_t n_pollutants) const
1198{
1199 if (obj_type == SwmmObject::SUBCATCHMENT)
1200 {
1201 if (var_idx < n_obj_params[0])
1202 return subcatchment_vars[var_idx];
1203 if (var_idx < n_obj_params[0] + n_pollutants)
1204 return _pollutant_names[var_idx - n_obj_params[0]];
1205 }
1206 if (obj_type == SwmmObject::NODE)
1207 {
1208 if (var_idx < n_obj_params[1])
1209 return node_vars[var_idx];
1210 if (var_idx < n_obj_params[1] + n_pollutants)
1211 return std::string("Node_" +
1212 _pollutant_names[var_idx - n_obj_params[1]]);
1213 }
1214 if (obj_type == SwmmObject::LINK)
1215 {
1216 if (var_idx < n_obj_params[2])
1217 return link_vars[var_idx];
1218 if (var_idx < n_obj_params[2] + n_pollutants)
1219 return std::string("Link_" +
1220 _pollutant_names[var_idx - n_obj_params[2]]);
1221 }
1222 if (obj_type == SwmmObject::SYSTEM && var_idx < n_obj_params[3])
1223 {
1224 return system_vars[var_idx];
1225 }
1226 ERR("SwmmInterface::getArrayName() - Index error, no name found.");
1227 return std::string("");
1228}
1229
1231{
1232 std::string line;
1233 while (std::getline(in, line))
1234 {
1235 if (isSectionFinished(line))
1236 break;
1237
1238 if (isCommentLine(line))
1239 continue;
1240
1241 std::vector<std::string> const split_str(BaseLib::splitString(line));
1242 if (split_str.size() < 6)
1243 {
1244 ERR("Rain gauge parameter format not recognised.");
1245 return false;
1246 }
1247
1248 for (auto& stn : _rain_gauges)
1249 {
1250 if (stn.first.getName() == split_str[0] && split_str[4] == "FILE")
1251 stn.second = split_str[5].substr(1, split_str[5].size() - 2);
1252 }
1253 }
1254
1255 for (auto const& stn : _rain_gauges)
1256 if (stn.second.empty())
1257 WARN("No associated time series found for rain gauge '{:s}'.",
1258 stn.first.getName());
1259 return true;
1260}
1261
1262bool SwmmInterface::readPollutants(std::ifstream& in)
1263{
1264 std::string line;
1265 while (std::getline(in, line))
1266 {
1267 if (isSectionFinished(line))
1268 return true;
1269
1270 if (isCommentLine(line))
1271 continue;
1272
1273 std::vector<std::string> split_str(BaseLib::splitString(line));
1274 if (split_str.size() < 6)
1275 {
1276 ERR("Parameter format for pollutants not recognised.");
1277 return false;
1278 }
1279 _pollutant_names.push_back(split_str[0]);
1280 }
1281 return true;
1282}
1283
1284bool SwmmInterface::isSectionFinished(std::string const& str)
1285{
1286 if (str.empty())
1287 return true;
1288
1289 std::size_t const pos_beg = str.find_first_not_of(' ', 0);
1290 if (pos_beg == str.find_first_of(" \n", pos_beg))
1291 return true;
1292
1293 return false;
1294}
1295
1296bool SwmmInterface::isCommentLine(std::string const& str)
1297{
1298 return (str.compare(str.find_first_not_of(' ', 0), 1, ";") == 0);
1299}
1300
1302 std::vector<double>& y,
1303 std::vector<double>& z) const
1304{
1305 std::vector<MeshLib::Node*> const& nodes(_mesh->getNodes());
1306 for (MeshLib::Node const* const node : nodes)
1307 {
1308 x.push_back((*node)[0]);
1309 y.push_back((*node)[1]);
1310 z.push_back((*node)[2]);
1311 }
1312 return true;
1313}
1314
1315bool SwmmInterface::getLinkPointIds(std::vector<std::size_t>& inlets,
1316 std::vector<std::size_t>& outlets) const
1317{
1318 std::vector<MeshLib::Element*> const& elements(_mesh->getElements());
1319 for (MeshLib::Element const* const elem : elements)
1320 {
1321 if (elem->getGeomType() != MeshLib::MeshElemType::LINE)
1322 {
1323 ERR("Non line-element found in mesh.");
1324 return false;
1325 }
1326 inlets.push_back(getNodeIndex(*elem, 0));
1327 outlets.push_back(getNodeIndex(*elem, 1));
1328 }
1329 return true;
1330}
1331
1333{
1334 if (obj_type == SwmmObject::NODE)
1335 return "node";
1336 if (obj_type == SwmmObject::LINK)
1337 return "link";
1338 if (obj_type == SwmmObject::SUBCATCHMENT)
1339 return "subcatchment";
1340 if (obj_type == SwmmObject::SYSTEM)
1341 return "system";
1342 return "undefined";
1343}
1344
1345bool SwmmInterface::writeCsvForTimestep(std::string const& file_name,
1346 SwmmObject obj_type,
1347 std::size_t time_step) const
1348{
1351 csv.addVectorForWriting("Name", getNames(obj_type));
1352 std::size_t const n_params(getNumberOfParameters(obj_type));
1353 for (std::size_t i = 0; i < n_params; ++i)
1354 {
1355 std::vector<double> data = getArrayAtTimeStep(obj_type, time_step, i);
1356 if (!data.empty())
1357 csv.addVectorForWriting<double>(getArrayName(obj_type, i), data);
1358 }
1359 if (csv.getNArrays() < 2)
1360 {
1361 ERR("No data to write");
1362 return false;
1363 }
1365 return true;
1366}
1367
1368bool SwmmInterface::writeCsvForObject(std::string const& file_name,
1369 SwmmObject obj_type,
1370 std::size_t obj_idx) const
1371{
1373 INFO("Writing data for {:s} {:d}.", swmmObjectTypeToString(obj_type),
1374 obj_idx);
1376 std::size_t const n_params(getNumberOfParameters(obj_type));
1377 for (std::size_t i = 0; i < n_params; ++i)
1378 {
1379 std::vector<double> data = getArrayForObject(obj_type, obj_idx, i);
1380 if (!data.empty())
1381 csv.addVectorForWriting<double>(getArrayName(obj_type, i), data);
1382 }
1383 if (csv.getNArrays() < 2)
1384 {
1385 ERR("No data to write");
1386 return false;
1387 }
1389 return true;
1390}
1391
1392} // namespace FileIO
Definition of the CsvInterface class.
Filename manipulation routines.
Definition of the GEOObjects class.
Definition of the Point class.
Definition of the Line class.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:45
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
Definition of the class Properties that implements a container of properties.
Definition of the Mesh class.
Definition of the Node class.
Definition of the PointVec class.
Definition of the Polygon class.
Definition of the PolyLine class.
Definition of string helper functions.
std::string writeToString()
Writes the object to a string.
Definition Writer.cpp:31
bool addVectorForWriting(std::string const &vec_name, std::vector< T > const &vec)
void addIndexVectorForWriting(std::size_t s)
Adds an index vector of size s to the CSV file.
std::size_t getNArrays() const
Returns the number of vectors currently staged for writing.
std::unique_ptr< MeshLib::Mesh > _mesh
Mesh generated from SWMM input (+ optional output data)
std::vector< std::string > _id_nodename_map
Vector storing the names of all nodes/junctions.
std::size_t getNumberOfObjects(SwmmObject obj_type) const
Returns the number of objects of the given type.
bool writeCsvForObject(std::string const &file_name, SwmmObject obj_type, std::size_t obj_idx) const
Write a CSV file for one object of the given type for all time steps.
bool readPollutants(std::ifstream &in)
Reads pollutant names and parameters.
bool readSubcatchments(std::ifstream &in, std::map< std::string, std::size_t > const &name_id_map)
Reads subcatchment information.
std::vector< std::string > getSubcatchmentNameMap() const
Creates a temporary string vector containing all subcatchment names in correct order.
std::string getName(SwmmObject obj_type, std::size_t idx) const
Returns the Name for the indexed object of the given type (or an empty string if an error occurred).
static bool isCommentLine(std::string const &str)
Checks if the given line string is a comment line.
std::string const _base_name
All files for a given SWMM simulation have the same base name.
bool getNodeCoordinateVectors(std::vector< double > &x, std::vector< double > &y, std::vector< double > &z) const
Writes the node coordinates into double vectors for writing of CSV files.
bool getLinkPointIds(std::vector< std::size_t > &inlets, std::vector< std::size_t > &outlets) const
Writes the inlet- and outlet IDs for links into vectors for writing of CSV files.
bool matchSubcatchmentsWithPolygons(std::vector< GeoLib::Polyline * > const &lines, std::vector< std::string > const &names)
Matches existing subcatchment names with subsequently read polylines marking the outlines of said sub...
SwmmInterface(std::string const &swmm_base_name)
Constructor.
static bool readPolygons(std::ifstream &in, std::vector< GeoLib::Polyline * > &lines, std::vector< std::string > &line_names, std::vector< GeoLib::Point * > &points, std::vector< std::string > &pnt_names)
bool addRainGaugeTimeSeriesLocations(std::ifstream &in)
Reads the location of external rain gauge time series files.
std::vector< GeoLib::Point * > _subcatchment_points
Separate node vector containing points for defining subcatchment outlines.
static bool isSwmmInputFile(std::string const &inp_file_name)
Checks if file is a SWMM input file.
bool readLineElements(std::ifstream &in, std::vector< MeshLib::Element * > &elements, std::vector< MeshLib::Node * > const &nodes, std::map< std::string, std::size_t > const &name_id_map)
Reads links/conduits and returns them as a vector of OGS line elements.
bool writeCsvForTimestep(std::string const &file_name, SwmmObject obj_type, std::size_t time_step) const
Write a CSV file for all object of the given type at one time step.
std::vector< std::pair< GeoLib::Station, std::string > > _rain_gauges
Vector containing rain gauge information as well the position of external time series files.
static bool readLinksAsPolylines(std::ifstream &in, std::vector< GeoLib::Polyline * > &lines, std::vector< std::string > &line_names, std::vector< GeoLib::Point * > const &points, std::map< std::string, std::size_t > const &point_names)
During geometry conversion, this reads links (conduits/pumps/weirs) and converts them into polylines.
std::vector< std::string > _id_linkname_map
Vector storing the names of all links/conduits.
static std::unique_ptr< SwmmInterface > create(std::string const &file_name)
std::vector< double > getArrayAtTimeStep(SwmmObject obj_type, std::size_t time_step, std::size_t var_idx) const
Returns an array for a given variable at all nodes/links from a SWMM output file for a given time ste...
std::size_t getNumberOfTimeSteps() const
Returns the number of time steps for the simulation results.
static bool readCoordinates(std::ifstream &in, std::vector< T * > &points, std::vector< std::string > &names)
static bool addResultsToMesh(MeshLib::Mesh &mesh, SwmmObject const type, std::string const &vec_name, std::vector< double > const &data)
bool existsSwmmOutputFile() const
Checks if a SWMM output file exists for the current input.
static bool convertSwmmInputToGeometry(std::string const &inp_file_name, GeoLib::GEOObjects &geo_objects, bool add_subcatchments)
Reading a SWMM input file and conversion into OGS geometry.
static std::string swmmObjectTypeToString(SwmmObject const obj_type)
Returns a string with the name of the object type.
bool readSwmmInputToLineMesh()
Reading a SWMM input file and creating an OGS line mesh. This is automatically called when the object...
std::size_t getNumberOfParameters(SwmmObject obj_type) const
Returns the number of parameters (incl. pollutants) of the given type.
static bool addPointElevation(std::ifstream &in, std::vector< GeoLib::Point * > &points, std::map< std::string, std::size_t > const &name_id_map)
During geometry conversion, this adds elevation values to the existing point vector.
bool readNodeData(std::ifstream &in, std::vector< MeshLib::Node * > &nodes, std::map< std::string, std::size_t > const &name_id_map, std::vector< double > &max_depth, bool read_max_depth)
Reads input information associated with nodes (elevation, depth, etc.)
std::string getArrayName(SwmmObject obj_type, std::size_t var_idx) const
Returns the name of the data array for the given object type and parameter index.
std::vector< Subcatchment > _subcatchments
Vector storing information about all subcatchments.
static bool isSectionFinished(std::string const &str)
Checks if the given line string is empty. Empty strings mark the end of sections in a SWMM input file...
std::vector< double > getArrayForObject(SwmmObject obj_type, std::size_t obj_idx, std::size_t var_idx) const
Returns an array for a given variable for one specific object from a SWMM output file for all time st...
std::vector< std::string > getNames(SwmmObject obj_type) const
Get all the object names for a given object type.
std::vector< std::string > _pollutant_names
Vector storing the names of all pollutants.
Container class for geometric objects.
Definition GEOObjects.h:57
void addPolylineVec(std::vector< Polyline * > &&lines, std::string const &name, PolylineVec::NameIdMap &&ply_names)
void addPointVec(std::vector< Point * > &&points, std::string &name, PointVec::NameIdMap &&pnt_id_name_map, double const eps=std::sqrt(std::numeric_limits< double >::epsilon()))
const PointVec * getPointVecObj(const std::string &name) const
bool removePointVec(const std::string &name)
const std::vector< std::size_t > & getIDMap() const
Definition PointVec.h:97
Class Polyline consists mainly of a reference to a point vector and a vector that stores the indices ...
Definition Polyline.h:40
std::size_t getPointID(std::size_t const i) const
Definition Polyline.cpp:160
virtual bool addPoint(std::size_t pnt_id)
Definition Polyline.cpp:35
A Station (observation site) is basically a Point with some additional information.
Definition Station.h:37
std::map< std::string, std::size_t > NameIdMap
Definition TemplateVec.h:41
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:102
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:99
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition Properties.h:33
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
Definition Properties.h:17
constexpr PROP_VAL_TYPE * begin()
int writeStringToFile(std::string_view content, std::filesystem::path const &file_path)
Definition Writer.cpp:45
std::string getFileExtension(const std::string &path)
void cleanupVectorElements(std::vector< T * > &items)
Definition Algorithm.h:256
std::string extractBaseNameWithoutExtension(std::string const &pathname)
std::vector< std::string > splitString(std::string const &str)
T str2number(const std::string &str)
Definition StringTools.h:63
SwmmObject
SWMM object types.
const std::array< std::string, 15 > system_vars
All variables that exist for the system.
const std::array< std::string, 6 > link_vars
Variables that always exist for links. There might be more.
const std::array< std::string, 9 > subcatchment_vars
Variables that always exist for subcatchments. There might be more.
const std::array< std::string, 7 > node_vars
Variables that always exist for nodes. There might be more.
std::array< std::size_t, 4 > const n_obj_params
PropertyVector< T > * getOrCreateMeshProperty(Mesh &mesh, std::string const &property_name, MeshItemType const item_type, int const number_of_components)