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