OpenSWMM Engine  6.0.0-alpha.1
Data-oriented, plugin-extensible SWMM Engine (6.0.0-alpha.1)
Loading...
Searching...
No Matches
LinkData.hpp
Go to the documentation of this file.
1
24#ifndef OPENSWMM_ENGINE_LINK_DATA_HPP
25#define OPENSWMM_ENGINE_LINK_DATA_HPP
26
27#include <vector>
28#include <cstdint>
29#include <string>
30#include <algorithm>
31
32namespace openswmm {
33
34// ============================================================================
35// Link type enumerations
36// ============================================================================
37
42enum class LinkType : int8_t {
43 CONDUIT = 0,
44 PUMP = 1,
45 ORIFICE = 2,
46 WEIR = 3,
47 OUTLET = 4
48};
49
54enum class XsectShape : int16_t {
55 CIRCULAR = 0,
57 RECT_CLOSED = 2,
58 RECT_OPEN = 3,
59 TRAPEZOIDAL = 4,
60 TRIANGULAR = 5,
61 PARABOLIC = 6,
62 POWER = 7,
64 EGGSHAPED = 9,
65 HORSESHOE = 10,
66 GOTHIC = 11,
67 CATENARY = 12,
68 SEMIELLIPTICAL = 13,
69 BASKETHANDLE = 14,
70 SEMICIRCULAR = 15,
71 RECT_TRIANG = 16,
72 RECT_ROUND = 17,
73 HORIZ_ELLIPSE = 18,
74 VERT_ELLIPSE = 19,
75 ARCH = 20,
76 IRREGULAR = 21,
77 CUSTOM = 22,
78 FORCE_MAIN = 23,
79 STREET_XSECT = 24,
80 DUMMY = 25
81};
82
87enum class FlowClass : int8_t {
88 DRY = 0,
89 UP_DRY = 1,
90 DN_DRY = 2,
91 SUBCRITICAL = 3,
92 SUPERCRITICAL = 4,
93 UP_CRITICAL = 5,
94 DN_CRITICAL = 6
95};
96
97// ============================================================================
98// LinkData — SoA layout
99// ============================================================================
100
109struct LinkData {
110
111 // -----------------------------------------------------------------------
112 // Static connectivity — set at parse time
113 // -----------------------------------------------------------------------
114
116 std::vector<LinkType> type;
117
122 std::vector<int> node1;
123
128 std::vector<int> node2;
129
134 std::vector<double> offset1;
135
140 std::vector<double> offset2;
141
146 std::vector<double> q0;
147
152 std::vector<double> q_limit;
153
154 // -----------------------------------------------------------------------
155 // Conduit-specific properties (valid when type[i] == CONDUIT)
156 // -----------------------------------------------------------------------
157
159 std::vector<XsectShape> xsect_shape;
160
162 std::vector<double> xsect_y_full;
163
165 std::vector<double> xsect_a_full;
166
168 std::vector<double> xsect_w_max;
169
174 std::vector<int> xsect_curve;
175
177 std::vector<double> roughness;
178
180 std::vector<double> length;
181
183 std::vector<double> slope;
184
192 std::vector<double> mod_length;
193
195 std::vector<int> barrels;
196
202 std::vector<double> beta;
203
208 std::vector<double> rough_factor;
209
214 std::vector<double> q_full;
215
220 std::vector<double> xsect_r_full;
221
226 std::vector<double> xsect_s_full;
227
232 std::vector<double> xsect_s_max;
233
238 std::vector<double> q_max;
239
244 std::vector<double> xsect_y_bot;
245
250 std::vector<double> xsect_a_bot;
251
257 std::vector<double> xsect_s_bot;
258
263 std::vector<double> xsect_r_bot;
264
269 std::vector<double> xsect_yw_max;
270
276 std::vector<int> xsect_batch_shape;
277
282 std::vector<double> setting;
283
288 std::vector<double> target_setting;
289
298 std::vector<double> time_last_set;
299
304 std::vector<int> direction;
305
306 // -----------------------------------------------------------------------
307 // Pump-specific properties (valid when type[i] == PUMP)
308 // -----------------------------------------------------------------------
309
314 std::vector<int> pump_curve;
315
317 std::vector<bool> pump_init_state;
318
320 std::vector<double> pump_startup;
321
323 std::vector<double> pump_shutoff;
324
331 std::vector<int> pump_curve_type;
332
334 std::vector<std::string> pump_curve_name;
335
336 // -----------------------------------------------------------------------
337 // Conduit loss coefficients
338 // -----------------------------------------------------------------------
339
341 std::vector<double> loss_inlet;
343 std::vector<double> loss_outlet;
345 std::vector<double> loss_avg;
347 std::vector<uint8_t> has_flap_gate;
349 std::vector<double> seep_rate;
350
352 std::vector<double> evap_loss_rate;
353
355 std::vector<double> seep_loss_rate;
356
361 std::vector<int> culvert_code;
362
365 std::vector<uint8_t> normal_flow_limited;
366
371 std::vector<uint8_t> inlet_control;
372
377 std::vector<double> dqdh;
378
379 // -----------------------------------------------------------------------
380 // Weir / Orifice / Outlet — shared geometric properties
381 // -----------------------------------------------------------------------
382
384 std::vector<double> crest_height;
385
387 std::vector<double> cd;
388
390 std::vector<double> param1;
391
393 std::vector<double> param2;
394
400 std::vector<double> orate;
401
402 // -----------------------------------------------------------------------
403 // State variables — updated each timestep
404 // -----------------------------------------------------------------------
405
410 std::vector<double> flow;
411
416 std::vector<double> depth;
417
422 std::vector<double> volume;
423
428 std::vector<double> froude;
429
431 std::vector<FlowClass> flow_class;
432
434 std::vector<uint8_t> is_closed;
435
442 std::vector<int8_t> full_state;
443
444 // -----------------------------------------------------------------------
445 // Previous-step state
446 // -----------------------------------------------------------------------
447
449 std::vector<double> old_flow;
450
452 std::vector<double> old_depth;
453
455 std::vector<double> old_volume;
456
457 // -----------------------------------------------------------------------
458 // Per-link quality state — flat 2D: [link * n_pollutants + pollutant]
459 // -----------------------------------------------------------------------
460
466 std::vector<double> conc;
467
469 std::vector<double> conc_old;
470
473
474 // -----------------------------------------------------------------------
475 // Per-object INP comment
476 // -----------------------------------------------------------------------
477
483 std::vector<std::string> comments;
484
491 std::vector<std::string> tags;
492
493 // -----------------------------------------------------------------------
494 // Report flag — per-object output filter
495 // -----------------------------------------------------------------------
496
499 std::vector<char> rpt_flag;
500
501 // -----------------------------------------------------------------------
502 // Cumulative statistics
503 // -----------------------------------------------------------------------
504
509 std::vector<double> stat_vol_flow;
510
515 std::vector<double> stat_max_flow;
516
521 std::vector<double> stat_max_veloc;
522
527 std::vector<double> stat_max_filling;
528
533 std::vector<double> stat_time_surcharged;
534
541 static constexpr int N_FLOW_CLASSES = 7;
542 std::vector<long> stat_flow_class;
543 std::vector<long> stat_norm_ltd;
544 std::vector<long> stat_inlet_ctrl;
545
548 std::vector<double> stat_max_flow_date;
549
552 std::vector<double> stat_time_full_upstream;
553
556 std::vector<double> stat_time_full_dnstream;
557
560 std::vector<double> stat_time_full_both;
561
564 std::vector<double> stat_time_capacity_limited;
565
572 std::vector<double> stat_total_load;
574
575 // -----------------------------------------------------------------------
576 // Pump utilization statistics (valid when type[i] == PUMP)
577 // -----------------------------------------------------------------------
578
580 std::vector<int> stat_pump_cycles;
581
583 std::vector<double> stat_pump_on_time;
584
586 std::vector<double> stat_pump_volume;
587
593 std::vector<double> stat_pump_energy;
594
596 std::vector<bool> stat_pump_was_on;
597
605 std::vector<long> stat_flow_turns;
606
613 std::vector<int> stat_flow_turn_sign;
614
621 std::vector<double> stat_time_courant_critical;
622
623 // -----------------------------------------------------------------------
624 // Capacity management
625 // -----------------------------------------------------------------------
626
627 int count() const noexcept { return static_cast<int>(type.size()); }
628
629 void resize(int n) {
630 const auto un = static_cast<std::size_t>(n);
631
632 type.assign(un, LinkType::CONDUIT);
633 node1.assign(un, -1);
634 node2.assign(un, -1);
635 offset1.assign(un, 0.0);
636 offset2.assign(un, 0.0);
637 q0.assign(un, 0.0);
638 q_limit.assign(un, 0.0);
639
641 xsect_y_full.assign(un, 0.0);
642 xsect_a_full.assign(un, 0.0);
643 xsect_w_max.assign(un, 0.0);
644 xsect_curve.assign(un, -1);
645 roughness.assign(un, 0.01);
646 length.assign(un, 0.0);
647 slope.assign(un, 0.0);
648 mod_length.assign(un, 0.0);
649 barrels.assign(un, 1);
650 beta.assign(un, 0.0);
651 rough_factor.assign(un, 0.0);
652 q_full.assign(un, 0.0);
653 xsect_r_full.assign(un, 0.0);
654 xsect_s_full.assign(un, 0.0);
655 xsect_s_max.assign(un, 0.0);
656 q_max.assign(un, 0.0);
657 xsect_y_bot.assign(un, 0.0);
658 xsect_a_bot.assign(un, 0.0);
659 xsect_s_bot.assign(un, 0.0);
660 xsect_r_bot.assign(un, 0.0);
661 xsect_yw_max.assign(un, 0.0);
662 xsect_batch_shape.assign(un, 0);
663 setting.assign(un, 1.0);
664 target_setting.assign(un, 1.0);
665 time_last_set.assign(un, 0.0);
666 direction.assign(un, 1);
667
668 loss_inlet.assign(un, 0.0);
669 loss_outlet.assign(un, 0.0);
670 loss_avg.assign(un, 0.0);
671 has_flap_gate.assign(un, 0);
672 seep_rate.assign(un, 0.0);
673 evap_loss_rate.assign(un, 0.0);
674 seep_loss_rate.assign(un, 0.0);
675 culvert_code.assign(un, 0);
676 inlet_control.assign(un, 0);
677 dqdh.assign(un, 0.0);
678
679 pump_curve.assign(un, -1);
680 pump_init_state.assign(un, false);
681 pump_startup.assign(un, 0.0);
682 pump_shutoff.assign(un, 0.0);
683 pump_curve_type.assign(un, -1);
684 pump_curve_name.resize(un);
685
686 crest_height.assign(un, 0.0);
687 cd.assign(un, 0.0);
688 param1.assign(un, 0.0);
689 param2.assign(un, 0.0);
690 orate.assign(un, 0.0);
691
692 flow.assign(un, 0.0);
693 depth.assign(un, 0.0);
694 volume.assign(un, 0.0);
695 froude.assign(un, 0.0);
696 flow_class.assign(un, FlowClass::DRY);
697 is_closed.assign(un, 0);
698 full_state.assign(un, 0);
699 old_flow.assign(un, 0.0);
700 old_depth.assign(un, 0.0);
701 old_volume.assign(un, 0.0);
702
703 comments.assign(un, std::string{});
704 tags.assign(un, std::string{});
705
706 rpt_flag.assign(un, 0);
707
708 stat_vol_flow.assign(un, 0.0);
709 stat_max_flow.assign(un, 0.0);
710 stat_max_veloc.assign(un, 0.0);
711 stat_max_filling.assign(un, 0.0);
712 stat_time_surcharged.assign(un, 0.0);
713 stat_flow_class.assign(un * N_FLOW_CLASSES, 0L);
714 stat_norm_ltd.assign(un, 0L);
715 stat_inlet_ctrl.assign(un, 0L);
716 stat_max_flow_date.assign(un, 0.0);
717 stat_time_full_upstream.assign(un, 0.0);
718 stat_time_full_dnstream.assign(un, 0.0);
719 stat_time_full_both.assign(un, 0.0);
720 stat_time_capacity_limited.assign(un, 0.0);
721 stat_pump_cycles.assign(un, 0);
722 stat_pump_on_time.assign(un, 0.0);
723 stat_pump_volume.assign(un, 0.0);
724 stat_pump_energy.assign(un, 0.0);
725 stat_pump_was_on.assign(un, false);
726 stat_flow_turns.assign(un, 0L);
727 stat_flow_turn_sign.assign(un, 0);
728 stat_time_courant_critical.assign(un, 0.0);
729 normal_flow_limited.assign(un, 0);
730 }
731
735 void grow_to(int n) {
736 if (n <= count()) return;
737 const auto un = static_cast<std::size_t>(n);
738 auto g = [&](auto& vec, auto def) { vec.resize(un, def); };
739 g(type, LinkType::CONDUIT); g(node1, -1); g(node2, -1);
740 g(offset1, 0.0); g(offset2, 0.0); g(q0, 0.0); g(q_limit, 0.0);
742 g(xsect_y_full, 0.0); g(xsect_a_full, 0.0); g(xsect_w_max, 0.0);
743 g(xsect_curve, -1); g(roughness, 0.013); g(param1, 0.0);
744 g(length, 0.0); g(mod_length, 0.0); g(slope, 0.0);
745 g(barrels, 1); g(beta, 0.0); g(rough_factor, 0.0);
746 g(q_full, 0.0); g(q_max, 0.0);
747 g(xsect_r_full, 0.0); g(xsect_s_full, 0.0); g(xsect_s_max, 0.0);
748 g(xsect_y_bot, 0.0); g(xsect_a_bot, 0.0);
749 g(xsect_s_bot, 0.0); g(xsect_r_bot, 0.0);
750 g(xsect_yw_max, 0.0); g(xsect_batch_shape, 0);
751 g(setting, 1.0); g(target_setting, 1.0); g(direction, 1);
752 g(loss_inlet, 0.0); g(loss_outlet, 0.0); g(loss_avg, 0.0);
753 g(has_flap_gate, uint8_t{0}); g(seep_rate, 0.0);
754 g(evap_loss_rate, 0.0); g(seep_loss_rate, 0.0);
755 g(culvert_code, 0); g(normal_flow_limited, uint8_t{0});
756 g(inlet_control, uint8_t{0}); g(dqdh, 0.0);
757 g(pump_curve, -1); g(pump_init_state, false);
758 g(pump_startup, 0.0); g(pump_shutoff, 0.0);
759 g(pump_curve_type, -1);
760 pump_curve_name.resize(un);
761 g(crest_height, 0.0); g(cd, 0.0); g(param2, 0.0); g(orate, 0.0);
762 g(flow, 0.0); g(depth, 0.0); g(volume, 0.0);
763 g(froude, 0.0); g(flow_class, FlowClass::DRY); g(is_closed, uint8_t{0});
764 g(full_state, int8_t{0});
765 g(old_flow, 0.0); g(old_depth, 0.0); g(old_volume, 0.0);
766 comments.resize(un, std::string{});
767 tags.resize(un, std::string{});
768
769 g(rpt_flag, static_cast<char>(0));
770 g(stat_vol_flow, 0.0); g(stat_max_flow, 0.0);
771 g(stat_max_veloc, 0.0); g(stat_max_filling, 0.0);
775 g(stat_pump_cycles, 0); g(stat_pump_on_time, 0.0);
776 g(stat_pump_volume, 0.0); g(stat_pump_energy, 0.0);
777 g(stat_pump_was_on, false);
780 g(stat_norm_ltd, 0L); g(stat_inlet_ctrl, 0L);
781 // stat_flow_class is flat 2D [n * N_FLOW_CLASSES]
782 stat_flow_class.resize(un * N_FLOW_CLASSES, 0L);
783 // Note: conc, conc_old handled by resize_quality()
784 // Note: stat_total_load handled by resize_loads()
785 }
786
795 void erase_at(int idx) {
796 const auto ui = static_cast<std::size_t>(idx);
797 auto e = [&](auto& v) { if (ui < v.size()) v.erase(v.begin() + static_cast<std::ptrdiff_t>(idx)); };
798
799 e(type); e(node1); e(node2); e(offset1); e(offset2); e(q0); e(q_limit);
800
802 e(roughness); e(length); e(slope); e(mod_length); e(barrels);
803 e(beta); e(rough_factor); e(q_full);
807
810
814
815 e(crest_height); e(cd); e(param1); e(param2); e(orate);
816
817 e(flow); e(depth); e(volume); e(froude); e(flow_class); e(is_closed); e(full_state);
818 e(old_flow); e(old_depth); e(old_volume);
819 e(comments); e(tags); e(rpt_flag);
820
828
829 // Flat 2D: stat_flow_class [link * N_FLOW_CLASSES + class]
830 {
831 const auto base = ui * static_cast<std::size_t>(N_FLOW_CLASSES);
832 const auto end = base + static_cast<std::size_t>(N_FLOW_CLASSES);
833 if (end <= stat_flow_class.size())
834 stat_flow_class.erase(stat_flow_class.begin() + static_cast<std::ptrdiff_t>(base),
835 stat_flow_class.begin() + static_cast<std::ptrdiff_t>(end));
836 }
837
838 // Flat 2D quality arrays: [link * np + p]
839 if (conc_n_pollutants > 0) {
840 const auto np = static_cast<std::size_t>(conc_n_pollutants);
841 const auto base = ui * np;
842 auto erase2d = [&](auto& v) {
843 if (base + np <= v.size())
844 v.erase(v.begin() + static_cast<std::ptrdiff_t>(base),
845 v.begin() + static_cast<std::ptrdiff_t>(base + np));
846 };
847 erase2d(conc); erase2d(conc_old);
848 }
849
850 // Flat 2D stat load: [link * np + p]
851 if (stat_n_pollutants > 0) {
852 const auto np = static_cast<std::size_t>(stat_n_pollutants);
853 const auto base = ui * np;
854 if (base + np <= stat_total_load.size())
855 stat_total_load.erase(
856 stat_total_load.begin() + static_cast<std::ptrdiff_t>(base),
857 stat_total_load.begin() + static_cast<std::ptrdiff_t>(base + np));
858 }
859 }
860
864 void resize_loads(int n_pollutants) {
865 stat_n_pollutants = n_pollutants;
866 if (n_pollutants > 0) {
867 auto total = static_cast<std::size_t>(count()) *
868 static_cast<std::size_t>(n_pollutants);
869 stat_total_load.assign(total, 0.0);
870 }
871 }
872
876 void resize_quality(int n_pollutants) {
877 conc_n_pollutants = n_pollutants;
878 if (n_pollutants > 0) {
879 auto total = static_cast<std::size_t>(count()) *
880 static_cast<std::size_t>(n_pollutants);
881 conc.assign(total, 0.0);
882 conc_old.assign(total, 0.0);
883 }
884 }
885
890 type.shrink_to_fit();
891 node1.shrink_to_fit();
892 node2.shrink_to_fit();
893 offset1.shrink_to_fit();
894 offset2.shrink_to_fit();
895 q0.shrink_to_fit();
896 q_limit.shrink_to_fit();
897
898 xsect_shape.shrink_to_fit();
899 xsect_y_full.shrink_to_fit();
900 xsect_a_full.shrink_to_fit();
901 xsect_w_max.shrink_to_fit();
902 xsect_curve.shrink_to_fit();
903 roughness.shrink_to_fit();
904 length.shrink_to_fit();
905 slope.shrink_to_fit();
906 mod_length.shrink_to_fit();
907 barrels.shrink_to_fit();
908 beta.shrink_to_fit();
909 rough_factor.shrink_to_fit();
910 q_full.shrink_to_fit();
911 xsect_r_full.shrink_to_fit();
912 xsect_s_full.shrink_to_fit();
913 xsect_s_max.shrink_to_fit();
914 q_max.shrink_to_fit();
915 xsect_y_bot.shrink_to_fit();
916 xsect_a_bot.shrink_to_fit();
917 xsect_s_bot.shrink_to_fit();
918 xsect_r_bot.shrink_to_fit();
919 xsect_yw_max.shrink_to_fit();
920 xsect_batch_shape.shrink_to_fit();
921 setting.shrink_to_fit();
922 target_setting.shrink_to_fit();
923 direction.shrink_to_fit();
924
925 loss_inlet.shrink_to_fit();
926 loss_outlet.shrink_to_fit();
927 loss_avg.shrink_to_fit();
928 has_flap_gate.shrink_to_fit();
929 seep_rate.shrink_to_fit();
930 evap_loss_rate.shrink_to_fit();
931 seep_loss_rate.shrink_to_fit();
932 culvert_code.shrink_to_fit();
933 inlet_control.shrink_to_fit();
934 dqdh.shrink_to_fit();
935 normal_flow_limited.shrink_to_fit();
936
937 pump_curve.shrink_to_fit();
938 pump_init_state.shrink_to_fit();
939 pump_startup.shrink_to_fit();
940 pump_shutoff.shrink_to_fit();
941 pump_curve_type.shrink_to_fit();
942 pump_curve_name.shrink_to_fit();
943
944 crest_height.shrink_to_fit();
945 cd.shrink_to_fit();
946 param1.shrink_to_fit();
947 param2.shrink_to_fit();
948 orate.shrink_to_fit();
949
950 flow.shrink_to_fit();
951 depth.shrink_to_fit();
952 volume.shrink_to_fit();
953 froude.shrink_to_fit();
954 flow_class.shrink_to_fit();
955 is_closed.shrink_to_fit();
956 old_flow.shrink_to_fit();
957 old_depth.shrink_to_fit();
958 old_volume.shrink_to_fit();
959 conc.shrink_to_fit();
960 conc_old.shrink_to_fit();
961
962 comments.shrink_to_fit();
963 tags.shrink_to_fit();
964
965 rpt_flag.shrink_to_fit();
966
967 stat_vol_flow.shrink_to_fit();
968 stat_max_flow.shrink_to_fit();
969 stat_max_veloc.shrink_to_fit();
970 stat_max_filling.shrink_to_fit();
971 stat_time_surcharged.shrink_to_fit();
972 stat_flow_class.shrink_to_fit();
973 stat_norm_ltd.shrink_to_fit();
974 stat_inlet_ctrl.shrink_to_fit();
975 stat_max_flow_date.shrink_to_fit();
976 stat_time_full_upstream.shrink_to_fit();
977 stat_time_full_dnstream.shrink_to_fit();
978 stat_time_full_both.shrink_to_fit();
979 stat_time_capacity_limited.shrink_to_fit();
980 stat_pump_cycles.shrink_to_fit();
981 stat_pump_on_time.shrink_to_fit();
982 stat_pump_volume.shrink_to_fit();
983 stat_pump_energy.shrink_to_fit();
984 stat_pump_was_on.shrink_to_fit();
985 stat_total_load.shrink_to_fit();
986 }
987
988 void save_state() noexcept {
989 std::copy(flow.begin(), flow.end(), old_flow.begin());
990 std::copy(depth.begin(), depth.end(), old_depth.begin());
991 std::copy(volume.begin(), volume.end(), old_volume.begin());
992 std::copy(conc.begin(), conc.end(), conc_old.begin());
993 }
994
995 void reset_state() noexcept {
996 std::fill(flow.begin(), flow.end(), 0.0);
997 std::fill(depth.begin(), depth.end(), 0.0);
998 std::fill(volume.begin(), volume.end(), 0.0);
999 std::fill(froude.begin(), froude.end(), 0.0);
1000 std::fill(flow_class.begin(), flow_class.end(), FlowClass::DRY);
1001 std::fill(old_flow.begin(), old_flow.end(), 0.0);
1002 std::fill(old_depth.begin(), old_depth.end(), 0.0);
1003 std::fill(old_volume.begin(), old_volume.end(), 0.0);
1004 std::fill(conc.begin(), conc.end(), 0.0);
1005 std::fill(conc_old.begin(), conc_old.end(), 0.0);
1006 }
1007};
1008
1009} /* namespace openswmm */
1010
1011#endif /* OPENSWMM_ENGINE_LINK_DATA_HPP */
Definition NodeCoupling.cpp:15
LinkType
Link type codes.
Definition LinkData.hpp:42
FlowClass
Link flow state.
Definition LinkData.hpp:87
XsectShape
Conduit cross-section shape code.
Definition LinkData.hpp:54
@ FORCE_MAIN
Circular force main (Hazen-Williams or D-W)
@ STREET_XSECT
Street cross-section.
@ IRREGULAR
User-supplied shape curve.
@ HORIZ_ELLIPSE
Horizontal elliptical pipe.
@ VERT_ELLIPSE
Vertical elliptical pipe.
@ CUSTOM
Shape from CURVE_SHAPE table.
@ RECT_ROUND
Rectangular-round bottom.
@ DUMMY
Dummy (no geometry)
@ RECT_TRIANG
Rectangular-triangular bottom.