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