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->reserve(max_depth.size());
832 std::copy(max_depth.cbegin(), max_depth.cend(),
833 std::back_inserter(*depth));
834 }
835 else
836 ERR("Size of max depth array does not fit number of elements. Skipping "
837 "array.");
838
839 _mesh.reset(new MeshLib::Mesh(_base_name, nodes, elements,
840 false /* compute_element_neighbors */,
841 props));
842 return true;
843}
844
846 std::vector<GeoLib::Polyline*> const& lines,
847 std::vector<std::string> const& names)
848{
849 std::size_t const n_lines(lines.size());
850 std::size_t const n_subcatchments(_subcatchments.size());
851
852 if (n_lines != n_subcatchments)
853 {
854 ERR("Number of subcatchments does not match number of outlines.");
855 return false;
856 }
857 for (std::size_t i = 0; i < n_lines; ++i)
858 {
859 bool found = false;
860 for (std::size_t j = 0; j < n_subcatchments; ++j)
861 {
862 if (names[i] == _subcatchments[j].name)
863 {
864 _subcatchments[j].outline = lines[i];
865 found = true;
866 break;
867 }
868 }
869 if (found == false)
870 {
871 ERR("No match in subcatcments for outline '{:s}'.", names[i]);
872 return false;
873 }
874 }
875 return true;
876}
877
878std::vector<std::string> SwmmInterface::getSubcatchmentNameMap() const
879{
880 std::vector<std::string> names;
881 names.reserve(_subcatchments.size());
882 std::transform(_subcatchments.begin(), _subcatchments.end(),
883 std::back_inserter(names),
884 [](auto const& sc) { return sc.name; });
885 return names;
886}
887
888std::vector<std::string> SwmmInterface::getNames(SwmmObject obj_type) const
889{
890 switch (obj_type)
891 {
892 case SwmmObject::NODE:
893 return _id_nodename_map;
894 case SwmmObject::LINK:
895 return _id_linkname_map;
897 return getSubcatchmentNameMap();
899 std::vector<std::string> system_name{"System"};
900 return system_name;
901 }
902 ERR("Object type has no name map");
903 std::vector<std::string> empty_vec;
904 return empty_vec;
905}
906
907std::string SwmmInterface::getName(SwmmObject obj_type, std::size_t idx) const
908{
909 switch (obj_type)
910 {
911 case SwmmObject::NODE:
912 if (idx < _id_nodename_map.size())
913 return _id_nodename_map[idx];
914 case SwmmObject::LINK:
915 if (idx < _id_linkname_map.size())
916 return _id_linkname_map[idx];
918 if (idx < _subcatchments.size())
919 return _subcatchments[idx].name;
921 if (idx == 0)
922 return std::string("System");
923 }
924 ERR("Index out of bounds.");
925 return std::string("");
926}
927
929{
930 std::string const outfile(_base_name + ".out");
931 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
932 return 0;
933
934 switch (obj_type)
935 {
937 return SWMM_Nsubcatch;
938 case SwmmObject::NODE:
939 return SWMM_Nnodes;
940 case SwmmObject::LINK:
941 return SWMM_Nlinks;
943 return 1;
944 default:
945 ERR("Object type not recognised.");
946 }
947 CloseSwmmOutFile();
948 return 0;
949}
950
952{
953 std::string const outfile(_base_name + ".out");
954 std::size_t n_time_steps(std::numeric_limits<std::size_t>::max());
955 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
956 return 0;
957
958 std::size_t n_params(0);
959 switch (obj_type)
960 {
962 n_params = n_obj_params[0] + SWMM_Npolluts;
963 break;
964 case SwmmObject::NODE:
965 n_params = n_obj_params[1] + SWMM_Npolluts;
966 break;
967 case SwmmObject::LINK:
968 n_params = n_obj_params[2] + SWMM_Npolluts;
969 break;
971 n_params = n_obj_params[3];
972 break;
973 default:
974 ERR("Object type not recognised.");
975 }
976 CloseSwmmOutFile();
977 return n_params;
978}
979
981{
982 std::string const outfile(_base_name + ".out");
983 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
984 return std::numeric_limits<std::size_t>::max();
985 std::size_t const n_time_steps(static_cast<std::size_t>(SWMM_Nperiods));
986 CloseSwmmOutFile();
987 return n_time_steps;
988}
989
991 SwmmObject const swmm_type,
992 std::string const& vec_name,
993 std::vector<double> const& data)
994{
995 if (!(swmm_type == SwmmObject::NODE || swmm_type == SwmmObject::LINK))
996 {
997 ERR("Information of this object type cannot be added to mesh.");
998 return false;
999 }
1000
1001 if (data.empty())
1002 {
1003 ERR("Data array is empty and cannot be added to mesh.");
1004 return false;
1005 }
1006
1007 if (swmm_type == SwmmObject::NODE && data.size() != mesh.getNumberOfNodes())
1008 {
1009 ERR("Number of mesh nodes ({:d}) does not match length of array "
1010 "({:d}).",
1011 mesh.getNumberOfNodes(), data.size());
1012 return false;
1013 }
1014
1015 if (swmm_type == SwmmObject::LINK &&
1016 data.size() != mesh.getNumberOfElements())
1017 {
1018 ERR("Number of mesh elements ({:d}) does not match length of array "
1019 "({:d}).",
1020 mesh.getNumberOfElements(), data.size());
1021 return false;
1022 }
1023
1024 MeshLib::MeshItemType const item_type = (swmm_type == SwmmObject::NODE)
1028 MeshLib::getOrCreateMeshProperty<double>(mesh, vec_name, item_type, 1);
1029 if (!prop)
1030 {
1031 ERR("Error fetching array '{:s}'.", vec_name);
1032 return false;
1033 }
1034 std::copy(data.cbegin(), data.cend(), prop->begin());
1035 return true;
1036}
1037
1039 std::size_t time_step,
1040 std::size_t var_idx) const
1041{
1042 std::vector<double> data;
1043 std::string const outfile(_base_name + ".out");
1044 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
1045 return data;
1046
1047 if (time_step >= SWMM_Nperiods)
1048 {
1049 ERR("Time step {:d} not available, file contains only {:d} periods.",
1050 time_step, SWMM_Nperiods);
1051 return data;
1052 }
1053
1054 bool is_var_idx_okay = true;
1055 int obj_type_id;
1056 std::size_t n_objects;
1057 switch (obj_type)
1058 {
1060 obj_type_id = 0;
1061 n_objects = SWMM_Nsubcatch;
1062 if (var_idx > (n_obj_params[obj_type_id] - 1 + SWMM_Npolluts))
1063 is_var_idx_okay = false;
1064 break;
1065 case SwmmObject::NODE:
1066 obj_type_id = 1;
1067 n_objects = SWMM_Nnodes;
1068 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1069 is_var_idx_okay = false;
1070 break;
1071 case SwmmObject::LINK:
1072 obj_type_id = 2;
1073 n_objects = SWMM_Nlinks;
1074 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1075 is_var_idx_okay = false;
1076 break;
1077 case SwmmObject::SYSTEM:
1078 obj_type_id = 3;
1079 n_objects = 1;
1080 if (var_idx > n_obj_params[obj_type_id])
1081 is_var_idx_okay = false;
1082 break;
1083 default:
1084 ERR("Object type not recognised.");
1085 CloseSwmmOutFile();
1086 return data;
1087 }
1088
1089 if (!is_var_idx_okay)
1090 {
1091 ERR("Requested variable does not exist.");
1092 CloseSwmmOutFile();
1093 return data;
1094 }
1095
1096 INFO("Fetching '{:s}'-data for time step {:d}...",
1097 getArrayName(obj_type, var_idx, SWMM_Npolluts), time_step);
1098
1099 for (std::size_t i = 0; i < n_objects; ++i)
1100 {
1101 float val;
1102 GetSwmmResult(obj_type_id, i, var_idx, time_step, &val);
1103 data.push_back(static_cast<double>(val));
1104 }
1105
1106 CloseSwmmOutFile();
1107 return data;
1108}
1109
1111 std::size_t obj_idx,
1112 std::size_t var_idx) const
1113{
1114 std::vector<double> data;
1115 std::string const outfile(_base_name + ".out");
1116 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
1117 return data;
1118
1119 bool is_var_idx_okay = true;
1120 bool is_obj_idx_okay = true;
1121 int obj_type_id;
1122 switch (obj_type)
1123 {
1125 obj_type_id = 0;
1126 if (obj_idx >= SWMM_Nsubcatch)
1127 is_obj_idx_okay = false;
1128 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1129 is_var_idx_okay = false;
1130 break;
1131 case SwmmObject::NODE:
1132 obj_type_id = 1;
1133 if (obj_idx >= SWMM_Nnodes)
1134 is_obj_idx_okay = false;
1135 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1136 is_var_idx_okay = false;
1137 break;
1138 case SwmmObject::LINK:
1139 obj_type_id = 2;
1140 if (obj_idx >= SWMM_Nlinks)
1141 is_obj_idx_okay = false;
1142 if (var_idx > (n_obj_params[obj_type_id] + SWMM_Npolluts))
1143 is_var_idx_okay = false;
1144 break;
1145 case SwmmObject::SYSTEM:
1146 obj_type_id = 3;
1147 if (obj_idx >= 1)
1148 is_obj_idx_okay = false;
1149 if (var_idx > n_obj_params[obj_type_id])
1150 is_var_idx_okay = false;
1151 break;
1152 default:
1153 ERR("Object type not recognised.");
1154 CloseSwmmOutFile();
1155 return data;
1156 }
1157
1158 if (!is_obj_idx_okay)
1159 {
1160 ERR("Requested object index does not exist.");
1161 CloseSwmmOutFile();
1162 return data;
1163 }
1164
1165 if (!is_var_idx_okay)
1166 {
1167 ERR("Requested variable does not exist.");
1168 CloseSwmmOutFile();
1169 return data;
1170 }
1171
1172 std::size_t const n_time_steps(static_cast<std::size_t>(SWMM_Nperiods));
1173 for (std::size_t i = 0; i < n_time_steps; ++i)
1174 {
1175 float val;
1176 GetSwmmResult(obj_type_id, obj_idx, var_idx, i, &val);
1177 data.push_back(static_cast<double>(val));
1178 }
1179
1180 CloseSwmmOutFile();
1181 return data;
1182}
1183
1185 std::size_t var_idx) const
1186{
1187 std::string const outfile(_base_name + ".out");
1188 if (OpenSwmmOutFile(const_cast<char*>(outfile.c_str())) != 0)
1189 return std::string("");
1190
1191 std::string const name = getArrayName(obj_type, var_idx, SWMM_Npolluts);
1192 CloseSwmmOutFile();
1193 return name;
1194}
1195
1197 std::size_t var_idx,
1198 std::size_t n_pollutants) const
1199{
1200 if (obj_type == SwmmObject::SUBCATCHMENT)
1201 {
1202 if (var_idx < n_obj_params[0])
1203 return subcatchment_vars[var_idx];
1204 if (var_idx < n_obj_params[0] + n_pollutants)
1205 return _pollutant_names[var_idx - n_obj_params[0]];
1206 }
1207 if (obj_type == SwmmObject::NODE)
1208 {
1209 if (var_idx < n_obj_params[1])
1210 return node_vars[var_idx];
1211 if (var_idx < n_obj_params[1] + n_pollutants)
1212 return std::string("Node_" +
1213 _pollutant_names[var_idx - n_obj_params[1]]);
1214 }
1215 if (obj_type == SwmmObject::LINK)
1216 {
1217 if (var_idx < n_obj_params[2])
1218 return link_vars[var_idx];
1219 if (var_idx < n_obj_params[2] + n_pollutants)
1220 return std::string("Link_" +
1221 _pollutant_names[var_idx - n_obj_params[2]]);
1222 }
1223 if (obj_type == SwmmObject::SYSTEM && var_idx < n_obj_params[3])
1224 {
1225 return system_vars[var_idx];
1226 }
1227 ERR("SwmmInterface::getArrayName() - Index error, no name found.");
1228 return std::string("");
1229}
1230
1232{
1233 std::string line;
1234 while (std::getline(in, line))
1235 {
1236 if (isSectionFinished(line))
1237 break;
1238
1239 if (isCommentLine(line))
1240 continue;
1241
1242 std::vector<std::string> const split_str(BaseLib::splitString(line));
1243 if (split_str.size() < 6)
1244 {
1245 ERR("Rain gauge parameter format not recognised.");
1246 return false;
1247 }
1248
1249 for (auto& stn : _rain_gauges)
1250 {
1251 if (stn.first.getName() == split_str[0] && split_str[4] == "FILE")
1252 stn.second = split_str[5].substr(1, split_str[5].size() - 2);
1253 }
1254 }
1255
1256 for (auto const& stn : _rain_gauges)
1257 if (stn.second.empty())
1258 WARN("No associated time series found for rain gauge '{:s}'.",
1259 stn.first.getName());
1260 return true;
1261}
1262
1263bool SwmmInterface::readPollutants(std::ifstream& in)
1264{
1265 std::string line;
1266 while (std::getline(in, line))
1267 {
1268 if (isSectionFinished(line))
1269 return true;
1270
1271 if (isCommentLine(line))
1272 continue;
1273
1274 std::vector<std::string> split_str(BaseLib::splitString(line));
1275 if (split_str.size() < 6)
1276 {
1277 ERR("Parameter format for pollutants not recognised.");
1278 return false;
1279 }
1280 _pollutant_names.push_back(split_str[0]);
1281 }
1282 return true;
1283}
1284
1285bool SwmmInterface::isSectionFinished(std::string const& str)
1286{
1287 if (str.empty())
1288 return true;
1289
1290 std::size_t const pos_beg = str.find_first_not_of(' ', 0);
1291 if (pos_beg == str.find_first_of(" \n", pos_beg))
1292 return true;
1293
1294 return false;
1295}
1296
1297bool SwmmInterface::isCommentLine(std::string const& str)
1298{
1299 return (str.compare(str.find_first_not_of(' ', 0), 1, ";") == 0);
1300}
1301
1303 std::vector<double>& y,
1304 std::vector<double>& z) const
1305{
1306 std::vector<MeshLib::Node*> const& nodes(_mesh->getNodes());
1307 for (MeshLib::Node const* const node : nodes)
1308 {
1309 x.push_back((*node)[0]);
1310 y.push_back((*node)[1]);
1311 z.push_back((*node)[2]);
1312 }
1313 return true;
1314}
1315
1316bool SwmmInterface::getLinkPointIds(std::vector<std::size_t>& inlets,
1317 std::vector<std::size_t>& outlets) const
1318{
1319 std::vector<MeshLib::Element*> const& elements(_mesh->getElements());
1320 for (MeshLib::Element const* const elem : elements)
1321 {
1322 if (elem->getGeomType() != MeshLib::MeshElemType::LINE)
1323 {
1324 ERR("Non line-element found in mesh.");
1325 return false;
1326 }
1327 inlets.push_back(getNodeIndex(*elem, 0));
1328 outlets.push_back(getNodeIndex(*elem, 1));
1329 }
1330 return true;
1331}
1332
1334{
1335 if (obj_type == SwmmObject::NODE)
1336 return "node";
1337 if (obj_type == SwmmObject::LINK)
1338 return "link";
1339 if (obj_type == SwmmObject::SUBCATCHMENT)
1340 return "subcatchment";
1341 if (obj_type == SwmmObject::SYSTEM)
1342 return "system";
1343 return "undefined";
1344}
1345
1346bool SwmmInterface::writeCsvForTimestep(std::string const& file_name,
1347 SwmmObject obj_type,
1348 std::size_t time_step) const
1349{
1352 csv.addVectorForWriting("Name", getNames(obj_type));
1353 std::size_t const n_params(getNumberOfParameters(obj_type));
1354 for (std::size_t i = 0; i < n_params; ++i)
1355 {
1356 std::vector<double> data = getArrayAtTimeStep(obj_type, time_step, i);
1357 if (!data.empty())
1358 csv.addVectorForWriting<double>(getArrayName(obj_type, i), data);
1359 }
1360 if (csv.getNArrays() < 2)
1361 {
1362 ERR("No data to write");
1363 return false;
1364 }
1366 return true;
1367}
1368
1369bool SwmmInterface::writeCsvForObject(std::string const& file_name,
1370 SwmmObject obj_type,
1371 std::size_t obj_idx) const
1372{
1374 INFO("Writing data for {:s} {:d}.", swmmObjectTypeToString(obj_type),
1375 obj_idx);
1377 std::size_t const n_params(getNumberOfParameters(obj_type));
1378 for (std::size_t i = 0; i < n_params; ++i)
1379 {
1380 std::vector<double> data = getArrayForObject(obj_type, obj_idx, i);
1381 if (!data.empty())
1382 csv.addVectorForWriting<double>(getArrayName(obj_type, i), data);
1383 }
1384 if (csv.getNArrays() < 2)
1385 {
1386 ERR("No data to write");
1387 return false;
1388 }
1390 return true;
1391}
1392
1393} // 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
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:100
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:97
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition Properties.h:36
PropertyVector< T > * createNewPropertyVector(std::string_view name, MeshItemType mesh_item_type, std::size_t n_components=1)
Definition Properties.h:17
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:252
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:60
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)
MeshItemType
Definition Location.h:21