From b5f24553a534f2f89b8fa1e7c3a8297f804d65de Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 11 Sep 2023 14:31:18 -0400 Subject: [PATCH 01/32] WIP testing build --- .github/workflows/build-and-test.yml | 41 +++++++++++----------------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2ded6b4..9ac92bc 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -6,6 +6,7 @@ on: branches: [ master, triplet ] pull_request: branches: [ master ] + jobs: build: name: Build, Unit Testing, and Regression Testing @@ -13,6 +14,16 @@ jobs: fail-fast: false matrix: os: [windows-latest, ubuntu-latest, macos-latest] + include: + - os: windows-latest + cmake_generator: /g "Visual Studio 16 2019" /A "x64" + continue-on-error: false + - os: ubuntu-latest + cmake_generator: -G "Unix Makefiles" + continue-on-error: false + - os: macos-latest + cmake_generator: -G "Xcode" + continue-on-error: false runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.continue-on-error }} environment: testing @@ -22,31 +33,11 @@ jobs: # working-directory: ${{ matrix.defaults.run.working-directory }} steps: - - uses: actions/checkout@v3 - - - name: Set reusable strings - # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. - id: strings - shell: bash - run: | - echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + - name: Checkout Repository + uses: actions/checkout@v3 - - name: Configure CMake + - name: Build # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type - run: > - cmake -B ${{ steps.strings.outputs.build-output-dir }} - -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} - -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} - -S ${{ github.workspace }} - - - name: Build - # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). - run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} - - - name: Test - working-directory: ${{ steps.strings.outputs.build-output-dir }} - # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest --build-config ${{ matrix.build_type }} + run: | + cmake -B .\build -DCMAKE_BUILD_TYPE=Release ${{ matrix.cpp_compiler }}. From 40ea08d1b703a6e5b9852bc40511f83651dfdb3d Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 11 Sep 2023 14:32:04 -0400 Subject: [PATCH 02/32] WIP testing build --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 9ac92bc..a5acedd 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -3,7 +3,7 @@ name: Build and Test MSX on: push: - branches: [ master, triplet ] + branches: [ master, triplet_build ] pull_request: branches: [ master ] From 9e92c2a50552d8b8ecf9f2f035837d8bf45fca09 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 11 Sep 2023 14:42:13 -0400 Subject: [PATCH 03/32] WIP upload artifacts' --- .github/workflows/build-and-test.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a5acedd..d4faaca 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -40,4 +40,11 @@ jobs: # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | - cmake -B .\build -DCMAKE_BUILD_TYPE=Release ${{ matrix.cpp_compiler }}. + cmake -B .\build -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_generator }}. + + - name: Upload artifacts + if: ${{ always() }} + uses: actions/upload-artifact@v3 + with: + name: build-test-artifacts + path: build/*.* \ No newline at end of file From 700c44d38f95c975403216626fed51f418823e02 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 13:43:35 -0500 Subject: [PATCH 04/32] Configuring build --- .github/workflows/build-and-test.yml | 15 +- .gitmodules | 4 + Bin/epanet2.dll | Bin 418304 -> 0 bytes Bin/epanetmsx.dll | Bin 318464 -> 0 bytes Bin/runepanetmsx.exe | Bin 125440 -> 0 bytes Bin/runvc.bat | 7 - Bin/vcomp140.dll | Bin 177552 -> 0 bytes CMakeLists.txt | 89 +- EPANET2.2 | 1 + Examples/example.rpt | 177 +-- Include/epanet2.h | 435 ------ Include/epanet2_enums.h | 471 ------ Include/runvc.bat | 7 - Include/x64/epanet2.dll | Bin 418304 -> 0 bytes Include/x64/epanet2.lib | Bin 50330 -> 0 bytes Include/x64/epanetmsx.lib | Bin 7182 -> 0 bytes Include/x86/epanet2.dll | Bin 367752 -> 0 bytes Include/x86/epanet2.lib | Bin 78770 -> 0 bytes Src/dispersion.h | 22 - Src/hash.c | 106 -- Src/hash.h | 24 - Src/mathexpr.c | 936 ------------ Src/mathexpr.h | 34 - Src/mempool.c | 204 --- Src/mempool.h | 19 - Src/msxchem.c | 1285 ---------------- Src/msxcompiler.c | 367 ----- Src/msxdict.h | 36 - Src/msxdispersion.c | 584 -------- Src/msxerr.c | 116 -- Src/msxfile.c | 260 ---- Src/msxfuncs.c | 165 --- Src/msxfuncs.h | 35 - Src/msxinp.c | 1505 ------------------- Src/msxout.c | 398 ----- Src/msxproj.c | 791 ---------- Src/msxqual.c | 2009 -------------------------- Src/msxrpt.c | 400 ----- Src/msxtank.c | 422 ------ Src/msxtoolkit.c | 1132 --------------- Src/msxtypes.h | 547 ------- Src/msxutils.c | 525 ------- Src/msxutils.h | 51 - Src/newton.c | 158 -- Src/newton.h | 29 - Src/rk5.c | 287 ---- Src/rk5.h | 34 - Src/ros2.c | 293 ---- Src/ros2.h | 30 - Src/smatrix.c | 815 ----------- Src/smatrix.h | 21 - readme.md | 8 + run/CMakeLists.txt | 43 - run/msxmain.c | 177 --- 54 files changed, 74 insertions(+), 15000 deletions(-) create mode 100644 .gitmodules delete mode 100644 Bin/epanet2.dll delete mode 100644 Bin/epanetmsx.dll delete mode 100644 Bin/runepanetmsx.exe delete mode 100644 Bin/runvc.bat delete mode 100644 Bin/vcomp140.dll create mode 160000 EPANET2.2 delete mode 100644 Include/epanet2.h delete mode 100644 Include/epanet2_enums.h delete mode 100644 Include/runvc.bat delete mode 100644 Include/x64/epanet2.dll delete mode 100644 Include/x64/epanet2.lib delete mode 100644 Include/x64/epanetmsx.lib delete mode 100644 Include/x86/epanet2.dll delete mode 100644 Include/x86/epanet2.lib delete mode 100644 Src/dispersion.h delete mode 100644 Src/hash.c delete mode 100644 Src/hash.h delete mode 100644 Src/mathexpr.c delete mode 100644 Src/mathexpr.h delete mode 100644 Src/mempool.c delete mode 100644 Src/mempool.h delete mode 100644 Src/msxchem.c delete mode 100644 Src/msxcompiler.c delete mode 100644 Src/msxdict.h delete mode 100644 Src/msxdispersion.c delete mode 100644 Src/msxerr.c delete mode 100644 Src/msxfile.c delete mode 100644 Src/msxfuncs.c delete mode 100644 Src/msxfuncs.h delete mode 100644 Src/msxinp.c delete mode 100644 Src/msxout.c delete mode 100644 Src/msxproj.c delete mode 100644 Src/msxqual.c delete mode 100644 Src/msxrpt.c delete mode 100644 Src/msxtank.c delete mode 100644 Src/msxtoolkit.c delete mode 100644 Src/msxtypes.h delete mode 100644 Src/msxutils.c delete mode 100644 Src/msxutils.h delete mode 100644 Src/newton.c delete mode 100644 Src/newton.h delete mode 100644 Src/rk5.c delete mode 100644 Src/rk5.h delete mode 100644 Src/ros2.c delete mode 100644 Src/ros2.h delete mode 100644 Src/smatrix.c delete mode 100644 Src/smatrix.h delete mode 100644 run/CMakeLists.txt delete mode 100644 run/msxmain.c diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d4faaca..dfe830d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -16,7 +16,7 @@ jobs: os: [windows-latest, ubuntu-latest, macos-latest] include: - os: windows-latest - cmake_generator: /g "Visual Studio 16 2019" /A "x64" + cmake_generator: -G "Visual Studio 17 2022" -A "x64" continue-on-error: false - os: ubuntu-latest cmake_generator: -G "Unix Makefiles" @@ -27,24 +27,25 @@ jobs: runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.continue-on-error }} environment: testing - # defaults: - # run: - # shell: ${{ matrix.defaults.run.shell }} - # working-directory: ${{ matrix.defaults.run.working-directory }} steps: - name: Checkout Repository uses: actions/checkout@v3 + with: + submodules: true - name: Build # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | - cmake -B .\build -DCMAKE_BUILD_TYPE=Release ${{ matrix.cmake_generator }}. + cmake -B .\build ${{ matrix.cmake_generator }} . + cmake --build .\build --config Release --target package - name: Upload artifacts if: ${{ always() }} uses: actions/upload-artifact@v3 with: name: build-test-artifacts - path: build/*.* \ No newline at end of file + path: | + build/*.zip + build/*.tar.gz \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..050f6a5 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,4 @@ +[submodule "EPANET2.2"] + path = EPANET2.2 + url = https://github.com/USEPA/EPANET2.2.git + branch = master diff --git a/Bin/epanet2.dll b/Bin/epanet2.dll deleted file mode 100644 index 544c418729b1f018466c8f25e2c5a46f346040ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 418304 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�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 z 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 H5C8rjA~xqY diff --git a/Bin/epanetmsx.dll b/Bin/epanetmsx.dll deleted file mode 100644 index 86bfd20d94a21e049fc6786c42c439857833e981..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 318464 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%0A`-jP)6 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 diff --git a/Bin/runepanetmsx.exe b/Bin/runepanetmsx.exe deleted file mode 100644 index 1a64ac999b555c9b6add4811fa61a6d9b770c2c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 125440 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 nul -cd %curdir% -CL /O2 /LD /nologo %1% diff --git a/Bin/vcomp140.dll b/Bin/vcomp140.dll deleted file mode 100644 index c2cdea4b91df137659a7fd550fb3433aacf21146..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 177552 zcmeEvd3;nwwtsISorLBFr7yB7?YqQ_xC+@Z>PIMP<+1M zKflk9&xiEAwVXOzRh>F@s;>Wgj~dJdgTaFTs%kK7!7u%D@xNdFC);Q+47lo*0fv_{ z_6*-*^z9iwXUW~m9aYO7xNF%ROC1$=+<*TA0mt|6bSw+r@3{MZhkM3s$I=HD-#ON1 z%goh5J4Wn#aB<1@5%K@NYhN3A2i|?xzA`e0|GqkMDSoXtyfShb|9y4j68zQ_ZX0Iwh8cbWg8Sn?{zdM>pKShE!&B(lWH9u@PbU7;FaLK8iC}J}&y4JHFOi*$K~35%F7~BI2=K~r|@G*_T?6M z*+D7nx4Px~a`Py`;bWhRuNl$|2A{mtDze?4!d6dVL}GhY`{Tbf8l=!$s+)DxMS@pK zVcRp`F&TWUOOpLoui8{OrFhJP!A|$4rG}VQVt#9r$6$2Tb_SM9b%z5JB(=HHT|8!W zuv286c#+Iqg{@L}(DkbQ7J|&WC4kM5*e=yRjwkr7s{K27YDY&wzQ^hdr`7W&cS*84 z*CDZYCH9t5hQSZNs{M;!5SX{xZ>Qqnx)#t0DzZVm17t{H`iW4@0*UR%Yc?kvL~>}V z{m-b+X&WYm(-xv3iD>g=OP~#yR|Pvgn?H=1#g~k#{dd$>cy6ATy#=%-c0d%Kctf@S z6v?4(qwsiyXuhd761Y)fbF+P6e-2pgW=$yX1G62fJ;<@03!;$6ns_R5Rr>;Dv{Rq; z)P5XXrrH|Sij|Q%f4O4tKQu+bnV1~4DQaid)>`G~4 z+A%zUqspqyMo7w&O?+T;t%a@Xen===wKx9<@r*eAI-c5x0KQi4V?wCNt)W{`*v5Ia zwf#%tDaW76vkvdJ4we5Cr0^6$ayG3rds&kdI@X~~SfsTn!nU5uMN)V{u8Y7F z$N|#31;me~fJeOG;K3=#h_mB%N{8@uREi4QcufwCBca($ zXxV~Xs|1R(ZCmu zstov-s!9y}lUN{El0rKQ76G`#cE}QdmuCB97g#7cW}^*<6fVnFx;GMxM)YCjAvC!a zA~rOo1y`61M&*$k3mR++C^U0L4(UGi5-&IS!F*U zN|0opkG&~{7Uw#&rrwj7RcYL6Foaswx`-e}foRd9g}2`ZTwOY9X}j`BIS)#*v9rM# zxVp2!5*)1B!#^j1H5Rr>tVOl2#9J)$l^o!#R8U(WB(%dpaN_?8BS|kv)Znv&in-We zs5@M3+iGwa49 z5ZFB9fP8y>k^MjL9vq0`f&LPk>L|(A^V{v{_RNWLeej^ zq@&E%AMLs~t!@*)+8$^L|Wyp`3jV^{s0Q_LG<>#Y}|}bbwqmJqMi?j|G@67w47%TX!z> zLd;{f0@y+Hs&!}#2(Bh~ZYh-DGEn7XB{^)i16q`=6rx#XGom=~OqbZ4+#)p4rrJOG zDQS=|w@g#Aqd_8IL2ecFx_lA(#>qV8-a6Qrc+YEOEz0i!>Ct#s;lHW&0y~L1t9)$j zDqr|d7(nGK(TDqV`Ep?s2f$s2Z6^ZLC zcrd!r#x@$4oK4l45KkcA<21@U17WLD1cIW~?|9JVvP9OZ zoclsm+1j^Voy}%wl>;zgH9UzQ_O4IxL@>i_ftalrMPq-_*uuw)g3Tfrf3WiaMqLMC zaz(2fatIxFxmk%d6dlPfRZ6T-vI(KpgA5RdE0|rg+F=M-)P|Tz-6!19_&T?^5RxwZtxVSGiatXs8zM8CE_K7gUH#6lËRev#xbrhid;B^75NQ z-HVsKR~YFKUR-Vo=2I_27YYt0u{d0t0=W+58m!hNxg;Ai4=lydP8IzURS8pxkSryk z(R7>gZwt6!NJ`v73&*5)%*~QqhRJyeD5}bl>tw5g**>-=x1612w!xsv!%q3w z;@l-7Q`jMqb%f5ULhY{sO|^geI59T@AqcfUL5jpAN9ZAoQK*G_p`UgJ2G(`1OAqZ* z3)NU4|0rvW4XpckUHYq}%duG35!RfKIkoFEj3JS(2Q6Z8_S*ho$tViXTf;+*C>#k4 zVJ+b@l~T+*%?E|&j|k7dX+CN`8_Q)!>pH75@{c%=3crlRG9DVpAD@cAzO}NW=5sMq z{t;2WS(Jz7>bA*!agKq$GLkLtvI~eUU(XL{AhV^xjE^(K%M{ofFg-X&c5{xr|5$<} zucUC~k2*&%4|lH1k~mM=|DB5DABFu8vr7rid?#SUW%ho4msFEfVo*Fip|Jy$o+7Imi;7*Ru+m@={v?K18SC0a!QEZh#+u#2 z^LxauGj3G9_NUK}TjiQ{MzbB5F870C~NxP%5 zNn+?rWANs}Hs{f`{Wv=PG*r4efkwQBoYMnezDkq_$a!H=6`p^C09$fnBje?I(Tw3t z!z$$9BS$HXab+}oEa~Y7v?}NsAyVa;)2BQO;_@tjbZA@b?lZ+2-tXbQUgA zxB?;3m$8!M679e%Nz_*nm*^3s_$spfaf$jNQD|#$42ks0IC)-8q@xA9R?A5 zNv4DFu-1lNR^1`xe}Qfk8$d4~NL}xfolc^aNVe32Bo_6ObZHRdk6wt^%XUe1ZC);7 zRQGnB@j=W!$k>by=#^nuX}m=LYn5cHmo?xCQ{gQ}$=v9bVHjz8$MYd;nQ2v{gqjqX#?SreUVR0BJqV$ya&h0g{|2LFDMyZ}8S2^s9Rs?8TKHsY~aH zy}Xy$d(XN0R8Rmj3Z2o-PP?(LnmUH0)$L=Y4vCfJiR>1OkIjax+JduSeN?&G9+(_? za2$y2JxtvWr5IB(pVXiPnAZf%bP}ezY~k@}Z7X^xrU=jnj^ghw<*tW~hF7So!ssPm zz|=e%xD&cs4pqT)H6yQSYJriaJsQ6?oxKqLUIqt~;?wZon14b1=aMyB#vD3`<2z;8Vy*f3gYzEeK4eVVvt+GN^=G<$OBfH;9SgFvZ=KvJq8=C=mkkG1NT`q+#-P9k?I zD93aXcjsL^i8_6{AH~6Jhv%3K81VvCs=bAgxz>#VFYtXD?8rn4lu4`#>ODYW^Q|Po zdsk8+sC}s09K@<`I+xsdcA2sVrd(_k?pFLUKFDOWW5_F7_aEnsxkxcGUHK=Z2og2PeO zMOAaOswPyep{i)Pz>B(I{CRBUJk?hx^Cc|oF3X{XG-eg7Rc@0>mE#^G58foU2!c8s zfL(&+$#SHq_UlqgUBydLJK?mF!2~NkF2j_z;HyjvU6yF;(@n{39mE^jg8szYO6P60 zrj+_KFQv8ho;{^4(wIbh+@GLi!_9@|t1&PNf4NKS;S_L-@fNeaQpyMKU5fvt<`v^i zOHxBk8T)`g^gQ^Nr@*&p@Lf9mk7Iqn*L6H)-N^R|&bo_WeLWt*3bwFS49|qCJOFr- zJk^R$8JwfqZFudyfE?va5f-ka3PhdClm1m%zYJU+$ zRQu2IH=)0Eyc%hXE=--*Jm7xFf_nR{PI-%wqXGy_YUrgcT7XXQ-bfY@W zC9!qcp%%46h^Av>BRFE?N{h22cts4@FXx!f09CDlQ%zH?kab5L(G31|@dv#h>x=so zUF?wu`v1fl;Omkgk!+#%aiFi-pXc>UDDjJIT_(RmT8d00W#XsbKqd~=Ue3Y#zHlf% zqneP3qqj_kp$PmR_?wW)sahiID`m0`P6>l#hEZ@Z^pHeysS$qom?jFMVqdmUM@w~* zj1Q8@p*3W_R3Je%*5Fc2HkFV~DHn{dcxtvTn7m}c{5vq=f{`E?#{~p)h@+b#m|J-g z1hcS*l!Vts8-sFSbXei#@7YQWopiB3<~|Li3lF>5A(*G34+MDs*dBMd!iZI&B{n}i6}E}_k*?3g@I)*?cdN0SL|%mQqFP?p`*rZt z#XRhDEJ%;zzXFJ#X4JLf@pCa0!^-tNw78XqOIpYV%9QkvN%S3jRrF^hd$78M{Rs!$ zYq>T2eGeJcv?a<~-11_WVkgNn6iyp85Uy!?g-eqA$<;-Jw)3cRNP4@3yhe*&mqWYe6`k2Q<5Sd#B|VFm1#@5h1&2_n``d==ax zJU`tfn)k@l-S8T)GZJfxtqD(2r3&~W`g^75ag*5D>#A~KUn*Ipu*B#~r=%pMD)3cYcNG2#Xq07|2_|rp)Q4744PC8#DQe~KQ7gZ$R#%b3 zCryH430_hxZ$6wmpLwBKUec_g$=T2?Z+=wIrln$CtB#NjUsErnCiLqBbcUk?{UN>2lUN?p;ot6URtD&X+|Oe^p-4?q)GT4qDd_&S^(u~Pno7U8r; zm+vpdVjL*lUyi1ymwL@uq)ji2>sxybT2E0qGgr9@P@pBs3+wxPx`rc~f0QYtBf)tkAs^jDa!j>6pa1DR8D#s3Y%{3%l^yZfD@k zoM47qUOut?LnIcjo)EkPi|GbfO(Hh5|Jj^;RL7p(Qi4snc7yJ#SQo~5m>}g_j z(XteIfrPVnk)&RIYON7_$rqM~KS>_jRr@O_uF0cRm&e$48{~mDX$n14F4UciOT-6> zED2`#5U#dv*xJX{} z$tA8BV39~xYa%HnkzA^a1a_mCEkP(t5<LfZ_`Tf5pCOVau%0n)NP2&^$iU z7+Q=c=3eiXO_afW>!lZrqHNVYmRz1bw$INFcq`z8J>&~pyd|ME8ze)}GCmTUE#X~c zb2j+oOG`rT4U!rhE;?tqg9Al2*&)gZ5Sd)mWHB0J-w~O6Ln%^X!#wolk_l?=JdT0}jT|=L4XMBqLM%mS(z|YiHDHU|#}2xM>3c=i0B7bZ zXV5CX;)0gM#(B(blPC(#EtKpP#!1n?Ii#!x))I|c3R}eRWOZbVXx>@*%9_U-vtKp-ilKk{{x{(gEjm=|KGzO`1oL;-v=i;{Oilz zFecb+mpkk-x&?Q{?QB?{?%XL%-iN>@w%5&CS=61sv%>=leZd+Jo1IHM1P|a)b>~ND z)anm5aZkHB66;TtH(3UN>=K7;CbHAxWP@TN5@b7c(Q%d2^-T(`iI!>#hi!5^O3WQC zlQf;fx+z-zg3(J#*QdTs3$1A=*Ys@;>6@3$X;>o3mre`a*HCT@4);1|l?4Yv)AGDr z;UrDryv*HDg_PJZKRx-8XP#B+l~LKt@L=9c&s8Z3r;lGGLDDz)L&}mA?#{{o+Y0Ar zCFMRS-1T5BCc20h3g?A5%7f2Hq;cN-X$4&4BwgcBE>9wr^Ib^g;$5Bpex?5X8-h&H zfBqNs59BN%ch72X#k4Z$I-`v>A`M1|4@QTN3=U`O@(iCd>J=up#4tXzdf8qon7@xG zpS?t=TMnm%pG`x+A__ep;XKNZ07Sq>K6-NZdv$e$s0UzY0RtlGqwj0=k;|9+mNfs% zzpy+=^}l=$*H>aO_;}>0uC8mVQ(C zdtv&g;(ucb{9Fw_nW_Ze))#zT=TrPUupx(-VMA6R5XxA1SiTz@EoncpkW~qdIfd?v z{R3IVJmiKIAd3a`fXPTKlH~b_wGgjk?g=dhy}vBzkdx@EoNoqQQ{zX+Rns^ zA@7x^VeH9E3gjgd*z}xed%v3F#!XTYysr*PmRzuz|Vb`a0 z6Nc2%Y$*(9VyN91?4V6n+GkkkQZ7LwK88rxDH6z@;JlL3jiEp{WhQ{tjfxi7FReX;5EDwujHx|p=&w;9NTCLGUD-YR>LKH>S z)#a<$>86g|TGv*6gF9SiL?|)#b&p8l*>3!HVttBD7?>R;VM{-cxv_cjzhM0tqiV*GDY()vDw9u5@nZ#8uF5&9iujy+(jz3%2pQ`0%Pjb>O7d4zHo_K46XW?fgh{VjrJJyJO)rmRI&Hm6rlV+{qKa&{%LNnFs_YY*KkuTI3+xM|+Of*vf`C=qU8K%*zySMU$vD zVM=P2nkRRY2E%x2_L|`qF?r36k~|rmbrz%#eclgGLa@l^Y$9cLr9qip7#$$@CUR1Q zhQle~MM+JW+p6IdD#5hBQ&Z=1@OkYlUwA%-&-PowgFM(jHNb}9xCqaGDydQUA@>85 z77C~qo`1`0-tEb6kmSr;!j>TtR`+oPb(}cANt>l6cLCRC7in`RX)_j~v&*E=!`+%T zgRLg7?6#IeR#>%0uuMWv=u4Zq)Z$K}^JJCm9O@Aj_L9lH^fd8~o%KO##C?RlwD{%K z2n;CM!cHi+B32BJjEX%NY<`JO=_jWOHl1p@k5TG6!!3*|vM@Tx@MuB+0$8)($4>az zG0YhgJ&4~8&w%L%cL*5%9(%tq;**Vj=ljHV=(bmF$-MotZ6HN&p~6X#y|HkQM;k?Plo z8x_6n72k)w=lfgkPqtSk;0^Xl8Rz9LWmp@{Ip4rusrh?v_$QVo!+#rZfWJzI|N6c@ z;Op~gJoddOo=>P{s8%y+v@a&8_ARI#--kH`)#kB&`8=_AX#MUjbekfcWezjNQ4EA-B1sg6K01UeR*jfC@ z=2RPRUP`krYS#9O3y{gi8>P40r;Xaz95at%6Ir_w$sho*qqHy-H(Q24%-PuSX$vk5 z-{MeSdxuEkrdu8`JB!gyegH;TI$mA_d))F$E4?*O%?2vS8;U4q)If|S1Z1NKmDPw) zX{enx9L%@GUB9pf$WSG#C?ESx)|;SQerLVVLk3Uv!RS z5nY%+wmZ-SkG0wX;^0q2TST1#;)L24IP+Z&H><)9#yM<6{DP<44nj2g*M?`fl!x9X z7V=#K+Khg=i-g+`PYbx1`-vD_u;&0aR%gpo^5p6Bv- zN;oKx8uYVlUJpxo(2ob0NZFWIWq)3ir@$CX+rnq7BtCPyn3%2cmc}5c1|r!j3yHgB z_W)Zg?hr+x2U}Rl%KQ=`u&9y8dky&4`)mrWhKg|hfx{R?Ff<)n*aHTR#WH9V;@n|L zV_AWCn9%AxaAsPLT;izC+d_`ljU{7fPm*s&esniM!TAfm8Cg<*&BzL#^p^4fuu%q& z<|q{{O741mNKN!NW_xrzQMG|rgmnM~qxc_8(RR!edCGMZTt3wSLj_n^V`k>E!u1N# zAW~d`5{32S#9}lPBNMTI34RVn%M`?ttJ=-H`4-|U!na+H z&?*G6^bZvy*t{?jv#KtuCMKQ1nmpbeN0_%P(d1!^*Q++GI2RNbg+?!z-*0*OpHg|& zg1H@RGck(v(uBrKYJYmp)6iZSdM!?!RA+B7I1sIWfR3CD`z~A{M3&B34WB81PxK5@ z?S(p08H5ybS>kG@x5aFq!0Axe%F-@J9brZ^X{;p-;{Exb1z1lUCYUzWe)KMlP!r4P z)m?Y9v^JDX0EyRssi*!Ws{NOGeT+6PhwySTkREy);d21J8Fhz+C(@<@M~z6~<+K~| z($hds`NxvW=OmZUN-m$!H<&hC3&2z*$j9dcB=JF^@;n1y0YfgT{k=*IHn&%`Zn*kN(8zS%JjDRveT@nNeV@6tM(Bb z@l=}$gU%4K3u6+(Sk8K`h=}Wt8DKbIX@Zy%n*{%{ zXGf%s>9K*xls4k{6gMgUv6u=`1X~KTsclTIzFf_5C29js*k1K9iid3v-DEN-3!v^A z{J=6PY`^xO1PLnp6bH#|g5gL|{xyT@%t1g)a}+BpRecYgDm}C&x4;;zLdBuHB2=w{ zSLD5bS8VKEaeus`DR={4kJz`I<%C> zF>V|^i;6tZl84pB5TrLFTX`%F4YO7cMTznArF?4Ox8J8GiOE9UzXAQQ zk^$pPsKNqm$9#xCIrOIplX!`vsRXCvV3XlFkH$C95A<-vRkio$7$$76zU;4_^D~H* z_G~`JZ10Vxqv)rTjIr16AVSHm5^DdO%L!bqxW|H!aG~};c>*j9-4cTW`@gGvf)hWw zB{BvESU#s}oo>$lse^1=keF=E`s9_4i?(Rb_>zUDS+uY)5J0J0vF=Tatw8Bb<#jk~ zVgo#zcX-*mA|il)jIowv>LTZdME$jtd?8qkCm*b#!4LnwmR~|W81~yy35K;=0 z@&v=`do%2}y%@FvUW%n-k*I9N6p+NUPV`8(9A{b?^yS+zZQHc3VOk|3bja!arm~R^ z^$8xKKF+pT{V#@XU&}8BcCEx&<+y&eaCY5}!aKR z!?f{h_iYJ=eS`7q?2Z(sU9TiFtqkh+?U;6M%GWS0F@807^%}pv&x4-6ZrJbDALDyA z2xmMijH)`oY_E>QvMLWD5n6ZDxb=(geM4?(!`Ch>ijqcq>pzmYwG#^W?YOnq^EKQ$ zBMb~^!J9Iw<-`bb2raMhj#2J=`xyrncr!sub>z2)9LImNUZq z1_;p9ct$9@1P_-qroi`OB@~BWlz^XENpOpT*T<~<$rKoa-}9R|BYcE5ur_M|(WXW$ zw=TiMC5=qX0pi}gtBI87h!QO%coGpJ)IJS9Od>*rTidu<8<-+h%p58?_g3fn!r~Z7 z-FZe7vJJx61`uZjDBI7V_1N*SNcnq%A4qJbgBXK+Ve_8=OsM-E{>HBNRft1<&PX+G zN}4&wtG4Kc9!?9Ig}j~EHL>{eBf<8h`hfp{Fm~s|mLTqu(7DF>MW8rt1P?piI=uOr z*hk_}5DhE>i}}{r=nIrB%Z#_Emn{P+11Y8o`~l-r`SU(!3g-`5eyRMC;{3T9{3!r` zP7{A16V4#OvdJHD2I0u%UfQvp=^)8c0b%otoI`&g4i&{YgjM#;0&pl^D#0Qvu}DdV z03JOENJ&g0xpRr1N4W-*bBP1ultV%K;*wUDb1AuOnH8XkONoD5V2smZJwGg>4ZWa>nKzUfc##90`OcZuY{N?aE2k=$kS8c`HhX>RSCTE;V2w)V|3d zfk<4}36~XIq=E51wv(?TeYi1VFl!KN*5Ix>;pJArgJbOtUT1X8NiUrLH8(=7=|FMp zIv+cv*Em#-fd00U&F<{H&I6vyTYcs>_lQ<;bF1IEe~l8a#t)9ywrWHsHz%OE@jgSI z-p(1E0do{sv6Y*^h>B$PDq=mq$cSD=98{!D$Fi;ZGB?{%d&-fG&SJnmviMP^kTTLjEuDN625hHbT>Z8wwFl)#8OGy?UrGJbAQNZLJjH zY)<12GK_O3zOx(iA$pTCgt`F$9&_><7y@n??GKk?gTLPB4|`3OT?Z=Ro~m?@#A*C` zfJKPI2UHa!8da{{2OKKvNFORi+0Yno8l#%lbfFcIELxN3uV`|d_54Cvy$faZQD|iE zLc^_%h$>4^itsbwy`2I^Ou}~33r^`tiOq5d+oO;yl8E)ZijHARrCEmyH;#s(@qE3w zmBnYW_-Ih9YsDB{E3S&`1bHKaqhtNJS8@bbi6{vl^XC9D3)gLkBQdWbI3)r-(RCm( z8u9Vlhp^3=+60GdEQV_C8GWj|JfReHP(fD;y6ch0!D>g~Ch-C49!(*}ViTP0Lriq_ zU~kxqscUC3{ApgG;MwcPh>qwzucO!~)cqAeV%Ji^%l(*>C=fwpCO_t+t^-%Jj@;+Z zKM?$c3gdJWoGvsu*0n+KvJw50H*g6ec&LFw3fi&|@Xx%M$;M^(E|8U4Amh9OBU1|u z?!;Ji-v?TyD@c)Ux0`Q2#w4iFMer=pNL-? z;=hYu8dgW(m)k^$Yk^d+jivL4KrSL6afc5AFB-ihS1-xcOL9frKm>6ijXte&L$H{S zAy3SC7Z7NELZICVf$mHQ^eO&G=q%F&TF@iV%OFt9bUP(3QL9&%Xa@-iX+qt{s2dwc zTp0$D7LZ82T%=Zkj^ZKYz|BdGJc>mP*8^dW=yh|>C-tj)~!z-2u4sXUA;(hq8?w|iiYyZSX zMjT+TUwzLBF}GUO&7sie#^6Mym98cXUpIIf8Vz5275z9rTaNp+uB075+(Wucd1eCk zX7@{>CM&X*eHgm>C3r3jvHqc}|3D8o?HbHf+A%!0zlA@z#BpWOuxfH{)NQ9Rn_c%L zUMNNcJ4*}m=t>OxRN$}LGdN96`bOfJsYExT=?({RW25bHR6?BS7DEkSG^fp^rtnX- zH=-7^`3KTQ`PEA)S+#$c_%SE+g*iBb*~TM__V3-Q{VJsEn}^pk+Yn^X<%R=!>TJaS z*xnotFo^cRHY!E74BJNU&X(Zc>Ecm@A7LjH8`#>uBpg0Pv=y=tJ8}A5YgHKgS0UiM z$}v|8Kf8ps|JI*;6evk7ZGS(2Dn!A$8ce0CJp}r;k+T^zVebk7vuT^Mfl#YEJpHe@ z*ACef0xGBd3^;_VvB4e@YJY&L*a^LCAMtA|=Mdjit9=82uq8HjFA<3C&@kmujXzQb zv&|(!!uI!V5TfORQs1xjEL?CWPm~cjr`bEDEJ&6;-XgV zAD{#s#+B24ObrlCH9*)Gb^{XPza2PYbX3{;Hy$-{hid-=oOz+{hlBHQC!s_6@$=Lh zc$|}mSD_1OAK`@q4v`(HbURmME*~t^&x2QE`f%Z8vN;RP2c-P>g18}f1%M$)Q&-7y zyvf5(;7Dt%9~<^J{NmoK%W1P7Tk<8q6H!BD&Sqh9vz)dAxvKr&Py;7QXgePSJbD$S zjnGK`4joh|06l?Wm+veM@XIVV&#VbR8Yi)h_u2G;G&@0MMv> zIiNW3dkI`uwBZkT#zNbV04xR{Lbh!wo~Tw8916A^v=8mM`z@nEq3b58@$o${tCUqR zE-CFwTs&P6%+VlMXKyt)5Oot3W<=$*tygMTQ~{1ia1KBgROfnV*V9NKT5%=L?HYDN zkovPk>QtT@%oI1D1C772C1BYJ)+0JBhyp+qJ6Cq#j<$IIeR@7^{$9%wp@ zkHC16ilz4yJ4(=4m^z;woEeNedVmek7L~W>CI6p9s_lKKM zg&&=tI86$#JQu^x`ZsgjF6xOiFS|8w-y^oL!mydPE zE~P>@=*aubU06o*QVQ13V*~k>V(6wZLR}5udc)IkiUwDUDi}Ap?3Y#+=LMJ0E*^rk z$|0QkJw`*NJQmkTsrK0=80S!sl=ZvF`vdZL#*N4T8foEb6D~Lm+neDYU6v&YY9>Ol~P5VZoxWq_>OcTPqOPA6JS zZ!#NSFydmYuzfmmcnHv+kV(k6HWkJ`;M5^mxeI8Ma%WefKV%gnED`ICP3BlsJ7HO% z#js!wSkzcaVJlFOBJG|+3B6XL^9yt~g}Sh7D=pbnyN@>%$k>ehh+@vA;I|?;+4y|y z7V0zL>4I$zexJQIm?r+WF_!5W-$t+bK`XgMu+xm|E9#@K(rjOu-v|+Btek{vZ-n}N z`TN(Oee%gChpa@^(C29@ub~QIiyZDhnW|y1+qEp6U=^>}>#1!E4Cp$Dvnu^HO|v%E zwXXW7C}+W25&L9I2EfOif3O|suy^|(5XG(A5t@AxdI-@K>|pg6EizIZ3V%)zW4Jdj zmWjAP7jYNI1hwc$2cjcAlmv!-MLc9Y{+L%o{IQ9ugwrl1QOUjHkKcs@GGPWq@P_zf zVhnnl^4za9ONgdyYBMDOatm%KNTH9;i|cBm#XrZ}-vFp+|FPYDv_CJUeV5jLk>38O zuWCPGfAK@Pyk%zlfmILfrTJX7KR`|E(IgZHNr9^DZY`MPSNxrVNwnDWYAvYm>1T;( z9tU*;uzr6RVNHS2AH2z*!XA}2fAr93+&7(vqcJ(nQ-=bap=qjv;{E`jBpZ7F)uGZq z8{OwF5TZ(8(@}V|a^GRXg}DFqV;GICpg&!w|5A(?p#P=>{YDyWlITB`O21II9tm5C z_sUbh>*2wTp#0#@I1jdS9ZLUN9>`M*E}9LGjp~aHp_{;VJxV-0KPSj7XTl3tIrDps z%+yoj0mZmFSPv+Ef}fP*6277s zbZG!|9$C4dkl)KVE?5$t{#|9wZ;3xV7%v!Ilb%GU!cCQ zjSy(ZEo#c+0DxVWbhq$)qnl&VMwhE4WAPwCNoilJ{~XnyLpy=n(x2@5f>(Z`cjXB> z3aRy9ruOfq`h%$c%jvkj_6!Fwr#FBzH*y}N)aU#gP1WB)jMwJ$5jy?7>(*;^Np9!Y zKQRdPpWyY!YxNHxC57^pUseD2RDUk7pQ+XVY47?sd{zB>sJ@-o-@L2s7^i+-ZwQ|i z>l$!A{-de>JBZfWoR0e4y#CIb9&c5Q*^%kh3(Y-D60Q90x|8dkub?C3w{@X}Q;lT2~+Sll(`g5p$J=b3iz+=4ujOPGS z+voM~ruu`l`jsQ&^!KiQ21aae{nhw4it4|OfGXmDpNyYe~wmv^RCMM$211~q&I|d1fehbss5lu{cf%PtlsrcUEg-%UZy z1T&JX$K>$@o)mVL;90v41L6=4F-#DP2x5AEBiG8+9OBg%f|%e>4}NyRmcekkJA$#f z8ArTd#99291LzhI@WY4>V`k)Ve1~!9&DUKFzBmkbknp_%@ZBr}Cybx$!VOArsz$X| zPViQC3TP$BTR}c=r5;JD{f@p`=>z|v8hknp9qsB$ZlFCj9Aw;04GiK9VEFIiEzIRD zsBp>k;(H(P(>jK0;&Tw7U5NW)=8+mZ25>N2&Ii*oh4%?>oCa?%TocM_4zEyyw~c#0 zmV8rq85+DAf|t+XWohv4=kRjA8N9)y4`%ijadQ7L5|uglDd*%>)WA-Ja#8mFW1N#& zyotXQp2taz1%1$;0>3*M{&sjalzZavyE*(nAWgN;{hz{DlHo5R_?dC|3Wq<9!~bmj z*W!M2{W;-LetHEeO_71UPlMb>Yg22p+X&lvpmB>4MWic?O@%BCb#ot({{? zR_&YnY$x7fzM?%k6^^_9y3TKJBegePYY#rhE_{55xYB@D&aI91j27*xvYa|4e}}3jRSM z57!#-8SH94BElu*LRcXGTh@elJUqc!?!q@}vVzC>0C^662<16kAdHyFLX;?k7M?&F zzQ>4`dLmqtyf_!x-h%VnBkBB*+AHSmWt-0kycB8v3f`upk2Wu|z4_<2M^ovQ)Lv@` z(KkO%UnXzsrE9+xeGAWTkLdd^_%)RIygj0imm>Q94e6@g)km9s(3c(@r7Ji|5Z-hql@YL95#2}isV zJq~rUNz1qC!_U8B19?9@~)Lt5IZ+@JFYN~{zd@h_23=D{0OYu0odvx74{o=BD+Rjs+9Zb(N9N~FJx*K5; z9WjIje*st4PF^#`l{J+o!Bs>aXB}zXD@)@o@Wq}6?t)HcR03sehl=6*O=76i7{HCP zGYVq37Gg$`Vt-9lL+h-Dpf8T7imjsyAsS(CY@}~>8G|nqeYxjj`JeFU#h&a%--wO( zTAYe@>c0a8bhm5VNw<_IVPk?Qqpb-pjztUgdm%!Id}0TMAJA?ro0(l0LFCfo5n0T} zp7IpBYomBzwOyWRDVm9k(KpS6NWHkrJ&)sdTS3Tas1E9P4{*$v5a#zJV-cH%Dg`*L zUwuW*L%0@R#AX9Ru?94WI7!KY9p=SvDP0wLTa+v~ zgt3c!p9$-6d;oC?UT_^WwDvT7$9}5L zac&;p=Qbm#PoggXA`Ac(aPJ6Q@3Rmb0TuY{n&b_Rqj-}-l{nVQ7Ft#Nft1V!Ez=63 zw)2cP^lj_sc*ZrTL|<&gRyq`P6(sAzw{`f4!EK%7eX|FFGj8$i3>1Kj%Q+d^XJ~$V z328pR#$yq%yEO#?k=kL4fY{9`>7#i1RnX_8WNkRZAi!fN=-OTra&aSE)82#&@2B7aCUSk*g6R05vJe zq^nl`{s|&3u-%W1-sx7M9(Pppnv*wMGK<{1h6kcv&iB7?oNZScNQ51H%zjIGb|8d7 z*G&7uHXr;@#J2*dmK$k##OyZ-afkXIv?b7=x8g-B=PXcAewSG9JH#;d@o|stzt`@I zE(OD%`#bnZks{b4WNE8EA@x;pi8SjLqo0`Yxh*mDkr7JjIV*NX9oQl57N&M1!h8Jd z1_w6kzg#hjeHosCedTCB-1lcu!at;rM(+OLXcDT~E#Cy*b)yThPeZCPi0`H%Rg~$o zBZJUf`}@e+3RniY2-mt<-0~{y7`gf*)u7x=&_Lhi;RkR-OcCx|$LA<$zuCQMmDMM& z%8sRZS+k1!4@>gs3xPAY=1?`OUM*YB12{`hVcfgf%uAqrf%3Po2K-VvuQyaGh%!a7 zT<4^_J~kRw;M>;pm2m3P^udo%F1RL_xMCKcyxIk_R^TS4X=UMCA*T7=KDiiy9ohWu zyHA0ZQ2Qyc@)b{-c+O~`-~|d6A>X2}7#GI|uF#?)FnWxkmUpPqD3H@LYv;ZGCG6=Q*fjZ5im9zp=OdcYLWg{~p2)nJT zE%Y}N%|n>dlINgXIoZ3Ef53@F8^g-xN9f^vo(a8A|bqk&gSUK99v4Q9`vph`$LI-^SB! z=V@^kPsLlW0gWs%orfv$BdnNzFYh4rJApg_Ez0mss@hJcwqAx+t^Q5V+xn_*{F^w%hb6-r|NirAF69Y^-=3DTZVje+SnyM-Zc zr(%a2n+7C0uXmHSQz@5}InS*?Jpb|~{6p+}yrD>%H+szCGdC(9!Zl2z&eiy=7j8KW zHDx=ymL1TM=!pl38(pMZ&DcBziWi}kQ3oz{J4csVt=27C{?QrTNSd11obA4f#GG{TZ2MMzo$6c9@|KLS#yyaVQdw=`6);5Y3vIDhaF zBSa>iC;R;)E!zY+_985#_-69P}0M}6`xVEE* zYc4XvAr9?MhXO1gz8T{-0sKWVZu^zzF>WFy^)T*T?(@Qc@DTNdOfXLSUi4f(Er$P? z`!vaa{mF9NiibIIBPJ*R$Wh#>oicFM4?CdRAEIYD?ek8I#Tlx78P9?l za#*OXL^aIafHwv;N!^Dc7ur6Qx{=GuE%w5;tp=3i)_QF-&BM(08vvuIPZ$w_+%a*a z1dh~mLv^H{*N_?#N2-Q02r1m|_;-4i({9(1dY@;(yvOm}Ra6a8U(xiQ1w$U$0b@Mj zCAf=r4_zT7)ZPR{V9ntG;bGN2?+Th4;?uw;ylLS&!OSfKAj|e)9P77~`vH>porhpj z4zdT_rzB>ILoL2OfUyszg+3~?{bXpYQq0sIY!b}=n5h~wQL-@jZp=bys{NhI34wTk z>UO+=lDcQ1=CJU73D}6A0*T@l6=3)%f;hiQ5#JjKmu6Nv-wgDt44t(FO{}3(u7j}) zVZKg3D1sA$Pmp291J@{2HYctzV_ow6FUu7|E%JZ^eK?%0U*}XjJ9BiT4++Hx(dX zc@#}kZ+r>@)VkZU-^9BcFEG1AE3ld?#@rXs4JjSpwFkqX7G7s_@N(5&HH6=)RUg46 z8|gI|CZWMD|*p><8m~NqhCzDP%9u3zVV&zW#-wM57xp0Y;gmXOBZRKHEm# zCC(P=j+4L&>M}&xK;%=fG6q#RCVUugU_W8)7c( zCaMDMWF3{oql7vWGKKm#-C=*GJM6*5mveISlsp%$CUH?ZJgMH$o2s~78}i@8hm(|i zWRjA#K)L=9lx7c36wRy%aMF-jy{+wHY~VJM@e;oMONRVXA#RsKSyuY{6~n zO~Ma$fF~rOf2<=d#OP?-iV6tRC$9@T0Oc=G?dO0zsbUC)h59U<sGDdnA|h0^GbE!!3oE6Sojvj*#+u zamDfn+~cB!hG(_A(63bcr74iU#PW*znk)7qze8>P$r_RiOMCq79)4FLg|3hWb>bGX zY)D3~!d84g5^Ul~^PBfzjT8?RgI%x)+|%)qY@$YTMsbQKq?js0MGJx_E9D%G>Ts=w zdf0yNe*y+<5Qj#6fSa_WRhXUe)eDV8!q+C8$@dERx!1(na;NFdzwdwgsLc2Q5M{syaKzKa7 zJtF)fru-wpQ-I|}(aPfD0B-sh(Y1J_YTP4*1staX7-Wb%*qWlQal*e+)Pt_4!-9GB z$sy=32)!2b_anTzab+=&yk0jRX%T9vGJ4EZ={83yJ!ZtE)Mwziq0*Cx!)}Cw3Qb4j z@&0tE8<_nC9u8VU_WD;@DO^0}ev8q&ubq|z-u&aLx ziG9eALjadV``(aZS&0jHF$(&b(GMS-dUXV)6D{Lrd43TkR&Y}OF|12qzU*+Io~Z;a zM<=7{9VD~wc+V)Y+W((ZL z216p9+4kXZ4$!nX;)$>wY%j$VQE>}~FXapZTtOs16M=h4w^{*3foVW|%4^)MAG65Q z$$SE$0GU=GTEJR3oo#4dd5|iQasvCUz@F&L)9LimJ4<_pe&n=EQM@_r?7=u~XYi!a z_ND$5N0(^(3~7vR6_p2JFtPO`j71IOJU;F@DCXD&IjZ)35T3+d?Iu)cu!b#!5ks{{ zDIG}TV}y%yaWN&v0|Cw5Yx0u#ebLjIGI9)kYZ?8Df-V$oBJkcKJN*tw1ZEpmssm&qPwB|+L;=-ie z{_}lX$=`3qcOm@jEL>Z-!W5r9P;#LOes&kes2jX&QIS9YpPe2{rN~xF+HDRr=Ypef ztUC*Z&}MKSr=rX%bAMs+IXi?6G`-`+N-rVuI)>JKfvb^f=>x=g>~9QQhV1@CLxISH zWRW{a@X-n~k|!YB%ci<~>O3mg;M)Rj>NP+6&mKImDr^MfL@Q%YE%1l z7y_{VdIONX_|%@8WqI@eB|1+Dp+6zX!=iL~Sc_zCWA6PLiR6F93z4{dotxc`yW2l- z1n3)cxSE5$0*8xnTA6#71y`~z8-@oQzU^K<2vxF+-Mg}bnRx1tr~UyezKr5=?p?MU zxA=IR`+_%78Nld|3c*|tj#Q0_4GT{(zKDzN#Aq zvK!`s49*Mwp@@t5N<`B5%sZ+)CpX6p{$zWbqmH!4hQzGem{s|xKDqVGXY`IvxpV;f zM%ezz0~iFH4S|t&O3ZR~0hf^cQ~GgA*~|LjuXRQGRxHynv}usYBEDbM!`zUVi{8L<#aFoESTtR!PDW%biNCx zo#5u|+$~j@By%+Mu*I-uu&?44i&QZSb9es?Uxg*pZ;pD+5#8^upIaa=;rg3rm6RL{ zT(bUV{|x+QuD_W`3yg?e%Fj85Ruvekt;&tSUB!L5WWu29qsc{$%GJa#d6h$Aw^8?!xzvW0Dm=9=22>>vPGV?LEdAh5UD%ZStQ@A1JW zjZ+SM<0U+)a6Wkzj(eGcp~}l@Riy@ZFJtxR#p}fZFW}kJbxPN9e86G?!0(TQlt!zJd1c=yJUI+sjG*NR^hn{NwV(o@z_=^i@dv5*7y|g@GX}30` zI6r$I0d)9_3y|(9{JVC=HqOlYu`U_YBcVnxtqHCaeD#>V zSBDv^luVNXs*L%!?gijS;S{W{h)_qNB~&p$fL6KXJ8RsV?%af??%a(3KgG*amBPBZ zr%{VGrc259UGA2D15b-V**6FfD&TPK4EXTHWFvMZ>r{ML0DTA$5_5`k|$3Xdg{07?ALui+GjrvjpEh5j_E024T+B!rjUe z^5U=GK}_dLvw(YW2-uI}AcC*IO5K^5Redh@m!9#Zr+;!&eG7`vzjd%Aa3$i3fg;If zd<36C8`Gb<*#fL6!xJu%inm(P7?yqO&l&KrB13Y%NDnJ5IN*B&tRLl%5Sl);;PV7w zDy}S`H2FX1*@ZQs{1>WH*s8dZ?%Ld}k0GgBTfN7T6g+Rf5T1+hQCOfF{m66?s2ck~ z^+k*ceWCg!(l3PSZVx^k7iu>J#^bLsFbd~=GXf*UP`52GEOgu=Zuu1J6C7l&44tT` z6zle)tHRg$c%<)X$+1P$99?n^=W6 zcUY>yv#SysC%)35<+!Wp?bXT*UQYT5Zz$vI(0)rRVUpl|PL=jsR*EZ#@xI`D+Hd(@ z?RW7Z?RSX-P737TH(L9xa%J=Pz%APEs$*EpA%D#Y`mN2a0X^B6$?;f=$IF4c*wus( zNcj9WU}~*&9uzh-VR!;lZd?vtH0DR!U!-^EAtCfQJ&5>x%7$OzY3n_p2o;uRp_rH- zX_vL^L&Any%KkhhyP^FaE&H&r;ZDk~0tXVc8{4O8*=Ttw9T*xiUYB-GGdhSGLbb zdZqIzF3#oYB(R2<8Iw$?TMgz4^}E92_VCPKhPsEW$P9fxWJMaXaMRA`L&D-QVQMrK zp>K+$^F6%S!-#AUw;rXwT|W@}>?VAKHaz)R^zdjvLSK|*fv;q7p&ktUj!GE6qbiFB z26B}#*F&YWo_pSwijJ7dE^^vM0@i%Iy;K_q6|l5=7@wA+%0=f`a@APg^wIJfIhBX%A}I(9J5! z)^szTy|aCumJQvUN!gli#|-$02Uag9U+WAPT2u=#b6ddRN)mUcL#wIPCQC{`fQ zGEGC59l_KGr9`zZ&_lwUuxuyNppZ!WKu?>v>}8rFdD>fgntRzZNP{Ax+^c$;Z`lu# z20cOA@ANb%;R;e(m;*fhM|wJxaG{nCB|NZfHMI>TyhTfc5*}D~7o|Z7uh-I`ga?+* zrZgzw2rUgtcwpJhlm;anKxvQX)}RHhgbiE?hZ7Ta#_T<6h^-w+=Pl@AtBQ-0NDudi zCvS%mhA00LdI)7qLl*Q9DYrlmcZS+;@Ue8!`R4M8q#*1K+#A^x9%L2SZYREmzC-v) zRCKnp6T-hovRX)eqQ^~|`h;5Hc}mYZ)qV&LW%}YGEre0xoR9r6cQ2liTL}}}URj(I z$W}HK_GoHoJZ8YoCTkF1tD1_yvzy68H2Y-47PtQZ6|vn+9 zngWGDXGI}v66phEp<^cT|FHKi;89iQ;`dBu0s|rJfJCE+j1V*$&}gs?1|^%!$R3#} zR;}Qzv}nBbLSaU*q68<=Otz!6UTRz0(yFcYSnFvm0$#`@kc9h91jI|gsypmj5i2BE zneX?mJ(CM!PkX-eJm3HM&fiBed#}AN?^^3!?|RpJTdl#dqsS>)qGMtkU^=go6P(x? zYiu^=YWqCB+?uyRmEL>kEt})WRX$oIPC|Ds{PqyD_kM?wd%UonieZZu^V7{si-}c_ zZOBnJ;w2RgVlZQd#;<@eVI!L3jdf*f4>s@;Ihlj*_hnz7FMqx*f4&v#B8XxQUqc8^ z5FTO4th!qhI7fX}&>tjk=CGjCX0OV}T&q)FLw(cF!$HTHdEQJXaPN z=Il=U8(&OkfM@X~D4#2i@wvaDt>n`f?M42MJa&dx`Q+7>&h9jms=WwvaPW=+#-X=k zYbxSXi{x_Ly9Ts!JDb3Lf-&pzlGq-+uPS|f#71zMHByuuu;$*_tfF^XD#PwT!)lI8 z*yT&$hS#mHvKQL@dAOMQK;@RS`acaj9lO(TEfYE?2d$|U)f3zi&4^W2FbBNF-Kk2$ zxzoKu45f@?SlghyoX(K{pF00%{co9nIk^0j`CrMjtNGu`3iw|%|6~8R%)j{6{ge4$ z$Z=QAe*+}se{TN87?LRAA+tt~qU>MM{>w!7U=PNB(J&WHlhmY@MU>)HC^4+Uh+hUJ zkz1ex=8O`=$VhV+W=l}-Vs+bfvcnVCONj5(PFM%Mf``TuPTJ6ZU1*Yy5PP$|itzZM z#N;ev%i;KC26m1V3YAX3TRPo z^aYwB)VqhUDS*EWL+3y}h45HSdO}ah;AwhtALkw92;tqMM@kx zwAc8unHH7#zcJH~9&4u8A2ruU0sk-0wLsr@u0#KWb8VPt@)vi)5bzXe@HM!J1URf= zb3>DU{uXYUPbC}N4V#I=_ctE-RAvtt8+`g5xCi+{`p1}@5-_^KJ+UNmNIxGdvCG6f zVoSKVNpJAx8L6iFEV6w9?^xl;Px1J|RVNw}@l;tV|G5Kjy9@JN$PG)PgG#ryOvyvO zb(K#%1<=`X@s)CX_F5Hs%Pn_PgN7mD9j z5Q@)L+D%H{;u9Z6Q_q7h3?-)e(5xN_#i#BMB`&uN^SZG*+9h==<iWpYV%>^=n8P@$1G4P)5d~u0)icN6X>T zelx(N`!Lom{Se04nDER@2tqWk7jN6~5L>q~;g-B;Nm|aEW_m?cN?ELz7&N7A#cIO3 z4&{l+de5O$YSGQq7F#ZVv$WdbBP=ZLvKIk$ibCt*%m1pC@6*v>kz4^S^ZBth3#p=v>T==(=M}VOwjX?JmO+eQFaT5kBwNkw#MD|Dco_L60D6mIepdK9hrWK zxw4*T5o)ypfz0VKCbRCV3`;|0A&b{Lv48aJR7|19OAcz(9pDhF4D^mxqNMMFqE=ro zoRn9Eb7s@&<>!?>V z*Lg`)SKmZD!Z#*N?>^)8X%S3!G#u$OUWBI7XS~=Q<6Tj~$&gmNO6Don8P;n5(|NkW zxk#L}nBn#P`tUo6})Y=7qNEhER7Nk^#@t!MnUn(UNRtdM7p5o*^~JC73b^t?ym@dov)`> z$E@k(@XtHJSmDmQ$1g1!+7nH4`%?)*B^PHrW+F|S@?;hfo@2AzBRY@$bsAczEzhR4 zP|!P>(v|b2CUaL}UV9*MQ=B$#m^VkOm0OT_*0tJp=czI>f%kxR?{4RPigs^{^K^M6 zT3y}}DdF?g5kG&wsn!06^J$h=_bg9nN|!PbYTa3)r|D2)h=$j!g+$xvh&h>Wx?QI9 zmdK6#{cc2h`#tW7iFMAFrP(<*qVYExnOcpm=<3p~cC$5#(X~UZdPyD?FbpzU_A}zI z#1TAOuU!@CudV3l&-og<3N;yujM_fY`bf^vLt~+$Jm5M)I0PFzS%512kX@}mX!vm! zGMKX4%Cx$_@WgSyv=OR|x7YS+e#`V%{4}JF`O-$IJoS^O96b@tl`P}!;drL{*K|5Mdp?K`x9|!+Hnys3*{{0qU_*Unz%s z`HprZ$n{BH*8NDTT5!d9jQv_75=*sH=Vq-Jk5rTR6|pQe?;KlvxcE-vU~*7&X29G~ zm%4j~In^I_s0`N)`9c#a@}fiavYQJc-c(YF+2T|E_Gt;-9k29Pxo7sKPl5Ouy$BQ) zNhot)(6c^JzG=bl6a`UxOOp^1to{BZge`1t44E6n0%*LI!&E7`Nz(GjP)tvDWHCfh zP9Cd)Eo2T3nTXIPLo+AmAtWoiwHH`}?UMzneqr~wFnvK7Mhw|F9&G&#sHHhL4a=%P zdFz7Z%v)Hids`-`63$Y4KsJf6d7Do!`wlm4V>x5>XYKPbY~EP`$wPWJKO_cs!j@1k ze?#VuusPKio>k$q4m0@VGG<}RqdibVWx&ex!P;a`<@ znQO6NC!Cr)Bn{K!n0Oi3C#74&*?={jZaaka&K4_-xf96UhQ_W!dK4C>oHT&h!Kf99 z3e+#yKGQl6`lRqK8$sd%kx)i&$N$h*v#`h&WkNSuyP=CBM+|diHwR9z_=kB^s@F`+ zyD>5(giTT^De03BdMmt9F2h^e$fx;HZ=iu=vbjhdLlT!|$@zhG+u*Lx;{4E%r8l$% z)MKEb5t8;dp@(d7Qy_C#0%Ty4AkMv^sY*j*B(5s3hN(bJQ!6;9jEm;NlvMzWU{Hg5 zY-r+`c_WM!r_z1-r#8ym*sP*M%jWW09j`oJ?1O-$X5tVRw&@_)Y!Q+!D4ZX^+z@_W z>>Kez?%7W>F-%%?;qi7M%@CB=3wmL~+%s6OvStB1aJIA=Wt*GQ&9ogQn4jV> zifN{8B|2bs%loOzywp(=pdeT{HgX|yg0Bk0f0Fze?C}3x?#OASyX{dgF#;}o_)7w- zJxs*+nq(L#;`?lyfG%$sG20zEOZ^?m-z+S!P#o9YfJon%HN{VG4m;nR;^&8u98>(& zJY+Xq>aQQ%GNp`=>e6v~AK}OrTg7QDeO5abtunt~5<7ywM}|Jl?^NmZ|X_Y(`EMo0S|RalyL3GH`hI8?#<#c?kKkN=~99BhndiSEvkA*;yL7T>_>fpMK)- z?7#&=bd$29;WB6V%mYkH&7IETTW4KQQ5GI`ZLK?a_c?kEH`5if#5gR7F2lz*>TXoTB)$Io0t{W&88Ae$z7WM=>lQX^ zgjEa2vv{gkPgDG1FvJQD7vR8%#8rO5>|gP2-YX_KPiL_l+p^;7rDaMH;)tWn;nvF$ zR7E%Wl7lo&bcJTg3@C3Z=O`5&QbVBkNVe`i$G%vP4M^Dmqgc=5-T?C9#S_*h@1L4D z`75|WTHBtKjk>?#F5qw2J)4cVf6aVKd);5PbHn8au|CpLwkP1mK1bn8w`v5rgKTxm zwz+3~WUnbmTk+2}%wUP!iV|%ET`TINoB3z)Z$JOo{4j0eQczo)aNfgzbRz)J^0Ieh z?9dXl+@EL*gF8izRwgEUrB&oTi`vT60nA7Q8=YPJgUe3a^GI}jYw)k5 z7=F7y4`SUSd0T?}k*g>>F^NH;*nM?!8w1iIhN!vA$^vW6U}J2FOw8vMWzqc+&Ajff zI1Myflm5m=HQi5QrzHMeC7!7gx&4(WEoN))J1JlRy6>Z4>-`eDoKZp88g1#vL5!~B zPdX7D#5U(I*ydae;Asv2R3H@FoYcQ)ngC$RIBc3E~M!k#u zZ?WTP{l9iR;D?wh{9ikse`3c26W?ve(;6^4d)e{aFtmG>-#CPosm$5_Jv$z5CJjoh zX*-@n`pa?z)?e+h<9YK7c0B7dc06zYUpt=v^Xzyw{x|G+HubXOX;pSS8^n%h^}lS# z^MbP7aqM`~TTvf7o)ua*roMzJBvv)uc08xcE{+`!*SG#Vc0AlSqU?As`v1a?$MJVv zP?*=vro?V+bj2E*oiJrRyaZ>8 zZoBKW9>q_nG2QG?j$7PAL@4ri0%Z#dXGRdGPZ@V;7q>G9A#B9}O1illIg4L)^%4FTbKZ4)6e@aI)O53rPE1kav2pJb z-Zv*&mrDb}v(doissTBeT+=Mf-(GDg2XXp?TG`DF_wxo>g&BBk0{Q7j6ll2gE~_V_ zcwkA{j%I`m@bMy-FKxuMdSJ9)-I_a49dO$8TX)D&NudIcOyj#FLwT9$;K7#G44EV@t3r~0H1l5|Y32+73Nh8(cG)IF3@(dvFc2UJ~J z^+oY3W*iA7rcLXRpdHe>l_em{jCB~&QNjC6AK}NtCeZfn;}-gr>Ejk8?qBGmbdS3Y zojyi#fFa#G-1xc(i7`an)stB&aNB;FRc^MNFedGX&qtdJZ)Op z(iheFvq=I69Df*G@o6bn=F}(PpIjY3(b`2{GyUF$k|1*-CpH$qT&Z9NyVc$0z{FGl zv?cvR(tV=!Qz@=a9V-Rb9Qu+uN4My5=@$MnM31FWPCQw5UhINjJq59e=5pk*9(B7o z?)0-Sv66l{HDeCKiMU?QlSX_nPja3#;zY6{@In)FDprn(tMaT-tN@ZN5$ zfjZxFj>bXai>F!xIai*F(c$>uEc&ZIOQw5BSdP{oV;Z8>e#lA4JYPcXyvviGT1!MS z!MVLa6EMH!<@^%+hdX+jIm0V~ECS4!H+~k>5HeMtdEk1yCIwPLw~Q^8vnYNyW3XB&+52UnqJ8SV&nOF*!(nDzJvH!=K9HI;88D2 zHTk|j=-CmDs!6MUW?csj`!-JOO-K^H$ufyA|uUh7OMMHn22-|jV%9e&2B zZcY3WpEQ}0Mn7dN^ztU{zI{9d&8E<-t%2gkAa)`6=ag?-5E9S{i6PFdxXQjAF5Vd~ zej63=4^6i|!J88uqH~WlH)zK?@BrO*SBHH9#->>9BOeXTN}Az&z50akqu#k5J=Lg= z_={+W;eE+Zg+ckAm~uonzfC^vm1O)`73~4F$x9>o9w^?)dEDHs7w-|>WI;r@>h4aa#dY1?u z37FU3>s4+f;M!OWnI*Ue3jnzps)L}oB5@)QZL=WN+uFl9-1_jY9{b!gr-1K%D*W65 zGLW;=&X#yMD5o%BG7fzb5TmL#q5$1~f}zCFf*#0p36#Ty-pyf8V^w+UyfbNXrohw0 z_2~plXd}9&Ka{hMm>Rba4lzH)O<_+nId6X#+T%ne37gvk=35-LFA+;%6}TqW?A1oP zB+Se;au0hl?ActI@RouVfRNnh7a&9C)=;WRFX!Te%B@VZo@$N<9`FX(I+crKnOUob zCRE-ucXGhoP6K7(bOT{?b%-{o^ISwyGI&N}*uA>xsiHx;680nm@yXs$(((t&cg)!V zxW5rBGvJ;Bv`h-OTI3>~ru!$cmhq4l+=(MdY)@QV`Yk zhBF-h@D<2WD)fYrWlaFPmDi&6TUv8?1L{R8hud(0)IBt`Vz%+d*B`y`<2vrspf=lO zEd<3DuV3FWi4{m0bOw3UjuUucUdK!HmNeN-3Q8NB30xu@*KyV5S<%5z3U0?b!_mz+dLi>13A)10dN5kfJ+vF)fl!=Pl--H1IAT;^OJ$y0tb*=DIIf}; zl~}vD15j3ygfNSH@Q2?lJ&@&Tf^;J4R$R#!_9Hexxl-igva9o=#L+mDwpbhSZ}`Oe zi1=evBQ0Hxz|xD^d|!#AtbYgYD<$rC;@QGHiLATmult!jl;)2oGOnBL42o`cngN{I_E(l@S;zdtuK2_Ca?dGos=qk_&1Z?I`}A+u$9afVVwa(O?;&w&EbTR%0Fk5 z$Wi}{D=B%dAmo#|5m{a;|5Vat*5D*==pCP-Ld?uWOIgKuh!#iDB2}p%(Tf@3FUU3foXdaDzQ-LUkz1&M6)xn^*VpB7Ax?gWOop1 zKHu@owN8^TLrldK!>kdj5P2>Sn6lm#OT*N&w9dS0yfN}+Zj=`FnnZG#q^99$BOHQe zNZ5<{s5~zrRGf95ayc1szDY>Io+@!#X%3g}inUK_XbWvyC;Tb;z-IeLvb!LECa|$E z`h|3bC92K=j#dWV0Q6B(U{o7@Vwm8)hZlIq`ZO6~u6oGG2}D$ZjJT}>xGbmgCz1)S zY=tBceO3}Pn*I-U!jm_-ONiQn3?wAE{v`j8@$1fglJweuZ<=7V7BV>IGfmU?UgN}*e z7R6_FF?P=^;aDTuSAqkm@9)y7%=iA8?|$by{P0&UCl|_uq!@tYe*Kpc$Hu=_;WNR= z`tbzoc{**IJ1uUkPsNcEOY06#t<-#7?en1bYt)8}Zf&QXZ>{jFAsi#>oeQ1k6RG|X zj$|qfV=CWE&4MMb*}2vg)Z6NUy_Mix>AsoSSr19(t$-Hm%+~H_a9#SrM*L(UPnU6? z;<8JvmLOQH$La|KwOW{IkhUocN95?=l)Y7K&&Xvo?lOwu0yZ0mc2y1E9Ui?iw8gF} z-&Unfexr2F)P#3Bhswxcs=%l+UHm|(cr&)aq4I57U65+45`)n7WBtdFwznIeCb9Ak zm#>YCSpD%wYgQ$r(E+PJ-;u0qT-`Y@I)D&Lem+LurSfU^KrUt;5Rt^JFxPW_3|@5D z02S+WYxlSG=@dW$i&iULO?N6O;CFZGPf~7==7aT zqHEuCS8LH^wYH;C&`JVANpId)y%{XM(Q3cSjAeTCVaFM~$)q^&NAeWxUl>g+;=$Pr z-ef=V7#jwv%n4bMS&x)7#jmTz{ur&9Tdw z*}sL19NpG7$S7?sIP*)|n(LJLLR&v`$_0)pmp=RT$Z0a}*qC0x1U}8o1xt6=H3sTW z(#=n*%q?1IzdDL{B`(Sd&uT+vGOyGy?=Ng4r=GZGl-jf$S|#=gevE{%zlhHmi{0T( zL}li5EXA?Xji`3WR!LX0#6*rPc7WJt=`5 z+>>3CoK}zVBn4*iY1ud_fZ)Yf??KEIGPQ5QzA1 z|H9;Z*&%jK`A>7jR`)mR+M*`}>M>C2AEK9sb{fM|i#|9)1-7Tfb52zvQs{<@%Ekpi zLJB;t`W`5|rYH*OS!b2*O%ZNscTbhU#8g-)Q4`m9(x73w8(ez5x3H@21npjSZx_A> zNn?cogF4KGe)(*g#w>#|767=HQTK>{@Pykv)t=RQeZSPkP>SQIVo))YhTUeDq z&j+-E5@Q5C;E0Mh8O5kx*C>-aLko4m6Kh5?kO+BnWMUYuv<2&Z#-fzPkS-`OmTfw8 z`MXd3j8Jgwdd8uTjO1bD6HQb($?$B}6W$?uz00_zNwQOO2;zo#Bz41rvy5dqJD!+* z!N46)NHNb2N@9}MyJWps#Td6WJ$x$ups->be$(mI1FxfF zf++EoV{ayBX z0T$F^fH9cG3aP9NdpDwylz^mgPgIL#1x-Fi9^U*GM;Jc!y}Cjyb)cZrh!%dV{yVWE zVt*wJQD~M0q6Ql}!g4(5(k@*cYaC!a#y&c)N+^;Dq15>d&w+L*QYbcSCs+&%)kBfC z6PaEPdVP60U=S-IWmT=K;ja7e?sFO{xo_|V1)HKQdd=Np6vE=LLT|G< zi3L&5!uHkYXiM)`trN25ir0Z5_OaXWyk&TH8O5JLA3`w-C5BB3X@MP9<>@jTTAfe< z98a@?wI4>HF+uT&s3|LnToo`cBJ!8zzN5c>XlF~MdmQ$qH!K*wY-F8%nSRJh9?mwK zlGaGiX4mCeU^#Im$uN)%g5N3wk(|>RJhwF+BtyW(ZAS}`l|+Zt5MUTN-(~n_u(n)Q zQA{|aj$bHl^@c(}gWt`<1{iqZZ;zT|W%8FnYMAu&P<5mC8w9Trgf?GSmy%gyibS-B zERU+wNWB>hQ&`BklZ7J42687u#arY!P!jO8C`@GB0?2uw5`#_zsdp$;x4wB=8lOF4 z`9uC9l@0*|kNsc(b*{67-#!{|LD`H=*|GEbvzmZQH*nY{~A zN+kS$EV!`T$$r;)f%49~1~mvnfgRzY`btEO&L>riv*tneEhpJ`@ zkWCR-Coe}UfwMPhZG_e8jiRj3u#hiBT0vC9T=fOta7VJvu}UsOdO5?w7^B|^YAg4L zM!yM>)kTJpGPc>=xq)|MbP$#`KJB5#jwhH!Yih2HL3EA;YY-FhMq~8q(CAgda>P1` zsHb8f+Lz9S*V$p??LZkeO0LQ*hBIjl)vbz_>aimwkrNRfdJVDI<3F%u^y)C5w^{a( z9yTjn*QgU@NFRm!n_YB)3#JWdI88qho-k>_FYJdd5LZ_xX)#H6nRd;&U{+s~FmPeI z@av8MQO>6DtUa>BX;q?GKq&wU!86IUOv*xd9!@`dyHLQHMobH4{nobRK< zg`i0}C2dqwB|bCp>0|9xqD5*C^Sy@e2;?H$(mPkIOONCx^p}V#czbrmxd-vvT8f6` zaYfJ$Hsh!BJ|ztE1c%pf*d^lvVVbnMb@FMsGkzMGn)GFIOf^O)5rD3-#~Bi~g8zK* zxLfZSh=kcON**Sa5m{E4RL)m>{(&^m2WL1*d|JZgJLmS(Te4jCO|s?HZjBtr+c*&< zlUP;0GvW!Q)>UXrUpEpX-b6$aJK!b+CHo{{jR!SDkt%B@a(Fpdinx2H_Gn`u;f2}T zhQK&vuD!(cHe2`joefM5uPjk4ushD=kq~V)@A`#9jqP>E)@B{tJ$(1*#|xLxgIEWS zEVRXgSF06rCN`&6%Aez69VcnEe{{Y@=Hj9jxgawWtQ&QnF9Y#YyF88A+ggOjQMv;o}+GW zRoqm>v2sQrg^01wzPlbLN!fS5aPD*N2jjXih&%Ff2dr3=Pte+tr~{XjvhSQ;-Ll6y;1{l~WGdG*sLqW*LMx?U*w-P;z3Bfek#ik3-I5Wdb3f)B~!04fVIG&kE+f1JDS1#Eh@{&g^wqp{8_?Yxrcz?f{ z?Up8XuM`%G4&l-dnX$9WTeWbjF{@2kLB_M+yblRvCBy)=WjyP!w<(mxteap5-e@3)K_GU zX3r)+Z0ZkHo!jN~6poMg80Kn(o#Jj9GQFFTzP1%PI)<*SdHq`Z!5m_)k4mWpLfq^# z)Gu}ezi>toZlya=9>iKKztugYjy%R1Gm+*?%IGFag4~bpmEH`>v5qGhfZlQ5k;o)V zQu+E)5>*qQ6-4n_$Zh1a^#_~wV`KirGhdZ}QnDi#b(5d@QqQ0NS)R?@?+__Ugnet= z#)RB@%D^f(wipr`QMoVs)%xi)2U;aSu~%o7c|ITY^360*OTTK>jY+0HVxAfrml;-?w$s+}kzb{g@Z6(+2>+G)An z!&;V2;dsy=4;H1rb5TODoqV0jH!>dF91p&RMD~?BS*^kL_+@0w{Rpos1ohO1jwN@< zJQ?NS&iG={;ydX|b=I2$rD)H{_1*LRsr*(1mS*m+sH*g!xl^=3BdqU1Kb(s? z#bTsW4#G$5IcDyi(jYD;)-N0alWmws?5kI_(MLr&tXFw5bFYwW>YmT2I46Fe%m~EJ z?SR;Ce{U_%fd+bwl(!h^$VEDq=Plhy_xjQ9W&)9!TZGg1&gUs0f zg#_6e%-rY5Ne{NE_R?ej8}ue*zmM!P_7D9@U=if$Gwes&PznGSIl?Z9z=K^Nxctj_4ypL3;YoO^gstbwSChzbcd{G2%Ci7|FzW57Lxm_OsxA zCQ0yqCmIt6bS1Y*(=ifBh5Q5iX0Qz>R)`LnpMy7fKlUVE~GMhI%B83 zxCUb=V|259R%xml8eJi0trFa6nL*LYCN6aoj@+t+Cc{(UPJq11-t25X=_Tc?r7)bV zD7@E128&jBayy0{q4LH#l^9v1Zwe&Jg`-EB(@)h_Bx7+9noG^xJeK!b+Fea4@+8k}kFLNXT(i^}{H`ngz!`NHK@SA!c9d^p0*GA0uDV$p^}FeQ~Bou z8{7@qWla$1<@+ilYg=@@a(YWl%j&p-7QcYALQ;-nf1~(_;ok<=)(Nhaj#wzPWZOCj z#t^mpDZy-pIw@J9q7hIq1m0glBOdHaBjiSLrP88g1!z(FVc=A*r`DIc1NGQT#JaK~ zr^dRxk#MZ5U*v>XmoG9o)|C^vAl9Wtd+;9 zAwJ=QBwD9&{0pnQ$D;)>_Ht|&_D>KvE#8;AFq!3CCDY~d9MI7oFk!kEEQvMd$$|U; zG)Q(O>%;c$gTmk5f$l$NBOQAg)obY9OStBDqOwgb|yGh=KvJ5jbV z$lxAvt9t_;0Oh2S(bi~zVp^WU+tO_%myUeg#MUTmX5alR{Yh=M3)H8%JEn#1O=5$@ z|M|1{l-erYd_i^dIXQ|;7en!&PpbX7wO*747?H${Jo`a`!k4(jV_gpn4m2)!9!#$? z`d{vEIE(VKs!m};U=8`Vo&1jW;g(eX!T)e}9q0U*B_|8VL?T_5z1u$9Stp;|+_O%; zceh$6eC^>;Tu|CGP;fh9E-|T+t!ck++~IrYSX8{Z#i&r!U<( z-t3iQzmr2MwN~{?U#6bb6^PR9Dbg6H7gO0(E$TQT`5$)ji(CB48WK=NS~X5ufeaU~ z-*;YR^sF15XX(53lw?o*sfg!SoPp#r?nL&hg25A}?2q8(udaz6Dt*ee&QwJQTchMR zwve%fwZBxfp14nwBir(+FD>wnt$riM?aBWMDy8|*?gO$MCp+GLQ}NXlJ((8AvnR-T zC{Ll-el5A^T3|{wHY?k}0y9>{-!sWL)l$!*y0IHD?f1%AG`! z*Ish!9}Jo6uDvZ&JN!L+6?rjpVMKJKJ^KT0?nyVhvC~U}9FH^TnR(CPXXZVFpw4@5 z484Vwp)eGDR2V8*IHL)Q=4MbdotDPYHEA5R&dcl;YL8N;jn;=B)6K-P#Q<#9%Mq7# z^&PH(YLnCBNb!#tyWGo1YuZ?~H1iiD50O(^kxaU|)A@KQALYaYOWb=KvpzsP265PX&kiH~xSX|=y%aH%}ij^h9#HQB;VJ}boSPL8&3$$VAIve_9yn6b|K z5!vikhjH!MGyCqnXqdZj7Ge8+xLCpN>5)x9W?^pR)(A8Alpj#B2s8w!@5utWPFGBh zg#J%VyBjBHZHQaTGxD?{A-td~{Mr!R&wB~)CA?SgUcvh`-ly?CllPg1XDvyyNm6z@ z$Y`TW8(j5n`}ESS7`>`>^BuIHG)u(`duC!!+F8X)F6u#MA%brAic!^d-tn=(xGTNN9@hcR{Y z8H(6vN1{Vpvv22_H#oOEsF0l>`|R`Ru-5EvbSHoOBq+VpJ|XtmKak|2rz&dA*3)0j z>4VVUl_}cJ^ryYS)R`UDJ0mwvn*a+Cv1CDd>h|3R8wpf*4kF+j0^fZ%$c$X>6+`Oy zLt>?!xVT^SC;tK7e!wU5Fo75^P7KnFRBMA?fGLNs1S1Z?f(3BT*{fvGig%J@pu`nf zB$HiVn{zJp7>f=|4;Q@K>wF`4j^V9xgqRw)|R%}Ipyo-4r&Pun(a>!i@fdj{bK#rAkh@xG^Z$cli4ucC1MFG+>MgR z8HqY^F%Su@@JJsr*W{^yF{fop1%z_^SVm46Ww3z+XVXn(FI&We-^xPp+NX#U$L6R~ zb?mO9;^HvMzK5~1NjxI(7>Ow-9?T+eM~yF!kb$lb>>&rUvgFmz ztNR1g&TEkOQASz#F*bzth;Fba$?RWxq8hRQq1*{^I5 z7TtCIBB>nx4}2*4+;{X2&vrm>r`_xD&Cecouf+EobM2j!0B2Ae4S)HAj(7~n;0Tfk&JtUrcCSWkdf7nJ}xcbWR zO9I(Iw7EEJ^|Eni{4+6v9Icp{T?I&W%5e=&Ew)^E1r??JCj!2G!}4r?tdc^t$NthG z@3Q{NPl;S8TlpwwqwvT^aXiHC)o(B)94W{l<1!qW4D?j-`<$ZmP4Vzl;naL!H2tO? zW(pFaTqwHzC#<>+a2UdO)m-p>Bw(&+7!LdKZ_z?Lw~7SXyF}Vc^@=aoFNAo;uP>;MUk@{U zH#<|aib5va5EfUhwBPYA#RO^ma?RU&KX>X{#r)xUSJ2Iv47!o!fXXi`es`u`txlbf zLABG$t}Q$*GPZ1nJ94_VRA)mNf)U!V;-v2dmT%x9F#H2XF@6hIf?QaI zW`9>6U?8%ulLr(`*%-n<#w?W*sx`VVNgiM{gdiQJm4X{>b zOBKDyBi?KjjL={8k~^F@xgwN&*IVUT2PM_ZPK;bwcC|Y)fgLYPHoX8Y&4qaH5~Ap^ zY}#{A&>Q*(uqX8e&MgRdwx{#l-Y%O&*-6nR?5=%b&*$OdPovKP9Rv1h!Kf(9IG8$lPtkvKy4{)Y~en1 zF^;*kk*!&oL-u!C{)1e;_EgBc!)GLBxUt=}^BejjbIgVXv$LKraSReuZIoX4KBm)J zeT|?E2AQD9IZ#!Sr7?EUUN$glehWEG{qu;;}B}-Xq`R; z(Mx~+;JX>|axW-qqUI2WKg2U^wa)~KJC5&V{)3>gzf!u;0kAn~l^)tmR7IkE1!1PW zdU2~(`*tbv1Lv3Fjlt1Pfka`ypr_sX zGsA0HjMxEfY+L-gClia9h?-dY5s3n6ByIobWc<3P+4U>TW|FoZdPDc@h+nxxU-Xah zP&MtIlW3RQ;pz;?tTYy{3-A>GGlu`Jy4_msAnId+@Yb$-a`J>)_0=JtK~F0&S)=d4 zZ2*WluJv{$Gl04s6mHA1mAioHa;R(ugE!|wGREWOLl;c6B(24-fsB+ zac>0|JBs;Be1NZLwG|A&Kf@6}-@k|>10}ULj%cqmXJ(yIF77NpqH8~D(YYIwxt596 z?yYlB;MK1%-ZBk(@!yR^LNL-iQo1$yQMUPxk$jg3ea)76EtB#7NEUHL!^Umx@!AoR zjlj1!GC8O{#O}t3;~X(E$ch2B90oxR9W9`kf( zb0kG5WJu67vyH!qqO@93y6ekMqY9QCffckVVwo0BwV9pR_un%I0~u}U3-`?B7x61I zUW)%m3=WbWLPOeK5>#A_8$R@7f5sEA87aeUO@c0AS(fY1g(SS-a!13G)hM*mi0mB#(9j8gUT;`4c_V`&MZvZ zH)b$cOILSK+l#BZr%h&DKI;csWC$j{=}zbE*h9KFQ^`dxgg}8i298~ab|Y(niL7Ky%J<30vit4 z_Rl4LN0qdr)oxJT-<)pik)zr&?^h`_CvAD!;?8@zS_xjT28ab>oEI&?@&b_-KC(9|y^IVqTEoTV5(1^R2?|7ms+H}Yf#mjvR%tGMr4(lJj}m7xvxPY!V*clNj6Jd!%J zhmnAXbI4nnxfvQ3kbXZ1fmtrpt$d5wq)ovmTgabKHv)#UnwSA#LHrlSk1tQo4!S#^_sW zyyj6z#%u17?y)jqn>>f?pQKxYip`Lk%MWSy{Y*f)?#XTvb|3%`D%Snyr|DPKlM)iF zn|K|m>Os_BUjd?aHFhKF;gy1@(Ir9_#GzeLuD^n-sxu>*auAy%)`Uq!6`oFP_X2;M`iHfnVuW#}PR--lSKydCYN z{};rn=#7e&QCRVDgKE!HzA7XVA;OZ<)n0W}}7l>7D53yR;n^>u8`w}a| zAyz`H4YR6VopCa>%2u?h#o^4NUo!cMO1Z;5lm8UEnDviWyC?tiSDeXDlc;9}udXNz zupoEughZjXQ0tC;B%syZEfh*tD5tJ8h05uH;vU)Nd6Hs`t?;cA%nXo1Umj-4*2$^eFyv}f0UWK za!J5si-7-Z)R+5Y*tLgS0>!)27w)xl4O>G~qq=S{Yfa$Hq@I|~WqVCQt~(xDx&|`e zQc-iHL<_V98a}ph14~xaj~5%LfTu0Mk#iZEZ82ObF^Zc*<*P#4rK@m7l%c3g$%-jW zA$XFIkR^C`wc0wE-tjvQDRRRL&)em>pYxoQ=fg_#prjyt{tZduN_##I3`|cM)uGOu z?ZWa^ggMsGlV#~+E}c+<9%O;TA`HT!RU!z=1d+Ptx-YuTJc37mT4$eFRFEZX$S#EU z=+brV(WcVWqOS8+xm@#3PAqz@9F-AwZx7O!{g&+j8=}TJrLnFv?b8-@J@z`XU4EZ= z+vU2wU{Tkf3O-HIUkA^4}fZ{WFbs8-ntrfoiF?UK&>t^DVq1eI?s8VDxOR?kP@p(x2|+@N_5tlJ4Z2PA8+D z*j^ui-hHnCnuZgAkeVrAm8Q~fJ$NdMCf4blcM?ReLWMAN2cR`AsWbBPJWCKVM!;3pKk7r9&69m{ z*%Y_DFonqW8m43&+*vieF?48WDAwqyGS`Piy^#)WHPd?EFBNW9X7zU>hC~qiZJ`80 z0+`}*JV)KPhZZH#c4E%p+6fg;GHElD7Rv1n)p|~2b=+0&H+`l+{#|i_uHgx# z=D*Q9rM#hc=*M#WY7SBn6>01NnU1J!byhR&{EKHp5O1G%+NyavU zz3$LzuVKby$g!_z>X^n$RrxBdb{D-iqmYBg4>s0iDRtRkMRH{mRabvinJ*l4Z5OL~ zXa>^)wM*qcagQ1-mRR)CRQ@ZAVEa0+icU^Uf1XUDkx%58#o44+LM>T_XE;eg4Ecoc zJmaJu2mMyHrt&X$>SJ~7rh{X)z}#X%gk4f==)PJ7nT=IobLK^sHck>4`;L-=WWCae zt@eh>|Ekpq>&9SoAfFQD#O}z&A@LR_?-9V1lILRExR%c=D(IuGOt_1;G$3K!%vgm= zH&4CqVKt=oIO_Qo8SP~}JjMefyIcw}u*Gf0woReZ!&C2jS!F(!Slw}$O~<2tk?b`dO_8Fw!5I!nCp6b?4Kc!~yGp}ZV`XccUsZ~C+qSC_GDpn(tieWs;xIC0` z*m}(MqmavtshTfHcOv%;)i3sk{E^b3b`Hh}=*n_xL{v zmSss*lv2M|7Q}pjtXc0N2Sz@<$=2!qSwK+sc7qZ|DE-rx^b;QPb`8Q-Fp4D;)GhIt7f_7f8j z?14aGsmKs)ohAY{L`YIEX+`o!*^Us^L-L{ZhjqVS+2&gkri42NHS3Wq0q5~TFh|J8 zOoAO=-&`Lq^rc-*Dq=S(SCFFEjedGk)o$Pt;`n?7F%?nXjDIm47m-emG6lEor8_{ZP@msZ@B3j3G%x8ju8pcP>Do>yjE_w zQFngH{HgK%Pj|-zU`gxtL3Mh=>Y)A8)l%-q(+C5Ha_bj=NTv2Knl)@C*%>0aU^wpK z!dHg|uKdjUp1hhSBjU1lJgc4!d0yu{3u|nxl;?ywlV>Wwz^ULd=k4rt z9}U8AU-pV#JBkxziuYCZ{2Lf@0!ilc;r0RKas5S z6(r*oK@H;9_DA;OGv^OF^m9Rrpt-5aTxD(=zLm`#TCKKtPMoPGYdpsN;aU43GW~JZ z+DPUQw~ToXVvhw5?3b`7quU~v8;iO`2R;wNrE7Sm%o}Jd!dqEd~n-xdn)8JJmwZ!D&k2LH&RTJy0yKa{L=n&m zE;x?*ShGApTa-tgm8b#40J0x*n=UNY4fB|dPHIyw0Ykuv{fj0@BhhT@FTaz$g{#nV z7!6nYW-uXyReqy%gLTF%0gUlA8DEp}P2AXhJahJ-SzBPJwg!cAHO2O3C>N(AZ)2Jg zeHam+9+mHR|194ImCr$Me7lulwqgtX#w=7l^XHV0xHSZ|yp^L5$D-@0OM*n0pBTv_ zP|Jypw0ZDgptHJ4@}1G)%m2=t*n^gTDnHrF z@%T!WZiP?3U1rvM(1?X8%rW(N>#1il1l#%nk1@Yk#5oI7xzCHRQ5H3k=b#~JI-hS{ z;^eieyNlbG(1UZ!bDw5$%{>!(&!{~f=u7X1t&veX7}!h?K+eGCBKu^^ldfubcU9KO zPctb3hob(pn;Nqy$`~)&CNT5!< zz*WIdE_s(r>soNFJs67;d%$uRBmtS!S{+kB*vfrbW8}0vdPfe|_9REQk|5h{Ue0Eo zq=C`R`l3BG6p|DV_9*J_<{b1x=GrkxK~l**SveRG9G}zFth$7R#|O>kZ^21367dNt5jb$WxqgLmsAV zcU80&ZW`E9L@ypoSNCjo6Z7+4U zNGHIK<(MH63zSAAA&VPUwHMz;CbUj<(z*RPXOq16)VJ69wpL#AxQ7}LRM{4UMX|kp z$xRG&%$2Ki9C=_h10!?eU)CssGr^wfU{10+FuD=G*f(a9h@`X^+j5dH$3E>jra{Jz zq1so#@JKuELp#l;;cI{`w#R>Hr>XG9LMSBTr8wC4?&ps0%egtb^DJqjU%GOWdoj5@c(Sjmw2e}sZEGl1RlW(QvGUcC z-&D!5i+$2!53(O4uxToyNxxg46yZ_!vrb(c_rl_EgwBEoZsE*4S~4TM*mnrGca*2UDr zCH9U?r*t=4LkXVi-Z3-PP#XRTGkgo!&JZzJ&wdDXUQk%VK}B6Ai_lH+T3_TBrok^% zz%Ll^3)A2iHjZPY6u;mzW?eUvvEbe-*Z~Hkt8Vw*F#X#?<{GPc+nNfH0wJD!iUF!%7}(XsB1vR^>c>bn5B&JFQD)Wfj&^TFY+}rI9qCzh-~GZ+JpXoUNe}08^tDA5xBVk`iCI( zDqH_LivjM~qb7cn;o-QXGhl7qyjS_!dFOo@-}S<{^q7gEuc*Yurm36vI_1|gU|+_2 z&5;g%$v9x_s-P7vOvS%~=A7dU7wp=p2nqs3d&6N0OI>p#?Bk8370Cy`^%sJ7NXMcx z`>mQv=i&`WOO+q=%a*F1&bCpc+M05EaKcUjA?vu$@Dx=y^G(8E~%i* zn&(u2bV9~jl4ATDiEP1I;Cvcjy>y~LZTGGZMS?P*_K9(UFB8)-wGa+n0yQpYTKKP` zk`OHt4imaF=Y&k^{)N2Wj@Rtkj`yH=-N}LxW4Y(g_nVx+WrPFx8{70!xr_Ia)RYPCCQjhe=s_=xPL zgh9{#CHcambD!oXv}F%Ic(nZ8HcE{7vy`~!9jC8jt2H~{qw2DAKa(CH}na&2U-nrsT>`&5Bzv-8yN^v!?>7}wK$-k3p7H^vq6OZt95`j`sW@Vtd* z`L~yU`$!wJ*(pEHasbGD+nUZtp1k~T|41O6{vO~1VBUFQ-l>bp-#x-9e{D10+evHY z-}-d@bZo{({=LmN=~R+`eDCQLGjy4%`r7=E`pw%%mHEH_A=QIU^l9$)@zvVlaqIXB z)_mIWF}j`V#nDrMBKI`11@GwN zES~c0c6r!n?gmxE?h)JN zchB5U+^hGzwno}&TfJ-dn343IGGlf~8Hv9nD|zhd4m*F0)b_ERJAz-3_&3{m{p8xU ztCDlUZW5xaC1FN#^=Ek_Zjrp7<&8Us-&K1*erAM`ei-)-tumbLDs_~~HiMTf%iC7% z-Lrf>7378$_<7@M`CYYl&42XZ@Td)G9A0ft-_EDy+0#_s=}oJDOk@ zlwW)L=GC8Fzn1hdGt+?0cUt~<^(WKU(B_s^dpn*PQ>uXMcxK$i^3|TPW%ceEd->g} zp0~}|w|e*V_g3$|_I(C<#6_xxYnw@HCtvPw9;D3f8DpN4-*;zZtM_+jjCeraKbyXa ze+sIHXH_Oct=@8Y+=bGE!ysb?oUy`>=vnk6 z_fd?Rz{gE|w$`#4^r|;~!9WK8BzL`&`zgu&c;DQMLCYC@j-1Xzg**s;-o%38 zN>x+J=DN6w-Yvl;j$-rT&ac?1u#Ro1mdPmiCo6*jbh1~fh)O+9omY<%o*Vg<;u>Bk zTmpK96ZykY2Vm<*2%@u5c@pNBO(bmY<;DlOJXOcL)6jy41Lo(XbmIS0HT+J2-Kx9g*~*k=SA zCVO>rsNQgOKWwFsOw7{mdzow%=f9=h^Cu~L{!T51J{xm=J5>Hrz}!%!Rc^9RaloUM z#)&mrU7QS@jQ31Rw)Zo)|hNs%pcA_rL%HqBANen&qgd z7*eEG7#?O|MrU+J@r;$PC>}6R2s4W10US+mM^af?X42v9wX<(;C0Z$n2Rx)`mY9{8 zmYe8+R)`(szn{IHJ%IIob$$Q;U*C6K-?w4b+V?uIXRqV4p0!qX7mD6`GcK{kJ$c4= z%SjKm7PPAgM6L^0NimI$>N(DfZJ0VpZ6&%b`Q6e37=7g;VCd1rq<|iS9br=9_|;Ka zomHY(3p!l+lmsM*i}|5409336FYpr_udLh(AhsAo>glG@G`iVq(L|nF+?)4@`L7V0 z!Rc0zU>Kaf?ONmR^GHXbzN@taBD>O45PXQ;bG*Tkj%gO;5q@?Af@Qejl%)atiIAX;9&E9B^AWMVEMX#a-czMAlyi@%oBAnS zURzaHfWoo#8KOi{jX0-V1&6MP#CyP~ZHquKlE&K)FvTXieKh7Kj%_NIhBCz}a#P$r zDMCah;w){J66{QvDdJYwk8z~GSb-X>Tsu!6=dfI-+>5ycMRoFDh^m54c)W~E;AH(E zIIqQ8*+@E0#}lSp*+8E#9o%iWo*soH?q^E*Pgwjf>v+DwpMYuc=Zko)yER|LqeZ(X zQEq54?tgee^wGJ0vK+TVHT;w1I5l0@uVZ7Ocv+1~^gu^CM!Q%`!OcJoSk?`)Ai2bj zE{srF(SoVkLz(;yk*cCGGA#|m<}(<1-q;u!{tr;1N_h%&#-+?}K@)3q*mZ@a-6X^S zZbCDj4_1j)h6Z@rzF%lrZ>8T$?L4q~QxhZ0`hm@xf>AV*^3E+t3fA;6`sQUl!RD<1 zn-_O{U|xk4=M-9XrXvb4nWOb*nm4Jd(=_aND8Ey+Y_D|iN2GLoRFp^`aY)p%B^p_A z*-2r>%XD8M73Bl=EAWg1^-%KUpla-RS6g0tN368F3hY~4>6eLRR^a{tlg5=4af%b= zqQHLEEr0JU`yB@|&)*Fh`)6^C5b@g!>=#{NwvUik*QDS^*AcR z4V<~f=&J<3m6AaeE3hA1*9ME}7EHKp*7s2krMzF%lUUZQ1dva;_NScKibI1ymkcWC>J4`bvajg(i{l8+?Zz1=Wm zm~q#Oor-e;aMIgetGqXMPl0{CL!PkK5&MZNz0`&4rq(}%p%$29)^)mkTWcIcU535e z&cvh3zQ;Uf1x^fb4N9czX=wS?>9XTiEhNqwi@d=E|d)v1~*(xc$3P5O|hO*xnm7D@|?C#$@cY_ zSf%5Nol7;XK@uE+KFYZ3wJ0?wg>GE#;a=;CJ&J{5bSTF4SKtIOt_K%vyL41=l_;3pq&$y3fc%YFqfm#T9F@^<3~Tdy^aER3ie zAwP76zNB@XK0eLTLt3#>2RBIJC32)AAq&MFt5os+z_y%HSA|Wq!{wVkQi3Qib0eiOcY!I?k5Tk z-%_bUV#Y+3z%xPswlT7J;-8WxpGfl%?EXNSH*sI+eDmXDWh3SHryFI|X?l>r)EyU|>)hK=NS?!AJ;3?>H7!W$dA_U|D1aIOx>eq~M-T zYKkVnGr5*9v2b8GOk$C^V{HfZZW#LQI)<@_f+FSYUk|mvM(Pc!2l*%w+ky+z9Dz8u z>WD3Ne`DmG7+%9^R3HxbLD~Bdy-Dl=v`a{M%>ax88Y6Fn3$Bb0MH6YLBwCUMxrvA< zi7170EmRWeYB@UMM2uZAZq7lkoo2@H*{WTu26w0JIPOCJ#*u#2*Lcm_#k${`ptJg> z4Uq5_ud^Po_9dC88fwF6>+^%q69;cb70m{x5p5A}`fkJ$e&o8IVoe_xKd6$UxRLUg zdWb*iJQJ}TRdg21ju_IS$C(C)u*3)(bx?KTjikFc4kW8F?N3h7`O*hKv;r(^+Wm?9 z;*Tk5h!$---WE_u^8VTZRK;TcOL7IVwJ87u(>{Z&7%jVFD40RZqhRdMP;W;Pb0Sq9 zLOU}=5J&zNJj{&#*!j`mO2>wR(=Pe4x;5|w4I*&N%bjZ6m}6KAmJYz73`8#MhylT9 z8bUJyN}$?rC?vl|3yB-44@PfS7{sbn|kob&p@MSDU&C@{R>W`2SryO31-m`9m z?5c^u`P$>DjG_mJm1Q*+vGVBU+EMHR(izt#B9_sG(L<1^O1FH?o%oZ{r*^X5lUQ`d zY3miUATX)yYK3vmc6S{~Fx-I#tH66wt&lgU?Uk|x)}rNteTT;Vutsl)TI){y&FK3O z5!U{@F|zGg)CGHG%?H4c03vFe)vL7KSRgp5yaYiJFsURt$568cPMAFB!M>m@fh;u% z%g4w^kqOTobbru|IMP|%NJ^pMEN=ux0o?}S_1bq@nhk^ia_w_1&4RG`qqa~b6P*f< z&AI3>x?wJWYiuw!#7!GjjgjNW5c$wiMUKTAOy%WONTt0JTz@;dNA(j9B^HYeh^_W; zJO!_47W(3TVQ9#ALVzP%Yu{W$H4()utVR6z^u@n|Mc6)=RRyC}a=_I-wOgb|&$ zZL@R{52<#djhZ;*UgZ&B*7hhq7c$eXF)}p;qb|&KKT>wB0m&+9i3B`r$WiaZFdId9 zC}yQJ0mNsZx}nYk!z*%U98dV2=e+Zp7ORD=;un7eRn z0QC0m!g~S=t-En1A+8d|k%YT##^DEn3P+eB!D1YKD7MVo3U{1&f}M1%@!s+ya?mI= zbLF@z8;uzDlI+1wjmFa4K?cctndWU`ElaVYeZ&-WJTz4L`tqTkk(k<-%O62hg#=YF zwDDD75DhsG8%8-5zJvN`1C|wywhH+;Znugy$>m1dajb;lyj&gn5Tor-eR+T<2&-f@ z?U6RI(sblV4JtggPpSQ<_#}|0W0?h;{H1)_ns=dVpdnCs6YL^75(9^~memAWedkOV z0b6%TXnY{h<2z)q_t=l^%}!A(uKx`3QHr zz=nb|NQ8dVz(50VrJR^`rbI-w7+Ua7P}=BdYLwpQghn8dic z7zt42BTSGFf)EfEKU;kgZBWxvDjx#j!lLzRVpXf-(E*wj3o3;;o?x-)fcy2>W+#aKc+J5_ko+e}TP8Q$!-7x+Q zLlBkB{Ml6U)`khov#^v8JFiqnI=PwF$S?cOca^W!ml-?}X!n;Iaf}KEp0Nnfcm7K4B=sm~%j&CG!8h*wIy5^> zF{xI+)(*1NAJBO^ka1YHQS93I2~qmaU#m64E&!)v!>(0!djJ#8sRxZE<%H_uchx9@ z?8CEL?=X{1iE0D34KDKOUy6%FK&p65<*BaIS~_SnVVt_PqA=qi*g@6sWbBg(x&)oZ z$wPt-^aJ+)$d^=-?a1v)H3E%ul~PTW*gch|$PQ}5Eld}%a~z-|NTlG<8tNRqOF%t~ zZ~4jqFU~pG?W;Zyd+(dRiogQ znA-qcITKHfxdT0?h*LfWeab?4!fbLLuf`q&6^oS0&**$=yI@3DO#^5Q1|4cnlx|4A zmSQlrFu7GOjQ;>M9*&Uz#1@=@TPI?WwSs zau@tZ2M-Fi8*OC>E*2143^Y~7z@+XQz^Z@Hggr>=4hS8M13S6lg!I_W1~E&5ln_lWtmt&2K|x!CAJJuz&{FjS=;GgPTXypT$3!#r^m zc}ehPUqNVp%9l-brQ^K3gP_4RZ`A&z1RNzXVn8$RHH8QRY}zziVo)axEVCy$Wej>F zTO$eJ(~_iB6Q36M71Q)%02Sgi`hFH03SkbFKoo@rYrO1&%Im*Z z4EganqtqQS$h*~00GX`1rinq{k@TQKm6E?W)p|&$%Y4z6XUl->?(} zff^J-pL*G$zg9L|U-x|rVbm_svOXG)4CNHO5KdLaPj{4Jc-PHuHp_TRP}puPA4Sj` zB%`IpVV51oxC$sY3mIxT^4~!?UF(pef8@rlYT=;m!#Ho@aUm-#M?M03oNJ{z@iup& z4joahAey;oeCpRB`BlXKZ|s@ipd4UYNSpv_3Ua8}#L!!&sNU#~D31=bOQ_!ksUTTq z6z1J#TC?KqWN1V_waS<^eEA=oD6&63&J?7%CUhG+|#drm|{OK4-Y8evjS{ zaEXzDfZgPCgzM|~nEW81evjD?baLPhDGed@D8tFhVx-v%x&=cjjL^%xD8dNB5Lnw= zeKB7XIG`5y=EA~^2?W{e=x|xWzmb;rH4fjD%DxWDGk3+tWikp?1A>rVg3n>r`IcKG zaByJ0^Bfh#6nsQ`JdTxy32ucU&F4sie68KoEhUXKxlMs1rPe`|u$Ex8uTi#|NdUbf zpunnnh9EAvL&0d~eS%3&N@Hh9YB;n%vLGcz`4%M$%}$})Bp<`C;H+&jNSvpdnyd|EVSNg7JE(5RM3@4 zk%iW4h-68W5}c!*dQ;mMP8%aUTQu%6*}8SuA{bGK78eP-ocf*jg37jdi>hz7}}Hg+`)D_e#O(XzRcpm9Yt_l+iibP zJQ)%%%6D$JvYJ9bBUo!7w3txKbykedMA}Hca2V{7xK`zu&LXGx)YxGFc?vX(v1ElM zH*WD%KNht8hcSACm;`ljIJ6oawXHBY5IP1}t%vVar;yY)nei%Fu%9^@Bq<1boW^{# za`Je&N(4Hhqs2pUVz2Rh)!o(KmtZe>Co5A^v_%F-L5A8M5y31DUs@ITAPsK0LcWYC zDmIX-Yp|_j5kh0+W(##F7#!Z$82K{ZeGS3hsR+Myv+!wO1h<8StsmL}M>8OyU@Zwm z%F%~6&&AOs;na)<_ZS@=UJz6siZK(>_T$FLTh-WT%|BI)3R0*eN(1fGJ1{7tf~GH` za{3H<<>ol*Q4Q2>F@0U>)y=7uplIq)Q7Tl?*b;FWoz9C5QC3_=SC*HcUPjk;M=Lapvj#e% zyul?XhZ2t1poDN4D-0T00@BeMudaR%?r7MFH3Uh)0qii;Y6H>6En6Ycdk9B&E9h3l zMSmJ?EaU9h%Ya_TcfJ89S6k~PJ;rdj%^TMsyVFzjSE^ir#~tYvt{%so>E$Ej2((Da zCXfl5q28toG7l*I+cR4F?fP0#v?yZBw*)lB|L%xz;SRpTwOBbq6}~$H z(+4TvVc?*J>vE2tqgLU&NqRMOJtjk8xN5lE_-*~rKiN~|sKujROnRw8+%8Kbtk#F!)4CexktInf3Il+`M(@{(GB1K6{ zTGt0XizTH1NN*1zySwmTswrnR@3)Fm|^&hHAA`E0%dyIzTa1d;y1<&WwHgzv^1En%SAxYA1xO8 z)1^XxzMAykR~F<7{gGm!KUFI9=c=JQaHJ5TcI53L&6%eNP2|Cc4z1F+2mmHB2^w$t!c)EV@-Iu z+YDuTJjC}y@f%};GT97eT0G20SfGqeA!ljiEE5(^3%N@ncWLA<6Xle`MmZ%7f@F zK&m!RM-7Su(Q=mWcG3FY2}kU4XJ7@mh;8c}L@S?SsxLD_=$n}E=jx0m*y-CE+kyvD z=8i4L;K^B56XIED?4zrVP(P3sp0SVBWb6~F24yt4+EzRAYKRCh&ouUNrjZ411ah^t zI2#YbFa?IV>&Mm>*9N)Tnqd+T6Em5ZjHd9m-Zv;jr>}Y?wjYRi^`6d6?GJ7aq7+l| z5TF-V3svJnQ|ucEvl`pBf-S^mxsz_zZ8iCyL_CgX#bk*irw;{t4sNGs)1x5QL4myDajuMfHrVl@HYCy^8k(r_&b7TwR)xnemp zA)djm#Mb*8L7}y2DxGwcVJ=8`Eyiz~pj9beEAhkTfj-tc?@6MHMw0f%uDS3osq`o_ z5iNdFX%UDluk35{tMoeY2}21ZaAg(@>{#z?gw)vVm3zU0Ix&(EZR42_%RGOTD1 z#SUz6hK@UYU)EuD#R}FCc#GDLKxj|EEaRzCOii(V?Av34v1W#$?{~)caaiS^a^K*e zAo~ztEZj<8;N3lLY}G=DP6Q`cl%2zl;aMmr2>G%xvjWRM{@|@5d{}25m#~#$&nz~< z-4yt*@WvTGIAolJ-6#w9I0Fyiv`V8Lef1s_xeL=A!}?Su7Vtij%dS-QC~K_fQ3-EN z?jhoCHSUrU_qeh2X2nTJo^NrZ2$&>B??t2*X)8rgccn{~?AEUIgYLizhMv7nx|8i<2Isun!mZ-b>gn zQjWdSRVXQFQ35m;MV;??9Gj8~lYVrv_PNu;mLOvU^| z6w%>S+l~KejrpCzjx2wEn3st^aI?T#~QkVIs>oAkUNpSlT=48DZ z4=YD|Q%K=Ru_X;lz4?yxVI~xo#K&l7VDE329&Q_Z-O+8q2-b=G=V*%*WgYbA*` zJd6$*^D){SM^kb%de`w~RgpmTB&}Z*J5mdNDg0sItuoFZh*JcDduVWlDR%G64osOa zPKC>(%1@B*;CX_dT}p9)TJuzyH~*@v6-Sh~WC)L-UATnl3C^TczQ=IYjk%4ixC%O8 z#l+)8h8rPp5V6})*rmuBIMt9iSHI$`#JPr*)lS(+R89dax-qhD8wREjP@kWa=!w#=2qDd|A{E19dBUU~l|DtA6DTw#0$U zI@l7I>Q|aDrN@dcHiBD?_A*)rr&|llB5($D);`#|u!|b2{(DHr!LxSE#js2!WT&z% z#MHGG+HtX;jaK9BC|3JyVE-qeYmUYkXr&!H%T~Hgkh4nA@a9ip*G7L}om zml)iG^d$8QkZC5yemwTo?{>=VR5mxn(vO*g9_!Q?xgefug4;-obUVAC-igIIaQw9T z3C2ZRrM3sG5>r#NTPfA_Dmzk9sUaUV(x4n8gMw5PMva{z${+Jyt}1V+o^w*Yw<|BG zo>Nlk&^NHeG`>`l&<L)l8;A0yjbV zT!0MaB)!O!62OGO7JbZtsir#u9cleb^Lb4wp2{LEYnq8caVnh1t=3$swrCD16)KO6 z^5RZ+bU~Mkrr#>-b;Mz8h3P$s?ysW4pk`X+PnA8SrDEb&I>3oePsYj)0(~8T7d74QjJ-2V`;rYLEa)#7!+Pnyj&|^vO{! zd8}b%p}sxwV%R!N&vkc(W*%K?W6l(0+TML~yh(doD zmo}L=wP;~#e^ws2SLMqzwf7`^7v&drjK?KkYP*kB^P2vR)`2;CkI|i;qgTEliK)T} zTs4m--i8x9=v?k4m}1+}K(|$P!%Oz_|SCM4n>GMItz9J93Y)P)5oRbB&fM{rw_xa7e|$6aQK4N zw<5w|T=Oc~4;*4#{XD(MZJdP@4N7TODv`l8G&{5oToL6lI@A9VrPTZenY4R8)z9%Ed+fjm|f`Xw$Dqadou2lQSqe>4%T$@OKJagzQgc+!sZIwqT zT=atJ!=f|_QXv>_T^Ag!udlk{;FZ&jW%5-j=-6;Yd|edt6e{6p7?!DB6rWvHt~`D> zZm29GMJDAzQu3e_DG!k9@4s4}Lq!Zhth$}C4vbok%w4Vxai(YDJM~jO#Mh<8k3qEf zG22l%3E3JIqda>Pq-y25fm5SA;mUC;=;>3D_$sTqD64V}!T&v~JlqZgo_N2v+0DH@ z-Q=yw!x(rd67@qJ&>(*ns&im5Dm!pG1nktkX6jwH>gG#LS~rajt}X@ranK1mU>6-c zBGEPiD7p$(XsP6Z z%GqBicca4H5ZRN(nGoPmuY({ooPa}*{W~cL--X)bpfwi@20IC~BZE%GM)QPjQVD_d zBMlCU$qSvLNz%vEE7Fbt>Jv$tMH@(EkFs+X~G!`R}#Nm2lp%X7+Dr8)9 z5Fz;uP;%h!PIo^Qaw;d>xnGOi&OpEC4D%p!ZIdJ zz0{YH2^1?f<>a7?#IYF4dE}dCTsKh^-l%55FM;4a1-<%x3hDy&kiHzuI|eCLct;=! z$}zm)^U(;@mzE$Y?;$U^MLLo$IoyI(NxG@#9{8^52gQZ50#Xb!fL5iDu`SUu_!_vL zB7@K4tyv0;YafAuz5jQ%feXWp555D6%WH}$&xI38)Xt^QUFCvE4>Du6%lnl^9IOU; z)G8Y0U_O>zWtfFi8WQbwMqds*V>c2`(3x3D0uVVEK~y+o$&sF7!iFof8@W!*R$PVp zb#!0>S_zkADsXS303h9345>QfdWg2-o7;;?w$+wcXIxM18&0L!N(1>oG%002m@(KW zLd$DhO}qswMC1`N0$hhc8f4o#Q-R%}3~iwAG7@v!QoSR6OgN?tR1hU2VYc?WfAREci;DccHFd-Lxb}H@*PlKL<9B!oKI0UirW`XQf zF&QPmE}ve|W?&~YUQmNTd?g5NByESv!PmkTHe2G%I^(LRP+75WDOV2ZiFmsX?uK$} zT!n4I5_povsMjPa>kg{6n&R36y#@^y1it$H~piq#Yf=TcZH4>OC zQTyPacEJM5C*T(kACy7VmwCwLS%_uV4)(1Kmlofd`vHZ4nzxyfwx$>=(G>1*A157B z1HUKL0~3kFDv_4Kjk2i|S0psoSOKTe=b&~l%G*mVN>j@N0kOBRD1TVFB?`9q*h(lQ zG$4Hc2E2vec%aULLN-u~3y?*eBH5Li zVOo>}Jt#Fz^q5jk!EyWXCfbjG(RVODcn6gQHJri;|7vOsP@~;vmG5zaCK`mZ)F5nc z)*xKTeiDtrS)06kHzo_ik;Lu(w&1{jYYR?sTX4XNBm39Ch}6N~0nrvz8`nd;MREkv z@y=5q`dw?r#juzYZ^G{>-vfHd6X!~wt5@Ptgq(rG zx?VSBv_8<{wK3_i>kgt~Dh1Jir%F&#FcC%#MJ)tHQC>5KHreW*k@ zp2ih;)VTT#3^7(RI?|Wul`*gY{eo!>c3A!~VKN4qBn?m>lIsbpw@W55q=WmmN>6f& zo<4mzvR_9d(;wLkqg6YNRvn3#JR=8A#agG*fQI0D$7JS$OJZ=j0!!&wR99@N@m&M< z)J90LhrA&Wc?WCoJB%UdcG-d30#@5`!f<_v!4s_xMDdDK(ebJ$Q@y8+b#<^uzdFQ! zn45OKk;;h#zX1*4^((7dz4{~l(2`;zg<(4#r$;*udPjijPe)Qto{7!{S$6b6UEA3U ziZ90^c@y%668qB=KhTIRa4VyX-ZqZBm1)%9*9Hvi=!ud8MN8TpCRt(i$2mRMd>CAAp(f{pfrcpoN+*T$nvm26pt`>5_+;)kWjON^g7tb>J}xH|zS{PiH5ZgGX%C~4gZ~-KlIMN*k2nBd7xX+D`^FK=MxjKsFYXETe zgJ|COU@%E!0*b-3fu>)W;{Kyzk z$1nyd0d?R87X=WH3Vo~xLUtJbWS5NC2lrzt<96uWSMGc~QQfh$uzT@Hx(1$|xRqqdX^N2a6TAvKXWEEVRoU5cc^ zl^n2R>2yDMM!9-Fx)gqDb4Z|B_5C<}`_e3MBGQe@x(zNQPdDoHk17L^NGg7meN2_i zHrWy-r|4xvZEIKID8OM+@XN1mreX@=Gn-hU|v{#xV(bmww6$nW|egidYoeQEk!ye zT4k%*8e58a4J9Kf#yQX$<86H)kjN!m_7^VuT4g6(R`{+4EHOKMOXDSPC&i9*9k5u) zv0C|rKXo#W0*HjzP{A?su|;F(+ z3FMO-l+UR9w8Z-`u2@}5NyDzbhrh%NnLHeU1SGCNt4LybuJkL46=7j^Y8X+duagJq z)L~#;Gc(^Z9fk&7lupge9O?J!^hyYs1eU8=z}J{8?nZ}kz2L5qjQlJnyF!?fw38tE2KHPCLFm|s@tH@ z=EO@Y49drNZFCSBu+=N^x0TUN$y-GU_w8kt2Th{yDOWaQQKCqBl2kvB!_T7!{|}`X z!cPt8D#6}R)*=XXr9%wc(Hmi$Iq@QWmIK_y)FI`GRV#X^``}UGFkes%@P^|>n;Zqg zpw`rc--9RAN$SU`uOdFH+MRP7s09t-o6Vdp@RJ}6))wcQ%`VNZWV;;qZx>Q~AH_Ya~}s&CWP zUPSkY!#Es`)#w|r3xZ@BaOI_p15U)MrNg%rTVx7@-bQEaFxstu*dU{JEKTd%#7|bc zciQ)mU;~-aB(_7psAPqKK9$NQXv7o6rXmdJ+KH1slnG?2GMfK(c-=*KBU}1x8UJ;$ z{1DnA7Fy45>0Z4ShMFq}NI;4HfPA1+u^{E=)OV3`PWH3@0I%mAs~0uof_B*bjWtUT z7GZV7#I@1&WH_NLcMvYrx#B1sty8RM8>qX2Z5J1s^ukH#hANb2AE2nqt^0==bk2fc z$o`@Ooq{toYO!*GDM-NnBzzgIB7v4o>_D}jr?BBUKXp%6*_S?2Ukr5jLsYjsF!wAS3-*_ zH`WK3aPgZQ3Rx1wh4iPQQdumGkpns+b6B4+BlXyCLI`ETObahY@TU$V|+R2`bVm!IcEBh*ojC^a?CVWP`7^&pwYfJT1hidX+$Um4tz=qG}WMt zB*Ov>;2upz=W@Vq28rp$BC5%BRGdGt@Ik4dwATFNDSW8rHmRD8&2NL?MMh+uY$$LK z=wF(5l~Rt4js@61f#}i6QMNT|A@UY5njE@Btf-WxsW8zXzcwWMdq|=PN>GWWg z(at5$Pf>X4e^7WcZYUF*$^8Wl`JwNFp}!jk<^@yHD9oko7hq71Z%rQ?venAXWL1!w zK_md@BmuH!Gq49r75GQqi&ZZ+3=U=H3a+6!pF@5;U)4gD8|yIkxe$a%aAaV#gXeD6Gg)83`a0I1W&M5DkFfqF>)*3}jrE8* zB3v`;{a7Ex`n{}sSkGmBBkS8(uVDQo>)*3(xKD&1&$@+m7wZ#QpTT+->-V$%5bIB~ z{tD|mSwG797p&K@evNh0T+Scs16Uu%`gqpwWBozai&@{v`hM0=u>LjcKe29@C*p}> zJ%)7~>l0a@#d;R&`K&+9dI{@CSyx#9jr9)mMLajN?qL01)^k{Yko6~6e}(l@)=#kh z8S4t`Kd~ORK*ZCT^;=lCu%5#D4A$>w{UO$$W&JhQwK9&=z;ZDTlr+8c8J&u&uhTX6 zf2m&;;Z@p2IBBzlZq5|?_5SM`g?r0FcK3_G*Spj34N-WjB1XIga}KF<021Fw9L%K) zpj2i;Ikp^%?LjEPYoXk{0ZQo;P>@GS+D3|mv5jPc5?~=E6T?F(9w7%M(?h7z!?3zRx^VgaRH33h{$*&RxJ4=AQ+D0QS1^&~TJcLPd$!>>68ie&(lOj7Dd z*>*cAcR;BoCGAcq@d;2Y1ECa?BHe{wofS$-5|p%LD4C>`l2S>E#fCUcb|`72WDbK; zOp0YVlu}Y82b6eH(nu*HrIeIvQcO-LW>Qi}$s{G0lwwl0ks^(Nl0r%mDaEAJkzyJN z#Y{>HDW#-TkAh-Kfnvc)K>?X#p%jmUQaK)qG!aVtBq-*|l={1&WZna%PF1GhO-jSB zavGGYEsNg$c&U?QmRQY=a3mG#iUe|VqQvSq!g1m9FrbK(I#N=WL)k`(w1OZh+ek65gi=IGH7W7AP;yDBCdHBmrI-}c zDk!<6)RB_rgHlO~Wi^y-q!h1_K(Gg)6m5ZGevu$4MWjeq@iYGd1r-wHwCf}ZRTpoh zpmM^N>XvB{luX9;1Wqlex;2bGVnlEKT zU4r)o(9@-bQkFCmZ?j-B9dB8x{XFS5n2Dc=@2~u4OG^=Ax|9Kb!goKs#S70+=c-{Z zfI3g=FZJ`Aw+vSp2S6J(FMIe*&%|l-yi_d3!{+0fn>!cG@ywYvZ_fQQle6%aK5gE( zndzQ63m4c?Qkp-(1_^(p>I|wms28Z>U_*dG0*f$63eu~8h9LR_#uJD?176{eyx|vM z2nY!z>ku`Z5V#2;SL6Y1fZ+zN$OnD|@dQi32KA>#3FD9uLr6#nH2f%B;gI~(o2IIM z|G!XT@O8YP{XD6U8eGf*@4R{9RRn*b)p(*Wid=f!KMu@QGmnz^&3B$*mCy9ug0+50 zn)dUKS9ia7Z~3J@>1dhp%y{Sb0YQ6Dtey4f)yTwoHq}froi3WWp>NXkQ#yP1r#trQ zJ(|kDCE)RpvVw`xUH2^9p{N&s==s3$4>Nx_JGbkQ zZ#GX2R0F%P;9B{I_l3Vdt6$fFw*&^*@9x=fV$sAAd&)lr(M;=a*=k6B>y>4lyFF|< zy6(qTNB6Go-Kut3`G%gaJKIsDoj?C{{FWoTr%nFs)mQI55N-?ld3J~QkB@zG`>%Zp z*Qaf`S&gGx_`3HxzWDH)6JOpkJot{cMoy`o`dMz+E7$5Qryt&0ncI184>XT65?uYB zI55fgangtj)4IQWda!BG2U$OU^@t~Oa%t6=X-eU0!;Yi_z{+UNyyZhj!D z%aw~f2Hd;hCFH;i=B^v=lJ5xJ zWSEor!LFH$&9!@bZQ88Nj$9BLxjFW7zeVlGICdR<{ww>~m7OUA@8xW`5>V>7;UQ^C z-8S$3GcQN%IQ`|>EaObq$e1M^s_WoYI?doU5wGNSU^ zpX%~^tlT$0EOnuNcXIiZxCV!z?e|?K7ylAd_tS?%|9MNN;zgglzt%Qqxo*K#)8>ht zmwI1ZFG=U#+A+wRzv{6LLqD8**V_eOtbNun%9%b~AcUAV;E>+3hesFay*oA7GriPZ3y4)>Zi zajmb*ePutb^)6OyeUA+n{zTY^_zQo-AK-+IMk>U!62Z5>~|{&4za)5XJ2DsxWt8j^M4?FU~e zx~KcV{?B+r?jQL`&G5J-R~I~e(bB5J-iAlRO?6W*x1CqsGfBRBaPuRrvfo_R7_=rX zdD|RsY+T>flU_3Y(6v&s+<)M!=_Sg2`BkQ`Hhx&KZ$g1-!n>0zPwx6P^|n6hUzr^HMd}xWj-@sZ>mIpm($>k|i@nCpUeYmr z``5Ko!+t+MXQ0ym_Tr$eYj@mMpKR>f?M(9BRZskU!>iAC8k(U80cTuWzUx-~!I9g( z`}y3bqn=xzeJ1q6GvAM%-Fi#p%b&dSPJNpv60#rJ7|MQ4B;?A7o zXOoVXebIeLWNpvL_*hq~Hi6G24!Rbz^SAsZsmaflym(=7_MXebmTjEwS#Rvt>C7ANzHrN1 z5hbluyxy_aNlUHxQUkc>;Hg1%h# z-IHVYPAi}OO4X-pzxbwq$+V2R4Ieyxr2Ty#mlejT1;*4~x#Rx*&-Ur?Q`k`FkH=p6 z=aLtC?0Rw4J}X+h``)jg=&`-id-}bxM}oH> zs{Qxy&qjuBJ{0iTzK6$reOvCt@`tyk-Z~)ZCcPZ-)$VKUe`^dfE=`~P`yC(8TAXrj z$Mj&(ZQ8ckox^k|O3wvVCT6!gGxU}%FMPTAt!ZC=mVWd5`d%A0eVjS%iJs^8?C`dV z=+^hfu4(tRFL^%kL_zlQOKE3M9oipzc24k}YfGZP3w~@??E+_~g=Y#M^RDvzld55Q+yB){oo&iCf>Q^e8LNd z2akUCL|)%#ue|6vaJBr&i(T$ZxG?p#XXGD4e)%^45T@UdwLzRQ47Zc>+OS+(Tk}fz(3JAVQ3JB?m5ndbykhe>Lp+ls=Fo&cM z8!PEsO_B8BbEKefuN2gJl@!#bND4A;k%EnHNWrFEQgGX2Qb^lsDWu(HDWrXn&d@$e zXNZi`89F5ELOV>>g?7x;g+}G;!lH_GVV!p9!a9GX3%lWaU8@^H16pz4w4Q%ok$s=;@$y2DvtD{j*fI{-=grN@m*{Ds0fAP zN5fVctS&8Cw}AGbWOg zpRsI?39RaV5_AfGGJX{IJp3q}`S_Xf%ft^X0?b!LT63XOTJu<61)cKX!;ivQjUV}c z1V0+~KFjzy=#{G6@PrJ_EIck_RXTdCKly#J}VA=xGW5z+DywU@+m~1E-CVS^7 zn+8?;ISXc}cxG&Te7x}HS1lDHe>T<~th-oGVSPO7sjT12`V7`HS)Tj=oAnab-)Fs)^}VcDuzrN~O4d)ZUd4Jf>k8{XvHlzDTKM{dBH!VxN3d>YJ)ZRh z)*Y;mXFZkmG}bd&&u3l76yC_VnDwo!Z)3fL^-|U=Sg&Ngn)N!?r9&d!QLM+aZecx@ z^)%KqSkGiVhxJ_6^I0!qeIx6|tZ!v~8|x*kSFm2qdL8Rp_|jpKP7~{9*5g@su%60# zChMzNe~9&stZ!qziuF3y$9We>?u84a@!%&+nmI!npW&5;WzCVsP4h^wn=uVcB-pDu zeG<6KCIGh!#GCj~@Ry}p0K&iDJ;L#3F&csTH*Dr~$vrJgvSwyMUn-42{3E>cB&&C} zG;U_5G&6tly`b=sM=|T7l2_cT=#uT3)Tiswu;YW|#ed~-Fw=Pw~B|HO9U$YyJnO>IS zA!EtmxNH9WyRyOW6VEts6&B#t4Nem21gsV(&GgkM1c_L@*oxSnXf0p73o~)Hxuc--j$aA zmgZKZlAaXS>D`ULTS3zqP?t8#51G(kU-Z`GhW^Zc6LKkBJ0u5~@AL6@7t-!8R!BGT zCntcu|MwvZnE&t>BWZtswELrp10%Hm(cfx}kgor0={^r*EA3Aw{k^~DA*_;`{=gso zTYs8=^Z)UMAUAK7Z}pl7*X9?jlOHO4czw|$k3P2H@h6_#_|(&zp4t5Dmg480f8oV{ zzVxrHFTe8YYp=iY=C*&o^`E!jd3Srsj-Btl|G}=^rDc1{_wL(&pyJ@6!$&?mdaUyJ ziH}Zx{K=`R)1RLC?DH?qR-gOw{DrT+zNplEQ~T|A-~Ui|>GF?1{ak;g;p#8H{)QXs zBwawDJ}5ZE5E|AhymcF+scpOV5s@7_Ms@0ZLzf$G>T2%Ry+?Gi?Xsk-o;CDmfnBQy;J@% zHSNFKKd@~1ik1JX^Z&m({{PqXwl`+I+y|K|Dmd--kdgWe5) z(*C#8QTXwGn+Pca@50oCckPW_{Z&p|+F$Sf@8!11l}T!P7jHTpbpj-&cztI;7ImWn zkVo+lZ-d;CdH86Wy^Du%6tFh8C3mzQs;z>~ly1QYh1SR7|+FFl$Ii*lI~YmLX$Bb6wh3Y3*)4bDxZT)g#CDold-gm-)%i; z22c7Jn!-b;*}E{e!Mylm5x=&+Tg}+~i7?M(y^?kFDPgXy1E(=AX1$tqa~1n%y^?kF zX*OqFTSv}kT+F({ddqd(Kdvv+sGCNk9?SyfL)TV`wKe9y@=xp2^P2gi)#ZMmi}w7L z|9PN)I?^x?;oPsLWsW*y(b7TT-KGTw{eM0@8e3;0Y)UQVxOog($@}Z@Y4$-Wruhzy z=`(<5B2_bhv=E7Q8V&v`y%Yw`z!qTE(%iq6qQCaP6fu+kSxA=_LKD^g%D*TPSxANE zmr}3A{@3)#QK=xx5QQLOZVKVget5naSQYZh!s27<~s&4ycksiwSAF`Fsnz}@xo7%fvc1L07KU5IZs9cs>> zq*E)heop{rv2eR%;c2CP3=gFG0V74j&;x}Ii(U6&=rp=!@ zexWPbNlmKCqqb&drYxK{Cw(cTO}MciKQn9ooCVWJh{Qe9ld+K47{o6xCH}AWK>ndr zuL0;!T!#yRiI=WD4_}9|>fOS==sFBObqo7PufvaBhu;op>HeMTu*Rzf3+oFHK_uFwPPW(Y)oO3NJM?s)N*2^QVD?o0>gM6lv5F!nW6k4Iybfw7Ssjsk;t0 z1t+!ns#oL#htCXc=32^WhHrm-QOun$ZynOiKBc|wBftBeL#BT*^oPLa_T<#k%spP~ z{O*N$brZfm1FD0xCVLe(xu2juA75u*>Bmn$MbAM$7Vh`?u^L>%`chSg@;g<8KRnx7 zx|hDc4qv(sQ%w?&pnu~^4SzkJQt*!7{mK11k-h>y-ZJJ=NDt?9Kdx(>QZXQRkRMYx z6s8s)k&8xVS~1YbXZ}`9C@#@!g38Fy!#dPaoTgK-SoM>CFR+>>zv<6ev{jC(V7Fz&-Rg)yz+ z(UZzJRzN9@abLz6jN=$*GQO2@4&yr*=Q6&NaX#Y&#zl+=GTz8oYj}zoYZYfJV+*_A z#@NcZgmE(CQpPsM6^veIk@G-K&|@%>U5 z8yHVyY+_9F9(tk}-z}hIW;~N|4C9rI;~7I^=V*C2dC1b%|qKU z*5;w@85@2O^p9X1#W<324C4-r6BtJ^b};V5IF)f{#uIt#yO1R7#A_Vm2olSevG#<9>BPi@$HN&8Q;OUn(>{C>li06mM)3>4rFX%d>3Og zV>-T!o_NMX7+V+*Wt_s;!Z?kwm2oEHWX8FSZHzZEwlm(!co^dn#={v`Fs9S^=&52n zg0aGQB;y9gF2;t-BLAZpM=>7FIEHZw;{?WZ3?MxY#uFK*GM>aZgYn&ra~RKLoX>bJ zA|=&<5b2sGR|b&mvJuRM8+E#4`IBOaWdl)#&a20GS=~cs+zH$aUJ6j zZNT-D$X_U96XP((X2#)+;~95mY+;??)s~9ITRv7DefY-oS&)D#@$bSgqD8`|TV;F}qPGB6)*ul6n<5b3pj58VQ zc)*y;IFxY_<1og>jKdjkW89f>DdR-ORg85!pi~%#GHzfT#@J9V^4pnl6yrq3@r-q5 zwfIUF#-WT;7>6-V)BH2e)ci*a|GAof#zmTc#>JX{#@jUiF~WbT=AUt;=AUu3=Dx3R zU#GceEL{=#4P$I#tcw@!&5T1C$7}8xTQv6rg!>fDJ>xXZJ>yKxeS&bGtJyOy((DHb z`(n+W@ixugBJ4{wd&ZR-wh8-c4Lby`)38fmse$vKBCv_Eewn~##+@0*GZs=C68L1Z zRfojurAOn#J6Mt+9b7qjh#xI1 zNDr+8&_n!wdKPfF3m9iI#xVw}J#l&IA-)(r#OI|aoB1-?(jvx-Rh>A&^bj|f9^ysP zGY2`MhxTyMlkLxsh-aQEl|piq0?*=fF6R7YfR9PfG*FD5nVg>aoQ`Rr06lZrA8~={ z$zcDqjzZ5|c0ZTH%LaFq9xsRM;rKH-oY@=?aUIO;<%f8^;~=ji9x5MkQj(<2f2f?qNp`=S36+mHDOu9yBUDb}AkCxA ze~6Ds*v{bzuI6z6x(=0>I7sDfgvYXbDnD_s)rvbwFU3IyW&+z&c_RC9eoS0q zC*+*OL**$Bt4f;x1^D8GwfPs7uQ;qiY4%jkD8E|#RNmr%H1|~Q2y5|E`J?n`?x`FS z{j~g3d5i-!weYh+ZL-(sLFF?Jspaa8*eSg6{_v>0Qu?&;sN7QixOqToD832Jz8BFe zNtFX83Q)PG_%!;`8Vh|tEq*HJaY&su-=y+RSfd}6dx}rXAC><&xYp*gR1YYBLefdp z2f}x&p%BMhYafViP34B_NgRA>`6735@THZz9F;Cj_PF8=rCFs;t9|fI~{q-+fEhi$M&C?;$-;_@+T`5dqkuI0N-iUOK z^QTj!%hfC$RNk8673mu8Pq&sX?R$y#HmO-U=VJ`fRC7iAHh=jM@w@%)fEIsKdr0v& zl{XQ8vcJ6(@i(QH)~c!WTA{Z5{vsXPmlf%7`_n1t@AQ{L5l@QWUc}?(uS@MVm9syO zhgtxwgo=2^`^%4rr>Q=Pcx?XsHxIYvcb%`c1TE7)8Z}8gBHR(pFwtS6KR?;3WJps_ zF48sGZ!i2O``ZzX&RV}p{^?6-B}@3%S`jhMBzkD=uSP$uy%p|9`12{^8}Bbi!oAi1 zU4?sBv-D8xcdPOxlw;vut8H3+8`;dB+^6{45iLJjKQF?!Hp@TJYl6RC2>Yb#{HI)J zKgM4^MEF{(sikk6zuy-2j%MY6;v3bh-zS{n&wtZ6U-a};E}B0Y-&kw+H9mb`c9a_| z&QTDfZAmioI)@fU5!+X>K{4Y`8E<3!Z^osJiy2okUeCCi@iE4Aj6Y^9g^2W=U~FRi zGGjC29gO1{?`3RZ{2AjE#@aeT8sj5upUHSP<6OoSj5Cq@ z<5IRy*X)_TI>wc3uZ;t%882u1I>y@>$FqNJozP$q^wR2&gYEU~K8o$N@l6clwQQfl z?t>U7u)Wq!r?S1auIOO<=h=NK<3|{0FxJ}T9LE1)`+UZ)GLB(Bzcyan$o4YZr*Zrt zjJLAAwoa45_6D{uVfz;tS1|sNaTVj&7%PkqGHzh}C}TsYpzlt`QH=L7j$!;Z;{?W^ zFm^DmWSq)a8!u-tE@k^1#vd`x#^oWuAG<9xajE$V%TiJdi+j|&m>+DgCx3c}4j7u16EMp zX&he+<0`hlkFlBUyE0bTej4MA9DWJG2X`Uw`Cl~?dwp+8SK7*aSr2g zntzVJALD$s7hE!|8?k*)w%^G1vl(01KAQ1XwijG9oS@G5VYbg<_pyvC*nU3aD#kv> z2F}l5#tPd%$hd*SOVlviuV!4#_VJ7jt;P4;%s7g%;ND463}Y|bCorDCxP;D)TpRYQ6r*)qK=3f6?NFd>i;=a)yZTMy!XEE_kI80`~AL#lc!GA zsZ&*_PF44GS9K@K^i7i2)~T2zpC!}pk-S6Z50!k5OwX2lgG`?+`Q0*oi{yP|dLPM` z%JiEhUnBVx$?K(jU&+_W^cano=@TS>Sf+25yteMjAo&KF9w+%Ang2S;H_CL2E1K2P$yCI77C zOC?_}`5MX3l6;-yZIT!FXKCkvIK=PWSp2Sb<>Tbj8SVFVf_&B{(;bap zBcG~h{95_+MB|fjx8JqAWZa2!<>{V>E1!zH5U%_!Zs~Nl)HR*%cDnM~-EOV?jV|q_ z`+?%FV7$xyKoKMUCL>+bK+mN{q4t`7@f=2bT1U^V=>7xkFA#^gFBJz3wA#N}k9b}~ zcL&5Fp4Y@T*_rAxim#U!>EiiK0`7KeJk^8rx$@2XuEqT{`s9qdeHGfi5{Y3hjrhXQDikp60 zlV6H-?J1mA9<91})!*#rLVi<|ABy`j{U_43r;nO`n~OcEJ!0>FbNRL=zZLoE?zpS| zOt87QN=Lnhxy01^? zBuxYH^t{G3op{%DvZz)g?YTlTPtVh7mzP$aHh$>sytJl4q=@GntNq5hz^qliPS7qB&*zlHaRzpnOijdyLYc)q_LwGfAR4&PiK@!Wvs z6EVXy^I`;Pyp~_^iB0tpJne83hv3tj<_E!NG@U=ibN}Y@ueG1qw%CK!NuBK^O2~cs zwH0(5!*-}@EurP%moo_M>v!GCael}aLbJ~k+X!oKxq262cJ9qP2%T$Qy`Rv2r{9Bw zju&3oNoZaevx|@|ZvO~j{o8vVC3F@>K1OJ`aQ1OR+uM&mNoe;DeVVZPoiCo@yzUh{ zq2c?x@(61^mgI9>-M@e^H{f@U*}9rS;vJz|iwN~E&n+f2-5FRySiAcu$NGx}rJOHc zQ$|={W-KQ}Jvg$*U#TEI_rBZr5b8e<-%Dt}#jBFgmhdje>dL#Sh_4ME#P>rvhiv1R zd+-O2#*x$iN$IALe2$ji*t5jzBV#x^5?|wJHuipw;vJ<~9F3oS&e2{q?s`kPKK5zhjXI9haXb2JwBsp0XS>p2>O zKH+HkY3R!opSv!bqrLJlN7&~Tinqt)aJ1Eb$FchI#8)Z4{`h?yjdvgCX!>=^K8m;b zJjhXh{3nj~+orxo@!6k0$dR4+iKG3^>tCn%>ZQ3H?G?v4*4Bo;!Q~&hm!ol%gQNYe zp0!;6!s#3>uO)NL_J4#U3wwj3eqjSg=d^$~N!}hbg=2Po9LL->J2>ipevYGY)=|Od zc)dmPjy)qe);}M`(fQ0~j@c=N9IFinIOe{1nj`x0ZOUi3f11GhB#znVayeRbH5?tz zZ#f#@X}6!Z-#JgynUlUUpq$@{Vqr2y(c)Dio5XrddA{Vj^=xB=9nA3jiaeU zIY(RJCxRbzmSg=rz22qr%!gHu_5N0l*}?Y+98ty5(e02(|GAN)EwAr;+#b`WaWoxR z#nB$NgQM}$DvtUipK&yMHgYs{?^8$lasx~pYtP1Wbi8#JN4BwoBm9q}-F}LrtxI>l zKe2k3G5Wjk$sZI(YE<9j`r@aaIAmo zD~`^9OB{{qy+5Y>7)Kng9Tr2GHCv3A5Mj{51kPpN!Uq+a0i zejJU_qdBsLVI1qj=5e$STEWrgxrU?pt1OPDvb#81Y>#lXk167a`GI5YBX4o6RzBtE z{PsJJwhe!9wD?@%Xn(N7L8_0rYcGzr`+_;@*(8p}wKF-^f4rC@8xbe?J8T?HAKlK; z()B)$hR7#4+V3vo=y>@hfydtASnYL)qq*NPjZu%vZy*UvcpS=cgVV$rWR zo(b#l#`jYbr|%C7D0h{a0#z1AP{Q-B@?2&ybyF<8H|^T-slRf2+2*0vy*-q&m}lOZpA(>Lt@pO<59pyZ z`iz}A+INgH<@*soyc5_%d3<5|m6BJ7D0gmiyzs!8D`5|JnE&1rV+JZ+{WnH5q+bY2 ziGJ5--+}9t-E$%@{L-zzQZsh!a#N2n%7oB_!8<PyNlxcgV#e59fm7ct;H2f=l4_M7ftM$>)&6QICS~dtj>*LAM~jkoD->6)?}=^ zZSlj7Fkzn{W$HsSPn1@BD`j7w?cI2zUg`Gvk|7t5^-$h8Uirp}rh)pCL+Qe(WbBRt-~(L-z;NO%GBget2VtR}&0Mp>F6l{}4ari;WMwu;l(;%HvPn z{AB-8zl5#1a!1FX;#DOue$kOmPmEUlC&cy49XL$ca&uN_PU<+Ns<>j_nibb8eb(Q9 zbj<)~*zdijjQw)XRHes#>6;r8x+y`c?m2nlf$_?!^&8GUy)#UyvES#sK4P*mB)a^M zPTyRwyfVpS`8WF~EAM^qo8y<$y_7v2hi+Z`@dV|SmxnLTSU6dU+Me_9(2(|ubM6lv z*p2?OABQT9_x}F;U^ZB>A3XK(j!)6POh5n8!TpsFN|uj5ZR@BEHkEe0{f-gJb$9oF zJH)v#6LR!(?|LK!`v4J<|xX!N3J^^&~>8nc<20;cl8^s z6umrocG|-um1EJ$ria^wDj}ZF{5s_17{zz#{maiTo~%UdU)q@Z=0xR8?5WNJJ{+Xv zFAn?M@cjg3>8ZP8?}(hDbbj*CUzeALDqnpWymhp{QE_}XV^@9GlVQcnf9({nAFKp? zIj(co=po7{jrv|kl;6Yt@zLDd=U4|S{r6_i&RWqfhb@ZuM|w)rxO2c3fvv zc168A2P-Q_ z=D*pk!(U;ueEa-7GirkJk9FRS#-FZNCMO?pe)rg5WlQw~|NO^+iAr7Rb!^=YAxgi` zx<8$xPEzg~zOkcz*?8rgF1B*xr`IdT&b_@lO27ugz%3LY42=Scbgy;0Wcr5ibt;Zqsn({gkbB z3)crJ&cx0?hAr%;{P6I`%nvN*!){oV{n_oSE{COlx2EU0@spIbcPgj#FO5;U>Jwf` z$(gM5y0@x6aq*?FTZY}&JL%pDsK>ei)?HV_9%ZWc?a||vpl7;x{2Vk4VL zCMta%8a`!f=upMDvqz_#fT_yW$aVJ}4I8WU_+`M|pZ@_r{bud9oy&(QJBE&qng4Z1 zW&Z^4;U|kuhJ{QWnd6)`OS$=mb0tswFn`t>Z97x3H^^Vdy+% z#V22MADuNviCFd3#+Bw7O8<}M|9Yrwp0e-r&2eG34O6<7@4K+_p9bZd^`FEWR*Y35 zhL)fH>CR!wu3!E-lQ2(JI^Wo^`IXmaDK*6lt|UEqy;4yab7#?-5z42(ci#B+f$554 zp=tlT+F{C5hch?LO*biBx;yrJ&FHP{ium{~>pLdpqX|dC1K%63EVzE{lAVQVVbhO> zd-`59C})oR;A?wev@-J^uN~)l&sCO|UHmTc4@G&+dYt*Lohj#s`HJP(r0w}B5sEY4 z|74YQmXdKIqUuV(80EcB3%B=veV$@nUwU;#^baLu@^Oa?1{7WA4ny2^|7k&K2 zopY2|mc7%__JvXLd##~M^7}KCZUcXKsOQKqW!l!5uKnK|pxl=6)qLggp~{Go@T6xN zFNclwIq6X{yT9^v=9bNK_byQUevZFtOj@9f`Qymz-rt8SJNum6IwEnDvbpfZb`TQ92Xdes-})?HNR+>_WoeAz{{S7A8* zUsUaV-nnb|$cw7S+)Wog>yCK44*xHzN5<ApbyVWo9?yJvLG{QxzTnfhE~sDW zm;5@Y@`5Vf7jr@VtM>kmWBzeLO{?*5JZ`(7R&MyA!>cPVsE%L0xLh4^LH%ju6L-8D zazPz-tbX<-!v*#8TwRxi9WSUCgPwfg%?pjHI_c!5$e$Y3&w`Bi={{>zr~HKrsW%$c z^3!WOzr3eWee!PIx!T7X)j8D_&L6iosxR-X-8VF&Q4QK2i~o&kpm)|=Y+5g{Ag6YgDlxP??%;hhwe(dGw0R53vXOB_}F>%OuO5{W9rYVn{}gi zKKJ^0_3aZ5p8^J-mT)|PqqoL4)(`*?uQ#`Eew%R-JHU433%m#KT} zgQe%ySv_vb_;luZ^}eg&?>IxwtNXs4bw}`^^Q!OWC)Z_lJ+IofbXe)|IIs4woa$~l zbxwV6()6|GzdxtO)@>P5{OLKhNAjE9lixh2hV?4&oBhvoYHr%%Pp9UcQ)}yUrrhu# z(i69IPuy}&?X_Ar@tIrBsTT$;T5}@yoLVsF`hP5pJf|k~@36dX+Bx;x+Iwo2jz6cG z;&dA>4m_vssvMj6T;Ms?yL+@{OS^OG{Dme-=nt}58i)PwX}=YEzLfwPFZW7 z`uiPM=XHw;NO9`0h}*6 zf1|v1MqTknr2UJkGwK}O`n`ALpHWxWKl{VvhtH_l5xN2Ga?Yr?23Fqi{iZYOD$DYa zkJp`1AOGa+dmmcPs2{9<@7R&WXVgna;;fCc&ZzVMs4xzlaz?$Y-{*r@jXI+)T7L78 z7Yt|AKz<;)CXUH_ZQHq1 z>fBGS<}LW`l=^7)+}gp8Q>xuOO6T`EaO9Txm)<|6228r~{tK_4QcWXtd%d1NrM7$X z^v*tIr_`sr93K|`^eMH-t7b*oL#NcP)j3_Nb55!AKh6uic-tv;!q6=>=JZqQP~8`s zpG!QYp4^#j8*uX}_1O&%-u~3$Q|it^v+@6wy28@q(U+7{>UaAd&srLCN*&(CK0r78 zl$v#^|CX2fol<{V5|O>J+bQ)(?P~uUI-F9w70#4|wOKI_&pZra7;kRDXEo)auRuJgGi% zYp>XsOHQg!2RM4_o<6BQnSXEg;$0`zuSewGS$)q*wM)>JfS@fW)oow&?s?CKlj_Fw zX?J_4oK$t=E}QR5IH`6Vni+H5ij(U5pI<3>dC^Jr`j7lN#YCJ`2i*{IUnljX8c;U@ z|4*uWYJb0b$Hs`-PTyZHNA zr<(iZPixPfaH;{8txLR*JJm;KJy2@++Nn-?dcx8f2c7EmU+r6X%ll6Cmhc_hOKP2J z-BW{4{PdDjec{CDv@umqwM3ujx24#rTJEeW{`x7W8s)2-tUl~ik6AOHtGL&xZqrZm z>Awy9uQkJ-xz(w@d;SK$A?Z%_QkRWSzOcrrUM@R%aDJRq-JY3d|6{pR^$Pj&{G*GU z>N^SD56qtJRP|or_z$@ow!ZXks8j8AbH5iJG&gusZ5y}6G_j#%KemfoN+tabLg!bGl!HyEXMsd1W zuY(UxX6uk+81Byzx*wfo1bs-}J?;MlpC#*wZ({QL;ft6Ym!zysN!^fQux7>MO9*&% zpRA1Y8uD?m2`ywTV@3OYWImhZ+e<#nEj>r_zA}Bcc-bd-e0EIx#d43d2gBS za7%Z(@ob!^uU0=F$!p~YNnTq|9V~gRzE=+kyUF5Mh)nmA5hlrN`XeN-`NTZQdq{b+ z8z1E+AMKXD(v7#c@rjbx`Xj?FJxlUheKxzLXS?y++~jlI_T*+(e&33t^?{?## zbmQ%k*X&d1mR{z04N8(-(fA8_OA-S|Up{9!l#sN^+! zIo$Z;Zt@Lo{0TSSDS6Fb*?8ga8n2hU=AS{5*Zd_|@`0K^yQP~Y-$kY;N?u!UnIm~^ zJ!Pp|dYxN(gIl^!h^X&CsoyAhZM~~m@&=inCHa1m-!1telCO2k?~uGUA3G(l+5e2> zo1Ps{5cSdI^^(`>7b1CW{xL~jv$t9Don(D1lGoakEqTp;cF7Nx@^zBu=NiO0-O__5 ziu!5m-y@h|&rj~-+kHOREys^GKboX}YU6{23VUel z;bUUrV$-b&n)z5v3_jNopA59crsLJQ(v0BKGZMgS5iv0tiAf|NBVuA!#inPt^6T+E z=F~JT26~e=D!xq@hKT;46*mdVRGT#|7WE|# zcP;t1-bTPFM`5E1{xkAV8k3`x;rQYWW8~jZ#il|B#F+vd2@D>_=-cA#X3%EP5M>Z&(HKnbbit#Ui>(m+NM<*41Q?D#MAw;1mk ziD_2+uxTFlOqe^uP?$ zXxf;b9Gjl*l4^*}Fo;u!YkGKETI@z?SD7Uu2}2!UwcF^DnM)X^r>?Wn3~g8#w+3en z!#vDmF6CNcQ&Lklu1n2KH=zHl={5{$shZb!Hdgr2TEsLUt)?{aFs&O+Lzup#Al}7rY|%Ykc+;vUtny3TWRe`Om+< zKr3a*=V;#teY2qX3o^KYf^udzO*2#<(c;SPRuL@_jZ;b6ob1v^e(TNc<;sxyyd4keHmittzt2dUWhlp%*LBq zmb;`c1|NZZGoWW4kdBou=`$d`06OOLoXvU{Kz1?oQcgNzG4AMV5893hT0c%BM~g|o z*rO3k>*V7hPx}pM^}qOfB&|oL700B3Qt5k-^sX{dAG)@mg*wbbi4-#$v=rfah+81v z(DQfwL+x2?%@CbpPP4AErlnaEmdu_Pn}Qj1wUt%`lfD>~NN*mYduH_Jw-|Zf%#8Rb z$k6e3_ks~wu%YljNCYqdj@ ztDi39Y9(s@sG&{9Tdt9Ak^O92A@peZ>SG0et#oGj`}A7tzetb&`*i0`{~}%1_geKc z-T3$U4a-G(y-i@PM6LZzDB~TeLe41>1CaNl>-S|AC#G(gVO?)cri-l^NwKR_Qq%D( zjSqBJxn=kecj^ZG449vaYjH6T%*R*AFeOb(&05CiVVqs~J%91sm#_bZpuGQYdcZ`v z>bt~;6aH8hZXu+5kt;ySGdx)GaB*i+OY4aEJ&3A9TAf=O-9y7Eie=p3!7@gPe4#o- z{BJmXY~sFzyXv}U#r^8T5}$ug@D-Y1X1HDp{-4AwSr30%XuYhTLt=x(+D&b@>))-b ztGVr)@J*iS=m(-}93*dYNjJNMDGTY)4tgR)VH1e!B}N{u>@mxj#R8W~wI=6Q-;TH;!EyvmrHY?aHy^R;I698HW!=r6pO@SH`YO zm>7cJ?-V1Ll`GfB<2TLN5aVc`INFvFhwFgpQS<17Rn_I2aN1P8($j#<*L5MRn$4y6&g|?LAc}*?i%sg)d;+o4fM^oPDmU7V~ zXlWV8^(D55i{kohE#tTx#u~rZHhQ%+5qEz0Pgl$XY$e%f^{S)4}eHf`FJ5C_w-EX;4ExP~5`CGr}Ud9Yl>3w{vaQe2I= zQcRYktwJW+>VfZMf){9aKrSY7MmV=_tp~Gk zo1~}34>Iywu9i13wsCWRbQ+K2?SKgDIkdyfp3?($U0FwG2ZwKc``UIkFN>$q1C^S3 zi;n-s(RKD_ofCXn=MW#(IkJOI*TaML7}wRP>(Y*OiR)zRXz@39FyfnS-X6?*oQF|2 zz>f`p#_rBQN0)kiEtfEMFzfuhm|sXI=J%|(&DTrEyr!W7`SM$DL5y_=(U|BBl)B8i zKwlPktaaUZdL+v7@nAlYUPc{0co3KXifYdSL%dnwIK55O+Yj|d-KpMv{aN3P4yZ(t?mLC^FF5#i5nm9%aLJ<4`tlyEpS2=Pm06TWV>fBcuxpO5=I!JJtHzI#~S7 zx_F814t+uO8$IC^TXh#s*5j0Mg+s=cv3&GdBsn0Sz znO}k{5Bn#0A{}!i&)*68J0d^oFUpoS>I@rof{i-DMzC3$tBv%qLuc5i6YG=aVxyjZ ztY?NV>xn+-i9YCww)Gs>&7qV1tPApFL2-e$uH+}3z0h{prpYetg@(CivVQpRPY2Y=n|!T{59<=;$GSjQmvNmO)Jr;ic%v)q(G~XSn%3FT(dKXI*$?01 zMStmc`aAs`KDPE2Z!?Xh2)Mhhn-A*-AM6Gn?1p~p7KsHlBYase-3ivg>Fa1;-*Wt! z+hdFlfIi)P=IdJjWYIC$~Eas6N~&JXY$JYX?KgT|8#K5EnvZS6SD+pP1!`D7a6xF2_9erfPy zd^E`?&CBL#fo+7ErgJax8u@nAv5s32kuT!jFT{6GK<%H>an!Z4~zeOY(i4A$A%(b1vS*XCnsZ}x`$`qO-P zXgbp$MSp*bYo__aMy`BMIVO#_VxB-9<`LoVDwfPrw3g*kc$lDir`$qD) zrC!*hGwjg`_UH(E__LlnVGlm{!tPP9J8a@=d(mf|P>+tN2kNsE^&q<*hn|cUdYn36 z59Yhm!yLfp9x*33`Qt^#j)0zmKhn{bjPE7J`hheVU3(pT7P5gj*Wlb3i2fs=(R4n9 zEA9_LFG-y}JBvA_W-G?gAsw@O>iG8(d*Z`c*P-qKJN?X*W<(lYx7HT%s^FSJ)XA65 zt!Wq`atz&~)3HxLpF)2x$jI|yo9&wbIR&KEJs`k`1;CF3(%?JwzP0Ub-WJm9fg-K# zbZnrvj$M`YE<^ZD7rrgq{Dih#1~uuI*8y5xJHb|iK>ePU_H{WIYBFVhI`%4Pf|Thw z*pGEbpLa)}cTel$)H}pkk$f-|_2lh^J$mwMljiwa^Xd1y=vYu!9ZQt@bc21_;Dp6& za7ZK@jCm60d>frBdX8w%dS#qpy+Tf74t6pcn|z+cyery@>xZ-sP5o-^fH?v4*#fPe zeD1#5=Dgy74xP6r^Tzqs+lFutKh`6v6Xvy!tVd*5XMm$~eaBjii$J<|!S~p49tp&G zB=A|iEr8p|m-$5^r|k1h<8-VMv_)$ZpDQ|JuIR+NJd3%)AJ@HU?b`H#apQID3DDy* zZvf?`Ip$e;#*k&yLnaH?4=-qCbn;-G#`zg_LEe~y+G7p^jtjK(9My3`zl=cE8}nih zT)T7~-|1ODr;o$C-m6x-c7!SAyomE$LVL`M-mKfW0Eey}u1PX*4dOBu1JG9;;_%xN zW5DvYjvWZU_E=nE(y$*jY;f3=Vu90wl_d@%7 zUI#x)<7Z)UhLGo3Beg^C&GZ=OdW>^@q`xgd?}adUgth+JX4bI>K?gP4(K!=sYHQ3~ zSfpc%BX#UoO*Rm7$Xl(ia|8O|T690Iw=kdef!}D?Tw0k8D|Bq=O8De6!d`S;G&p1k z>#4hrb#nSU{OWyby>0C*Ug(TLX*l2NJ=kw(&#zH({u$-VdPn7Y^bWb-qqpuJ57+Al z6Mp#g9NU5Qi+aSPU&tU=H^ zWrKR7&V>9Ley5kQ=MbFZ5;2$K<59R0!mQNJNcE=iSWA6C^GX+7Yjp6$HCa2>{w>6j zjnQ{)*|=!6j{OE|vN2uvO@kuRMdv^diCclaeOT`d*aFwDy>ac=dt9K|*Y$VLxaK(^ zEk(yRf~fw4zHQ8BPuX;=9%P0Lq0U3cufce^T`<>rcrnlJ%-h4FLn?TkC-VTWv!O0j zKcen52l`_U?7+H@YqosPKAx--Y^05|dXnY#hV3992zfdu`v&1!`e0zwIiu<}oHIZ+ z)QON^cWo8dUF7@MMfP$AIl9*e)^@Q4SoAy}enzv=kHG$*r|kkyKaBep;GYLi$ACw1 zj{>CeJ@Iim{Xu^1Tkl;ft`Dj2VQ$uLmyQhw>5!L@_tD#>v zxYe&>@U#O%oDs-+J=@|}u30yj#@|4kV}e)D|;Qc@CZ;<<3XUt`t#5I%1 z#{bss6!tdZ9)si55v!E7Ake|1o=n1cjqd%s|`6V&*{=|3x%hx z6!+Y2L73<;>hR=p+=E!*!Hg)(lEIh(E43VW#ZdKaxHq{4ad!go(mYER@K(lh?|=+= z2gz-M92QqOw*t382Jr^SnILC?oCEsokjsXg8FJZ>GeORPm$o@b4(qUt*~kapfHHHz zXM?wcw}5wocYt?*w}UsMPA1gJ4!suWH9{{f?$SeVJ?iN|`F7}aqI?I+H=&XCS-=~h z8+T|-$XDGTw{`{~??B`m1f7A9?~8jk{UF;L>3tyA4e9t1XoS28cdBZUpMDfNA)h-K z@mNFVSb+TS71JW|51-%D43OWh$zR832 z1{py!K{tX@LEAu&fhs}!L0^HKAn%(Y4>E#gf^Gz*g0_KngZ6-GL5D!UfUbhN#^Am< zC=3({S`FF^+6gKJy$(7A`UP|q)YSrcP#7o@v>LP-^dP7h^aAK0=y#B3tOwJBfT?YBYd9dq1A)q;+n?W|vKR~-d)u8>L!=Mu&7LR*~pkUBckQtN! z$^zX7$_Kp+`UvzL$O-bseVgu};h@Q&xu6(O8YmldKj>-D9?%=0Pe4aOe}Jxl0<0da zA7~sX9E2H%p_R;wwPW6_J?;(T+LCo({;VUzOvCgHzd2b~-0SSdy0acEi1lQ>SZ~&c z^<~$we$2r7vjJ=%_L2<7`pBWUCp`>nCr4l{i=>c=k;z2UcMf0j=*@gQxPzcot6YX0x%S(-+P+)7|(P^X9SX z*SGb>1@>^l5Eu?ip*?fP!Zc!`I)U6C1l-e zur4#Xb*p%!yH+0Q-YOp1md;kKBFR>*N=<8BIK{b_O>yo;Q=EIr>4|N$hDW+<|kx)<#d-L{(aBwFp+s>(8-OKQvPYqhdhTQjinfEK&Pq-3ts zVw0`0>#eN}whq>Y9o;%bi?yy!O40JmIF~l2rX^UhCM+h-RZNR)LoPWr)#hp=c~H?v6}IUrh*-lE5v zB3<1m9X*3Ck-d|yH6|U)S?q^NjCfEU!!r(c zDdN|~W;GQ^IVp~EVN*yGi#pk`1T(!wjPRl6I2WJNGH$>U9Z?_B3T~a1t4K=0));yH zK(aIjnrq3qmK7(dnBiq1P7rRoC87(q!u4R##DJ=>SY_kZi`slf| zc9bV0T&>gC7D&&k>9|p%P2%km?~(Yl#C;MENIWL-4~bVL1||u;28rV&E|9oVVur+Q ziMu6MORST4Na7z7ebxy5Mu{eg^CT{nm>@At;wFjrN_<>mxx`l_ek}1@iB5@ECF4@&$=;u(oP)OR?7BnC^IA#th1RT9%A=16>8VvWR) zB{oRBEV27KQOM`c$61O-WQYq6iS7A9ZEj`DYD(_`Dhg-Egtef|; zqy+2q#Mrc`)cM#;l{9T5cBTyzQnQkhtt^T3&BJ+XW?CBUMH|HRXJUDBid;rKI{`oa zJtM5KHeM^+4Q{ec*(8DWqM6CE zSE1tvO$JrXpesl`ot3$G>+hpH3$QU_y>;X-$dW$WHRMa@i=H z2g4KAWTt1(&N?=YQf8)L*IjA~MJ&a#INHCsj4ks{##X*$YYJ+#fQRGP*^-vA@3<~L z-e|88Z}rDskyf0sq|fyuiRr@YHEWNDAI4)@tT{D_`-4CH%#|NN{Z6)?A@(UYujYr> z>tVbrAI&g4&&BD-`+3YH9GR=AT!?KOvfe!D1Z+B&RS6q`-BFWu)k zJ6+m0HEkC5=b&tChe)S>{gFx#sxc$XB;79a(stzJ^X6)6nwH~^X1j?Y!F%>0NMc+i zB}}Kz!%AlMiVpS-pN@N(cFM7E=6njjPqEX@+!N1xHqDMvsoIpuUiO?feSWO1X{Me; zbt3yom!Lg94sPEj-$K8|kd(_PEz!-Q-%*rLOw|}uK9oz&(&C&zHS%(ar3Kme#)Ma7 zY*IQpKVEy)$VYNKle%T>d$O51J}Q-1Ovd;Lp`CvIAO06D@X<|%gR2hx_1C!k??yc~ zLOiRWD+F41?Q;#CI>R**{+rPr(A)M^@_$b;=@nN!|8+guvl;f0SRb#|Q$y118va)$ z?N0mqb?g6sr?;wqR@?Q>{zTY=eJU{f9m%&+@b?kMTZH~f)` z^HW=Yg|y+CM_bzd=f%aw;ms7QRwpK{S)05rCDnEdPUo5HH)L(3r*b&Lr%j(RbJh(J zv**m6H-EuG^P z>(-51`^(7U??fQ4NZ^)d9G59%x;>j?DdgWQ_^QAll3V@Va#ci`B);%(%7;t&7a{*i z{_*@??8p3u{1w;Me|sL!v8Wwmi@v(~D+7!9YRy;UTFZZS_*=&X#>U<*YIYSTGFPG9 za$YaITg<=zUA#jcPfER|Qty9?wC9-UfBK>O7l()2;VBQT-R{>E8c+R52k~@mGsYlu zG)k19$&j25f3*B9rT*7(iNji6CyZ9Zm&V~~Leu*LO?c0d$;8@{bC;o7wIxTd=D}^@ zRjJVP|BnBr1@w#+b(MRxfF6O2J&FBVUchkB9)wo{D?!gATn#)2+K(`;fe8UonAX^& z_F(J)!Zx6P5M##?CL9QIB1~(Nru4+U)CkA}_koNE*8->X!rCZ=rveXxOb8zW-hwqe zQ3%sop1oMhlYlU->G>IJd?-w7eQL1QCmUf}^HbFy^(Pr%@&KeEOzVTj3>0BnC**;3 zKNL^vg?^M_S_^c~V662)Jgo^Djx|9PrnN!e%kXjFf}ymg2Wv@yugEa=jI)4X5s!W5 z>=qf$0QMOs+Cum(i1IpsWy2Xef$$z+8h&?CdUJZW~0u) zXE4nh5w-(ELqr(+_1UkW2*hL0JFA?4^+gC{pFAs?h;tmmct-$RF-gc^pFQgzDrB%X zpG}x7WU$|#JqV)uV6Q$qDZ^M)!WMxjJ_@+_deN>Z;Owa)JP&v@3~QoL7NM7ldqW5l zR%57AnDEDN#tIR30>h^Xop`?i%ah?k;7!woA7URpdl5uFhCTOe!VDp=t;4E?9$JsJ z97Hk}VDc=ixk5ax&3Y1a7-2hb>cu?~#lXlQH9h5y|D??+7*1?5g9UO&eJ=~f|5vFxpf5HWz zWW<|+cs~I5c`QU?;ULm)2EG6y+u}U~Y{D%fOzQ{3(u96m2e>00d+(u#))EfNfPW%P zYbGB9QC?b?ctnOBzZyz`h%$JTOLvXLWb6eJ}JYruJi{PrnQ^nH%l4doia>o zLw}NCS{FL&HX%c6LW^aX)~sHTVOkeD55&g{uuO(&y=uT6BA(W$ZjoVH*LqlnY3*om zwvaIbvt&3M_>BxZfMHvN46R9hN``68Z2PT@?S^mAy3|``I2-u04AXkq6?Y05T3`F2 z4AUA`b(@H%b+Q#QOlxcV{X@hXfRBP`zOn=7ZWn%N1_s}Sc@pIko&b?=6TW{p&R>W> z09<;H7#GpN8+M4fHv;(GeK;3G#sTdAfRGsk?3OG1KL|MVL8%{T*~wS~;73V{QOtBb*J) z1LY!I2sA%~xd~yyZ6Io6E-=n6#&`m71Bm9jEMQw z;{0L&hJxx5Zvuvc4k2s?E&?4!I2U*YbQEE)BKRtZ>JSZl9Yp>{d%`{d@%a|`qYO6y zONvF?OMz!f#I*B$AoDu=D-d9Vne6J$a>;S&`id=xnCIn)y}Gk`N* zfEeDm8xDVi;h))0x`B3<0FmTWT$ir5I`#>a5IQAnEHUVFh;TqsgAHz4G z#{#_N6P!B{&H(y-Dcb7~d=2C?A2tW>I*e;YgbA;JjL^@H;Jg8%Ium+*C2UKm`&x#9 zNg(RSWMKQFqCT#BF=>yc^E=cB`UxjHFsCCt75FxY+Oi+m>wD4feSot-$&kqfUIfwk z;xaJen2;wd_<^x|AyWuckHc;Vn}F?p#I-cSKENR$s(&yr6-0hj1N;g^bv_EbEaM6L z{3PoDj0PQm9>Nzve7rQ^o&<=(`+*l^_%d+RFCyLuw90TI(BpU5b^&}I==BG~Nflw> zkALF29r_!9FFJ93kN6s3z$wuefxwv4Xfxt1!1ZUuc|Qwy(|PnG@>+mjHVPj*47>`W zHnIzt_b!UL&H%g>M0MT+{0)={ohN`}FTsWghX8e#Fte+H4B z24MA75l@)@mk4J7kAZ5S#|gX+zk;g~HURGhHKJ~W_^HnIcmabzRA)jnC}JVz4WPjT zgfQXHphoCv0QSN@OsYd4;5-oJC43#^fXo44fR~PyB5xpY8i?vJ1NfG=jwK_0Kky2O z^sx3i76Lke_&T71JybMTBm$oXkq^`XZP>d>Wf6W0IsthHa3=OklC2_u-LY?S7dEX2 z0Urh#5#CMMNyrfPz~-7Pk^$b;1$zMz&H$S?KWs-V7oc3ou|j>bwYj0jvbgL%1548v>gm zO!zx!2EtC@rU}CSn}PEuqHho%4crZ)_7a{4k$sGlbZiP<Mz2tKvajL zz~hr)Q^*kBay|S3;r+ndr$P_H*}$_DhED%5^eqwMXDB*$n~FX{{2AZ`la8H1d?+v- z6cmYh6}T%LVU$bwC5R#ZFfeeMs59ZPnP@xWM*`mhO+~mK_%n#gZ2-=lCFJJ;lVzB& zMurJ}ZV)o{z+30Tm!M}i@Ro%-whiG7;6Sse&miDaplZb1fio7t4hRz-1(9tDS4V$Pb?}0K-5O zp9}m3v=2J*9TRpvh{~cpdCNgOFYqOhgX#(FpQd9C2-Duz0uWu_)&m_NC*qwz>qgiX z;cQ?oh%JFX0BJ9|Kf;8!f@r+dZpOTH8|;Gk9N-a96v9V=V{R8VGy-n~QQcMoYh^s) z-FLw6A%8FM!)zVD|8M~K$rkhx;_HEaTSZ=fU<`=Q6~HtQwJ`&@U50ajb`X_CNc*QL zOsL$6zJ^W{a5aeXCITM>ae3g^Aku#vIA@!Pp9h??9lo>_=MJF%UGN8l3BLhVBkTYc z;T>1G2$uq1yC3haLbw)qJzXO$7Qp34)9P_!KAz;acEZpjuq3JAgld>JX-P z7tuRS^r#yl?N7gqctUy)1jQ55I~yoWNbgxN;ao{b??<3`LV6DZg$e0h0~98t_Zd)_ zklq78VM5y1PhmpZyH8<4+KWzMLfQvSWf9VTaf&CTeasY3c!P|meao~@m}CfPzitNX zPe^-pDV~t_1XCLcY5y<96MiYfxT5>Fj_cA)KnBoHnL73z=u^S9`2b}?Vfj7>?p)wy55L+k~|&yj4G zNCeTZUL0CR%XodOt`hQwYs4F`5pTLiyczKg`*GdsQhMS$xK3!-9O3)`=`Q(g2Rv9K zPSM(t_zCvGY7CIx_m<4rPCly?|zR(OcFvV zkWNIJ4lNO7&wz$>o;L}y%~H5O-b!aB*E$B8N8q0Uwy+_03M9?oB3UNFq(Rgwj`epb zXDKAp_#3Z9E%3V$ts9Nqu%Z0#WVClIcE*lIdkriOx~P8CjySY+3XtB}ya77aLW>Py zI;LP>u8!N!^{w~KmRX9rig$riX+~(D0b9=Fd9%UcY8v%g4f`Z>d)ZJH^$zWv&45%H z%580jYuR=*q{E>p8Q82PopWSmvH-mSJOL%+z7encLMcfeLAB8OMZ681diU?z5QW{x z_{9qysnD7Ut7QBOzo0%`iWa6rn#wb9kIY1F@{dZCXM#_=>vZqEYxf=QbwP&?WyGRZ zT5Fm;9QUCxHt?hXspQA$sDrC_GR!g6B;a-gV#l+vpaJ7j`2;_fF%3e83L{PC+;Y`AAE1DfCW$8;=ujh^O&l;F1PDOQc~GP~8#`n+&bAtJ}4_ zW}Wnoc`BP?Xh(P!FLmmFTxuN3i^sUr%B9w}RWg+!TGMvPqmfGQaZiD+QQR7vn(F7O zk>;aBq>x98uT%Ux)*QjaHznxn4+i8W%ck9)|xn7b<#!N+XBk78VZklyOsnpvB-t#mEiBaIHJ)P?x-9o>+eOqdz??O-u z4A9ovlZAg#o9QbcXm|CM-hdv>0v|8Zj|w34N&qyIjH1c%!+K#&aBRqwo|; zCp%624@x4>BkPD!NR~-rp_&Z_w8*`l_jxADq@E$qq?}|)?W+-5Yn#6s zL2c{#FSO9?NAn-mo4yi5dFVSS^c@#5=B`~b`He`WuUh;H|PiG4n8Da+1(x^2 z%=sB;pOwqCoNdJ1PG34|9+leYZ(RqvvZgs*T(MFKR90IWN8qY12`yX2YoXQ8wG{XB zEsb)a|L^q9g!wzUBB5GiI|!Y9XBg=}L`S z>^hHXb!@(tqkf!>t7tK2YS#Hr{Hg7$0e5RRmneD-#s2G~8uvdTRhM6%e>mTPHOD~( zhJxS%V?jiLxgfegUlLSeC_w$T)kQT$wMBJB^+kt^97PR9&Z5R5R_s%(FAgd;6bBa@ zi$jY|#Sz8k;^<;aabmHpIIB3jIHx$bcz3bAxU{&sxTd(axURUq*iqb2>@039W+gr) zuC+3iM3k6IqDw3#i6yp@tdi`KoRZv<-6i&t(vs?unv&X*x{~^m!zGTAh7xBvJ@p2*^087 z+SjnRaj#EhP-SpsXk|oYbY)^?R%K4*?#j~2n##J$!<7w{jg>xCK~=$3p;Zx8(N&36 zSyeezyQ@m8YO3n04p%i)HC8bPo+r z?2UGxyr8_`ywJReyy(2dysW&Oyxn=Fc{O=;d57~F@*4Ae@`Lh&^F#9^@}u(;^Rx1E z@^|N#=GWxcp;sI78}oe%g3zm>=+)?g#Dc7XoPym2r3Ezwbp?kD8VVWe+Hv3BhZhD z=))ZJUn%;ouJ|zet+Ch#eiRHJia<{#qL*^eL#61QI`m8fdc_Al5{%x6D2*;nEX^v- zDcxOKT3SBu`H`Br)+mwX<1EKUD@HXhO)*opYovc z;PTM&i1O(2#PY22obuh}rR6o{b>)Z48_FBYeJX+~f-6ERA}XRQ5-YMQaw>LLlvdPK z)Kwg=XsBqc@YxfzhdI#^_-`sTms(0~rP-yqrS{V5(%RDcQb(z?l$Ghr3}wbLQ<=HU zQf4d5F3T;mmsOY5merRz%A94aTwiV|H=o4&wH5UhjtXZ5+oRuO*kjyd+GE~h*<;(2y(f2%eNXkC z+CBAq9DAI5*k1i!!(QWF(_Zsl%U;{w?7g{r?R%^D*6yv}>)7ku%PRGihDu|lsnT3& zskBvQSLRmQE2}GOE9)yAmCj05rLQtn8LLcH<|<2-ttz`Jx5{2sT~%9EU*)KBR?$jw z8sE&Ww;Sw6yUA|0TkJM_wmsKww^!S1?e%tt-Dzie`aDCPG0&7|&a>p%^0M=C^Xz%m zd9``iXe=}pnhPz3w!&M%rp$Mi~%Flgi&e1 zh|I=pW5-NWi&@5j8HQnYF<@pfVOFtVM!~~+hGi+t0?+Y59|gfrOz;%T|HM8r;+fZf z*hh)*l`MEm4*X>|Jf;*rQvKVK9@Z=Hw)wyVgW!X~@WN2|VFWxe8ornaZ_I)}=D;I& z!zWAOl@0JWA9&nu%y-q8@oMwwTOV{s&WL$(H|EI0m>+}TjS=w29PW$E?Hpj@^Ns~G zj}3EAHfEpPQZr@|dpT9-|K=liAX?{v=X+ZRZuRyZzCB|5`Hs5w9`>yR(-D>Gq0^1+ zZ0zXmYuO&5vwC`Y=-M&kN^idr-gu$v)=3^ZFZ%-HJYx@+n9fFDPaU&+<$Gi^<5;)6 zUWWKP-X9)P{OA40UM;?>W@6CA2@7^OLXKAa_HC#A$N!jC{f&KV$1TRK?fx=u_59iH z>7n!R=sF&=@^@>Uqj#3fc^=Oeh$FSKvbqka((PkA7=67xmw0)1^;oiaY*%9dF+N@W zmc^zg;_Vw5sVQUi#!eL3zH9qPYr?wJl!UR@8T(L-U)OH)lj74-(^FSv;CrcQwp4to z8gFG98*Cgx>7HHtxuz#r4U6$%Y-lx@r-vKH8OM$_Ue}`|aNO7l!C;D8rLs5zw}U5ar{R= z{P0ERCpJAXe8b7NKF@gafg3*i#y)mbpTfZ-_wP5YTKwhC4}PeQ{PlIen##-$OM~8< zy|^;tjZ?)Roeurw{-T1@9#3yd{bck0G0z>yyuntk{u~#u{hOH)W4c{>zWuyZ<-7AM#8Sd z3{)s705qcm(z4*U!uJ{R6J`|2sO#-KZA{#cE7>O}$5-ify(<8k3YZZN$qhFI^Z_(p z2d@>Q;f}%hDoRQQ1qDffB{#p@v;_FREJ@#!9zMROB%S;{CBgZC)gnL}2F;gXy>^5T zaX?NSke2}e2OM_J83KVH1x$e>J8b|OqxH8308i`G-y8x1P!cB20D*jiLjj__HVQg3 z3%1w0IKV7=lib7-gMzyKk%U#8@YyVUeaLrgqCB-Y-in z1U}RE6xRSiAN0H4Od!T94_RuIF=NV0@o73qRko3u+FSQE4XlFP^MXaQ=-r)eB&E(9 zd~9*=l2r~RLYg89AHdbS`7*Prd8uZ#NSae}Y4EKaa^DgzJz+JdKZJiTCX^*mT_l=* z<;0v=u?r4};tTuWFkdy2&2e4E^%;eUS-Rf?gS0uCNF6HYH2gtb8pq%oA6w7M(rVZ* zoSjrs{LjxH&wpp7rI61@9J{{m<0;l5eS&->rX&*~)%u0?M$fyM>zO9vWRW(4JpLry z^ZGjUPDF<|5Pkv^&q^87^LV2goX3mREiS)&p4cFADNcr&C(12$zVlRKZQ!R+=)MMB z+PAXrYnE!2sD$2e2nH)n%6H9jJt~f!8oq`q%@e9E$n!cX61GwJOz#}sI}$5@;leDe zgP#Yy$x{AK&a!>~X3lw;58<@~p2;2zta%+VwP)JNl#|kL1>MvAx^GT-vZor#(N`MB zi)kQ9F`;=mwLCm56prq=d!n`zt093|FMY2au4eo_7tL zLzxKCOU{;(8b7JfthOC|AOQ;~bzghrwWes3$GomxJ0b6U!`oRVxDf9|Bi^r;yg4;S zLN#C$Qh?q+OVxm92x>@CUf!BIU`@+yXfAR!)PI6ru^N4RaA`>+DeC3vJEvpVU#gVH z+s?%uj%HiUleBuBs3d+%%CfCmlTRCNoB$O~pD=*d0_E5CG$gTJWQbQ@*w|N3??~Hi;(dZa{H%!%a*T_3Y1% z>dz|V(aiIs>sV?u!?a#ExB7=p_|FQAH)?0LEw^x33`bp9G(-bMr5DE+k6kJIJbK&p zRdYJ_^wRSs{aN(>A_kGdqHwp!nRAZ8c6TJBUs&YWGzN)?yj${W6-f|FP?I~{Jo$@e z+ygR$wr2$zl9<#F-kZTZmSPOH_NiGahoz#2ZpZE$yKJ2t_7p++!p*np`OAKtAP0c;9@P1;=~2^fHl0#tVn2Zb<8{ng%ArQbhq4omQG{wAPqqp#a)OhLwk zSqPg%{~*SVFPkEbZqn&erg~ap!4JcgYb z`D6;xZC#=h!_R9QA04E;6xPS4&#`t;{k%!^2zs3+=n23qGu>MF0sx8`bj`n_jF)?NKlKUrjiB!C(s_02ev=cX(hqrY`+UuzG zri3-^17n|+dh2DDy#;SgmkBTRj;>LcWs0O{7*Z=!tdhn(=Wa!@yjp1!?>Tn)E?R-S zoxG*}=B?>FFNc|8k7!xSqx^)~BFfi=H^;;jc|0=iSjD+}`xI4UTGfaVg%D8@6`U%A zp({mGh2h3zLIj5oQ@B=9;Ix{k%e7Wp6UUfVPAA#)nDL>t%~j^SEaAz=1?jzSZJiEH z9V5v(tAYqZJVlfTa5FYII8?5Tw6nt-#t(H+i@Y6kkz7oFpJ$UcNc22UyWVOoy?{(# zmo_t!yO(HxTX}YYs#Xw}Oncwet5-rp`9A5Ua+hxD@JDW3-fTQst)KqtO+YZ);(}ae z2#fx==N0_!0W)QvKA(R>5xL-@RQ4HIf*V{M9}nYBBYi@M7G17uBFPIL+8@ham zyj*qbdUw8Ub6#w=g`c^Ru2z$JXLjH*@<`p2UqY@l*L!)L=rlRSKox5I7>Q%T05~RJ zkp2PK)PEYd{*(dkA*FciEdUHaKR6*73`x10#DgRirQ&j~igd-Q z@c9mf7Ag|52SFWW z(Nji-cbeTDZjg)~j=CGV6kW}tX(=jxI)XMp=K~@_;*-nN2c?Lp(^rm_xo|R>6J0mu z9t;~R8@?XKG@jn?!}(2?^JX>A#KDMBwKU(vqAvxCwJ$=MZY1$Gi|s4-3^ZE3k>c{L zv~KRWP`d7$)#D=QKs2RsvcFB;1ed+$rSA2xbR8}c;!{Tl-yL*bBMMng?wC+3$TgJ{ zRB750z2ctj*6BJbe&$mij{YlvqyMzKxG)$5iKAZtx6SNcA%ZqR{{r0955BtR_u2#w zVuhgCu>x99p1?tL!L`){Ax#am<{v{xTam*ce;`gwPrln|q7f-O@D9;{pY2e`n7DjbO3IPJ&cjq*7ckpyM#bah_%A;j! zq^PYSjTDzw*OV65M1iO%2=Ej3gE4UY9F|ZvQQQ>c;N{C>>f#^h;pBqHQ5ym{_(xEh zncO4IsPVHtKR%W!fZUd5)b<)SL7EBsk1WKGGlMa3{^5*&2s6MBVFp0TAmvcI zPRIgKKbrrO*9o-s-zWNeb)Q?|C#C!r1|$vpRp~zBN?e!jb)gj$%|07Fx?S08{t!rF zj-*e1(Y){wclC&a4U2!M3dcAfAg6^Av^O#!?WmlJb(Cu<;tG0SH37dEL5y6YSjZt( z8Nd5c*yx$?+Dk))uEWbZZyn6_^C)0BHSHbj=3l0dH**>HUU0P{>3o!96h80#divUv zK&A=*o27ho-D$R8I7Xbh6-zwlbcb1Zho|F|FNYwGbw-a0QqWyPksGwM2&&ncD*`W9 z4X8(2Nd_J$yqHw>TsEG`btEr2i}p-`pO&%1Fj{3|QzNy@>k_Km%zf_x(>?lYy0Z^z z)`Z1ssrJh`X^Y*Hb#Q;To9MEGE46P=S}UW$At4l`&2urnuOz^8b2eI>+U-}_>41}> z%{gS^n#SocZT2=Pck5rgjsoU{1P`os41h8W9+Y8rHIjcVI|cm=^fJ(32{H_@EyEzU zGgIrG%nr;<2_mcBP8-ZjRsIZC2s+Qt%=Ayj{;mGPKsWFZ4k1KN zlqNUv>JzvRxZh*2BH`XJal+6cEe$z}|{U z)VoyZPP;6fVh&uEMTGQca4inba*teO!+4IKXH;Wc6b=32F@)ty3vp+quv6?~$9XQ!o_+Xs|H1%( zL->IK&}v7NAj67oixSY^EY^RID6t&?kpQSdfFVyxR%Tn7migY4CN%%y@ceg?s+g0i zE{N`&BG2MyhV+e35gsWgF=n&_1>{7yU$&OQ-1Wum+FGX_S^}$8Tn`*uVKNnlBe@T; zv!!zOkTF~ga{#Q$0Zp2B_Oa1s8k8>#Yvf5Q)JKzVJU<0k2;r`2QS~lt=wKf=3fQA8 z?X_1ebz)G_To?zpBs;8G`IBUWOU(}oZJ#VIYjrUxc zzH^+hW4Y~@Aa3Oqi+~&T=hO|=jy$EwL8!PzY`8YT(lpO3_v(M~p3dqjzrGqON{(C^ zGD0L(#gfX*1#{e<&wPAvR#LOJXnn-FJ|EJ|LzW!;_;X!Tr>5<3<{Sv|VLrnhNQ_6TupTm;i1{d*b&bvy=)aFa>5n^|-pD*B$=<tA>MDt*}vEPfl zzP6)N9%B~GPsf0!FWobSTU3p&q~EK}i)Wrmi?ggFK(&d6|))(*)I z_uD0mVPetrc{nIYcc29J0tNx1y#HN(ah0DOJVz1)@d0WWlnus2q+T$?waQSagi4=5 zC9!KLkog}m#e`BNeTR)-7707Z?&%IC+@s!A zGYGU6iYEt13Ef~M;6pk)zacUBy*UavWf&GqL_$_^F%@BZvw`Zg!C7Zj9b#)fAD(CG zW8^E|Wf|QiQ#7S+9S0$kD=Hk(z}+Af89g&W0rWIhoHB=KHaC3~hYSUax>NEbeD1+&Fg{{H+74e6W$?4Ry?DQX+`wgw9m~qf% z6cPuc0?8!Vw#=0L&tB2*BGVsm*}WnY4x$IJ?Me}#%0%@mvEg?@5|e+Y{So)W@`YY& zbFBM#%edNU;_Iv*xA5|HbT4H0$pP3;dj^0?BC!hqb{4?C2C(&T9!c5Tl?&Z{`8EQ} zYyPXIOGB!iU13_;bZEtrDky0>=m#191+MVN3&#iNp1Ox!LtiO#`K>{zOd0*1hUX3HniKQ6J%TgiOYMhs8>}DCxP^sv$N9 zm+nMgM^_B0p1SI*?%X1GeM)A|$mAo%;_-FO}{86iPb;-pdwk1_= zX>wNBi9;OCY?mo`+4fIV<rfD(v9 dRRHklReF3YP5di?E=NHLOYh2&zEmQj{{v##Eo}e* diff --git a/CMakeLists.txt b/CMakeLists.txt index f9fab7e..019995f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,51 +1,64 @@ +# # CMakeLists.txt - CMake configuration file for EPANETMSX 2.0 +# +# Created: Nov 13, 2023 +# Modified: Nov 13, 2023 +# +# Author: Michael E. Tryby +# US EPA ORD/CESER +# + cmake_minimum_required(VERSION 3.9) -project(EPANETMSX LANGUAGES C) +if("${CMAKE_BINARY_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") + message(FATAL_ERROR "In-source builds are disabled.") +endif() + +project( + "EPANETMSX" + VERSION 2.0.0 + DESCRIPTION "Multi-species extension for EPANET" + LANGUAGES C CXX +) # Append local dir to module search path -#list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) -# Add building the command line executable from the run directory -add_subdirectory(run) +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) + +# Sets default install prefix when cmakecache is initialized for first time +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/install CACHE PATH "..." FORCE) +endif() + # Sets the output directory for executables and libraries. -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +set(TOOL_DIST "bin") +set(INCLUDE_DIST "include") +set(LIBRARY_DIST "lib") +set(CONFIG_DIST "cmake") # Sets the position independent code property for all targets SET(CMAKE_POSITION_INDEPENDENT_CODE ON) -IF (APPLE) - set(INSTALL_NAME_DIR @executable_path/../lib) - set(CMAKE_MACOSX_RPATH 1) -ENDIF (APPLE) - -IF (MSVC) - set(CMAKE_C_FLAGS_RELEASE "/GL") - add_definitions(-D_CRT_SECURE_NO_DEPRECATE -MT) -ENDIF (MSVC) - -# configure file groups -file(GLOB MSX_SOURCES RELATIVE ${PROJECT_SOURCE_DIR} Src/*.c Src/*.h Include/epanet2.h Include/epanetmsx.h) -list(REMOVE_ITEM MSX_SOURCES Src/msxmain.c) - -# the shared library -find_package(OpenMP REQUIRED) -IF(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)") - message(" ************************************") - message(" Configuring with msx.def mapping") - message(" ************************************") - find_library(EPANET_LIB epanet2 NAMES epanet2 PATHS ${PROJECT_SOURCE_DIR}/include/x86 NO_DEFAULT_PATH) - add_library(epanetmsx SHARED ${MSX_SOURCES} ${PROJECT_SOURCE_DIR}/include/epanetmsx.def) - set_source_files_properties(${PROJECT_SOURCE_DIR}/include/msx.def PROPERTIES_HEADER_FILE_ONLY TRUE) - target_link_libraries(epanetmsx ${EPANET_LIB} OpenMP::OpenMP_C) -ELSE(TRUE) - find_library(EPANET_LIB epanet2 NAMES epanet2 PATHS ${PROJECT_SOURCE_DIR}/include/x64 NO_DEFAULT_PATH) - add_library(epanetmsx SHARED ${MSX_SOURCES}) - target_link_libraries(epanetmsx ${EPANET_LIB} OpenMP::OpenMP_C) -ENDIF(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)") - -target_include_directories(epanetmsx PUBLIC ${PROJECT_SOURCE_DIR}/include) +# option(BUILD_TESTS "Build component tests (requires Boost)" OFF) +option(BUILD_DEF "Builds library with def file interface" OFF) + +# Added option to statically link libraries to address GitHub +option(BUILD_SHARED_LIBS "Build using shared libraries" ON) + +add_subdirectory(EPANET2.2/SRC_engines) + +add_subdirectory(src/solver) + +add_subdirectory(src/run) + +set(CMAKE_INSTALL_OPENMP_LIBRARIES TRUE) +include(InstallRequiredSystemLibraries) + +# Configure CPack driven installer package +set(CPACK_GENERATOR "ZIP;TGZ") +set(CPACK_PACKAGE_VENDOR "US_EPA") +set(CPACK_ARCHIVE_FILE_NAME "epanet-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_SYSTEM_PROCESSOR}") + +include(CPack) \ No newline at end of file diff --git a/EPANET2.2 b/EPANET2.2 new file mode 160000 index 0000000..2b3c2e9 --- /dev/null +++ b/EPANET2.2 @@ -0,0 +1 @@ +Subproject commit 2b3c2e9dc002ec2feacdf6b4455ed17826966cc8 diff --git a/Examples/example.rpt b/Examples/example.rpt index 5fbfb6a..9133530 100644 --- a/Examples/example.rpt +++ b/Examples/example.rpt @@ -1,4 +1,4 @@ - Page 1 Tue Aug 23 20:33:30 2022 + Page 1 Mon Nov 13 13:42:22 2023 ****************************************************************** * E P A N E T * @@ -7,177 +7,4 @@ * Version 2.2 * ****************************************************************** - EPANET-MSX Example Network - - Input Data File ................... example.inp - Number of Junctions................ 4 - Number of Reservoirs............... 1 - Number of Tanks ................... 0 - Number of Pipes ................... 5 - Number of Pumps ................... 0 - Number of Valves .................. 0 - Headloss Formula .................. Hazen-Williams - Nodal Demand Model ................ DDA - Hydraulic Timestep ................ 1.00 hrs - Hydraulic Accuracy ................ 0.001000 - Status Check Frequency ............ 2 - Maximum Trials Checked ............ 10 - Damping Limit Threshold ........... 0.000000 - Maximum Trials .................... 200 - Quality Analysis .................. None - Specific Gravity .................. 1.00 - Relative Kinematic Viscosity ...... 1.00 - Relative Chemical Diffusivity ..... 1.00 - Demand Multiplier ................. 1.00 - Total Duration .................... 48.00 hrs - Reporting Criteria: - No Nodes - No Links - - Analysis begun Tue Aug 23 20:33:30 2022 - - Processing MSX input file example.msx - - -Page 1 EPANET-MSX 2.0.0 - - ****************************************************************** - * E P A N E T - M S X * - * Multi-Species Water Quality * - * Analysis for Pipe Networks * - * Version 2.0.0 * - ****************************************************************** - - Arsenic Oxidation/Adsorption Example - - - <<< Node C >>> - - Time AS5 AStot NH2CL - hr:min UG/L UG/L MG/L - ------- ---------- ---------- ---------- - 0:00 0.00 0.00 0.00 - 2:00 0.00 0.00 0.00 - 4:00 0.00 0.00 0.00 - 6:00 0.00 0.00 0.00 - 8:00 0.00 0.00 1.10 - 10:00 9.17 9.17 1.10 - 12:00 9.17 9.17 1.10 - 14:00 9.17 9.17 1.10 - 16:00 9.17 9.17 1.10 - 18:00 9.17 9.17 1.10 - 20:00 9.17 9.17 1.10 - 22:00 9.17 9.17 1.10 - 24:00 9.17 9.17 1.10 - 26:00 9.17 9.17 1.10 - 28:00 9.17 9.17 1.10 - 30:00 9.17 9.17 1.10 - 32:00 9.17 9.17 1.10 - 34:00 9.17 9.17 1.11 - 36:00 9.17 9.17 1.11 - 38:00 10.03 10.03 1.11 - 40:00 10.03 10.03 1.11 - 42:00 10.03 10.03 1.11 - 44:00 10.03 10.03 1.11 - 46:00 10.03 10.03 1.11 - 48:00 10.03 10.03 1.11 - - <<< Node D >>> - - Time AS5 AStot NH2CL - hr:min UG/L UG/L MG/L - ------- ---------- ---------- ---------- - 0:00 0.00 0.00 0.00 - 2:00 0.00 0.00 0.00 - 4:00 0.00 0.00 0.00 - 6:00 0.00 0.00 0.00 - 8:00 0.00 0.00 0.00 - 10:00 0.00 0.00 0.00 - 12:00 0.00 0.00 0.00 - 14:00 0.00 0.00 0.00 - 16:00 0.00 0.00 0.00 - 18:00 0.00 0.00 0.00 - 20:00 0.00 0.00 0.00 - 22:00 0.00 0.00 0.00 - 24:00 0.00 0.00 0.24 - 26:00 0.00 0.00 0.24 - 28:00 9.17 9.17 0.24 - 30:00 9.17 9.17 0.24 - 32:00 9.17 9.17 0.24 - 34:00 9.17 9.17 0.24 - 36:00 9.17 9.17 0.24 - 38:00 9.17 9.17 0.24 - 40:00 9.17 9.17 0.24 - 42:00 9.17 9.17 0.24 - 44:00 9.17 9.17 0.24 - 46:00 9.17 9.17 0.24 - 48:00 9.17 9.17 0.24 - - <<< Link 5 >>> - - Time AS5 AStot AS5s NH2CL - hr:min UG/L UG/L UG/M2 MG/L - ------- ---------- ---------- ---------- ---------- - 0:00 0.00 0.00 -0.00 0.00 - 2:00 0.00 0.00 0.00 0.00 - 4:00 0.00 0.00 0.00 0.00 - 6:00 0.00 0.00 0.00 0.00 - 8:00 0.00 0.00 0.00 0.05 - 10:00 0.85 0.85 4.51 0.17 - 12:00 1.86 1.86 9.88 0.27 - 14:00 2.87 2.87 15.27 0.35 - 16:00 3.87 3.87 20.64 0.42 - 18:00 4.88 4.88 26.02 0.47 - 20:00 5.89 5.89 31.39 0.52 - 22:00 6.89 6.89 36.75 0.55 - 24:00 7.90 7.90 42.12 0.56 - 26:00 8.91 8.91 47.50 0.56 - 28:00 9.17 9.17 48.93 0.56 - 30:00 9.17 9.17 48.93 0.56 - 32:00 9.17 9.17 48.93 0.56 - 34:00 9.17 9.17 48.93 0.56 - 36:00 9.17 9.17 48.93 0.57 - 38:00 9.19 9.19 48.93 0.57 - 40:00 9.30 9.30 48.95 0.57 - 42:00 9.41 9.41 48.96 0.57 - 44:00 9.52 9.52 48.97 0.57 - 46:00 9.64 9.64 48.98 0.57 - 48:00 9.75 9.75 48.99 0.57 - - - Water Quality Mass Balance: AS3 (UG) - ================================ - Initial Mass: 0.00000e+00 - Mass Inflow: 7.34409e+06 - Mass Outflow: 5.15609e-11 - Mass Reacted: -7.32740e+06 - Final Mass: 1.66911e+04 - Mass Ratio: 1.00000 - ================================ - - - - Water Quality Mass Balance: AS5 (UG) - ================================ - Initial Mass: 0.00000e+00 - Mass Inflow: 0.00000e+00 - Mass Outflow: 5.79736e+06 - Mass Reacted: 7.13763e+06 - Final Mass: 1.34027e+06 - Mass Ratio: 1.00000 - ================================ - - - - Water Quality Mass Balance: NH2CL (MG) - ================================ - Initial Mass: 0.00000e+00 - Mass Inflow: 1.83602e+06 - Mass Outflow: 8.51117e+05 - Mass Reacted: -8.00156e+05 - Final Mass: 1.84749e+05 - Mass Ratio: 1.00000 - ================================ - - - Analysis ended Tue Aug 23 20:33:31 2022 + Error 223: not enough nodes in network \ No newline at end of file diff --git a/Include/epanet2.h b/Include/epanet2.h deleted file mode 100644 index 0b7daa1..0000000 --- a/Include/epanet2.h +++ /dev/null @@ -1,435 +0,0 @@ -/* - ****************************************************************************** - Project: OWA EPANET - Version: 2.2 - Module: epanet2.h - Description: declarations of the legacy style EPANET 2 API functions - Authors: see EPANET 2.2 AUTHORS - Copyright: see EPANET 2.2 AUTHORS - License: see EPANET 2.2 LICENSE - Last Updated: 02/01/2020 - ****************************************************************************** - */ - -/* -This module contains declarations of the legacy style EPANET API functions, with -version 2.2 updates, that apply only to single threaded applications. A second -set of thread safe API functions that allows one to run concurrent analyses on -multiple EPANET projects can be found in the epanet2_2.h header file. The two -APIs share the same function names and arguments with the difference being that -the thread safe functions use the prefix "EN_" and include an extra argument that -represents the EPANET project being analyzed. To avoid unneccesary repetition, -only the thread safe API functions have been documented. To see a description of -a legacy style API function declared here please refer to its complementary named -function in epanet2_2.h. -*/ - -#ifndef EPANET2_H -#define EPANET2_H - -// The legacy style EPANET API can be compiled with support for either single -// precision or double precision floating point arguments, with the default -// being single precision. To compile for double precision one must #define -// EN_API_FLOAT_TYPE as double both here and in any client code that uses the -// API. -#ifndef EN_API_FLOAT_TYPE - #define EN_API_FLOAT_TYPE float -#endif - -#ifndef DLLEXPORT - #ifdef _WIN32 - #ifdef epanet2_EXPORTS - #define DLLEXPORT __declspec(dllexport) __stdcall - #else - #define DLLEXPORT __declspec(dllimport) __stdcall - #endif - #elif defined(__CYGWIN__) - #define DLLEXPORT __stdcall - #else - #define DLLEXPORT - #endif -#endif - -#include "epanet2_enums.h" - -// --- Declare the EPANET toolkit functions -#if defined(__cplusplus) -extern "C" { -#endif - - -/******************************************************************** - - Project Functions - -********************************************************************/ - - int DLLEXPORT ENepanet(const char *inpFile, const char *rptFile, - const char *outFile, void (*pviewprog) (char *)); - - int DLLEXPORT ENinit(const char *rptFile, const char *outFile, - int unitsType, int headlossType); - - int DLLEXPORT ENopen(const char *inpFile, const char *rptFile, - const char *outFile); - - int DLLEXPORT ENgettitle(char *line1, char *line2, char *line3); - - int DLLEXPORT ENsettitle(char *line1, char *line2, char *line3); - - int DLLEXPORT ENgetcomment(int object, int index, char *comment); - - int DLLEXPORT ENsetcomment(int object, int index, char *comment); - - int DLLEXPORT ENgetcount(int object, int *count); - - int DLLEXPORT ENsaveinpfile(const char *filename); - - int DLLEXPORT ENclose(); - -/******************************************************************** - - Hydraulic Analysis Functions - -********************************************************************/ - - int DLLEXPORT ENsolveH(); - - int DLLEXPORT ENsaveH(); - - int DLLEXPORT ENopenH(); - - int DLLEXPORT ENinitH(int initFlag); - - int DLLEXPORT ENrunH(long *currentTime); - - int DLLEXPORT ENnextH(long *tStep); - - int DLLEXPORT ENcloseH(); - - int DLLEXPORT ENsavehydfile(char *filename); - - int DLLEXPORT ENusehydfile(char *filename); - -/******************************************************************** - - Water Quality Analysis Functions - -********************************************************************/ - - int DLLEXPORT ENsolveQ(); - - int DLLEXPORT ENopenQ(); - - int DLLEXPORT ENinitQ(int saveFlag); - - int DLLEXPORT ENrunQ(long *currentTime); - - int DLLEXPORT ENnextQ(long *tStep); - - int DLLEXPORT ENstepQ(long *timeLeft); - - int DLLEXPORT ENcloseQ(); - -/******************************************************************** - - Reporting Functions - -********************************************************************/ - - int DLLEXPORT ENwriteline(char *line); - - int DLLEXPORT ENreport(); - - int DLLEXPORT ENcopyreport(char *filename); - - int DLLEXPORT ENclearreport(); - - int DLLEXPORT ENresetreport(); - - int DLLEXPORT ENsetreport(char *format); - - int DLLEXPORT ENsetstatusreport(int level); - - int DLLEXPORT ENgetversion(int *version); - - int DLLEXPORT ENgeterror(int errcode, char *errmsg, int maxLen); - - int DLLEXPORT ENgetstatistic(int type, EN_API_FLOAT_TYPE* value); - - int DLLEXPORT ENgetresultindex(int type, int index, int *value); - -/******************************************************************** - - Analysis Options Functions - -********************************************************************/ - - int DLLEXPORT ENgetoption(int option, EN_API_FLOAT_TYPE *value); - - int DLLEXPORT ENsetoption(int option, EN_API_FLOAT_TYPE value); - - int DLLEXPORT ENgetflowunits(int *units); - - int DLLEXPORT ENsetflowunits(int units); - - int DLLEXPORT ENgettimeparam(int param, long *value); - - int DLLEXPORT ENsettimeparam(int param, long value); - - int DLLEXPORT ENgetqualinfo(int *qualType, char *chemName, char *chemUnits, - int *traceNode); - - int DLLEXPORT ENgetqualtype(int *qualType, int *traceNode); - - int DLLEXPORT ENsetqualtype(int qualType, char *chemName, char *chemUnits, - char *traceNode); - -/******************************************************************** - - Node Functions - -********************************************************************/ - - int DLLEXPORT ENaddnode(char *id, int nodeType, int *index); - - int DLLEXPORT ENdeletenode(int index, int actionCode); - - int DLLEXPORT ENgetnodeindex(char *id, int *index); - - int DLLEXPORT ENgetnodeid(int index, char *id); - - int DLLEXPORT ENsetnodeid(int index, char *newid); - - int DLLEXPORT ENgetnodetype(int index, int *nodeType); - - int DLLEXPORT ENgetnodevalue(int index, int property, EN_API_FLOAT_TYPE *value); - - int DLLEXPORT ENsetnodevalue(int index, int property, EN_API_FLOAT_TYPE value); - - int DLLEXPORT ENsetjuncdata(int index, EN_API_FLOAT_TYPE elev, - EN_API_FLOAT_TYPE dmnd, char *dmndpat); - - int DLLEXPORT ENsettankdata(int index, EN_API_FLOAT_TYPE elev, - EN_API_FLOAT_TYPE initlvl, EN_API_FLOAT_TYPE minlvl, - EN_API_FLOAT_TYPE maxlvl, EN_API_FLOAT_TYPE diam, - EN_API_FLOAT_TYPE minvol, char *volcurve); - - int DLLEXPORT ENgetcoord(int index, double *x, double *y); - - int DLLEXPORT ENsetcoord(int index, double x, double y); - -/******************************************************************** - - Nodal Demand Functions - -********************************************************************/ - - int DLLEXPORT ENgetdemandmodel(int *model, EN_API_FLOAT_TYPE *pmin, - EN_API_FLOAT_TYPE *preq, EN_API_FLOAT_TYPE *pexp); - - int DLLEXPORT ENsetdemandmodel(int model, EN_API_FLOAT_TYPE pmin, - EN_API_FLOAT_TYPE preq, EN_API_FLOAT_TYPE pexp); - - int DLLEXPORT ENadddemand(int nodeIndex, EN_API_FLOAT_TYPE baseDemand, - char *demandPattern, char *demandName); - - int DLLEXPORT ENdeletedemand(int nodeIndex, int demandIndex); - - int DLLEXPORT ENgetnumdemands(int nodeIndex, int *numDemands); - - int DLLEXPORT ENgetdemandindex(int nodeIndex, char *demandName, int *demandIndex); - - int DLLEXPORT ENgetbasedemand(int nodeIndex, int demandIndex, - EN_API_FLOAT_TYPE *baseDemand); - - int DLLEXPORT ENsetbasedemand(int nodeIndex, int demandIndex, - EN_API_FLOAT_TYPE baseDemand); - - int DLLEXPORT ENgetdemandpattern(int nodeIndex, int demandIndex, int *patIndex); - - int DLLEXPORT ENsetdemandpattern(int nodeIndex, int demandIndex, int patIndex); - - int DLLEXPORT ENgetdemandname(int nodeIndex, int demandIndex, char *demandName); - - int DLLEXPORT ENsetdemandname(int nodeIndex, int demandIndex, char *demandName); - -/******************************************************************** - - Link Functions - -********************************************************************/ - - int DLLEXPORT ENaddlink(char *id, int linkType, char *fromNode, char *toNode, int *index); - - int DLLEXPORT ENdeletelink(int index, int actionCode); - - int DLLEXPORT ENgetlinkindex(char *id, int *index); - - int DLLEXPORT ENgetlinkid(int index, char *id); - - int DLLEXPORT ENsetlinkid(int index, char *newid); - - int DLLEXPORT ENgetlinktype(int index, int *linkType); - - int DLLEXPORT ENsetlinktype(int *index, int linkType, int actionCode); - - int DLLEXPORT ENgetlinknodes(int index, int *node1, int *node2); - - int DLLEXPORT ENsetlinknodes(int index, int node1, int node2); - - int DLLEXPORT ENgetlinkvalue(int index, int property, EN_API_FLOAT_TYPE *value); - - int DLLEXPORT ENsetlinkvalue(int index, int property, EN_API_FLOAT_TYPE value); - - int DLLEXPORT ENsetpipedata(int index, EN_API_FLOAT_TYPE length, - EN_API_FLOAT_TYPE diam, EN_API_FLOAT_TYPE rough, - EN_API_FLOAT_TYPE mloss); - - int DLLEXPORT ENgetvertexcount(int index, int *count); - - int DLLEXPORT ENgetvertex(int index, int vertex, double *x, double *y); - - int DLLEXPORT ENsetvertex(int index, int vertex, double x, double y); - - int DLLEXPORT ENsetvertices(int index, double *x, double *y, int count); - -/******************************************************************** - - Pump Functions - -********************************************************************/ - - int DLLEXPORT ENgetpumptype(int linkIndex, int *pumpType); - - int DLLEXPORT ENgetheadcurveindex(int linkIndex, int *curveIndex); - - int DLLEXPORT ENsetheadcurveindex(int linkIndex, int curveIndex); - -/******************************************************************** - - Time Pattern Functions - -********************************************************************/ - - int DLLEXPORT ENaddpattern(char *id); - - int DLLEXPORT ENdeletepattern(int index); - - int DLLEXPORT ENgetpatternindex(char *id, int *index); - - int DLLEXPORT ENgetpatternid(int index, char *id); - - int DLLEXPORT ENsetpatternid(int index, char *id); - - int DLLEXPORT ENgetpatternlen(int index, int *len); - - int DLLEXPORT ENgetpatternvalue(int index, int period, EN_API_FLOAT_TYPE *value); - - int DLLEXPORT ENsetpatternvalue(int index, int period, EN_API_FLOAT_TYPE value); - - int DLLEXPORT ENgetaveragepatternvalue(int index, EN_API_FLOAT_TYPE *value); - - int DLLEXPORT ENsetpattern(int index, EN_API_FLOAT_TYPE *values, int len); - -/******************************************************************** - - Data Curve Functions - -********************************************************************/ - - int DLLEXPORT ENaddcurve(char *id); - - int DLLEXPORT ENdeletecurve(int index); - - int DLLEXPORT ENgetcurveindex(char *id, int *index); - - int DLLEXPORT ENgetcurveid(int index, char *id); - - int DLLEXPORT ENsetcurveid(int index, char *id); - - int DLLEXPORT ENgetcurvelen(int index, int *len); - - int DLLEXPORT ENgetcurvetype(int index, int *type); - - int DLLEXPORT ENsetcurvetype(int index, int type); - - int DLLEXPORT ENgetcurvevalue(int curveIndex, int pointIndex, - EN_API_FLOAT_TYPE *x, EN_API_FLOAT_TYPE *y); - - int DLLEXPORT ENsetcurvevalue(int curveIndex, int pointIndex, - EN_API_FLOAT_TYPE x, EN_API_FLOAT_TYPE y); - - int DLLEXPORT ENgetcurve(int index, char* id, int *nPoints, - EN_API_FLOAT_TYPE *xValues, EN_API_FLOAT_TYPE *yValues); - - int DLLEXPORT ENsetcurve(int index, EN_API_FLOAT_TYPE *xValues, - EN_API_FLOAT_TYPE *yValues, int nPoints); - -/******************************************************************** - - Simple Controls Functions - -********************************************************************/ - - int DLLEXPORT ENaddcontrol(int type, int linkIndex, EN_API_FLOAT_TYPE setting, - int nodeIndex, EN_API_FLOAT_TYPE level, int *index); - - int DLLEXPORT ENdeletecontrol(int index); - - int DLLEXPORT ENgetcontrol(int index, int *type, int *linkIndex, - EN_API_FLOAT_TYPE *setting, int *nodeIndex, EN_API_FLOAT_TYPE *level); - - int DLLEXPORT ENsetcontrol(int index, int type, int linkIndex, - EN_API_FLOAT_TYPE setting, int nodeIndex, EN_API_FLOAT_TYPE level); - - -/******************************************************************** - - Rule-Based Controls Functions - -********************************************************************/ - - int DLLEXPORT ENaddrule(char *rule); - - int DLLEXPORT ENdeleterule(int index); - - int DLLEXPORT ENgetrule(int index, int *nPremises, int *nThenActions, - int *nElseActions, EN_API_FLOAT_TYPE *priority); - - int DLLEXPORT ENgetruleID(int index, char* id); - - int DLLEXPORT ENgetpremise(int ruleIndex, int premiseIndex, int *logop, - int *object, int *objIndex, int *variable, - int *relop, int *status, EN_API_FLOAT_TYPE *value); - - int DLLEXPORT ENsetpremise(int ruleIndex, int premiseIndex, int logop, - int object, int objIndex, int variable, int relop, - int status, EN_API_FLOAT_TYPE value); - - int DLLEXPORT ENsetpremiseindex(int ruleIndex, int premiseIndex, int objIndex); - - int DLLEXPORT ENsetpremisestatus(int ruleIndex, int premiseIndex, int status); - - int DLLEXPORT ENsetpremisevalue(int ruleIndex, int premiseIndex, - EN_API_FLOAT_TYPE value); - - int DLLEXPORT ENgetthenaction(int ruleIndex, int actionIndex, int *linkIndex, - int *status, EN_API_FLOAT_TYPE *setting); - - int DLLEXPORT ENsetthenaction(int ruleIndex, int actionIndex, int linkIndex, - int status, EN_API_FLOAT_TYPE setting); - - int DLLEXPORT ENgetelseaction(int ruleIndex, int actionIndex, int *linkIndex, - int *status, EN_API_FLOAT_TYPE *setting); - - int DLLEXPORT ENsetelseaction(int ruleIndex, int actionIndex, int linkIndex, - int status, EN_API_FLOAT_TYPE setting); - - int DLLEXPORT ENsetrulepriority(int index, EN_API_FLOAT_TYPE priority); - - #if defined(__cplusplus) - } - #endif - -#endif //EPANET2_H diff --git a/Include/epanet2_enums.h b/Include/epanet2_enums.h deleted file mode 100644 index 7b9a8df..0000000 --- a/Include/epanet2_enums.h +++ /dev/null @@ -1,471 +0,0 @@ -/** @file epanet2_enums.h -*/ -/* - ****************************************************************************** - Project: OWA EPANET - Version: 2.2 - Module: epanet2_enums.h - Description: enumerations of symbolic constants used by the API functions - Authors: see EPANET 2.2 AUTHORS - Copyright: see EPANET 2.2 AUTHORS - License: see EPANET 2.2 LICENSE - Last Updated: 02/01/2020 - ****************************************************************************** -*/ - - -#ifndef EPANET2_ENUMS_H -#define EPANET2_ENUMS_H - - -// --- Define the EPANET toolkit constants - -/// Size Limts -/** -Limits on the size of character arrays used to store ID names -and text messages. -*/ -typedef enum { - EN_MAXID = 31, //!< Max. # characters in ID name - EN_MAXMSG = 255 //!< Max. # characters in message text -} EN_SizeLimits; - -/// Node properties -/** -These node properties are used with @ref EN_getnodevalue and @ref EN_setnodevalue. -Those marked as read only are computed values that can only be retrieved. -*/ -typedef enum { - EN_ELEVATION = 0, //!< Elevation - EN_BASEDEMAND = 1, //!< Primary demand baseline value - EN_PATTERN = 2, //!< Primary demand time pattern index - EN_EMITTER = 3, //!< Emitter flow coefficient - EN_INITQUAL = 4, //!< Initial quality - EN_SOURCEQUAL = 5, //!< Quality source strength - EN_SOURCEPAT = 6, //!< Quality source pattern index - EN_SOURCETYPE = 7, //!< Quality source type (see @ref EN_SourceType) - EN_TANKLEVEL = 8, //!< Current computed tank water level (read only) - EN_DEMAND = 9, //!< Current computed demand (read only) - EN_HEAD = 10, //!< Current computed hydraulic head (read only) - EN_PRESSURE = 11, //!< Current computed pressure (read only) - EN_QUALITY = 12, //!< Current computed quality (read only) - EN_SOURCEMASS = 13, //!< Current computed quality source mass inflow (read only) - EN_INITVOLUME = 14, //!< Tank initial volume (read only) - EN_MIXMODEL = 15, //!< Tank mixing model (see @ref EN_MixingModel) - EN_MIXZONEVOL = 16, //!< Tank mixing zone volume (read only) - EN_TANKDIAM = 17, //!< Tank diameter - EN_MINVOLUME = 18, //!< Tank minimum volume - EN_VOLCURVE = 19, //!< Tank volume curve index - EN_MINLEVEL = 20, //!< Tank minimum level - EN_MAXLEVEL = 21, //!< Tank maximum level - EN_MIXFRACTION = 22, //!< Tank mixing fraction - EN_TANK_KBULK = 23, //!< Tank bulk decay coefficient - EN_TANKVOLUME = 24, //!< Current computed tank volume (read only) - EN_MAXVOLUME = 25, //!< Tank maximum volume (read only) - EN_CANOVERFLOW = 26, //!< Tank can overflow (= 1) or not (= 0) - EN_DEMANDDEFICIT = 27,//!< Amount that full demand is reduced under PDA (read only) - EN_NODE_INCONTROL = 28 //!< Is present in any simple or rule-based control (= 1) or not (= 0) -} EN_NodeProperty; - -/// Link properties -/** -These link properties are used with @ref EN_getlinkvalue and @ref EN_setlinkvalue. -Those marked as read only are computed values that can only be retrieved. -*/ -typedef enum { - EN_DIAMETER = 0, //!< Pipe/valve diameter - EN_LENGTH = 1, //!< Pipe length - EN_ROUGHNESS = 2, //!< Pipe roughness coefficient - EN_MINORLOSS = 3, //!< Pipe/valve minor loss coefficient - EN_INITSTATUS = 4, //!< Initial status (see @ref EN_LinkStatusType) - EN_INITSETTING = 5, //!< Initial pump speed or valve setting - EN_KBULK = 6, //!< Bulk chemical reaction coefficient - EN_KWALL = 7, //!< Pipe wall chemical reaction coefficient - EN_FLOW = 8, //!< Current computed flow rate (read only) - EN_VELOCITY = 9, //!< Current computed flow velocity (read only) - EN_HEADLOSS = 10, //!< Current computed head loss (read only) - EN_STATUS = 11, //!< Current link status (see @ref EN_LinkStatusType) - EN_SETTING = 12, //!< Current link setting - EN_ENERGY = 13, //!< Current computed pump energy usage (read only) - EN_LINKQUAL = 14, //!< Current computed link quality (read only) - EN_LINKPATTERN = 15, //!< Pump speed time pattern index - EN_PUMP_STATE = 16, //!< Current computed pump state (read only) (see @ref EN_PumpStateType) - EN_PUMP_EFFIC = 17, //!< Current computed pump efficiency (read only) - EN_PUMP_POWER = 18, //!< Pump constant power rating - EN_PUMP_HCURVE = 19, //!< Pump head v. flow curve index - EN_PUMP_ECURVE = 20, //!< Pump efficiency v. flow curve index - EN_PUMP_ECOST = 21, //!< Pump average energy price - EN_PUMP_EPAT = 22, //!< Pump energy price time pattern index - EN_LINK_INCONTROL = 23, //!< Is present in any simple or rule-based control (= 1) or not (= 0) - EN_GPV_CURVE = 24 //!< GPV head loss v. flow curve index -} EN_LinkProperty; - -/// Time parameters -/** -These time-related options are used with @ref EN_gettimeparam and@ref EN_settimeparam. -All times are expressed in seconds The parameters marked as read only are -computed values that can only be retrieved. -*/ -typedef enum { - EN_DURATION = 0, //!< Total simulation duration - EN_HYDSTEP = 1, //!< Hydraulic time step - EN_QUALSTEP = 2, //!< Water quality time step - EN_PATTERNSTEP = 3, //!< Time pattern period - EN_PATTERNSTART = 4, //!< Time when time patterns begin - EN_REPORTSTEP = 5, //!< Reporting time step - EN_REPORTSTART = 6, //!< Time when reporting starts - EN_RULESTEP = 7, //!< Rule-based control evaluation time step - EN_STATISTIC = 8, //!< Reporting statistic code (see @ref EN_StatisticType) - EN_PERIODS = 9, //!< Number of reporting time periods (read only) - EN_STARTTIME = 10, //!< Simulation starting time of day - EN_HTIME = 11, //!< Elapsed time of current hydraulic solution (read only) - EN_QTIME = 12, //!< Elapsed time of current quality solution (read only) - EN_HALTFLAG = 13, //!< Flag indicating if the simulation was halted (read only) - EN_NEXTEVENT = 14, //!< Shortest time until a tank becomes empty or full (read only) - EN_NEXTEVENTTANK = 15 //!< Index of tank with shortest time to become empty or full (read only) -} EN_TimeParameter; - -/// Analysis convergence statistics -/** -These statistics report the convergence criteria for the most current hydraulic analysis -and the cumulative water quality mass balance error at the current simulation time. They -can be retrieved with @ref EN_getstatistic. -*/ -typedef enum { - EN_ITERATIONS = 0, //!< Number of hydraulic iterations taken - EN_RELATIVEERROR = 1, //!< Sum of link flow changes / sum of link flows - EN_MAXHEADERROR = 2, //!< Largest head loss error for links - EN_MAXFLOWCHANGE = 3, //!< Largest flow change in links - EN_MASSBALANCE = 4, //!< Cumulative water quality mass balance ratio - EN_DEFICIENTNODES = 5, //!< Number of pressure deficient nodes - EN_DEMANDREDUCTION = 6 //!< % demand reduction at pressure deficient nodes -} EN_AnalysisStatistic; - -/// Types of network objects -/** -The types of objects that comprise a network model. -*/ -typedef enum { - EN_NODE = 0, //!< Nodes - EN_LINK = 1, //!< Links - EN_TIMEPAT = 2, //!< Time patterns - EN_CURVE = 3, //!< Data curves - EN_CONTROL = 4, //!< Simple controls - EN_RULE = 5 //!< Control rules -} EN_ObjectType; - -/// Types of objects to count -/** -These options tell @ref EN_getcount which type of object to count. -*/ -typedef enum { - EN_NODECOUNT = 0, //!< Number of nodes (junctions + tanks + reservoirs) - EN_TANKCOUNT = 1, //!< Number of tanks and reservoirs - EN_LINKCOUNT = 2, //!< Number of links (pipes + pumps + valves) - EN_PATCOUNT = 3, //!< Number of time patterns - EN_CURVECOUNT = 4, //!< Number of data curves - EN_CONTROLCOUNT = 5, //!< Number of simple controls - EN_RULECOUNT = 6 //!< Number of rule-based controls -} EN_CountType; - -/// Node Types -/** -These are the different types of nodes that can be returned by calling @ref EN_getnodetype. -*/ -typedef enum { - EN_JUNCTION = 0, //!< Junction node - EN_RESERVOIR = 1, //!< Reservoir node - EN_TANK = 2 //!< Storage tank node -} EN_NodeType; - -/// Link types -/** -These are the different types of links that can be returned by calling @ref EN_getlinktype. -*/ -typedef enum { - EN_CVPIPE = 0, //!< Pipe with check valve - EN_PIPE = 1, //!< Pipe - EN_PUMP = 2, //!< Pump - EN_PRV = 3, //!< Pressure reducing valve - EN_PSV = 4, //!< Pressure sustaining valve - EN_PBV = 5, //!< Pressure breaker valve - EN_FCV = 6, //!< Flow control valve - EN_TCV = 7, //!< Throttle control valve - EN_GPV = 8 //!< General purpose valve -} EN_LinkType; - -/// Link status -/** -One of these values is returned when @ref EN_getlinkvalue is used to retrieve a link's -initial status ( \b EN_INITSTATUS ) or its current status ( \b EN_STATUS ). These options are -also used with @ref EN_setlinkvalue to set values for these same properties. -*/ -typedef enum { - EN_CLOSED = 0, - EN_OPEN = 1 -} EN_LinkStatusType; - -/// Pump states -/** -One of these codes is returned when @ref EN_getlinkvalue is used to retrieve a pump's -current operating state ( \b EN_PUMP_STATE ). \b EN_PUMP_XHEAD indicates that the pump has been -shut down because it is being asked to deliver more than its shutoff head. \b EN_PUMP_XFLOW -indicates that the pump is being asked to deliver more than its maximum flow. -*/ -typedef enum { - EN_PUMP_XHEAD = 0, //!< Pump closed - cannot supply head - EN_PUMP_CLOSED = 2, //!< Pump closed - EN_PUMP_OPEN = 3, //!< Pump open - EN_PUMP_XFLOW = 5 //!< Pump open - cannot supply flow -} EN_PumpStateType; - -/// Types of water quality analyses -/** -These are the different types of water quality analyses that EPANET can run. They -are used with @ref EN_getqualinfo, @ref EN_getqualtype, and @ref EN_setqualtype. -*/ -typedef enum { - EN_NONE = 0, //!< No quality analysis - EN_CHEM = 1, //!< Chemical fate and transport - EN_AGE = 2, //!< Water age analysis - EN_TRACE = 3 //!< Source tracing analysis -} EN_QualityType; - -/// Water quality source types -/** -These are the different types of external water quality sources that can be assigned -to a node's \b EN_SOURCETYPE property as used by @ref EN_getnodevalue and @ref EN_setnodevalue. -*/ -typedef enum { - EN_CONCEN = 0, //!< Sets the concentration of external inflow entering a node - EN_MASS = 1, //!< Injects a given mass/minute into a node - EN_SETPOINT = 2, //!< Sets the concentration leaving a node to a given value - EN_FLOWPACED = 3 //!< Adds a given value to the concentration leaving a node -} EN_SourceType; - -/// Head loss formulas -/** -The available choices for the \b EN_HEADLOSSFORM option in @ref EN_getoption and -@ref EN_setoption. They are also used for the head loss type argument in @ref EN_init. -Each head loss formula uses a different type of roughness coefficient ( \b EN_ROUGHNESS ) -that can be set with @ref EN_setlinkvalue. -*/ -typedef enum { - EN_HW = 0, //!< Hazen-Williams - EN_DW = 1, //!< Darcy-Weisbach - EN_CM = 2 //!< Chezy-Manning -} EN_HeadLossType; - -/// Flow units -/** -These choices for flow units are used with @ref EN_getflowunits and @ref EN_setflowunits. -They are also used for the flow units type argument in @ref EN_init. If flow units are -expressed in US Customary units ( \b EN_CFS through \b EN_AFD ) then all other quantities are -in US Customary units. Otherwise they are in metric units. -*/ -typedef enum { - EN_CFS = 0, //!< Cubic feet per second - EN_GPM = 1, //!< Gallons per minute - EN_MGD = 2, //!< Million gallons per day - EN_IMGD = 3, //!< Imperial million gallons per day - EN_AFD = 4, //!< Acre-feet per day - EN_LPS = 5, //!< Liters per second - EN_LPM = 6, //!< Liters per minute - EN_MLD = 7, //!< Million liters per day - EN_CMH = 8, //!< Cubic meters per hour - EN_CMD = 9 //!< Cubic meters per day -} EN_FlowUnits; - -/// Demand models -/** -These choices for modeling consumer demands are used with @ref EN_getdemandmodel -and @ref EN_setdemandmodel. - -A demand driven analysis requires that a junction's full demand be supplied -in each time period independent of how much pressure is available. A pressure -driven analysis makes demand be a power function of pressure, up to the point -where the full demand is met. -*/ -typedef enum { - EN_DDA = 0, //!< Demand driven analysis - EN_PDA = 1 //!< Pressure driven analysis -} EN_DemandModel; - -/// Simulation options -/** -These constants identify the hydraulic and water quality simulation options -that are applied on a network-wide basis. They are accessed using the -@ref EN_getoption and @ref EN_setoption functions. -*/ -typedef enum { - EN_TRIALS = 0, //!< Maximum trials allowed for hydraulic convergence - EN_ACCURACY = 1, //!< Total normalized flow change for hydraulic convergence - EN_TOLERANCE = 2, //!< Water quality tolerance - EN_EMITEXPON = 3, //!< Exponent in emitter discharge formula - EN_DEMANDMULT = 4, //!< Global demand multiplier - EN_HEADERROR = 5, //!< Maximum head loss error for hydraulic convergence - EN_FLOWCHANGE = 6, //!< Maximum flow change for hydraulic convergence - EN_HEADLOSSFORM = 7, //!< Head loss formula (see @ref EN_HeadLossType) - EN_GLOBALEFFIC = 8, //!< Global pump efficiency (percent) - EN_GLOBALPRICE = 9, //!< Global energy price per KWH - EN_GLOBALPATTERN = 10, //!< Index of a global energy price pattern - EN_DEMANDCHARGE = 11, //!< Energy charge per max. KW usage - EN_SP_GRAVITY = 12, //!< Specific gravity - EN_SP_VISCOS = 13, //!< Specific viscosity (relative to water at 20 deg C) - EN_UNBALANCED = 14, //!< Extra trials allowed if hydraulics don't converge - EN_CHECKFREQ = 15, //!< Frequency of hydraulic status checks - EN_MAXCHECK = 16, //!< Maximum trials for status checking - EN_DAMPLIMIT = 17, //!< Accuracy level where solution damping begins - EN_SP_DIFFUS = 18, //!< Specific diffusivity (relative to chlorine at 20 deg C) - EN_BULKORDER = 19, //!< Bulk water reaction order for pipes - EN_WALLORDER = 20, //!< Wall reaction order for pipes (either 0 or 1) - EN_TANKORDER = 21, //!< Bulk water reaction order for tanks - EN_CONCENLIMIT = 22 //!< Limiting concentration for growth reactions -} EN_Option; - -/// Simple control types -/** -These are the different types of simple (single statement) controls that can be applied -to network links. They are used as an argument to @ref EN_addcontrol,@ref EN_getcontrol, -and @ref EN_setcontrol. -*/ -typedef enum { - EN_LOWLEVEL = 0, //!< Act when pressure or tank level drops below a setpoint - EN_HILEVEL = 1, //!< Act when pressure or tank level rises above a setpoint - EN_TIMER = 2, //!< Act at a prescribed elapsed amount of time - EN_TIMEOFDAY = 3 //!< Act at a particular time of day -} EN_ControlType; - -/// Reporting statistic choices -/** -These options determine what kind of statistical post-processing should be done on -the time series of simulation results generated before they are reported using -@ref EN_report. An option can be chosen by using \b STATISTIC _option_ as the argument -to @ref EN_setreport. -*/ -typedef enum { - EN_SERIES = 0, //!< Report all time series points - EN_AVERAGE = 1, //!< Report average value over simulation period - EN_MINIMUM = 2, //!< Report minimum value over simulation period - EN_MAXIMUM = 3, //!< Report maximum value over simulation period - EN_RANGE = 4 //!< Report maximum - minimum over simulation period -} EN_StatisticType; - -/// Tank mixing models -/** -These are the different types of models that describe water quality mixing in storage tanks. -The choice of model is accessed with the \b EN_MIXMODEL property of a Tank node using -@ref EN_getnodevalue and @ref EN_setnodevalue. -*/ -typedef enum { - EN_MIX1 = 0, //!< Complete mix model - EN_MIX2 = 1, //!< 2-compartment model - EN_FIFO = 2, //!< First in, first out model - EN_LIFO = 3 //!< Last in, first out model -} EN_MixingModel; - -/// Hydraulic initialization options -/** -These options are used to initialize a new hydraulic analysis when @ref EN_initH is called. -*/ -typedef enum { - EN_NOSAVE = 0, //!< Don't save hydraulics; don't re-initialize flows - EN_SAVE = 1, //!< Save hydraulics to file, don't re-initialize flows - EN_INITFLOW = 10, //!< Don't save hydraulics; re-initialize flows - EN_SAVE_AND_INIT = 11 //!< Save hydraulics; re-initialize flows -} EN_InitHydOption; - -/// Types of pump curves -/** -@ref EN_getpumptype returns one of these values when it is called. -*/ -typedef enum { - EN_CONST_HP = 0, //!< Constant horsepower - EN_POWER_FUNC = 1, //!< Power function - EN_CUSTOM = 2, //!< User-defined custom curve - EN_NOCURVE = 3 //!< No curve -} EN_PumpType; - -/// Types of data curves -/** -These are the different types of physical relationships that a data curve can -represent as returned by calling @ref EN_getcurvetype. -*/ -typedef enum { - EN_VOLUME_CURVE = 0, //!< Tank volume v. depth curve - EN_PUMP_CURVE = 1, //!< Pump head v. flow curve - EN_EFFIC_CURVE = 2, //!< Pump efficiency v. flow curve - EN_HLOSS_CURVE = 3, //!< Valve head loss v. flow curve - EN_GENERIC_CURVE = 4 //!< Generic curve -} EN_CurveType; - -/// Deletion action codes -/** -These codes are used in @ref EN_deletenode and @ref EN_deletelink to indicate what action -should be taken if the node or link being deleted appears in any simple or rule-based -controls or if a deleted node has any links connected to it. -*/ -typedef enum { - EN_UNCONDITIONAL = 0, //!< Delete all controls and connecing links - EN_CONDITIONAL = 1 //!< Cancel object deletion if it appears in controls or has connecting links -} EN_ActionCodeType; - -/// Status reporting levels -/** -These choices specify the level of status reporting written to a project's report -file during a hydraulic analysis. The level is set using the @ref EN_setstatusreport function. -*/ -typedef enum { - EN_NO_REPORT = 0, //!< No status reporting - EN_NORMAL_REPORT = 1, //!< Normal level of status reporting - EN_FULL_REPORT = 2 //!< Full level of status reporting -} EN_StatusReport; - -/// Network objects used in rule-based controls -typedef enum { - EN_R_NODE = 6, //!< Clause refers to a node - EN_R_LINK = 7, //!< Clause refers to a link - EN_R_SYSTEM = 8 //!< Clause refers to a system parameter (e.g., time) -} EN_RuleObject; - -/// Object variables used in rule-based controls -typedef enum { - EN_R_DEMAND = 0, //!< Nodal demand - EN_R_HEAD = 1, //!< Nodal hydraulic head - EN_R_GRADE = 2, //!< Nodal hydraulic grade - EN_R_LEVEL = 3, //!< Tank water level - EN_R_PRESSURE = 4, //!< Nodal pressure - EN_R_FLOW = 5, //!< Link flow rate - EN_R_STATUS = 6, //!< Link status - EN_R_SETTING = 7, //!< Link setting - EN_R_POWER = 8, //!< Pump power output - EN_R_TIME = 9, //!< Elapsed simulation time - EN_R_CLOCKTIME = 10, //!< Time of day - EN_R_FILLTIME = 11, //!< Time to fill a tank - EN_R_DRAINTIME = 12 //!< Time to drain a tank -} EN_RuleVariable; - -/// Comparison operators used in rule-based controls -typedef enum { - EN_R_EQ = 0, //!< Equal to - EN_R_NE = 1, //!< Not equal - EN_R_LE = 2, //!< Less than or equal to - EN_R_GE = 3, //!< Greater than or equal to - EN_R_LT = 4, //!< Less than - EN_R_GT = 5, //!< Greater than - EN_R_IS = 6, //!< Is equal to - EN_R_NOT = 7, //!< Is not equal to - EN_R_BELOW = 8, //!< Is below - EN_R_ABOVE = 9 //!< Is above -} EN_RuleOperator; - -/// Link status codes used in rule-based controls -typedef enum { - EN_R_IS_OPEN = 1, //!< Link is open - EN_R_IS_CLOSED = 2, //!< Link is closed - EN_R_IS_ACTIVE = 3 //!< Control valve is active -} EN_RuleStatus; - -#define EN_MISSING -1.E10 //!< Missing value indicator - -#endif //EPANET2_ENUMS_H diff --git a/Include/runvc.bat b/Include/runvc.bat deleted file mode 100644 index 790d89f..0000000 --- a/Include/runvc.bat +++ /dev/null @@ -1,7 +0,0 @@ -@echo off -set curdir=%cd% -cd "%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\" -for /F "tokens=* USEBACKQ" %%F in (`vswhere.exe -latest -property installationPath`) do (set VSDIR=%%F) -call "%VSDIR%\Common7\Tools\VsDevCmd.bat" -arch=%2% > nul -cd %curdir% -CL /O2 /LD /nologo %1% diff --git a/Include/x64/epanet2.dll b/Include/x64/epanet2.dll deleted file mode 100644 index 544c418729b1f018466c8f25e2c5a46f346040ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 418304 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�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 z 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 H5C8rjA~xqY diff --git a/Include/x64/epanet2.lib b/Include/x64/epanet2.lib deleted file mode 100644 index ad37c1cfaaf7ad34cc58dea2b846bb8e3701ef6e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50330 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 vlvLR(=g#BK+`ZJ@F1^Xw*>mR1 zeDgTxyEAuwZ#W&<_p)n|Pk$CJ)^(wE@jr{Zm%hmU?s5UZasby!fa>c2HO&CtM@(8e z07zGCI2z6KP;6Qs!{K;N#gZMd z3g(+h=F$<}i^c6o4JlPlmp3JHa`c1k$kd7%EB`>w9-ymR#PM2WPI4z zV%fQlHMxwj@6D(Vq}W8;HMX{EXibtSb<<6)Xg2NXl59F3dGVwR;CeN3Vhz9}FF;2N zz;G?VVJwL_S0l%sM!C`iaIYR<1bOj71LMZyZh$+eFTt`6>vl8(9K>>M9l$A+o#=N1 z`#OUC?#K4Mt=JZQE@QvP@P8c3POL*phw0D)UT6Y0G(t5rLk%=Q9n`{Xs0R=k~c}eXnXl-?_k|Bd(Ws67jHRG3ahET0=W>mrKG9=CL z-3oAr+*fEt%Vj0oL`EQ22SB?|k+lg5xE1gd4@(%zWx3eNS0ipE;3ha1$rDp&G#*Ei{l8Ocpi3NMce$b?74YE9=%2M^fGowH&Zx0F zw|Bu-uEI+Eb4Vz>3_{&2ov~;*8(z>Ys*qmc63Q4iRA3o|uCv?^PonHW`i3&Z6Mke3 zg70iOmLB9xdS+{rdKTPuGtm02S%;@-WZ84Mh7GYuI+;oC$@-ofc;2_Zf8#n{uNC;l z02&GjATiTFWPBuM`lsPQFp^B9aJ=VoWo6^zY8!M$>LwA>4g#1%-X|>P1Q` z&FBy@QC1~?m5AvPMv9mdLg6Jv%oIgJA-mg-!+7H5r08{9DsF}>(_q>1AFm+*+iK@^ zn;_EyVyP%oDbv&^2tko)eqkrSQK9gX{H9=i3t8KFID`qpve?!2^V6ZvN4ITC*XT%d zRqrjl?&4EvJ1J?s>uFy=2Kak;0w`F!ve&=HqavQ^Of2^L)?tdyG$)*oj~;nUIOPn7 zoeN6ES&~1W!w0sUqwfzD3Jx7ObSOM{OnsQmIKSru8CbFmanm}`1L^t)3gFnCHN{pP}{rER8V%0J%^ID?y zTYNq{pxht*<~*U)F%X%st}Qs1k7;IAeR*f0a0+f#Imv zGaanxtnxdctr|XbpU~VEnz;8(0ot_0vD<{^;b_XYh$%q3`qt4$gw`n0PFh zpP%@Z_^?GHJ|#YM$m_xOPye92rtgl{H!N-4if1VYoT^zr|3Emc3eFb2XI(2`x12cl jR^>Zm#D;AghdzpwI2(tzNXNxb9#Z_ZGZf`xi;ndljHFK( diff --git a/Include/x86/epanet2.dll b/Include/x86/epanet2.dll deleted file mode 100644 index e28cfb12fdd0aa862a66996aa77f4cd162c35bb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 367752 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�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 -#include -#include "hash.h" - -/* Use Fletcher's checksum to compute 2-byte hash of string */ -unsigned int hash(char *str) -{ - unsigned int sum1= 0, check1; - unsigned long sum2= 0L; - while( '\0' != *str ) - { - sum1 += (*str); - str++; - if ( 255 <= sum1 ) sum1 -= 255; - sum2 += sum1; - } - check1= sum2; - check1 %= 255; - check1= 255 - (sum1+check1) % 255; - sum1= 255 - (sum1+check1) % 255; - return( ( ( check1 << 8 ) | sum1 ) % HTMAXSIZE); -} - -HTtable *HTcreate() -{ - int i; - HTtable *ht = (HTtable *) calloc(HTMAXSIZE, sizeof(HTtable)); - if (ht != NULL) for (i=0; i= HTMAXSIZE ) return(0); - entry = (struct HTentry *) malloc(sizeof(struct HTentry)); - if (entry == NULL) return(0); - entry->key = key; - entry->data = data; - entry->next = ht[i]; - ht[i] = entry; - return(1); -} - -int HTfind(HTtable *ht, char *key) -{ - unsigned int i = hash(key); - struct HTentry *entry; - if ( i >= HTMAXSIZE ) return(NOTFOUND); - entry = ht[i]; - while (entry != NULL) - { - if ( strcmp(entry->key,key) == 0 ) return(entry->data); - entry = entry->next; - } - return(NOTFOUND); -} - -char *HTfindKey(HTtable *ht, char *key) -{ - unsigned int i = hash(key); - struct HTentry *entry; - if ( i >= HTMAXSIZE ) return(NULL); - entry = ht[i]; - while (entry != NULL) - { - if ( strcmp(entry->key,key) == 0 ) return(entry->key); - entry = entry->next; - } - return(NULL); -} - -void HTfree(HTtable *ht) -{ - struct HTentry *entry, - *nextentry; - int i; - for (i=0; inext; - free(entry); - entry = nextentry; - } - } - free(ht); -} diff --git a/Src/hash.h b/Src/hash.h deleted file mode 100644 index a6b0433..0000000 --- a/Src/hash.h +++ /dev/null @@ -1,24 +0,0 @@ -/* HASH.H -** -** Header file for Hash Table module HASH.C -** -*/ - -#define HTMAXSIZE 1999 -#define NOTFOUND 0 - -struct HTentry -{ - char *key; - int data; - struct HTentry *next; -}; - -typedef struct HTentry *HTtable; - -HTtable *HTcreate(void); -int HTinsert(HTtable *, char *, int); -int HTfind(HTtable *, char *); -char *HTfindKey(HTtable *, char *); -void HTfree(HTtable *); - diff --git a/Src/mathexpr.c b/Src/mathexpr.c deleted file mode 100644 index f09baa3..0000000 --- a/Src/mathexpr.c +++ /dev/null @@ -1,936 +0,0 @@ -/****************************************************************************** -** MODULE: MATHEXPR.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Evaluates symbolic mathematical expression consisting -** of numbers, variable names, math functions & arithmetic -** operators. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 09/02/2022 -******************************************************************************/ -/* -** Operand codes: -** 1 = ( -** 2 = ) -** 3 = + -** 4 = - (subtraction) -** 5 = * -** 6 = / -** 7 = number -** 8 = user-defined variable -** 9 = - (negative) -** 10 = cos -** 11 = sin -** 12 = tan -** 13 = cot -** 14 = abs -** 15 = sgn -** 16 = sqrt -** 17 = log -** 18 = exp -** 19 = asin -** 20 = acos -** 21 = atan -** 22 = acot -** 23 = sinh -** 24 = cosh -** 25 = tanh -** 26 = coth -** 27 = log10 -** 28 = step (x<=0 ? 0 : 1) -** 31 = ^ -******************************************************************************/ -#define _CRT_SECURE_NO_WARNINGS - -#include -#include -#include -#include -#include -#include "mathexpr.h" - -#define MAX_STACK_SIZE 1024 - -//*************************************************** -#define MAX_TERM_SIZE 1024 -struct MathTerm -{ - char s[MAX_TERM_SIZE]; -}; -typedef struct MathTerm Term; -//*************************************************** - - -// Local declarations -//-------------------- -// Structure for binary tree representation of math expression -struct TreeNode -{ - int opcode; // operator code - int ivar; // variable index - double fvalue; // numerical value - struct TreeNode* left; // left sub-tree of tokenized formula - struct TreeNode* right; // right sub-tree of tokenized formula -}; -typedef struct TreeNode ExprTree; - -// Local variables -//---------------- -static int Err; -static int Bc; -static int PrevLex, CurLex; -static int Len, Pos; -static char* S; -static char Token[255]; -static int Ivar; -static double Fvalue; - -// math function names -char* MathFunc[] = { "COS", "SIN", "TAN", "COT", "ABS", "SGN", - "SQRT", "LOG", "EXP", "ASIN", "ACOS", "ATAN", - "ACOT", "SINH", "COSH", "TANH", "COTH", "LOG10", - "STEP", NULL }; - -// Local functions -//---------------- -static int sametext(char*, char*); -static int isDigit(char); -static int isLetter(char); -static void getToken(void); -static int getMathFunc(void); -static int getVariable(void); -static int getOperand(void); -static int getLex(void); -static double getNumber(void); -static ExprTree* newNode(void); -static ExprTree* getSingleOp(int*); -static ExprTree* getOp(int*); -static ExprTree* getTree(void); -static void traverseTree(ExprTree*, MathExpr**); -static void deleteTree(ExprTree*); - -// Callback functions -static int (*getVariableIndex) (char*); // return index of named variable -static double (*getVariableValue) (int); // return value of indexed variable - -//============================================================================= - -int sametext(char* s1, char* s2) -/* -** Purpose: -** performs case insensitive comparison of two strings. -** -** Input: -** s1 = character string -** s2 = character string. -** -** Returns: -** 1 if strings are the same, 0 otherwise. -*/ -{ - int i; - for (i = 0; toupper(s1[i]) == toupper(s2[i]); i++) - if (!s1[i + 1] && !s2[i + 1]) return(1); - return(0); -} - -//============================================================================= - -int isDigit(char c) -{ - if (c >= '1' && c <= '9') return 1; - if (c == '0') return 1; - return 0; -} - -//============================================================================= - -int isLetter(char c) -{ - if (c >= 'a' && c <= 'z') return 1; - if (c >= 'A' && c <= 'Z') return 1; - if (c == '_') return 1; - return 0; -} - -//============================================================================= - -void getToken() -{ - char c[] = " "; - Token[0] = '\0'; - while (Pos <= Len && - (isLetter(S[Pos]) || isDigit(S[Pos]))) - { - c[0] = S[Pos]; - strcat(Token, c); - Pos++; - } - Pos--; -} - -//============================================================================= - -int getMathFunc() -{ - int i = 0; - while (MathFunc[i] != NULL) - { - if (sametext(MathFunc[i], Token)) return i + 10; - i++; - } - return(0); -} - -//============================================================================= - -int getVariable() -{ - if (!getVariableIndex) return 0; - Ivar = getVariableIndex(Token); - if (Ivar >= 0) return 8; - return 0; -} - -//============================================================================= - -double getNumber() -{ - char c[] = " "; - char sNumber[255]; - int errflag = 0; - int decimalCount = 0; - - /* --- get whole number portion of number */ - sNumber[0] = '\0'; - while (Pos < Len && isDigit(S[Pos])) - { - c[0] = S[Pos]; - strcat(sNumber, c); - Pos++; - } - - /* --- get fractional portion of number */ - if (Pos < Len) - { - if (S[Pos] == '.') - { - decimalCount++; - if (decimalCount > 1) Err = 1; - strcat(sNumber, "."); - Pos++; - while (Pos < Len && isDigit(S[Pos])) - { - c[0] = S[Pos]; - strcat(sNumber, c); - Pos++; - } - } - - /* --- get exponent */ - if (Pos < Len && (S[Pos] == 'e' || S[Pos] == 'E')) - { - strcat(sNumber, "E"); - Pos++; - if (Pos >= Len) errflag = 1; - else - { - if (S[Pos] == '-' || S[Pos] == '+') - { - c[0] = S[Pos]; - strcat(sNumber, c); - Pos++; - } - if (Pos >= Len || !isDigit(S[Pos])) errflag = 1; - else while (Pos < Len && isDigit(S[Pos])) - { - c[0] = S[Pos]; - strcat(sNumber, c); - Pos++; - } - } - } - } - Pos--; - if (errflag) return 0; - else return atof(sNumber); -} - -//============================================================================= - -int getOperand() -{ - int code; - switch (S[Pos]) - { - case '(': code = 1; break; - case ')': code = 2; break; - case '+': code = 3; break; - case '-': code = 4; - if (Pos < Len - 1 && - isDigit(S[Pos + 1]) && - (CurLex <= 6 || CurLex == 31)) - { - Pos++; - Fvalue = -getNumber(); - code = 7; - } - break; - case '*': code = 5; break; - case '/': code = 6; break; - case '^': code = 31; break; - default: code = 0; - } - return code; -} - -//============================================================================= - -int getLex() -{ - int n; - - /* --- skip spaces */ - while (Pos < Len && S[Pos] == ' ') Pos++; - if (Pos >= Len) return 0; - - /* --- check for operand */ - n = getOperand(); - - /* --- check for function/variable/number */ - if (n == 0) - { - if (isLetter(S[Pos])) - { - getToken(); - n = getMathFunc(); - if (n == 0) n = getVariable(); - } - else if (S[Pos] == '.' || isDigit(S[Pos])) - { - n = 7; - Fvalue = getNumber(); - } - } - Pos++; - PrevLex = CurLex; - CurLex = n; - return n; -} - -//============================================================================= - -ExprTree* newNode() -{ - ExprTree* node; - node = (ExprTree*)malloc(sizeof(ExprTree)); - if (!node) Err = 2; - else - { - node->opcode = 0; - node->ivar = -1; - node->fvalue = 0.; - node->left = NULL; - node->right = NULL; - } - return node; -} - -//============================================================================= - -ExprTree* getSingleOp(int* lex) -{ - int opcode; - ExprTree* left; - ExprTree* node; - - /* --- open parenthesis, so continue to grow the tree */ - if (*lex == 1) - { - Bc++; - left = getTree(); - } - - else - { - /* --- Error if not a singleton operand */ - if (*lex < 7 || *lex == 9 || *lex > 30) - { - Err = 1; - return NULL; - } - - opcode = *lex; - - /* --- simple number or variable name */ - if (*lex == 7 || *lex == 8) - { - left = newNode(); - left->opcode = opcode; - if (*lex == 7) left->fvalue = Fvalue; - if (*lex == 8) left->ivar = Ivar; - } - - /* --- function which must have a '(' after it */ - else - { - *lex = getLex(); - if (*lex != 1) - { - Err = 1; - return NULL; - } - Bc++; - left = newNode(); - left->left = getTree(); - left->opcode = opcode; - } - } - *lex = getLex(); - - /* --- exponentiation */ - if (*lex == 31) - { - node = newNode(); - node->left = left; - node->opcode = *lex; - *lex = getLex(); - node->right = getSingleOp(lex); - left = node; - } - return left; -} - -//============================================================================= - -ExprTree* getOp(int* lex) -{ - int opcode; - ExprTree* left; - ExprTree* right; - ExprTree* node; - int neg = 0; - - *lex = getLex(); - if (PrevLex == 0 || PrevLex == 1) - { - if (*lex == 4) - { - neg = 1; - *lex = getLex(); - } - else if (*lex == 3) *lex = getLex(); - } - left = getSingleOp(lex); - while (*lex == 5 || *lex == 6) - { - opcode = *lex; - *lex = getLex(); - right = getSingleOp(lex); - node = newNode(); - if (Err) return NULL; - node->left = left; - node->right = right; - node->opcode = opcode; - left = node; - } - if (neg) - { - node = newNode(); - if (Err) return NULL; - node->left = left; - node->right = NULL; - node->opcode = 9; - left = node; - } - return left; -} - -//============================================================================= - -ExprTree* getTree() -{ - int lex; - int opcode; - ExprTree* left; - ExprTree* right; - ExprTree* node; - - left = getOp(&lex); - for (;;) - { - if (lex == 0 || lex == 2) - { - if (lex == 2) Bc--; - break; - } - - if (lex != 3 && lex != 4) - { - Err = 1; - break; - } - - opcode = lex; - right = getOp(&lex); - node = newNode(); - if (Err) break; - node->left = left; - node->right = right; - node->opcode = opcode; - left = node; - } - return left; -} - -//============================================================================= - -void traverseTree(ExprTree* tree, MathExpr** expr) -// Converts binary tree to linked list (postfix format) -{ - MathExpr* node; - if (tree == NULL) return; - traverseTree(tree->left, expr); - traverseTree(tree->right, expr); - node = (MathExpr*)malloc(sizeof(MathExpr)); - if (node) - { - node->fvalue = tree->fvalue; - node->opcode = tree->opcode; - node->ivar = tree->ivar; - node->next = NULL; - node->prev = (*expr); - } - if (*expr) (*expr)->next = node; - (*expr) = node; -} - -//============================================================================= - -void deleteTree(ExprTree* tree) -{ - if (tree) - { - if (tree->left) deleteTree(tree->left); - if (tree->right) deleteTree(tree->right); - free(tree); - } -} - -//============================================================================= - -// Turn on "precise" floating point option -#pragma float_control(precise, on, push) - -double mathexpr_eval(MathExpr* expr, double (*getVariableValue) (int)) -// Mathematica expression evaluation using a stack -{ - - // --- Note: the exprStack array must be declared locally and not globally - // since this function can be called recursively. - - double exprStack[MAX_STACK_SIZE]; - MathExpr* node = expr; - double r1, r2; - int stackindex = 0; - - exprStack[0] = 0.0; - while (node != NULL) - { - switch (node->opcode) - { - case 3: - r1 = exprStack[stackindex]; - stackindex--; - r2 = exprStack[stackindex]; - exprStack[stackindex] = r2 + r1; - break; - - case 4: - r1 = exprStack[stackindex]; - stackindex--; - r2 = exprStack[stackindex]; - exprStack[stackindex] = r2 - r1; - break; - - case 5: - r1 = exprStack[stackindex]; - stackindex--; - r2 = exprStack[stackindex]; - exprStack[stackindex] = r2 * r1; - break; - - case 6: - r1 = exprStack[stackindex]; - stackindex--; - r2 = exprStack[stackindex]; - exprStack[stackindex] = r2 / r1; - break; - - case 7: - stackindex++; - exprStack[stackindex] = node->fvalue; - break; - - case 8: - if (getVariableValue != NULL) - r1 = getVariableValue(node->ivar); - else r1 = 0.0; - stackindex++; - exprStack[stackindex] = r1; - break; - - case 9: - exprStack[stackindex] = -exprStack[stackindex]; - break; - - case 10: - r1 = exprStack[stackindex]; - r2 = cos(r1); - exprStack[stackindex] = r2; - break; - - case 11: - r1 = exprStack[stackindex]; - r2 = sin(r1); - exprStack[stackindex] = r2; - break; - - case 12: - r1 = exprStack[stackindex]; - r2 = tan(r1); - exprStack[stackindex] = r2; - break; - - case 13: - r1 = exprStack[stackindex]; - r2 = 1.0 / tan(r1); - exprStack[stackindex] = r2; - break; - - case 14: - r1 = exprStack[stackindex]; - r2 = fabs(r1); - exprStack[stackindex] = r2; - break; - - case 15: - r1 = exprStack[stackindex]; - if (r1 < 0.0) r2 = -1.0; - else if (r1 > 0.0) r2 = 1.0; - else r2 = 0.0; - exprStack[stackindex] = r2; - break; - - case 16: - r1 = exprStack[stackindex]; - r2 = sqrt(r1); - exprStack[stackindex] = r2; - break; - - case 17: - r1 = exprStack[stackindex]; - r2 = log(r1); - exprStack[stackindex] = r2; - break; - - case 18: - r1 = exprStack[stackindex]; - r2 = exp(r1); - exprStack[stackindex] = r2; - break; - - case 19: - r1 = exprStack[stackindex]; - r2 = asin(r1); - exprStack[stackindex] = r2; - break; - - case 20: - r1 = exprStack[stackindex]; - r2 = acos(r1); - exprStack[stackindex] = r2; - break; - - case 21: - r1 = exprStack[stackindex]; - r2 = atan(r1); - exprStack[stackindex] = r2; - break; - - case 22: - r1 = exprStack[stackindex]; - r2 = 1.57079632679489661923 - atan(r1); - exprStack[stackindex] = r2; - break; - - case 23: - r1 = exprStack[stackindex]; - r2 = (exp(r1) - exp(-r1)) / 2.0; - exprStack[stackindex] = r2; - break; - - case 24: - r1 = exprStack[stackindex]; - r2 = (exp(r1) + exp(-r1)) / 2.0; - exprStack[stackindex] = r2; - break; - - case 25: - r1 = exprStack[stackindex]; - r2 = (exp(r1) - exp(-r1)) / (exp(r1) + exp(-r1)); - exprStack[stackindex] = r2; - break; - - case 26: - r1 = exprStack[stackindex]; - r2 = (exp(r1) + exp(-r1)) / (exp(r1) - exp(-r1)); - exprStack[stackindex] = r2; - break; - - case 27: - r1 = exprStack[stackindex]; - r2 = log10(r1); - exprStack[stackindex] = r2; - break; - - case 28: - r1 = exprStack[stackindex]; - if (r1 <= 0.0) r2 = 0.0; - else r2 = 1.0; - exprStack[stackindex] = r2; - break; - - case 31: - r1 = exprStack[stackindex]; - stackindex--; - if (stackindex < 0) break; - r2 = exprStack[stackindex]; - if (r2 <= 0.0) r2 = 0.0; - else r2 = pow(r2, r1); - exprStack[stackindex] = r2; - break; - } - node = node->next; - } - if (stackindex >= 0) - r1 = exprStack[stackindex]; - else - r1 = 0.0; - - // Set result to 0 if it is NaN due to an illegal math op - if (r1 != r1) r1 = 0.0; - - return r1; -} - -// Turn off "precise" floating point option -#pragma float_control(pop) - -//============================================================================= - -void mathexpr_delete(MathExpr* expr) -{ - if (expr) mathexpr_delete(expr->next); - free(expr); -} - -//============================================================================= - -MathExpr* mathexpr_create(char* formula, int (*getVar) (char*)) -{ - ExprTree* tree; - MathExpr* expr = NULL; - MathExpr* result = NULL; - getVariableIndex = getVar; - Err = 0; - PrevLex = 0; - CurLex = 0; - S = formula; - Len = (int)strlen(S); - Pos = 0; - Bc = 0; - tree = getTree(); - if (Bc == 0 && Err == 0) - { - traverseTree(tree, &expr); - while (expr) - { - result = expr; - expr = expr->prev; - } - } - deleteTree(tree); - return result; -} - - -//============================================================================= - -char* mathexpr_getStr(MathExpr* expr, char* exprStr, - char* (*getVariableStr) (int, char*)) -{ - Term TermStack[50]; - MathExpr* node = expr; - char r1[MAX_TERM_SIZE], r2[MAX_TERM_SIZE]; - int stackindex = 0; - - strcpy(TermStack[0].s, ""); - while (node != NULL) - { - switch (node->opcode) - { - case 3: - strcpy(r1, TermStack[stackindex].s); - stackindex--; - strcpy(r2, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "(%s) + (%s)", r2, r1); - break; - - case 4: - strcpy(r1, TermStack[stackindex].s); - stackindex--; - strcpy(r2, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "(%s) - (%s)", r2, r1); - break; - - case 5: - strcpy(r1, TermStack[stackindex].s); - stackindex--; - strcpy(r2, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "(%s) * (%s)", r2, r1); - break; - - case 6: - strcpy(r1, TermStack[stackindex].s); - stackindex--; - strcpy(r2, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "(%s) / (%s)", r2, r1); - break; - - case 7: - stackindex++; - sprintf(TermStack[stackindex].s, "%.6g", node->fvalue); - break; - - case 8: - if (getVariableStr != NULL)strcpy(r1, getVariableStr(node->ivar, r2)); - else strcpy(r1, ""); - stackindex++; - strcpy(TermStack[stackindex].s, r1); - break; - - case 9: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "-(%s)", r1); - break; - - case 10: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "cos(%s)", r1); - break; - - case 11: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "sin(%s)", r1); - break; - - case 12: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "tan(%s)", r1); - break; - - case 13: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "cot(%s)", r1); - break; - - case 14: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "abs(%s)", r1); - break; - - case 15: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "sgn(%s)", r1); - break; - - case 16: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "sqrt(%s)", r1); - break; - - case 17: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "log(%s)", r1); - break; - - case 18: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "exp(%s)", r1); - break; - - case 19: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "asin(%s)", r1); - break; - - case 20: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "acos(%s)", r1); - break; - - case 21: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "atan(%s)", r1); - break; - - case 22: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "acot(%s)", r1); - break; - - case 23: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "sinh(%s)", r1); - break; - - case 24: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "cosh(%s)", r1); - break; - - case 25: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "tanh(%s)", r1); - break; - - case 26: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "coth(%s)", r1); - break; - - case 27: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "log10(%s)", r1); - break; - - case 28: - strcpy(r1, TermStack[stackindex].s); - sprintf(TermStack[stackindex].s, "step(%s)", r1); - break; - - case 31: - strcpy(r1, TermStack[stackindex].s); - strcpy(r2, TermStack[stackindex - 1].s); - sprintf(TermStack[stackindex - 1].s, "pow(%s,%s)", r2, r1); - stackindex--; - break; - } - node = node->next; - } - strcpy(exprStr, TermStack[stackindex].s); - return exprStr; -} diff --git a/Src/mathexpr.h b/Src/mathexpr.h deleted file mode 100644 index 71e0fb3..0000000 --- a/Src/mathexpr.h +++ /dev/null @@ -1,34 +0,0 @@ -/****************************************************************************** -** MODULE: MATHEXPR.H -** PROJECT: EPANET-MSX -** DESCRIPTION: header file for the math expression parser in mathexpr.c. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 2/8/11 -******************************************************************************/ - -// Node in a tokenized math expression list -struct ExprNode -{ - int opcode; // operator code - int ivar; // variable index - double fvalue; // numerical value - struct ExprNode *prev; // previous node - struct ExprNode *next; // next node -}; -typedef struct ExprNode MathExpr; - -// Creates a tokenized math expression from a string -MathExpr* mathexpr_create(char* s, int (*getVar) (char *)); - -// Evaluates a tokenized math expression -double mathexpr_eval(MathExpr* expr, double (*getVal) (int)); - -// Deletes a tokenized math expression -void mathexpr_delete(MathExpr* expr); - -// Returns reconstructed string version of a tokenized expression -char * mathexpr_getStr(MathExpr* expr, char* exprStr, - char * (*getVariableStr) (int, char *)); diff --git a/Src/mempool.c b/Src/mempool.c deleted file mode 100644 index f2cc2ee..0000000 --- a/Src/mempool.c +++ /dev/null @@ -1,204 +0,0 @@ -/* mempool.c -** -** A simple fast memory allocation package. -** -** By Steve Hill in Graphics Gems III, David Kirk (ed.), -** Academic Press, Boston, MA, 1992 -** -** Modified by Lew Rossman, 8/13/94. -** -** AllocInit() - create an alloc pool, returns the old pool handle -** Alloc() - allocate memory -** AllocReset() - reset the current pool -** AllocSetPool() - set the current pool -** AllocFree() - free the memory used by the current pool. -** -*/ - -#include -#include -#include "mempool.h" - -/* -** ALLOC_BLOCK_SIZE - adjust this size to suit your installation - it -** should be reasonably large otherwise you will be mallocing a lot. -*/ - -#define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/ - -/* -** alloc_hdr_t - Header for each block of memory. -*/ - -typedef struct alloc_hdr_s -{ - struct alloc_hdr_s *next; /* Next Block */ - char *block, /* Start of block */ - *free, /* Next free in block */ - *end; /* block + block size */ -} alloc_hdr_t; - -/* -** alloc_root_t - Header for the whole pool. -*/ - -typedef struct alloc_root_s -{ - alloc_hdr_t *first, /* First header in pool */ - *current; /* Current header */ -} alloc_root_t; - -/* -** root - Pointer to the current pool. -*/ - -static alloc_root_t *root; - - -/* -** AllocHdr() -** -** Private routine to allocate a header and memory block. -*/ - -static alloc_hdr_t *AllocHdr(void); - -static alloc_hdr_t * AllocHdr() -{ - alloc_hdr_t *hdr; - char *block; - - block = (char *) malloc(ALLOC_BLOCK_SIZE); - hdr = (alloc_hdr_t *) malloc(sizeof(alloc_hdr_t)); - - if (hdr == NULL || block == NULL) return(NULL); - hdr->block = block; - hdr->free = block; - hdr->next = NULL; - hdr->end = block + ALLOC_BLOCK_SIZE; - - return(hdr); -} - - -/* -** AllocInit() -** -** Create a new memory pool with one block. -** Returns pointer to the new pool. -*/ - -alloc_handle_t * AllocInit() -{ - alloc_handle_t *newpool; - - root = (alloc_root_t *) malloc(sizeof(alloc_root_t)); - if (root == NULL) return(NULL); - if ( (root->first = AllocHdr()) == NULL) return(NULL); - root->current = root->first; - newpool = (alloc_handle_t *) root; - return(newpool); -} - - -/* -** Alloc() -** -** Use as a direct replacement for malloc(). Allocates -** memory from the current pool. -*/ - -char * Alloc(long size) -{ - alloc_hdr_t *hdr = root->current; - char *ptr; - - /* - ** Align to 4 byte boundary - should be ok for most machines. - ** Change this if your machine has weird alignment requirements. - */ - size = (size + 3) & 0xfffffffc; - - ptr = hdr->free; - hdr->free += size; - - /* Check if the current block is exhausted. */ - - if (hdr->free >= hdr->end) - { - /* Is the next block already allocated? */ - - if (hdr->next != NULL) - { - /* re-use block */ - hdr->next->free = hdr->next->block; - root->current = hdr->next; - } - else - { - /* extend the pool with a new block */ - if ( (hdr->next = AllocHdr()) == NULL) return(NULL); - root->current = hdr->next; - } - - /* set ptr to the first location in the next block */ - ptr = root->current->free; - root->current->free += size; - } - - /* Return pointer to allocated memory. */ - - return(ptr); -} - - -/* -** AllocSetPool() -** -** Change the current pool. Return the old pool. -*/ - -alloc_handle_t * AllocSetPool(alloc_handle_t *newpool) -{ - alloc_handle_t *old = (alloc_handle_t *) root; - root = (alloc_root_t *) newpool; - return(old); -} - - -/* -** AllocReset() -** -** Reset the current pool for re-use. No memory is freed, -** so this is very fast. -*/ - -void AllocReset() -{ - root->current = root->first; - root->current->free = root->current->block; -} - - -/* -** AllocFreePool() -** -** Free the memory used by the current pool. -** Don't use where AllocReset() could be used. -*/ - -void AllocFreePool() -{ - alloc_hdr_t *tmp, - *hdr = root->first; - - while (hdr != NULL) - { - tmp = hdr->next; - free((char *) hdr->block); - free((char *) hdr); - hdr = tmp; - } - free((char *) root); - root = NULL; -} diff --git a/Src/mempool.h b/Src/mempool.h deleted file mode 100644 index bed1787..0000000 --- a/Src/mempool.h +++ /dev/null @@ -1,19 +0,0 @@ -/* -** mempool.h -** -** Header for mempool.c -** -** The type alloc_handle_t provides an opaque reference to the -** alloc pool - only the alloc routines know its structure. -*/ - -typedef struct -{ - long dummy; -} alloc_handle_t; - -alloc_handle_t *AllocInit(void); -char *Alloc(long); -alloc_handle_t *AllocSetPool(alloc_handle_t *); -void AllocReset(void); -void AllocFreePool(void); diff --git a/Src/msxchem.c b/Src/msxchem.c deleted file mode 100644 index 11cc3fb..0000000 --- a/Src/msxchem.c +++ /dev/null @@ -1,1285 +0,0 @@ -/******************************************************************************* -** MODULE: MSXCHEM.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Water quality chemistry functions. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -*******************************************************************************/ - -#include -#include -#include -#include - -#include "msxtypes.h" -#include "rk5.h" -#include "ros2.h" -#include "newton.h" -#include "msxfuncs.h" - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - - -// Constants -//----------- -int MAXIT = 20; // Max. number of iterations used - // in nonlinear equation solver -int NUMSIG = 3; // Number of significant digits in - // nonlinear equation solver error - -// Local variables -//----------------- -static Pseg TheSeg; // Current water quality segment -static int TheLink; // Index of current link -static int TheNode; // Index of current node -static int TheTank; // Index of current tank -static int NumSpecies; // Total number of species -static int NumPipeRateSpecies; // Number of species with pipe rates -static int NumTankRateSpecies; // Number of species with tank rates -static int NumPipeFormulaSpecies; // Number of species with pipe formulas -static int NumTankFormulaSpecies; // Number of species with tank formulas -static int NumPipeEquilSpecies; // Number of species with pipe equilibria -static int NumTankEquilSpecies; // Number of species with tank equilibria -static int *PipeRateSpecies; // Species governed by pipe reactions -static int *TankRateSpecies; // Species governed by tank reactions -static int *PipeEquilSpecies; // Species governed by pipe equilibria -static int *TankEquilSpecies; // Species governed by tank equilibria -static int LastIndex[MAX_OBJECTS]; // Last index of given type of variable -static double *Atol; // Absolute concentration tolerances -static double *Rtol; // Relative concentration tolerances -static double *Yrate; // Rate species concentrations -static double *Yequil; // Equilibrium species concentrations -static double HydVar[MAX_HYD_VARS]; // Values of hydraulic variables -static double *F; // Function values -static double *ChemC1; - -#pragma omp threadprivate(TheSeg, TheLink, TheNode, TheTank, Yrate, Yequil, HydVar, F, ChemC1) - -// Exported functions -//-------------------- -int MSXchem_open(void); -int MSXchem_react(double dt); -int MSXchem_equil(int zone, int k, double *c); -char* MSXchem_getVariableStr(int i, char *s); -void MSXchem_close(void); - -// Imported functions -//------------------- -int MSXcompiler_open(void); -void MSXcompiler_close(void); -double MSXerr_validate(double x, int index, int element, int exprType); - -// Local functions -//----------------- -static void setSpeciesChemistry(void); -static void setTankChemistry(void); -//static void evalHydVariables(int k); -static int evalPipeReactions(int k, double dt); -static int evalTankReactions(int k, double dt); -static int evalPipeEquil(double *c); -static int evalTankEquil(double *c); -static void evalPipeFormulas(double *c); -static void evalTankFormulas(double *c); -static double getPipeVariableValue(int i); -static double getTankVariableValue(int i); -static void getPipeDcDt(double t, double y[], int n, double deriv[]); -static void getTankDcDt(double t, double y[], int n, double deriv[]); -static void getPipeEquil(double t, double y[], int n, double f[]); -static void getTankEquil(double t, double y[], int n, double f[]); -static int isValidNumber(double x); //(L.Rossman - 11/03/10) - - -//============================================================================= - -int MSXchem_open() -/* -** Purpose: -** opens the multi-species chemistry system. -** -** Input: -** none. -** -** Returns: -** an error code (0 if no error). -*/ -{ - int m; - int numWallSpecies; - int numBulkSpecies; - int numTankExpr; - int numPipeExpr; - int errcode = 0; - - // --- allocate memory - - PipeRateSpecies = NULL; - TankRateSpecies = NULL; - PipeEquilSpecies = NULL; - TankEquilSpecies = NULL; - Atol = NULL; - Rtol = NULL; - Yrate = NULL; - Yequil = NULL; - NumSpecies = MSX.Nobjects[SPECIES]; - m = NumSpecies + 1; - PipeRateSpecies = (int*)calloc(m, sizeof(int)); - TankRateSpecies = (int*)calloc(m, sizeof(int)); - PipeEquilSpecies = (int*)calloc(m, sizeof(int)); - TankEquilSpecies = (int*)calloc(m, sizeof(int)); - Atol = (double*)calloc(m, sizeof(double)); - Rtol = (double*)calloc(m, sizeof(double)); - CALL(errcode, MEMCHECK(PipeRateSpecies)); - CALL(errcode, MEMCHECK(TankRateSpecies)); - CALL(errcode, MEMCHECK(PipeEquilSpecies)); - CALL(errcode, MEMCHECK(TankEquilSpecies)); - CALL(errcode, MEMCHECK(Atol)); - CALL(errcode, MEMCHECK(Rtol)); - -#pragma omp parallel -{ - Yrate = (double*)calloc(m, sizeof(double)); - Yequil = (double*)calloc(m, sizeof(double)); - F = (double*)calloc(m, sizeof(double)); - ChemC1 = (double*)calloc(m, sizeof(double)); -#pragma omp critical - { - CALL(errcode, MEMCHECK(Yrate)); - CALL(errcode, MEMCHECK(Yequil)); - CALL(errcode, MEMCHECK(F)); - CALL(errcode, MEMCHECK(ChemC1)); - } -} - if ( errcode ) return errcode; - -// --- assign species to each type of chemical expression - - setSpeciesChemistry(); - numPipeExpr = NumPipeRateSpecies + NumPipeFormulaSpecies + NumPipeEquilSpecies; - numTankExpr = NumTankRateSpecies + NumTankFormulaSpecies + NumTankEquilSpecies; - -// --- use pipe chemistry for tanks if latter was not supplied - - if ( numTankExpr == 0 ) - { - setTankChemistry(); - numTankExpr = numPipeExpr; - } - -// --- check if enough equations were specified - - numWallSpecies = 0; - numBulkSpecies = 0; - for (m=1; m<=NumSpecies; m++) - { - if ( MSX.Species[m].type == WALL ) numWallSpecies++; - if ( MSX.Species[m].type == BULK ) numBulkSpecies++; - } - if ( numPipeExpr != NumSpecies ) return ERR_NUM_PIPE_EXPR; - if ( numTankExpr != numBulkSpecies ) return ERR_NUM_TANK_EXPR; - -// --- open the ODE solver; -// arguments are max. number of ODE's, -// max. number of steps to be taken, -// 1 if automatic step sizing used (or 0 if not used) - - if ( MSX.Solver == RK5 ) - { - if ( rk5_open(NumSpecies, 1000, 1) == FALSE ) - return ERR_INTEGRATOR_OPEN; - } - if ( MSX.Solver == ROS2 ) - { - if ( ros2_open(NumSpecies, 1) == FALSE ) - return ERR_INTEGRATOR_OPEN; - } - -// --- open the algebraic eqn. solver - - m = MAX(NumPipeEquilSpecies, NumTankEquilSpecies); - if ( newton_open(m) == FALSE ) return ERR_NEWTON_OPEN; - -// --- assign entries to LastIndex array - - LastIndex[SPECIES] = MSX.Nobjects[SPECIES]; - LastIndex[TERM] = LastIndex[SPECIES] + MSX.Nobjects[TERM]; - LastIndex[PARAMETER] = LastIndex[TERM] + MSX.Nobjects[PARAMETER]; - LastIndex[CONSTANT] = LastIndex[PARAMETER] + MSX.Nobjects[CONSTANT]; - -// --- compile chemistry function dynamic library if specified - - if ( MSX.Compiler ) - { - errcode = MSXcompiler_open(); - if ( errcode ) return errcode; - } - return 0; -} - -//============================================================================= - -void MSXchem_close() -/* -** Purpose: -** closes the multi-species chemistry system. -** -** Input: -** none. -*/ -{ - if (MSX.Compiler) MSXcompiler_close(); - if (MSX.Solver == RK5) rk5_close(); - if (MSX.Solver == ROS2) ros2_close(); - newton_close(); - FREE(PipeRateSpecies); - FREE(TankRateSpecies); - FREE(PipeEquilSpecies); - FREE(TankEquilSpecies); - FREE(Atol); - FREE(Rtol); - -#pragma omp parallel -{ - FREE(ChemC1); - FREE(Yrate); - FREE(Yequil); - FREE(F); -} - -} - -//============================================================================= - -int MSXchem_react(double dt) -/* -** Purpose: -** computes reactions in all pipes and tanks. -** -** Input: -** dt = current WQ time step (sec). -** -** Returns: -** an error code or 0 if no error. -*/ -{ - int k, m; - int errcode = 0; - -// --- save tolerances of pipe rate species - - for (k=1; k<=NumPipeRateSpecies; k++) - { - m = PipeRateSpecies[k]; - Atol[k] = MSX.Species[m].aTol; - Rtol[k] = MSX.Species[m].rTol; - } - -// --- examine each link -#pragma omp parallel -{ - #pragma omp for private(k) - for (k = 1; k <= MSX.Nobjects[LINK]; k++) - { - // --- skip non-pipe links - - if (MSX.Link[k].len == 0.0) continue; - - // --- evaluate hydraulic variables - - //evalHydVariables(k); - for (int hi = 1; hi < MAX_HYD_VARS; hi++) - HydVar[hi] = MSX.Link[k].HydVar[hi]; - // --- compute pipe reactions - - errcode = evalPipeReactions(k, dt); - //if (errcode) return errcode; - } -} - if (errcode) return errcode; - -// --- save tolerances of tank rate species - - for (k=1; k<=NumTankRateSpecies; k++) - { - m = TankRateSpecies[k]; - Atol[k] = MSX.Species[m].aTol; - Rtol[k] = MSX.Species[m].rTol; - } - -// --- examine each tank - - for (k=1; k<=MSX.Nobjects[TANK]; k++) - { - // --- skip reservoirs - - if (MSX.Tank[k].a == 0.0) continue; - - // --- compute tank reactions - - errcode = evalTankReactions(k, dt); - if ( errcode ) return errcode; - } - return errcode; -} - -//============================================================================= - -int MSXchem_equil(int zone, int k, double *c) -/* -** Purpose: -** computes equilibrium concentrations for a set of chemical species. -** -** Input: -** zone = reaction zone (NODE or LINK) -** k = pipe or tank index -** c[] = array of species concentrations -** -** Output: -** updated value of c[]. -** -** Returns: -** an error code or 0 if no errors. -*/ -{ - int errcode = 0; - if ( zone == LINK ) - { - TheLink = k; - for (int vi = 1; vi < MAX_HYD_VARS; vi++) - HydVar[vi] = MSX.Link[k].HydVar[vi]; - if ( NumPipeEquilSpecies > 0 ) errcode = evalPipeEquil(c); - evalPipeFormulas(c); - } - if ( zone == NODE ) - { - TheTank = k; - TheNode = MSX.Tank[k].node; - if ( NumTankEquilSpecies > 0 ) errcode = evalTankEquil(c); - evalTankFormulas(c); - } - return errcode; -} - -//============================================================================= - -char* MSXchem_getVariableStr(int i, char *s) -/* -** Purpose: -** returns a string representation of a variable used in the chemistry -** functions appearing in the C source code file used to compile -** these functions -** -** Input: -** i = variable's index in the LastIndex array -** s = string to hold variable's symbol -** -** Output: -** returns a pointer to s -*/ -{ -// --- WQ species have index between 1 & # of species - - if ( i <= LastIndex[SPECIES] ) sprintf(s, "c[%d]", i); - -// --- intermediate term expressions come next - - else if ( i <= LastIndex[TERM] ) - { - i -= LastIndex[TERM-1]; - sprintf(s, "term(%d, c, k, p, h)", i); - } - -// --- reaction parameter indexes come after that - - else if ( i <= LastIndex[PARAMETER] ) - { - i -= LastIndex[PARAMETER-1]; - sprintf(s, "p[%d]", i); - } - -// --- followed by constants - - else if ( i <= LastIndex[CONSTANT] ) - { - i -= LastIndex[CONSTANT-1]; - sprintf(s, "k[%d]", i); - } - -// --- and finally by hydraulic variables - - else - { - i -= LastIndex[CONSTANT]; - sprintf(s, "h[%d]", i); - } - return s; -} - -//============================================================================= - -void setSpeciesChemistry() -/* -** Purpose: -** determines which species are described by reaction rate -** expressions, equilibrium expressions, or simple formulas. -** -** Input: -** none. -** -** Output: -** updates arrays of different chemistry types. -*/ -{ - int m; - NumPipeRateSpecies = 0; - NumPipeFormulaSpecies = 0; - NumPipeEquilSpecies = 0; - NumTankRateSpecies = 0; - NumTankFormulaSpecies = 0; - NumTankEquilSpecies = 0; - for (m=1; m<=NumSpecies; m++) - { - switch ( MSX.Species[m].pipeExprType ) - { - case RATE: - NumPipeRateSpecies++; - PipeRateSpecies[NumPipeRateSpecies] = m; - break; - - case FORMULA: - NumPipeFormulaSpecies++; - break; - - case EQUIL: - NumPipeEquilSpecies++; - PipeEquilSpecies[NumPipeEquilSpecies] = m; - break; - } - switch ( MSX.Species[m].tankExprType ) - { - case RATE: - NumTankRateSpecies++; - TankRateSpecies[NumTankRateSpecies] = m; - break; - - case FORMULA: - NumTankFormulaSpecies++; - break; - - case EQUIL: - NumTankEquilSpecies++; - TankEquilSpecies[NumTankEquilSpecies] = m; - break; - } - } -} - -//============================================================================= - -void setTankChemistry() -/* -** Purpose: -** assigns pipe chemistry expressions to tank chemistry for -** each chemical species. -** -** Input: -** none. -** -** Output: -** updates arrays of different tank chemistry types. -*/ -{ - int m; - for (m=1; m<=NumSpecies; m++) - { - MSX.Species[m].tankExpr = MSX.Species[m].pipeExpr; - MSX.Species[m].tankExprType = MSX.Species[m].pipeExprType; - } - NumTankRateSpecies = NumPipeRateSpecies; - for (m=1; m<=NumTankRateSpecies; m++) - { - TankRateSpecies[m] = PipeRateSpecies[m]; - } - NumTankFormulaSpecies = NumPipeFormulaSpecies; - NumTankEquilSpecies = NumPipeEquilSpecies; - for (m=1; m<=NumTankEquilSpecies; m++) - { - TankEquilSpecies[m] = PipeEquilSpecies[m]; - } -} - - - -//============================================================================= - -int evalPipeReactions(int k, double dt) -/* -** Purpose: -** updates species concentrations in each WQ segment of a pipe -** after reactions occur over time step dt. -** -** Input: -** k = link index -** dt = time step (sec). -** -** Output: -** updates values in the concentration vector C[] associated -** with a pipe's WQ segments. -** -** Returns: -** an error code or 0 if no error. -** -** Re-written to accommodate compiled functions (1.1) -*/ -{ - int i, m; - int errcode = 0, ierr = 0; - double tstep = (double)dt / MSX.Ucf[RATE_UNITS]; - double c, dh; - -// --- start with the most downstream pipe segment - - TheLink = k; - TheSeg = MSX.FirstSeg[TheLink]; - while ( TheSeg ) - { - for (m = 1; m <= NumSpecies; m++) - { - ChemC1[m] = TheSeg->c[m]; - TheSeg->lastc[m] = TheSeg->c[m]; - } - ierr = 0; - - // --- react each reacting species over the time step - - if ( dt > 0.0 ) - { - - // --- place current concentrations of species that react in vector Yrate - - for (i=1; i<=NumPipeRateSpecies; i++) - { - m = PipeRateSpecies[i]; - Yrate[i] = TheSeg->c[m]; - } - - // --- Euler integrator - - if ( MSX.Solver == EUL ) - { - getPipeDcDt(0, Yrate, NumPipeRateSpecies, Yrate); - for (i=1; i<=NumPipeRateSpecies; i++) - { - m = PipeRateSpecies[i]; - c = TheSeg->c[m] + Yrate[i]*tstep; - TheSeg->c[m] = MAX(c, 0.0); - } - } - - // --- other integrators - else - { - dh = TheSeg->hstep; - - // --- Runge-Kutta integrator - - if ( MSX.Solver == RK5 ) - ierr = rk5_integrate(Yrate, NumPipeRateSpecies, 0, tstep, - &dh, Atol, Rtol, getPipeDcDt); - - // --- Rosenbrock integrator - - if ( MSX.Solver == ROS2 ) - ierr = ros2_integrate(Yrate, NumPipeRateSpecies, 0, tstep, - &dh, Atol, Rtol, getPipeDcDt); - - // --- save new concentration values of the species that reacted - - for (m=1; m<=NumSpecies; m++) TheSeg->c[m] = ChemC1[m]; - for (i=1; i<=NumPipeRateSpecies; i++) - { - m = PipeRateSpecies[i]; - TheSeg->c[m] = MAX(Yrate[i], 0.0); - } - TheSeg->hstep = dh; - } - if ( ierr < 0 ) return - ERR_INTEGRATOR; - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type == BULK) - { - MSX.Link[k].reacted[m] += TheSeg->v * (TheSeg->c[m] - TheSeg->lastc[m]) * LperFT3; - } - else if (MSX.Link[k].diam > 0) - { - MSX.Link[k].reacted[m] += TheSeg->v * 4.0 / MSX.Link[k].diam * MSX.Ucf[AREA_UNITS] * (TheSeg->c[m] - TheSeg->lastc[m]); - } - TheSeg->lastc[m] = TheSeg->c[m]; - } - } - - // --- compute new equilibrium concentrations within segment - - errcode = MSXchem_equil(LINK, k, TheSeg->c); - if ( errcode ) return errcode; - - // --- move to the segment upstream of the current one - TheSeg = TheSeg->prev; - } - return errcode; -} - -//============================================================================= - -int evalTankReactions(int k, double dt) -/* -** Purpose: -** updates species concentrations in a given storage tank -** after reactions occur over time step dt. -** -** Input: -** k = tank index -** dt = time step (sec). -** -** Output: -** updates values in the concentration vector Tank[k].c[] -** for tank k. -** -** Returns: -** an error code or 0 if no error. -** -** Re-written to accommodate compiled functions (1.1) -*/ -{ - int i, m; - int errcode = 0, ierr = 0; - double tstep = (double)dt / MSX.Ucf[RATE_UNITS]; - double c, dh; - -// --- evaluate each volume segment in the tank - - TheTank = k; - TheNode = MSX.Tank[k].node; - i = MSX.Nobjects[LINK] + k; - TheSeg = MSX.FirstSeg[i]; - while ( TheSeg ) - { - for (m = 1; m <= NumSpecies; m++) - { - ChemC1[m] = TheSeg->c[m]; - TheSeg->lastc[m] = TheSeg->c[m]; - } - ierr = 0; - - // --- react each reacting species over the time step - - if ( dt > 0.0 ) - { - - // --- place current concentrations of species that react in vector Yrate - for (i=1; i<=NumTankRateSpecies; i++) - { - m = TankRateSpecies[i]; - // Yrate[i] = MSX.Tank[k].c[m]; - Yrate[i] = TheSeg->c[m]; - } - - // --- Euler integrator - - if ( MSX.Solver == EUL ) - { - getTankDcDt(0, Yrate, NumTankRateSpecies, Yrate); - for (i=1; i<=NumTankRateSpecies; i++) - { - m = TankRateSpecies[i]; - c = TheSeg->c[m] + Yrate[i]*tstep; - TheSeg->c[m] = MAX(c, 0.0); - } - } - - // --- other integrators - else - { - dh = MSX.Tank[k].hstep; - - // --- Runge-Kutta integrator - - if ( MSX.Solver == RK5 ) - ierr = rk5_integrate(Yrate, NumTankRateSpecies, 0, tstep, - &dh, Atol, Rtol, getTankDcDt); - - // --- Rosenbrock integrator - - if ( MSX.Solver == ROS2 ) - ierr = ros2_integrate(Yrate, NumTankRateSpecies, 0, tstep, - &dh, Atol, Rtol, getTankDcDt); - - // --- save new concentration values of the species that reacted - - for (m=1; m<=NumSpecies; m++) TheSeg->c[m] = ChemC1[m]; - for (i=1; i<=NumTankRateSpecies; i++) - { - m = TankRateSpecies[i]; - TheSeg->c[m] = MAX(Yrate[i], 0.0); - } - TheSeg->hstep = dh; - } - if ( ierr < 0 ) return - ERR_INTEGRATOR; - } - - // --- compute new equilibrium concentrations within segment - - errcode = MSXchem_equil(NODE, k, TheSeg->c); - if ( errcode ) return errcode; - - // --- move to the next tank segment - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type == BULK) - { - MSX.Tank[k].reacted[m] += TheSeg->v * (TheSeg->c[m] - TheSeg->lastc[m]) * LperFT3; - } - TheSeg->lastc[m] = TheSeg->c[m]; - } - - TheSeg = TheSeg->prev; - } - return errcode; -} - -//============================================================================= - -int evalPipeEquil(double *c) -/* -** Purpose: -** computes equilibrium concentrations for water in a pipe segment. -** -** Input: -** c[] = array of starting species concentrations -** -** Output: -** c[] = array of equilibrium concentrations. -** -** Returns: -** an error code or 0 if no error. -*/ -{ - int i, m; - int errcode; - for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m]; - for (i=1; i<=NumPipeEquilSpecies; i++) - { - m = PipeEquilSpecies[i]; - Yequil[i] = c[m]; - } - errcode = newton_solve(Yequil, NumPipeEquilSpecies, MAXIT, NUMSIG, - getPipeEquil); - if ( errcode < 0 ) return ERR_NEWTON; - for (i=1; i<=NumPipeEquilSpecies; i++) - { - m = PipeEquilSpecies[i]; - c[m] = Yequil[i]; - ChemC1[m] = c[m]; - } - return 0; -} - - -//============================================================================= - -int evalTankEquil(double *c) -/* -** Purpose: -** computes equilibrium concentrations for water in a tank. -** -** Input: -** c[] = array of starting species concentrations -** -** Output: -** c[] = array of equilibrium concentrations. -** -** Returns: -** an error code or 0 if no error. -*/ -{ - int i, m; - int errcode; - for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m]; - for (i=1; i<=NumTankEquilSpecies; i++) - { - m = TankEquilSpecies[i]; - Yequil[i] = c[m]; - } - errcode = newton_solve(Yequil, NumTankEquilSpecies, MAXIT, NUMSIG, - getTankEquil); - if ( errcode < 0 ) return ERR_NEWTON; - for (i=1; i<=NumTankEquilSpecies; i++) - { - m = TankEquilSpecies[i]; - c[m] = Yequil[i]; - ChemC1[m] = c[m]; - } - return 0; -} - -//============================================================================= - -void evalPipeFormulas(double *c) -/* -** Purpose: -** evaluates species concentrations in a pipe segment that are simple -** formulas involving other known species concentrations. -** -** Input: -** c[] = array of current species concentrations. -** -** Output: -** c[] = array of updated concentrations. -** -** Re-written to accommodate compiled functions (1.1) -*/ -{ - int m; - double x; - - for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m]; -// --- use compiled functions if available - - if ( MSX.Compiler ) - { - MSXgetPipeFormulas(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar); - for (m=1; m<=NumSpecies; m++) - { - if (MSX.Species[m].pipeExprType == FORMULA) - c[m] = MSXerr_validate(ChemC1[m], m, LINK, FORMULA); - } - return; - } - - for (m=1; m<=NumSpecies; m++) - { - if ( MSX.Species[m].pipeExprType == FORMULA ) - { - x = mathexpr_eval(MSX.Species[m].pipeExpr, getPipeVariableValue); - c[m] = MSXerr_validate(x, m, LINK, FORMULA); - } - } -} - -//============================================================================= - -void evalTankFormulas(double *c) -/* -** Purpose: -** evaluates species concentrations in a tank that are simple -** formulas involving other known species concentrations. -** -** Input: -** c[] = array of current species concentrations. -** -** Output: -** c[] = array of updated concentrations. -** -** Re-written to accommodate compiled functions (1.1) -*/ -{ - int m; - double x; - - for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m]; - -// --- use compiled functions if available - - if ( MSX.Compiler ) - { - MSXgetTankFormulas(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar); - for (m=1; m<=NumSpecies; m++) - { - if (MSX.Species[m].tankExprType == FORMULA) - c[m] = MSXerr_validate(ChemC1[m], m, TANK, FORMULA); - } - return; - } - - for (m=1; m<=NumSpecies; m++) - { - if ( MSX.Species[m].tankExprType == FORMULA ) - { - x = mathexpr_eval(MSX.Species[m].tankExpr, getTankVariableValue); - c[m] = MSXerr_validate(x, m, TANK, FORMULA); - } - } -} - -//============================================================================= - -double getPipeVariableValue(int i) -/* -** Purpose: -** finds the value of a species, a parameter, or a constant for -** the pipe link being analyzed. -** -** Input: -** i = variable index. -** -** Returns: -** the current value of the indexed variable. -*/ -{ - double x; - -// --- WQ species have index i between 1 & # of species -// and their current values are stored in vector ChemC1 - - if ( i <= LastIndex[SPECIES] ) - { - // --- if species represented by a formula then evaluate it - - if ( MSX.Species[i].pipeExprType == FORMULA ) - { - x = mathexpr_eval(MSX.Species[i].pipeExpr, getPipeVariableValue); - return MSXerr_validate(x, i, LINK, FORMULA); - } - - // --- otherwise return the current concentration - - else return ChemC1[i]; - } - -// --- intermediate term expressions come next - - else if ( i <= LastIndex[TERM] ) - { - i -= LastIndex[TERM-1]; - x = mathexpr_eval(MSX.Term[i].expr, getPipeVariableValue); - return MSXerr_validate(x, i, 0, TERM); - } - -// --- reaction parameter indexes come after that - - else if ( i <= LastIndex[PARAMETER] ) - { - i -= LastIndex[PARAMETER-1]; - return MSX.Link[TheLink].param[i]; - } - -// --- followed by constants - - else if ( i <= LastIndex[CONSTANT] ) - { - i -= LastIndex[CONSTANT-1]; - return MSX.Const[i].value; - } - -// --- and finally by hydraulic variables - else - { - i -= LastIndex[CONSTANT]; - if (i < MAX_HYD_VARS) return HydVar[i]; - else return 0.0; - } -} - -//============================================================================= - -double getTankVariableValue(int i) -/* -** Purpose: -** finds the value of a species, a parameter, or a constant for -** the current node being analyzed. -** -** Input: -** i = variable index. -** -** Returns: -** the current value of the indexed variable. -** -** Modified to check for NaN values (L.Rossman - 11/03/10). -*/ -{ - int j; - double x; - -// --- WQ species have index i between 1 & # of species -// and their current values are stored in vector ChemC1 - - if ( i <= LastIndex[SPECIES] ) - { - // --- if species represented by a formula then evaluate it - - if ( MSX.Species[i].tankExprType == FORMULA ) - { - x = mathexpr_eval(MSX.Species[i].tankExpr, getTankVariableValue); - return MSXerr_validate(x, i, TANK, FORMULA); - } - - // --- otherwise return the current concentration - - else return ChemC1[i]; - } - -// --- intermediate term expressions come next - - else if ( i <= LastIndex[TERM] ) - { - i -= LastIndex[TERM-1]; - x = mathexpr_eval(MSX.Term[i].expr, getTankVariableValue); - return MSXerr_validate(x, i, 0, TERM); - } - -// --- next come reaction parameters associated with Tank nodes - - else if (i <= LastIndex[PARAMETER] ) - { - i -= LastIndex[PARAMETER-1]; - j = MSX.Node[TheNode].tank; - if ( j > 0 ) - { - return MSX.Tank[j].param[i]; - } - else return 0.0; - } - -// --- and then come constants - - else if (i <= LastIndex[CONSTANT] ) - { - i -= LastIndex[CONSTANT-1]; - return MSX.Const[i].value; - } - else return 0.0; -} - -//============================================================================= - -void getPipeDcDt(double t, double y[], int n, double deriv[]) -/* -** Purpose: -** finds reaction rate (dC/dt) for each reacting species in a pipe. -** -** Input: -** t = current time (not used) -** y[] = vector of reacting species concentrations -** n = number of reacting species. -** -** Output: -** deriv[] = vector of reaction rates of each reacting species. -*/ -{ - int i, m; - double x; - -// --- assign species concentrations to their proper positions in the global -// concentration vector ChemC1 - - for (i=1; i<=n; i++) - { - m = PipeRateSpecies[i]; - ChemC1[m] = y[i]; - } - -// --- update equilibrium species if full coupling in use - - if ( MSX.Coupling == FULL_COUPLING ) - { - if ( MSXchem_equil(LINK, TheLink, ChemC1) > 0 ) // check for error condition - { - for (i=1; i<=n; i++) deriv[i] = 0.0; - return; - } - } - -// --- use compiled functions if available - - if ( MSX.Compiler ) - { - MSXgetPipeRates(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar, F); - for (i=1; i<=n; i++) - { - m = PipeRateSpecies[i]; - deriv[i] = MSXerr_validate(F[m], m, LINK, RATE); - } - return; - } - -// --- evaluate each pipe reaction expression - - for (i=1; i<=n; i++) - { - m = PipeRateSpecies[i]; - x = mathexpr_eval(MSX.Species[m].pipeExpr, getPipeVariableValue); - deriv[i] = MSXerr_validate(x, m, LINK, RATE); - } -} - -//============================================================================= - -void getTankDcDt(double t, double y[], int n, double deriv[]) -/* -** Purpose: -** finds reaction rate (dC/dt) for each reacting species in a tank. -** -** Input: -** t = current time (not used) -** y[] = vector of reacting species concentrations -** n = number of reacting species. -** -** Output: -** deriv[] = vector of reaction rates of each reacting species. -*/ -{ - int i, m; - double x; - -// --- assign species concentrations to their proper positions in the global -// concentration vector ChemC1 - - for (i=1; i<=n; i++) - { - m = TankRateSpecies[i]; - ChemC1[m] = y[i]; - } - -// --- update equilibrium species if full coupling in use - - if ( MSX.Coupling == FULL_COUPLING ) - { - if ( MSXchem_equil(NODE, TheTank, ChemC1) > 0 ) // check for error condition - { - for (i=1; i<=n; i++) deriv[i] = 0.0; - return; - } - } - -// --- use compiled functions if available - - if ( MSX.Compiler ) - { - MSXgetTankRates(ChemC1, MSX.K, MSX.Tank[TheTank].param, HydVar, F); - for (i=1; i<=n; i++) - { - m = TankRateSpecies[i]; - deriv[i] = MSXerr_validate(F[m], m, TANK, RATE); - } - return; - } - -// --- evaluate each tank reaction expression - - for (i=1; i<=n; i++) - { - m = TankRateSpecies[i]; - x = mathexpr_eval(MSX.Species[m].tankExpr, getTankVariableValue); - deriv[i] = MSXerr_validate(x, m, TANK, RATE); - } -} - -//============================================================================= - -void getPipeEquil(double t, double y[], int n, double f[]) -/* -** Purpose: -** evaluates equilibrium expressions for pipe chemistry. -** -** Input: -** t = current time (not used) -** y[] = vector of equilibrium species concentrations -** n = number of equilibrium species. -** -** Output: -** f[] = vector of equilibrium function values. -*/ -{ - int i, m; - double x; - -// --- assign species concentrations to their proper positions in the global -// concentration vector ChemC1 - - for (i=1; i<=n; i++) - { - m = PipeEquilSpecies[i]; - ChemC1[m] = y[i]; - } - -// --- use compiled functions if available - - if ( MSX.Compiler ) - { - MSXgetPipeEquil(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar, F); - for (i=1; i<=n; i++) - { - m = PipeEquilSpecies[i]; - f[i] = MSXerr_validate(F[m], m, LINK, EQUIL); - } - return; - } - -// --- evaluate each pipe equilibrium expression - - for (i=1; i<=n; i++) - { - m = PipeEquilSpecies[i]; - x = mathexpr_eval(MSX.Species[m].pipeExpr, getPipeVariableValue); - f[i] = MSXerr_validate(x, m, LINK, EQUIL); - } -} - -//============================================================================= - -void getTankEquil(double t, double y[], int n, double f[]) -/* -** Purpose: -** evaluates equilibrium expressions for tank chemistry. -** -** Input: -** t = current time (not used) -** y[] = vector of equilibrium species concentrations -** n = number of equilibrium species -** -** Output: -** f[] = vector of equilibrium function values. -*/ -{ - int i, m; - double x; - -// --- assign species concentrations to their proper positions in the global -// concentration vector ChemC1 - - for (i=1; i<=n; i++) - { - m = TankEquilSpecies[i]; - ChemC1[m] = y[i]; - } - -// --- use compiled functions if available - - if ( MSX.Compiler ) - { - MSXgetTankEquil(ChemC1, MSX.K, MSX.Tank[TheTank].param, HydVar, F); - for (i=1; i<=n; i++) - { - m = TankEquilSpecies[i]; - f[i] = MSXerr_validate(F[m], m, TANK, EQUIL); - } - return; - } - -// --- evaluate each tank equilibrium expression - - for (i=1; i<=n; i++) - { - m = TankEquilSpecies[i]; - x = mathexpr_eval(MSX.Species[m].tankExpr, getTankVariableValue); - f[i] = MSXerr_validate(x, m, TANK, EQUIL); - } -} - diff --git a/Src/msxcompiler.c b/Src/msxcompiler.c deleted file mode 100644 index c98de10..0000000 --- a/Src/msxcompiler.c +++ /dev/null @@ -1,367 +0,0 @@ -/******************************************************************************* -** MODULE: MSXCOMPILER.C -** PROJECT: EPANET-MSX -** DESCRIPTION: compiles chemistry functions to a dynamic library file. -** COPYRIGHT: Copyright (C) 2006 Feng Shang, Lewis Rossman, and James Uber. -** All Rights Reserved. See license information in LICENSE.TXT. -** AUTHORS: L. Rossman, US EPA - NRMRL -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -*******************************************************************************/ - -#include -#include -#include -#include "msxtypes.h" -#include "msxfuncs.h" -#include "msxutils.h" - -// --- define WINDOWS - -#undef WINDOWS -#ifdef _WIN32 - #define WINDOWS -#endif -#ifdef __WIN32__ - #define WINDOWS -#endif -#ifdef WIN32 - #define WINDOWS -#endif - -// Local variables -//----------------- -char *Fname; // Prefix used for all file names -char TempName[L_tmpnam]; -char srcFile[MAXFNAME]; // Name of source code file -char objFile[MAXFNAME]; // Name of object file -char libFile[MAXFNAME]; // Name of library file -int Compiled; // Flag for compilation step - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -// Imported functions -//-------------------- -char * MSXchem_getVariableStr(int i, char *s); -//void MSXrpt_writeLine(char *line); - -// Exported functions -//-------------------- -int MSXcompiler_open(void); -void MSXcompiler_close(void); - -// Local functions -//----------------- -static void writeSrcFile(FILE* f); - -//============================================================================= - -int MSXcompiler_open() -/* -** Purpose: -** compiles MSX chemistry functions into a dynamic link library -** and loads the functions into the running application -** -** Input: -** none -** -** Returns: -** an error code (0 if no error). -*/ -{ - char cmd[256]; - char arch[100]; - FILE* f; - int err; - -// --- initialize - - Fname = NULL; - Compiled = FALSE; - -// --- get the name of a temporary file with directory path stripped from it -// and replace any '.' characters in it (for the Borland compiler to work) - - Fname = MSXutils_getTempName(TempName) ; - -// --- assign names to source code and compiled files - - strcpy(srcFile, Fname); - strcat(srcFile, ".c"); - strcpy(objFile, Fname); - strcat(objFile, ".o"); -#ifdef WINDOWS - strcpy(libFile, Fname); - strcat(libFile, ".dll"); -#else - strcpy(libFile, "lib"); - strcat(libFile, Fname); - strcat(libFile, ".so"); -#endif - -// --- write the chemistry functions to the source code file - - f = fopen(srcFile, "wt"); - if ( f == NULL ) return ERR_COMPILE_FAILED; - writeSrcFile(f); - fclose(f); - -// --- compile the source code file to a dynamic link library file - -#ifdef WINDOWS -#ifdef _WIN64 - strcpy(arch, "x64"); -#else - strcpy(arch, "x86"); -#endif - if ( MSX.Compiler == VC ) - { - sprintf(cmd, "runvc.bat %s %s", srcFile, arch); - err = MSXfuncs_run(cmd); - } - - else if ( MSX.Compiler == GC ) - { - sprintf(cmd, "gcc -c -O3 %s", srcFile); - err = MSXfuncs_run(cmd); - sprintf(cmd, "gcc -lm -shared -o %s %s", libFile, objFile); - err = MSXfuncs_run(cmd); - } - else return ERR_COMPILE_FAILED; -#else - if ( MSX.Compiler == GC ) - { - sprintf(cmd, "gcc -c -fPIC -O3 %s", srcFile); - err = system(cmd); - sprintf(cmd, "gcc -lm -shared -o %s %s", libFile, objFile); - err = system(cmd); - } - else return ERR_COMPILE_FAILED; -#endif - Compiled = (err == 0); // ttaxon - 9/7/10 - -// --- load the compiled chemistry functions from the library file - - if(Compiled) - { - err = MSXfuncs_load(libFile); - if ( err == 1 ) return ERR_COMPILE_FAILED; - if ( err == 2 ) return ERR_COMPILED_LOAD; - } - else - { - MSXcompiler_close(); - return ERR_COMPILE_FAILED; - } - return 0; -} - -//============================================================================= - -void MSXcompiler_close() -/* -** Purpose: -** frees resources used to load chemistry functions from the shared -** library and deletes all files used to compile and link the library. -** -** Input: -** none -** -** Returns: -** none. -*/ -{ - char cmd[256]; - if ( Compiled ) MSXfuncs_free(); - if ( Fname ) - { -#ifdef WINDOWS - // --- delete all files created from compilation - // (VC++ creates more than just an obj and dll file) - sprintf(cmd, "cmd /c del %s.*", Fname); - MSXfuncs_run(cmd); -#else - remove(TempName); - remove(srcFile); - remove(objFile); - remove(libFile); -#endif - } -} -//============================================================================= - -void writeSrcFile(FILE* f) -/* -** Purpose: -** writes C statements to the chemistry function source code file -** -** Input: -** f = pointer to the source code file -** -** Returns: -** none. -** -** Note: this function uses mathexpr_getStr() from mathexpr.c to -** reconstruct math expressions that were previously parsed -** into a stack of atomic terms by mathexpr_create(). The -** mathexpr_getStr function calls MSXchem_getVariableStr (in -** msxchem.c) to return a symbol for a particular variable that -** is used in the reconstucted expression in place of the -** variable's original name. For example, if NH3 were the name -** of the 2nd chemical species, then in the source code written -** here it would be denoted as c[2]; the third hydraulic variable, -** Velocity, would appear as h[3]. Similar notation is used for -** constants (k[]) and parameters (p[]). -*/ -{ - int i; - char e[1024]; - char headers[] = - -" /* Machine Generated EPANET-MSX File - Do Not Edit */ \n\n" -" #include \n" -" \n" -" #undef WINDOWS \n" -" #ifdef _WIN32 \n" -" #define WINDOWS \n" -" #endif \n" -" #ifdef __WIN32__ \n" -" #define WINDOWS \n" -" #endif \n" -" #ifdef WIN32 \n" -" #define WINDOWS \n" -" #endif \n" -" \n" -" #ifdef WINDOWS \n" -" #define DLLEXPORT __declspec(dllexport) \n" -" #else \n" -" #define DLLEXPORT \n" -" #endif \n" -" \n" -" void DLLEXPORT MSXgetPipeRates(double *, double *, double *, double *, double *); \n" -" void DLLEXPORT MSXgetTankRates(double *, double *, double *, double *, double *); \n" -" void DLLEXPORT MSXgetPipeEquil(double *, double *, double *, double *, double *); \n" -" void DLLEXPORT MSXgetTankEquil(double *, double *, double *, double *, double *); \n" -" void DLLEXPORT MSXgetPipeFormulas(double *, double *, double *, double *); \n" -" void DLLEXPORT MSXgetTankFormulas(double *, double *, double *, double *); \n" -" double term(int, double *, double *, double *, double *); \n"; - - char mathFuncs[] = - - " double coth(double); \n" - " double cot(double); \n" - " double acot(double); \n" - " double step(double); \n" - " double sgn(double); \n" - " \n" - " double coth(double x) { \n" - " return (exp(x) + exp(-x)) / (exp(x) - exp(-x)); } \n" - " double cot(double x) { \n" - " return 1.0 / tan(x); } \n" - " double acot(double x) { \n" - " return 1.57079632679489661923 - atan(x); } \n" - " double step(double x) { \n" - " if (x <= 0.0) return 0.0; \n" - " return 1.0; } \n" - " double sgn(double x) { \n" - " if (x < 0.0) return -1.0; \n" - " if (x > 0.0) return 1.0; \n" - " return 0.0; } \n"; - - -// --- write headers & non-intrinsic math functions to file - - fprintf(f, "%s", headers); - fprintf(f, "%s", mathFuncs); - -// --- write term functions - - fprintf(f, -"\n double term(int i, double c[], double k[], double p[], double h[])\n { \n"); - if ( MSX.Nobjects[TERM] > 0 ) - { - fprintf(f, " switch(i) { \n"); - for (i=1; i<=MSX.Nobjects[TERM]; i++) - { - fprintf(f, " case %d: return %s; \n", - i, mathexpr_getStr(MSX.Term[i].expr, e, MSXchem_getVariableStr)); - } - fprintf(f, " } \n"); - } - fprintf(f, " return 0.0; \n }\n"); - -// --- write pipe rate functions - - fprintf(f, -"\n void DLLEXPORT MSXgetPipeRates(double c[], double k[], double p[], double h[], double f[])\n { \n"); - for (i=1; i<=MSX.Nobjects[SPECIES]; i++) - { - if ( MSX.Species[i].pipeExprType == RATE ) - fprintf(f, " f[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].pipeExpr, e, - MSXchem_getVariableStr)); - } - fprintf(f, " }\n"); - -// --- write tank rate functions - - fprintf(f, -"\n void DLLEXPORT MSXgetTankRates(double c[], double k[], double p[], double h[], double f[])\n { \n"); - for (i=1; i<=MSX.Nobjects[SPECIES]; i++) - { - if ( MSX.Species[i].tankExprType == RATE ) - fprintf(f, " f[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].tankExpr, e, - MSXchem_getVariableStr)); - } - fprintf(f, " }\n"); - -// --- write pipe equilibrium functions - - fprintf(f, -"\n void DLLEXPORT MSXgetPipeEquil(double c[], double k[], double p[], double h[], double f[])\n { \n"); - for (i=1; i<=MSX.Nobjects[SPECIES]; i++) - { - if ( MSX.Species[i].pipeExprType == EQUIL ) - fprintf(f, " f[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].pipeExpr, e, - MSXchem_getVariableStr)); - } - fprintf(f, " }\n"); - -// --- write tank equilibrium functions - - fprintf(f, -"\n void DLLEXPORT MSXgetTankEquil(double c[], double k[], double p[], double h[], double f[])\n { \n"); - for (i=1; i<=MSX.Nobjects[SPECIES]; i++) - { - if ( MSX.Species[i].tankExprType == EQUIL ) - fprintf(f, " f[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].tankExpr, e, - MSXchem_getVariableStr)); - } - fprintf(f, " }\n"); - -// --- write pipe formula functions - - fprintf(f, -"\n void DLLEXPORT MSXgetPipeFormulas(double c[], double k[], double p[], double h[])\n { \n"); - for (i=1; i<=MSX.Nobjects[SPECIES]; i++) - { - if ( MSX.Species[i].pipeExprType == FORMULA ) - fprintf(f, " c[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].pipeExpr, e, - MSXchem_getVariableStr)); - } - fprintf(f, " }\n"); - -// --- write tank formula functions - - fprintf(f, -"\n void DLLEXPORT MSXgetTankFormulas(double c[], double k[], double p[], double h[])\n { \n"); - for (i=1; i<=MSX.Nobjects[SPECIES]; i++) - { - if ( MSX.Species[i].tankExprType == FORMULA ) - fprintf(f, " c[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].tankExpr, e, - MSXchem_getVariableStr)); - } - fprintf(f, " }\n"); - fprintf(f, "\n"); -} diff --git a/Src/msxdict.h b/Src/msxdict.h deleted file mode 100644 index b68e97a..0000000 --- a/Src/msxdict.h +++ /dev/null @@ -1,36 +0,0 @@ -/************************************************************************ -** MODULE: MSXDICT.H -** PROJECT: EPANET-MSX -** DESCRIPTION: Dictionary of key words used by the -** EPANET Multi-Species Extension toolkit. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 09/29/08 -***********************************************************************/ - -// NOTE: the entries in MsxsectWords must match the entries in the enumeration -// variable SectionType defined in msxtypes.h. -static char *MsxSectWords[] = {"[TITLE", "[SPECIE", "[COEFF", "[TERM", - "[PIPE", "[TANK", "[SOURCE", "[QUALITY", - "[PARAM", "[PATTERN", "[OPTION", - "[REPORT", "[DIFFU", NULL}; -static char *ReportWords[] = {"NODE", "LINK", "SPECIE", "FILE", "PAGESIZE", NULL}; -static char *OptionTypeWords[] = {"AREA_UNITS", "RATE_UNITS", "SOLVER", "COUPLING", - "TIMESTEP", "RTOL", "ATOL", "COMPILER", "SEGMENTS","PECLET",NULL}; -static char *CompilerWords[] = {"NONE", "VC", "GC", NULL}; -static char *SourceTypeWords[] = {"CONC", "MASS", "SETPOINT", "FLOW", NULL}; -static char *MixingTypeWords[] = {"MIXED", "2COMP", "FIFO", "LIFO", NULL}; -static char *MassUnitsWords[] = {"MG", "UG", "MOLE", "MMOL", NULL}; -static char *AreaUnitsWords[] = {"FT2", "M2", "CM2", NULL}; -static char *TimeUnitsWords[] = {"SEC", "MIN", "HR", "DAY", NULL}; -static char *SolverTypeWords[] = {"EUL", "RK5", "ROS2", NULL}; -static char *CouplingWords[] = {"NONE", "FULL", NULL}; -static char *ExprTypeWords[] = {"", "RATE", "FORMULA", "EQUIL", NULL}; -static char *HydVarWords[] = {"", "D", "Q", "U", "Re", - "Us", "Ff", "Av", "Kc", "Len", NULL}; /*Len added Feng Shang 01/27/2023*/ -static char YES[] = "YES"; -static char NO[] = "NO"; -static char ALL[] = "ALL"; -static char NONE[] = "NONE"; diff --git a/Src/msxdispersion.c b/Src/msxdispersion.c deleted file mode 100644 index 2282539..0000000 --- a/Src/msxdispersion.c +++ /dev/null @@ -1,584 +0,0 @@ -/****************************************************************************** -** MODULE: MSXDISPERSION.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Dispersion solver for Lagrangian ADR -******************************************************************************/ - -#include -#include -#include -#include -#include -#include "msxtypes.h" -#include "dispersion.h" -#include "smatrix.h" -#define ERRCODE(x) (errcode = ((errcode>100) ? (errcode) : (x))) -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -static double* al; //vector helping solve tridaigonal system of eqns. -static double* bl; //vector helping solve tridaigonal system of eqns. -static double* cl; //vector helping solve tridaigonal system of eqns. -static double* rl; //vector helping solve tridaigonal system of eqns. -static double* sol; //vector helping solve tridaigonal system of eqns. - -static double* gam; - -#pragma omp threadprivate(al, bl, cl, rl, sol, gam) - -int dispersion_open() -{ - int errcode=0; -#pragma omp parallel - { - al = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); - bl = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); - cl = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); - rl = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); - sol = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); - gam = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); - #pragma omp critical - { - ERRCODE(MEMCHECK(al)); - ERRCODE(MEMCHECK(bl)); - ERRCODE(MEMCHECK(cl)); - ERRCODE(MEMCHECK(rl)); - ERRCODE(MEMCHECK(sol)); - ERRCODE(MEMCHECK(gam)); - } - } - return errcode; - -} - -int dispersion_close() -{ - int errcode = 0; -#pragma omp parallel - { - FREE(al); - FREE(bl); - FREE(cl); - FREE(rl); - FREE(sol); - FREE(gam); - } - return errcode; -} - -void dispersion_pipe(int m, double tstep) -{ - - double cons = 0.0; - double ldispersion = 0.0; - double flowrate = 0.0, velocity = 0.0, area = 0.0; - int nseg = 0, k; - double diam = 0.0; - double vd = 0.0, vu = 0.0, vself = 0.0, asquare = 0.0, dh = 0.0, frictionfactor = 0.0; - double reynolds=0, shearvelocity=0; - Pseg seg = NULL; - - double elpt = 0.0; - double d0 = 1.292e-8; //molecular diffusivity 1.292e-8 ft^2/s 1.2e-9 m^2/s - - d0 = MSX.Dispersion.md[m]; - #pragma omp parallel - { - #pragma omp for private(seg, cons, vd, vu, vself, k, nseg, asquare, velocity, diam, area, flowrate, reynolds, dh, frictionfactor, shearvelocity, ldispersion, elpt) - for (k = 1; k <= MSX.Nobjects[LINK]; k++) - { - - velocity = 0; - if (MSX.FirstSeg[k] == NULL) - continue; - diam = MSX.Link[k].diam; - // Compute Reynolds No. - flowrate = (MSX.S[k] <= CLOSED) ? 0.0 : MSX.Q[k]; - area = PI * diam * diam / 4.0; // pipe area - if (area > 0.0 && MSX.Link[k].len > 0.0 && ABS(flowrate) > 0.0) - { - velocity = fabs(flowrate) / area; // flow velocity - reynolds = velocity * diam / MSX.Dispersion.viscosity; // Reynolds number //#define VISCOS 1.1E-5 // Kinematic viscosity of water // @ 20 deg C (sq ft/sec) - dh = ABS(MSX.H[MSX.Link[k].n1] - MSX.H[MSX.Link[k].n2]); - if (dh > 0.00001) - frictionfactor = 39.725 * dh * pow(diam, 5) / (MSX.Link[k].len * SQR(flowrate)); - else - frictionfactor = 0.0; - shearvelocity = velocity * sqrt(frictionfactor / 8); - - if (d0 < 0) - { - ldispersion = MSX.Dispersion.ld[m]; - } - else if (reynolds > 2300) //Basha 2007 - { - ldispersion = 0.5 * diam * shearvelocity * (10.1 + 577 * pow(reynolds / 1000.0, -2.2)); - - } - /* else //Basha 2007 - { - ldispersion = SQR(0.5 * diam * velocity) / (48 * d0); - elpt = MSX.Link[k].len / velocity; - ldispersion = ldispersion * (1 - exp(-12.425 * d0 * elpt / SQR(0.5 * diam))); - ldispersion += d0; - }*/ - else //Lee 2004 averaged - { - ldispersion = SQR(0.5 * diam * velocity) / (48 * d0); - elpt = MSX.Link[k].len / velocity; - double interv = 16.0 * d0 * elpt / (0.25 * diam * diam); - ldispersion = ldispersion * (1 - (1 - exp(-interv))/interv); - ldispersion += d0; - - } - - } - else - { - ldispersion = 0; - } - - if (ldispersion < 0.0) - { - ldispersion = 0; - MSX.Dispersion.pipeDispersionCoeff[k] = 0; - continue; - } - - double domi; - - if (velocity > 0) - domi = ldispersion / (velocity * velocity * tstep); - else - domi = 1000; - if (domi >= 0.000 && MSX.Link[k].len*velocity/ldispersion < MSX.Dispersion.PecletLimit) //Peclet numer - { - MSX.Dispersion.pipeDispersionCoeff[k] = ldispersion; - } - else - { - MSX.Dispersion.pipeDispersionCoeff[k] = 0; - continue; - } - asquare = area * area; - seg = MSX.FirstSeg[k]; //downstream - cons = 2.0 * ldispersion * asquare * tstep; - vd = 0.0; - bl[0] = 1.0; - cl[0] = 0.0; - rl[0] = 0.0; - nseg = 0; - - while (seg != NULL) - { - nseg++; - vself = seg->v; - rl[nseg] = seg->c[m]; - seg = seg->prev; - if (seg) - vu = seg->v; - else - vu = 0.0; - al[nseg] = -cons / (vself * vself + vself * vd); - cl[nseg] = -cons / (vself * vself + vself * vu); - bl[nseg] = 1 - al[nseg] - cl[nseg]; - - vd = vself; - } - if (nseg == 0) - continue; - - - al[nseg + 1] = 0.0; - bl[nseg + 1] = 1.0; - rl[nseg + 1] = 0.0; - - if (reynolds >= 0) - tridiag(nseg + 2, al, bl, cl, rl, sol); //nseg+2 <= 1000 here - else - { - for (int p = 0; p <= nseg + 1; p++) - sol[p] = rl[p]; - } - - seg = MSX.FirstSeg[k]; //downstream segment - int segindex = 1; - while (seg != NULL) - { - seg->hresponse = sol[segindex]; - seg = seg->prev; - segindex++; - } - /*clear initial condition*/ - for (int p = 1; p < nseg + 1; p++) - rl[p] = 0.0; - - /*downstream unit boundary condition*/ - rl[0] = 1.0; - if (reynolds >= 0) - tridiag(nseg + 2, al, bl, cl, rl, sol); - else - { - for (int p = 0; p <= nseg + 1; p++) - sol[p] = rl[p]; - } - - seg = MSX.FirstSeg[k]; //downstream - segindex = 1; - while (seg != NULL) - { - seg->dresponse = sol[segindex]; - seg = seg->prev; - segindex++; - } - - /*upstream unit boundary condition*/ - rl[0] = 0.0; - rl[nseg + 1] = 1.0; - if (reynolds >= 0) - tridiag(nseg + 2, al, bl, cl, rl, sol); //nseg+2 <= 100 here - else - { - for (int p = 0; p <= nseg + 1; p++) - sol[p] = rl[p]; - } - - seg = MSX.FirstSeg[k]; //downstream - segindex = 1; - while (seg != NULL) - { - seg->uresponse = sol[segindex]; - seg = seg->prev; - segindex++; - } - } - } -} - -void solve_nodequal(int m, double tstep) -{ - - Pseg firstseg; - Pseg lastseg; - Psource source; - int n1, n2; - double diam, area, asquare; - - // double dispersion = 147.25; - double ldispersion; - double coelastseg, coefirstseg; - - int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; - int found = 0; - - - //let's take a look of the matrix - - memset(MSX.Dispersion.Aii, 0, (MSX.Nobjects[NODE] + 1) * sizeof(double)); - memset(MSX.Dispersion.Aij, 0, (MSX.Dispersion.Ncoeffs + 1) * sizeof(double)); - memset(MSX.Dispersion.F, 0, (MSX.Nobjects[NODE] + 1) * sizeof(double)); - for (int k = 1; k <= MSX.Nobjects[LINK]; k++) - { - ldispersion = MSX.Dispersion.pipeDispersionCoeff[k]; - if (ldispersion <= 0) - continue; - n1 = MSX.Link[k].n1; //upstream - n2 = MSX.Link[k].n2; //downstream - if (MSX.FlowDir[k] < 0) - { - n1 = MSX.Link[k].n2; //upstream - n2 = MSX.Link[k].n1; //downstream - } - diam = MSX.Link[k].diam; - area = 0.25 * PI * diam * diam; - asquare = area * area; - firstseg = MSX.FirstSeg[k]; //downstream - lastseg = MSX.LastSeg[k]; //upstream - - - if (firstseg == NULL) - continue; - - coefirstseg = ldispersion * asquare / firstseg->v; //dispersion should be pipe by pipe - coelastseg = ldispersion * asquare / lastseg->v; //dispersion should be pipe by pipe - MSX.Dispersion.Aij[MSX.Dispersion.Ndx[k]] -= coefirstseg * firstseg->uresponse; //coefirstseg*firstseg->greenu = coelastseg*lastseg->greend - - found = 0; - source = MSX.Node[n2].sources; - while(source != NULL) - { - if (source->species == m) - { - found = 1; - break; - } - else - source = source->next; - } - - if (n2 <= njuncs) - { - if (source == NULL || source->c0 <= 0.0) - { - MSX.Dispersion.Aii[MSX.Dispersion.Row[n2]] += coefirstseg * (1.0 - firstseg->dresponse); - - MSX.Dispersion.F[MSX.Dispersion.Row[n2]] += coefirstseg * firstseg->hresponse; - } - else - { - MSX.Dispersion.Aij[MSX.Dispersion.Ndx[k]] = 0; - MSX.Dispersion.F[MSX.Dispersion.Row[n1]] += coelastseg * MSX.LastSeg[k]->dresponse * MSX.Node[n2].c[m]; - } - } - else - { - MSX.Dispersion.F[MSX.Dispersion.Row[n1]] += coelastseg * MSX.LastSeg[k]->dresponse * MSX.Node[n2].c[m]; - } - - - found = 0; - source = MSX.Node[n1].sources; - while (source != NULL) - { - if (source->species == m) - { - found = 1; - break; - } - else - source = source->next; - } - - if (n1 <= njuncs) - { - source = MSX.Node[n1].sources; - if (source == NULL || source->c0 <= 0.0) - { - MSX.Dispersion.Aii[MSX.Dispersion.Row[n1]] += coelastseg * (1.0 - lastseg->uresponse); - MSX.Dispersion.F[MSX.Dispersion.Row[n1]] += coelastseg * lastseg->hresponse; - } - else - { - MSX.Dispersion.Aij[MSX.Dispersion.Ndx[k]] = 0; //sure - MSX.Dispersion.F[MSX.Dispersion.Row[n2]] += coefirstseg * firstseg->uresponse * MSX.Node[n1].c[m]; - } - - } - else - { - MSX.Dispersion.F[MSX.Dispersion.Row[n2]] += coefirstseg * firstseg->uresponse * MSX.Node[n1].c[m]; - } - } - for (int i = 1; i <= njuncs; i++) - { - if (MSX.Dispersion.Aii[MSX.Dispersion.Row[i]] == 0.0) //no dispersion around the junction at all - { - MSX.Dispersion.Aii[MSX.Dispersion.Row[i]] = 1.0; - - MSX.Dispersion.F[MSX.Dispersion.Row[i]] = 1.0 * MSX.Node[i].c[m]; - } - } - - int errcode = linsolve(njuncs, MSX.Dispersion.Aii, MSX.Dispersion.Aij, MSX.Dispersion.F); - - for (int i = 1; i <= njuncs; i++) - { - MSX.Node[i].c[m] = MSX.Dispersion.F[MSX.Dispersion.Row[i]]; - } - -} - - -void segqual_update(int m, double tstep) -{ - - Pseg seg = NULL; - Psource source = NULL; - int n1 = 0, n2 = 0, k; - double mass1 = 0; - double mass2 = 0; - double dispersedin = 0; - double ldispersion = 0, massin = 0; - double area = 0.0; - int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; -#pragma omp parallel - { - #pragma omp for private(k, n1, n2, seg, source, mass1, mass2, ldispersion, massin, area) - for (k = 1; k <= MSX.Nobjects[LINK]; k++) - { - mass1 = 0; - mass2 = 0; - ldispersion = MSX.Dispersion.pipeDispersionCoeff[k]; - if (ldispersion <= 0.0) - continue; - area = 0.25 * PI * MSX.Link[k].diam * MSX.Link[k].diam; - n1 = MSX.Link[k].n1; - n2 = MSX.Link[k].n2; - if (MSX.FlowDir[k] < 0.0) - { - n1 = MSX.Link[k].n2; - n2 = MSX.Link[k].n1; - } - seg = MSX.FirstSeg[k]; - while (seg != NULL) //update segment concentration based on new up/down node quality - { - mass1 += seg->c[m] * seg->v; - seg->c[m] = seg->hresponse + MSX.Node[n2].c[m] * seg->dresponse + MSX.Node[n1].c[m] * seg->uresponse; - - mass2 += seg->c[m] * seg->v; - seg = seg->prev; - } - if (MSX.FirstSeg[k] == NULL) - continue; - - source = MSX.Node[n2].sources; - while (source != NULL) - { - if (source->species == m) - break; - source = source->next; - } - massin = 0; - if (source != NULL && source->c0 > 0) - { - massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n2].c[m] - MSX.FirstSeg[k]->c[m]) * LperFT3 / MSX.FirstSeg[k]->v; - } - else if (n2 > njuncs && MSX.Tank[n2 - njuncs].a == 0) //we assume constant tank and reservoir concentration during dispersion which may not be true for small tanks - { - massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n2].c[m] - MSX.FirstSeg[k]->c[m]) * LperFT3 / MSX.FirstSeg[k]->v; - } - else if (n2 > njuncs && MSX.Tank[n2 - njuncs].a > 0.0) - { - massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n2].c[m] - MSX.FirstSeg[k]->c[m]) * LperFT3 / MSX.FirstSeg[k]->v; - - } -#pragma omp critical - { - dispersedin += massin; - } - source = MSX.Node[n1].sources; - while (source != NULL) - { - if (source->species == m) - break; - source = source->next; - } - massin = 0; - if (source != NULL && source->c0 > 0) - { - massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n1].c[m] - MSX.LastSeg[k]->c[m]) * LperFT3 / MSX.LastSeg[k]->v; - } - else if (n1 > njuncs && MSX.Tank[n1 - njuncs].a == 0) - { - massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n1].c[m] - MSX.LastSeg[k]->c[m]) * LperFT3 / MSX.LastSeg[k]->v; - } - else if (n1 > njuncs && MSX.Tank[n1 - njuncs].a > 0.0) - { - - massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n1].c[m] - MSX.LastSeg[k]->c[m]) * LperFT3 / MSX.LastSeg[k]->v; - - } -#pragma omp critical - { - dispersedin += massin; - } - } - } - MSX.MassBalance.indisperse[m] += dispersedin; - - -} - - -void disperse_tankqual(int n, int m, double massin) -{ - int j, tm, k; - Pseg seg; - double c, v; - - j = MSX.Node[n].tank; - if (j < 0) - return; - else if (MSX.Tank[j].a == 0) - return; - - k = MSX.Nobjects[LINK] + j; - tm = MSX.Tank[j].mixModel; - - if (tm == MIX1|| tm == MIX2) - { - seg = MSX.LastSeg[k]; - if (seg) - { - v = seg->v; - c = seg->c[m]; - if (v > 0) - c = (c * v * LperFT3 + massin) / (v * LperFT3); - - c = MAX(0, c); - seg->c[m] = c; - MSX.Tank[j].c[m] = c; - MSX.Node[n].c[m] = c; - } - } - else if (tm == FIFO) - { - seg = MSX.FirstSeg[k]; - if (seg) - { - v = seg->v; - c = seg->c[m]; - if (v > 0) - c = (c * v * LperFT3 + massin) / (v * LperFT3); - - if( c < 0) - c = MAX(0, c); - seg->c[m] = c; - - } - } - else if (tm == LIFO) - { - seg = MSX.FirstSeg[k]; - if (seg) - { - v = seg->v; - c = seg->c[m]; - if (v > 0) - c = (c * v * LperFT3 + massin) / (v * LperFT3); - - c = MAX(0, c); - seg->c[m] = c; - - } - - } - - -} - - - - - -// Solve tri-daigonal system of eqns. using Thomas' algorithm - -void tridiag(int n, double *a, double *b, double *c, double *r, double *y) -{ - int j; - double bet; - - bet = b[0]; - y[0] = r[0] / bet; - for (j = 1; j < n; j++) - { - gam[j] = c[j - 1] / bet; - bet = b[j] - a[j] * gam[j]; - y[j] = (r[j] - a[j] * y[j - 1]) / bet; - } - for (j = n - 2; j >= 0; j--) - { - y[j] -= gam[j + 1] * y[j + 1]; - } -} diff --git a/Src/msxerr.c b/Src/msxerr.c deleted file mode 100644 index 63dfa06..0000000 --- a/Src/msxerr.c +++ /dev/null @@ -1,116 +0,0 @@ -/****************************************************************************** -** MODULE: MSXERR.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Math error reporting routines. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -******************************************************************************/ - -#include -#include - -#include "msxtypes.h" -#include "epanet2.h" - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -// Local variables -//----------------- -static int mathError; // math error flag -static char mathErrorMsg[1024]; // math error message -static char* elementTxt[] = // see ObjectType in msxtypes.h - {"", "pipe", "tank"}; -static char* exprTypeTxt[] = // see ExpressionType in msxtypes.h - {"", "rate", "formula", "equilibrium"}; - -// Exported functions -//-------------------- -void MSXerr_clearMathError(void); -int MSXerr_mathError(void); -double MSXerr_validate(double x, int index, int element, int exprType); -void MSXerr_writeMathErrorMsg(void); - - -//============================================================================= - -void MSXerr_clearMathError() -/* -** Purpose: -** clears the math error flag. -*/ -{ - mathError = 0; - strcpy(mathErrorMsg, ""); -} - -//============================================================================= - -int MSXerr_mathError() -/* -** Purpose: -** returns the current state of the math error flag. -*/ -{ - return mathError; -} - -//============================================================================= - -void MSXerr_writeMathErrorMsg() -/* -** Purpose: -** writes math error message to EPANET report file. -*/ -{ - ENwriteline(mathErrorMsg); - ENwriteline(""); -} - -//============================================================================= - -double MSXerr_validate(double x, int index, int element, int exprType) -/* -** Purpose: -** checks if a number is valid or not. -** -** Input: -** x = the number to check -** index = array index of species or term that x was computed for -** element = LINK for a pipe element or TANK for a tank element -** exprType = type of expression that produced x -** -** Returns: -** the value of x if it's a valid number or 0 otherwise. -*/ -{ - // return x if it's a valid number - if (x == x) return x; - - // return 0 if the math error flag has previously been set - // (we only want the first math error identified since others - // may have propagated from it) - if (mathError) return 0.0; - - // construct a math error message - if ( exprType == TERM ) - { - sprintf(mathErrorMsg, - "Ilegal math operation occurred for term:\n %s", - MSX.Term[index].id); - } - else - { - sprintf(mathErrorMsg, - "Ilegal math operation occurred in %s %s expression for species:\n %s", - elementTxt[element], exprTypeTxt[exprType], MSX.Species[index].id); - } - - // set the math error flag and return 0 - mathError = 1; - return 0.0; -} diff --git a/Src/msxfile.c b/Src/msxfile.c deleted file mode 100644 index 26cc66d..0000000 --- a/Src/msxfile.c +++ /dev/null @@ -1,260 +0,0 @@ -/******************************************************************************* -** MODULE: MSXFILE.C -** PROJECT: EPANET-MSX -** DESCRIPTION: writes MSX project data to a MSX input file. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -*******************************************************************************/ - -#include -#include - -#include "msxtypes.h" -#include "msxutils.h" -#include "msxdict.h" -#include "epanet2.h" - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -// Exported functions -//-------------------- -int MSXfile_save(FILE *f); - -// Local functions -//----------------- -static void saveSpecies(FILE *f); -static void saveCoeffs(FILE *f); -static int saveInpSections(FILE *f); -static void saveParams(FILE *f); -static void saveQuality(FILE *f); -static void saveSources(FILE *f); -static void savePatterns(FILE *f); - -//============================================================================= - -int MSXfile_save(FILE *f) -/* -** Purpose: -** saves current MSX project data to file. -** -** Input: -** f = pointer to MSX file where data are saved. -*/ -{ - int errcode; - fprintf(f, "[TITLE]"); - fprintf(f, "\n%s\n", MSX.Title); - saveSpecies(f); - saveCoeffs(f); - errcode = saveInpSections(f); - saveParams(f); - saveQuality(f); - saveSources(f); - savePatterns(f); - return errcode; -} - -//============================================================================= - -void saveSpecies(FILE *f) -{ - int i, n; - fprintf(f, "\n[SPECIES]"); - n = MSX.Nobjects[SPECIES]; - for (i=1; i<=n; i++) - { - if ( MSX.Species[i].type == BULK ) fprintf(f, "\nBULK "); - else fprintf(f, "\nWALL "); - fprintf(f, "%-32s %-15s %e %e", - MSX.Species[i].id, MSX.Species[i].units, - MSX.Species[i].aTol, MSX.Species[i].rTol); - } -} - -//============================================================================= - -void saveCoeffs(FILE *f) -{ - int i, n; - fprintf(f, "\n\n[COEFFICIENTS]"); - n = MSX.Nobjects[CONSTANT]; - for (i=1; i<=n; i++) - { - fprintf(f, "\nCONSTANT %-32s %e", - MSX.Const[i].id, MSX.Const[i].value); - } - n = MSX.Nobjects[PARAMETER]; - for (i=1; i<=n; i++) - { - fprintf(f, "\nPARAMETER %-32s %e", - MSX.Param[i].id, MSX.Param[i].value); - } -} - -//============================================================================= - -int saveInpSections(FILE *f) -{ - char line[MAXLINE+1]; - char writeLine; - int newsect; - - if ((MSX.MsxFile.file = fopen(MSX.MsxFile.name,"rt")) == NULL) return ERR_OPEN_MSX_FILE; - rewind(MSX.MsxFile.file); - - fprintf(f,"\n\n"); - writeLine = FALSE; - while ( fgets(line, MAXLINE, MSX.MsxFile.file) != NULL ) - { - if (*line == '[' ) - { - writeLine = TRUE; - newsect = MSXutils_findmatch(line, MsxSectWords); - if ( newsect >= 0 ) switch(newsect) - { - case s_OPTION: - case s_TERM: - case s_PIPE: - case s_TANK: - case s_REPORT: - break; - default: - writeLine = FALSE; - } - } - if ( writeLine) fprintf(f, "%s", line); - } - if ( MSX.MsxFile.file ) fclose(MSX.MsxFile.file); - MSX.MsxFile.file = NULL; - return 0; -} - -//============================================================================= - -void saveParams(FILE *f) -{ - int i, j, k; - double x; - char id[MAXLINE+1]; - - if ( MSX.Nobjects[PARAMETER] > 0 ) - { - fprintf(f, "\n\n[PARAMETERS]"); - for (j=1; j<=MSX.Nobjects[PARAMETER]; j++) - { - x = MSX.Param[j].value; - for (i=1; i<=MSX.Nobjects[LINK]; i++) - { - if ( MSX.Link[i].param[j] != x ) - { - ENgetlinkid(i, id); - fprintf(f, "\nPIPE %-32s %-32s %e", - id, MSX.Param[j].id, MSX.Link[i].param[j]); - } - } - for (i=1; i<=MSX.Nobjects[TANK]; i++) - { - if ( MSX.Tank[i].param[j] != x ) - { - k = MSX.Tank[i].node; - ENgetnodeid(k, id); - fprintf(f, "\nTANK %-32s %-32s %e", - id, MSX.Param[j].id, MSX.Tank[i].param[j]); - } - } - } - } -} - -//============================================================================= - -void saveQuality(FILE *f) -{ - int i, j; - char id[MAXLINE+1]; - - fprintf(f, "\n\n[QUALITY]"); - for (j=1; j<=MSX.Nobjects[SPECIES]; j++) - { - if (MSX.C0[j] > 0.0) - fprintf(f, "\nGLOBAL %-32s %e", - MSX.Species[j].id, MSX.C0[j]); - - for (i=1; i<=MSX.Nobjects[NODE]; i++) - { - if ( MSX.Node[i].c0[j] > 0.0 && MSX.Node[i].c0[j] != MSX.C0[j]) - { - ENgetnodeid(i, id); - fprintf(f, "\nNODE %-32s %-32s %e", - id, MSX.Species[j].id, MSX.Node[i].c0[j]); - } - } - for (i=1; i<=MSX.Nobjects[LINK]; i++) - { - if ( MSX.Link[i].c0[j] > 0.0 && MSX.Link[i].c0[j] != MSX.C0[j]) - { - ENgetlinkid(i, id); - fprintf(f, "\nLINK %-32s %-32s %e", - id, MSX.Species[j].id, MSX.Link[i].c0[j]); - } - } - } -} - -//============================================================================= - -void saveSources(FILE *f) -{ - int i; - Psource source; - char id[MAXLINE+1]; - - fprintf(f, "\n\n[SOURCES]"); - for (i=1; i<=MSX.Nobjects[NODE]; i++) - { - source = MSX.Node[i].sources; - while ( source ) - { - if ( source->c0 > 0.0 && source->type > -1) //Feng Shang 09/23/2008 - { - ENgetnodeid(i, id); - fprintf(f, "\n%-10s %-32s %-32s %e", - SourceTypeWords[source->type], id, - MSX.Species[source->species].id, source->c0); - if ( source->pat > 0 ) - fprintf(f, " %-32s", MSX.Pattern[source->pat].id); - } - source = source->next; - } - } -} - -//============================================================================= - -void savePatterns(FILE *f) -{ - int i, count; - SnumList *listItem; - - if ( MSX.Nobjects[PATTERN] > 0 ) fprintf(f, "\n\n[PATTERNS]"); - for (i=1; i<=MSX.Nobjects[PATTERN]; i++) - { - count = 0; - listItem = MSX.Pattern[i].first; - while (listItem) - { - if ( count % 6 == 0 ) - { - fprintf(f, "\n%-32s", MSX.Pattern[i].id); - } - fprintf(f, " %e", listItem->value); - count++; - listItem = listItem->next; - } - } -} diff --git a/Src/msxfuncs.c b/Src/msxfuncs.c deleted file mode 100644 index 7af0311..0000000 --- a/Src/msxfuncs.c +++ /dev/null @@ -1,165 +0,0 @@ -/******************************************************************************* -** MODULE: MSXFUNCS.C -** PROJECT: EPANET-MSX -** DESCRIPTION: compiles chemistry functions to a shared dynamic library. -** COPYRIGHT: Copyright (C) 2007 Feng Shang, Lewis Rossman, and James Uber. -** All Rights Reserved. See license information in LICENSE.TXT. -** AUTHORS: see AUTHORS -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2014 -*******************************************************************************/ - -#include - -// --- define WINDOWS - -#undef WINDOWS -#ifdef _WIN32 - #define WINDOWS -#endif -#ifdef __WIN32__ - #define WINDOWS -#endif -#ifdef WIN32 - #define WINDOWS -#endif - -#ifdef WINDOWS -#include -HMODULE hDLL; -#else - #include - void *hDLL; -#endif - -#include "msxfuncs.h" - -//============================================================================= - -int MSXfuncs_load(char * libName) -/* -** Purpose: -** loads compiled chemistry functions from a named library -** -** Input: -** libName = path to shared library -** -** Returns: -** an error code (0 if no error). -*/ -{ - -#ifdef WINDOWS - hDLL = LoadLibraryA(libName); - if (hDLL == NULL) return 1; - - MSXgetPipeRates = (MSXGETRATES) GetProcAddress(hDLL, "MSXgetPipeRates"); - MSXgetTankRates = (MSXGETRATES) GetProcAddress(hDLL, "MSXgetTankRates"); - MSXgetPipeEquil = (MSXGETEQUIL) GetProcAddress(hDLL, "MSXgetPipeEquil"); - MSXgetTankEquil = (MSXGETEQUIL) GetProcAddress(hDLL, "MSXgetTankEquil"); - MSXgetPipeFormulas = (MSXGETFORMULAS) GetProcAddress(hDLL, "MSXgetPipeFormulas"); - MSXgetTankFormulas = (MSXGETFORMULAS) GetProcAddress(hDLL, "MSXgetTankFormulas"); - -#else - hDLL = dlopen(libName, RTLD_LAZY); - if (hDLL == NULL) return 1; - - MSXgetPipeRates = (MSXGETRATES) dlsym(hDLL, "MSXgetPipeRates"); - MSXgetTankRates = (MSXGETRATES) dlsym(hDLL, "MSXgetTankRates"); - MSXgetPipeEquil = (MSXGETEQUIL) dlsym(hDLL, "MSXgetPipeEquil"); - MSXgetTankEquil = (MSXGETEQUIL) dlsym(hDLL, "MSXgetTankEquil"); - MSXgetPipeFormulas = (MSXGETFORMULAS) dlsym(hDLL, "MSXgetPipeFormulas"); - MSXgetTankFormulas = (MSXGETFORMULAS) dlsym(hDLL, "MSXgetTankFormulas"); -#endif - - if (NULL == MSXgetPipeRates || NULL == MSXgetTankRates || - NULL == MSXgetPipeEquil || NULL == MSXgetTankEquil || - NULL == MSXgetPipeFormulas || NULL == MSXgetTankFormulas) - { - MSXfuncs_free(); - hDLL = NULL; - return 2; - } - return 0; -} - -//============================================================================= - -void MSXfuncs_free() -/* -** Purpose: -** frees the handle to the shared function library -** -** Input: -** none -** -** Returns: -** none -*/ -{ -#ifdef WINDOWS - if (hDLL) FreeLibrary(hDLL); -#else - if (hDLL) dlclose(hDLL); -#endif -} - -//============================================================================= - -int MSXfuncs_run(char* cmdLine) -/* -** Purpose: -** executes a program and waits for it to end -** -** Input: -** cmdLine = command line string that executes the program -** -** Returns: -** the program's exit code (or -1 if the program was not run) -*/ -{ -#ifdef WINDOWS - - unsigned long exitCode; - STARTUPINFOA si; - PROCESS_INFORMATION pi; - - // --- initialize data structures - - memset(&si, 0, sizeof(si)); - memset(&pi, 0, sizeof(pi)); - si.cb = sizeof(si); - - // --- hide the window that the program runs in - - si.dwFlags = STARTF_USESHOWWINDOW; - si.wShowWindow = SW_HIDE; - - // --- execute the command line in a new console window - exitCode = CreateProcess(NULL, cmdLine, NULL, NULL, 0, - CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); - if (exitCode == 0) - { - exitCode = GetLastError(); - return exitCode; - } - - // --- wait for program to end - - exitCode = WaitForSingleObject(pi.hProcess, INFINITE); - - // --- retrieve the error code produced by the program - - BOOL rt = GetExitCodeProcess(pi.hProcess, &exitCode); - - // --- release handles - - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - return exitCode; - -#else - return -1; -#endif -} - diff --git a/Src/msxfuncs.h b/Src/msxfuncs.h deleted file mode 100644 index 4cb7d19..0000000 --- a/Src/msxfuncs.h +++ /dev/null @@ -1,35 +0,0 @@ -/************************************************************************ -** MODULE: MSXFUNCS.H -** PROJECT: EPANET-MSX -** DESCRIPTION: Definitions of functions loaded from compiled chemistry file. -** COPYRIGHT: Copyright (C) 2007 Feng Shang, Lewis Rossman, and James Uber. -** All Rights Reserved. See license information in LICENSE.TXT. -** AUTHORS: See Authors -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -***********************************************************************/ - -#ifndef MSXFUNCS_H -#define MSXFUNCS_H - -// Define pointers for each group of chemistry functions -typedef void (*MSXGETRATES)(double *, double *, double * , double *, double *); -typedef void (*MSXGETEQUIL)(double *, double *, double * , double *, double *); -typedef void (*MSXGETFORMULAS)(double *, double *, double *, double *); - -// Declare each chemistry function -MSXGETRATES MSXgetPipeRates; -MSXGETRATES MSXgetTankRates; -MSXGETEQUIL MSXgetPipeEquil; -MSXGETEQUIL MSXgetTankEquil; -MSXGETFORMULAS MSXgetPipeFormulas; -MSXGETFORMULAS MSXgetTankFormulas; - -// Functions that load and free the chemistry functions -int MSXfuncs_load(char *); -void MSXfuncs_free(void); - -// Function that executes a command line program -int MSXfuncs_run(char * ); - -#endif diff --git a/Src/msxinp.c b/Src/msxinp.c deleted file mode 100644 index 01d6a1f..0000000 --- a/Src/msxinp.c +++ /dev/null @@ -1,1505 +0,0 @@ -/******************************************************************************* -** MODULE: MSXINP.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Input data processor for the EPANET Multi-Species Extension -** toolkit. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 08/20/2022 -*******************************************************************************/ - -#include -#include -#include -#include -#include - -#include "msxtypes.h" -#include "msxutils.h" -#include "msxdict.h" -#include "epanet2.h" - -// Constants -//----------- -#define MAXERRS 100 // Max. input errors reported -#define MAXTOKS 40 // Max. items per line of input -#define SEPSTR " \t\n\r" // Token separator characters - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -// Local variables -//----------------- -static char *Tok[MAXTOKS]; // String tokens from line of input -static int Ntokens; // Number of tokens in line of input -static double **TermArray; // Incidence array used to check Terms - -enum InpErrorCodes { // Error codes (401 - 409) - INP_ERR_FIRST = 400, - ERR_LINE_LENGTH, - ERR_ITEMS, - ERR_KEYWORD, - ERR_NUMBER, - ERR_NAME, - ERR_RESERVED_NAME, - ERR_DUP_NAME, - ERR_DUP_EXPR, - ERR_MATH_EXPR, - ERR_UNSUPPORTED_OPTION, - INP_ERR_LAST}; - -static char *InpErrorTxt[INP_ERR_LAST-INP_ERR_FIRST] = { - "", - "Error 401 (too many characters)", - "Error 402 (too few input items)", - "Error 403 (invalid keyword)", - "Error 404 (invalid numeric value)", - "Error 405 (reference to undefined object)", - "Error 406 (illegal use of a reserved name)", - "Error 407 (name already used by another object)", - "Error 408 (species already assigned an expression)", - "Error 409 (illegal math expression)", - "Error 410 (option no longer supported)"}; - -// Imported functions -//-------------------- -int MSXproj_addObject(int type, char *id, int n); -int MSXproj_findObject(int type, char *id); -char * MSXproj_findID(int type, char *id); - -// Exported functions -//-------------------- -int MSXinp_countMsxObjects(void); -int MSXinp_countNetObjects(void); -int MSXinp_readNetData(void); -int MSXinp_readMsxData(void); -void MSXinp_getSpeciesUnits(int m, char *units); - -// Local functions -//----------------- -static int getLineLength(char *line); -static int getNewSection(char *tok, char *sectWords[], int *sect); -static int addSpecies(char *line); -static int addCoeff(char *line); -static int addTerm(char *id); -static int addPattern(char *id); -static int checkID(char *id); -static int parseLine(int sect, char *line); -static int parseOption(void); -static int parseSpecies(void); -static int parseCoeff(void); -static int parseTerm(void); -static int parseExpression(int classType); -static int parseTankData(void); -static int parseQuality(void); -static int parseParameter(void); -static int parseSource(void); -static int parsePattern(void); -static int parseReport(void); -static int parseDiffu(void); -static int getVariableCode(char *id); -static int getTokens(char *s); -static void writeInpErrMsg(int errcode, char *sect, char *line, int lineCount); - -static int checkCyclicTerms(void); -static int traceTermPath(int i, int istar, int n); - -//============================================================================= - -int MSXinp_countMsxObjects() -/* -** Purpose: -** reads multi-species input file to determine number of system objects. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - char line[MAXLINE+1]; // line from input data file - char wLine[MAXLINE+1]; // working copy of input line - char *tok; // first string token of line - int sect = -1; // input data sections - int errcode = 0; // error code - int errsum = 0; // number of errors found - long lineCount = 0; - -// --- write name of input file to EPANET report file - - strcpy(MSX.Msg, "Processing MSX input file "); - strcpy(line, MSX.MsxFile.name); - strcat(MSX.Msg, line); - ENwriteline(MSX.Msg); - ENwriteline(""); - -// --- make pass through EPANET-MSX data file counting number of each object - - while ( fgets(line, MAXLINE, MSX.MsxFile.file) != NULL ) - { - - // --- skip blank lines & those beginning with a comment - - errcode = 0; - lineCount++; - strcpy(wLine, line); // make working copy of line - tok = strtok(wLine, SEPSTR); // get first text token on line - if ( tok == NULL || *tok == ';' ) continue; - if ( getNewSection(tok, MsxSectWords, §) ) continue; - - // --- read id names from SPECIES, COEFFS, TERMS, & PATTERNS sections - - if ( sect == s_SPECIES ) errcode = addSpecies(line); - if ( sect == s_COEFF ) errcode = addCoeff(line); - if ( sect == s_TERM ) errcode = addTerm(tok); - if ( sect == s_PATTERN ) errcode = addPattern(tok); - - - // --- report any error found - - if ( errcode ) - { - writeInpErrMsg(errcode, MsxSectWords[sect], line, lineCount); - errsum++; - if (errsum >= MAXERRS ) break; - } - } - -// --- return error code - - if ( errsum > 0 ) return ERR_MSX_INPUT; - return errcode; -} - -//============================================================================= - -int MSXinp_countNetObjects() -/* -** Purpose: -** queries EPANET data base to determine number of network objects. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int errcode = 0; - -// --- retrieve number of network elements - - CALL(errcode, ENgetcount(EN_NODECOUNT, &MSX.Nobjects[NODE])); - CALL(errcode, ENgetcount(EN_TANKCOUNT, &MSX.Nobjects[TANK])); - CALL(errcode, ENgetcount(EN_LINKCOUNT, &MSX.Nobjects[LINK])); - return errcode; -} - -//============================================================================= - -int MSXinp_readNetData() -/* -** Purpose: -** retrieves required input data from the EPANET project data. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int errcode = 0; - int i, k, n, t = 0; - int n1 = 0, n2 = 0; - long qstep; - float diam = 0.0, len = 0.0, v0 = 0.0, xmix = 0.0, vmix = 0.0; - - float roughness = 0.0; - -// --- get flow units & time parameters - - CALL(errcode, ENgetflowunits(&MSX.Flowflag)); - if ( MSX.Flowflag >= EN_LPS ) MSX.Unitsflag = SI; - else MSX.Unitsflag = US; - CALL(errcode, ENgettimeparam(EN_QUALSTEP, &qstep)); - MSX.Qstep = qstep * 1000; - CALL(errcode, ENgettimeparam(EN_REPORTSTEP, &MSX.Rstep)); - CALL(errcode, ENgettimeparam(EN_REPORTSTART, &MSX.Rstart)); - CALL(errcode, ENgettimeparam(EN_PATTERNSTEP, &MSX.Pstep)); - CALL(errcode, ENgettimeparam(EN_PATTERNSTART, &MSX.Pstart)); - CALL(errcode, ENgettimeparam(EN_STATISTIC, &MSX.Statflag)); - -// --- read tank/reservoir data - - n = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; - for (i=1; i<=MSX.Nobjects[NODE]; i++) - { - k = i - n; - if ( k > 0 ) - { - CALL(errcode, ENgetnodetype(i, &t)); - CALL(errcode, ENgetnodevalue(i, EN_INITVOLUME, &v0)); - CALL(errcode, ENgetnodevalue(i, EN_MIXMODEL, &xmix)); - CALL(errcode, ENgetnodevalue(i, EN_MIXZONEVOL, &vmix)); - if ( !errcode ) - { - MSX.Node[i].tank = k; - MSX.Tank[k].node = i; - if ( t == EN_RESERVOIR ) MSX.Tank[k].a = 0.0; - else MSX.Tank[k].a = 1.0; - MSX.Tank[k].v0 = v0; - MSX.Tank[k].mixModel = (int)xmix; - MSX.Tank[k].vMix = vmix; - } - } - } - -// --- read link data - - for (i=1; i<=MSX.Nobjects[LINK]; i++) - { - CALL(errcode, ENgetlinknodes(i, &n1, &n2)); - CALL(errcode, ENgetlinkvalue(i, EN_DIAMETER, &diam)); - CALL(errcode, ENgetlinkvalue(i, EN_LENGTH, &len)); - CALL(errcode, ENgetlinkvalue(i, EN_ROUGHNESS, &roughness)); - if ( !errcode ) - { - MSX.Link[i].n1 = n1; - MSX.Link[i].n2 = n2; - MSX.Link[i].diam = diam; - MSX.Link[i].len = len; - MSX.Link[i].roughness = roughness; - } - } - return errcode; -} - -//============================================================================= - -int MSXinp_readMsxData() -/* -** Purpose: -** reads multi-species data from the EPANET-MSX input file. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - char line[MAXLINE+1]; // line from input data file - char wLine[MAXLINE+1]; // working copy of input line - int sect = -1; // input data sections - int errsum = 0; // number of errors found - int inperr = 0; // input error code - long lineCount = 0; // line count - -// --- create the TermArray for checking circular references in Terms - - TermArray = createMatrix(MSX.Nobjects[TERM]+1, MSX.Nobjects[TERM]+1); - if ( TermArray == NULL ) return ERR_MEMORY; - -// --- read each line from MSX input file - - rewind(MSX.MsxFile.file); - while ( fgets(line, MAXLINE, MSX.MsxFile.file) != NULL ) - { - // --- make copy of line and scan for tokens - - lineCount++; - strcpy(wLine, line); - Ntokens = getTokens(wLine); - - // --- skip blank lines and comments - - if ( Ntokens == 0 || *Tok[0] == ';' ) continue; - - // --- check if max. line length exceeded - - if ( getLineLength(line) >= MAXLINE ) - { - inperr = ERR_LINE_LENGTH; - writeInpErrMsg(inperr, MsxSectWords[sect], line, lineCount); - errsum++; - } - - // --- check if at start of a new input section - - if ( getNewSection(Tok[0], MsxSectWords, §) ) continue; - - // --- parse tokens from input line - - inperr = parseLine(sect, line); - if ( inperr > 0 ) - { - errsum++; - writeInpErrMsg(inperr, MsxSectWords[sect], line, lineCount); - } - - // --- stop if reach end of file or max. error count - - if (errsum >= MAXERRS) break; - } // End of while - -// --- check for errors - - if ( checkCyclicTerms() ) errsum++; - freeMatrix(TermArray); - if (errsum > 0) return ERR_MSX_INPUT; - return 0; -} - -//============================================================================= - -void MSXinp_getSpeciesUnits(int m, char *units) -/* -** Purpose: -** constructs the character string for a species concentration units. -** -** Input: -** m = species index -** -** Output: -** units = character string with species concentration units -*/ -{ - strcpy(units, MSX.Species[m].units); - strcat(units, "/"); - if ( MSX.Species[m].type == BULK ) strcat(units, "L"); - else strcat(units, AreaUnitsWords[MSX.AreaUnits]); -} - -//============================================================================= - -int getLineLength(char *line) -/* -** Purpose: -** determines number of characters of data in a line of input. -** -** Input: -** line = line of text from an input file -** -** Returns: -** number of characters in the line (with comment ignored). -*/ -{ - char *comment; - int lineLength = (int)strlen(line); - if ( lineLength >= MAXLINE ) - { - // --- don't count comment if present - comment = strchr(line, ';'); - if ( comment ) lineLength = (int)(comment - line); // Pointer math here - } - return lineLength; -} - -//============================================================================= - -int getNewSection(char *tok, char *sectWords[], int *sect) -/* -** Purpose: -** checks if a line begins a new section in the input file. -** -** Input: -** tok = a string token -** sectWords = array of input file section keywords -** -** Output: -** sect = index code of section matching tok (or -1 if no match) -** -** Returns: -** 1 if a section is found, 0 if not -*/ -{ - int newsect; - -// --- check if line begins with a new section heading - - if ( *tok == '[' ) - { - // --- look for section heading in list of section keywords - - newsect = MSXutils_findmatch(tok, sectWords); - if ( newsect >= 0 ) *sect = newsect; - else *sect = -1; - return 1; - } - return 0; -} - -//============================================================================= - -int addSpecies(char *line) -/* -** Purpose: -** adds a species ID name to the project. -** -** Input: -** line = line of input data -** -** Returns: -** an error code (0 if no error) -*/ -{ - int errcode = 0; - Ntokens = getTokens(line); - if ( Ntokens < 2 ) return ERR_ITEMS; - errcode = checkID(Tok[1]); - if ( errcode ) return errcode; - if ( MSXproj_addObject(SPECIES, Tok[1], MSX.Nobjects[SPECIES]+1) < 0 ) - errcode = 101; - else MSX.Nobjects[SPECIES]++; - return errcode; -} - -//============================================================================= - -int addCoeff(char *line) -/* -** Purpose: -** adds a coefficient ID name to the project. -** -** Input: -** line = line of input data -** -** Returns: -** an error code (0 if no error) -*/ -{ - int k; - int errcode = 0; - -// --- determine the type of coeff. - - Ntokens = getTokens(line); - if ( Ntokens < 2 ) return ERR_ITEMS; - if (MSXutils_match(Tok[0], "PARAM")) k = PARAMETER; - else if (MSXutils_match(Tok[0], "CONST")) k = CONSTANT; - else return ERR_KEYWORD; - -// --- check for valid id name - - errcode = checkID(Tok[1]); - if ( errcode ) return errcode; - if ( MSXproj_addObject(k, Tok[1], MSX.Nobjects[k]+1) < 0 ) - errcode = 101; - else MSX.Nobjects[k]++; - return errcode; -} - -//============================================================================= - -int addTerm(char *id) -/* -** Purpose: -** adds an intermediate expression term ID name to the project. -** -** Input: -** id = name of an intermediate expression term -** -** Returns: -** an error code (0 if no error) -*/ -{ - int errcode = checkID(id); - if ( !errcode ) - { - if ( MSXproj_addObject(TERM, id, MSX.Nobjects[TERM]+1) < 0 ) - errcode = 101; - else MSX.Nobjects[TERM]++; - } - return errcode; -} - -//============================================================================= - -int addPattern(char *id) -/* -** Purpose: -** adds a time pattern ID name to the project. -** -** Input: -** id = name of a time pattern -** -** Returns: -** an error code (0 if no error) -*/ -{ - int errcode = 0; - - // --- a time pattern can span several lines - - if ( MSXproj_findObject(PATTERN, id) <= 0 ) - { - if ( MSXproj_addObject(PATTERN, id, MSX.Nobjects[PATTERN]+1) < 0 ) - errcode = 101; - else MSX.Nobjects[PATTERN]++; - } - return errcode; -} - -//============================================================================= - -int checkID(char *id) -/* -** Purpose: -** checks that an object's name is unique -** -** Input: -** id = name of an object -** -** Returns: -** an error code (0 if successful) -*/ -{ -// --- check that id name is not a reserved word - int i = 1; - while (HydVarWords[i] != NULL) - { - if (MSXutils_strcomp(id, HydVarWords[i])) return ERR_RESERVED_NAME; - i++; - } - -// --- check that id name not used before - - if ( MSXproj_findObject(SPECIES, id) > 0 || - MSXproj_findObject(TERM, id) > 0 || - MSXproj_findObject(PARAMETER, id) > 0 || - MSXproj_findObject(CONSTANT, id) > 0 - ) return ERR_DUP_NAME; - return 0; -} - -//============================================================================= - -int parseLine(int sect, char *line) -/* -** Purpose: -** parses the contents of a line of input data. -** -** Input: -** sect = index of current input data section -** line = contents of current line of input data -** -** Returns: -** an error code (0 if no error) -*/ -{ - switch(sect) - { - case s_TITLE: - strcpy(MSX.Title, line); - break; - - case s_OPTION: - return parseOption(); - - case s_SPECIES: - return parseSpecies(); - - case s_COEFF: - return parseCoeff(); - - case s_TERM: - return parseTerm(); - - case s_PIPE: - return parseExpression(LINK); - - case s_TANK: - return parseExpression(TANK); - - case s_SOURCE: - return parseSource(); - - case s_QUALITY: - return parseQuality(); - - case s_PARAMETER: - return parseParameter(); - - case s_PATTERN: - return parsePattern(); - - case s_REPORT: - return parseReport(); - - case s_Diffu: - return parseDiffu(); - } - return 0; -} - -//============================================================================= - -int parseOption() -/* -** Purpose: -** parses an input line containing a project option. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int k; - double v; - -// --- determine which option is being read - - if ( Ntokens < 2 ) return 0; - k = MSXutils_findmatch(Tok[0], OptionTypeWords); - if ( k < 0 ) return ERR_KEYWORD; - -// --- parse the value for the given option - - switch ( k ) - { - case AREA_UNITS_OPTION: - k = MSXutils_findmatch(Tok[1], AreaUnitsWords); - if ( k < 0 ) return ERR_KEYWORD; - MSX.AreaUnits = k; - break; - - case RATE_UNITS_OPTION: - k = MSXutils_findmatch(Tok[1], TimeUnitsWords); - if ( k < 0 ) return ERR_KEYWORD; - MSX.RateUnits = k; - break; - - case SOLVER_OPTION: - k = MSXutils_findmatch(Tok[1], SolverTypeWords); - if ( k < 0 ) return ERR_KEYWORD; - MSX.Solver = k; - break; - - case COUPLING_OPTION: - k = MSXutils_findmatch(Tok[1], CouplingWords); - if ( k < 0 ) return ERR_KEYWORD; - MSX.Coupling = k; - break; - - case TIMESTEP_OPTION: - - // Read time step as a floating point value in seconds - if ( !MSXutils_getDouble(Tok[1], &v) ) return ERR_NUMBER; - if ( v < 0.001 ) return ERR_NUMBER; - - // Convert time step to integer milliseconds - v = round(v * 1000.); - MSX.Qstep = (int64_t)v; - break; - - case RTOL_OPTION: - if ( !MSXutils_getDouble(Tok[1], &MSX.DefRtol) ) return ERR_NUMBER; - break; - - case ATOL_OPTION: - if ( !MSXutils_getDouble(Tok[1], &MSX.DefAtol) ) return ERR_NUMBER; - break; - - case COMPILER_OPTION: - k = MSXutils_findmatch(Tok[1], CompilerWords); - if ( k < 0 ) return ERR_KEYWORD; - MSX.Compiler = k; - break; - - case PECLETNUMER_OPTION: - v = atof(Tok[1]); - if (v <= 0.0)return ERR_NUMBER; - MSX.Dispersion.PecletLimit = MAX(v, 1.0); - break; - - case MAXSEGMENT_OPTION: - k = atoi(Tok[1]); - if (k <= 0) return ERR_NUMBER; - MSX.MaxSegments = MAX(k, 50); //at least 50 segments - - } - return 0; -} - -//============================================================================= - -int parseSpecies() -/* -** Purpose: -** parses an input line containing a species variable. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int i; - -// --- get Species index - - if ( Ntokens < 3 ) return ERR_ITEMS; - i = MSXproj_findObject(SPECIES, Tok[1]); - if ( i <= 0 ) return ERR_NAME; - -// --- get pointer to Species name - - MSX.Species[i].id = MSXproj_findID(SPECIES, Tok[1]); - -// --- get Species type - - if ( MSXutils_match(Tok[0], "BULK") ) MSX.Species[i].type = BULK; - else if ( MSXutils_match(Tok[0], "WALL") ) MSX.Species[i].type = WALL; - else return ERR_KEYWORD; - -// --- get Species units - - strncpy(MSX.Species[i].units, Tok[2], MAXUNITS); - -// --- get Species error tolerance - - MSX.Species[i].aTol = 0.0; - MSX.Species[i].rTol = 0.0; - if ( Ntokens >= 4) - { - if ( !MSXutils_getDouble(Tok[3], &MSX.Species[i].aTol) ) - return ERR_NUMBER; - } - if ( Ntokens >= 5) - { - if ( !MSXutils_getDouble(Tok[4], &MSX.Species[i].rTol) ) - return ERR_NUMBER; - } - return 0; -} - -//============================================================================= - -int parseCoeff() -/* -** Purpose: -** parses an input line containing a coefficient definition. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int i, j; - double x; - -// --- check if variable is a Parameter - - if ( Ntokens < 2 ) return 0; - if ( MSXutils_match(Tok[0], "PARAM") ) - { - // --- get Parameter's index - - i = MSXproj_findObject(PARAMETER, Tok[1]); - if ( i <= 0 ) return ERR_NAME; - - // --- get Parameter's value - - MSX.Param[i].id = MSXproj_findID(PARAMETER, Tok[1]); - if ( Ntokens >= 3 ) - { - if ( !MSXutils_getDouble(Tok[2], &x) ) return ERR_NUMBER; - MSX.Param[i].value = x; - for (j=1; j<=MSX.Nobjects[LINK]; j++) MSX.Link[j].param[i] = x; - for (j=1; j<=MSX.Nobjects[TANK]; j++) MSX.Tank[j].param[i] = x; - } - return 0; - } - -// --- check if variable is a Constant - - else if ( MSXutils_match(Tok[0], "CONST") ) - { - // --- get Constant's index - - i = MSXproj_findObject(CONSTANT, Tok[1]); - if ( i <= 0 ) return ERR_NAME; - - // --- get Constant's value - - MSX.Const[i].id = MSXproj_findID(CONSTANT, Tok[1]); - MSX.Const[i].value = 0.0; - if ( Ntokens >= 3 ) - { - if ( !MSXutils_getDouble(Tok[2], &MSX.Const[i].value) ) - return ERR_NUMBER; - } - return 0; - } - else return ERR_KEYWORD; -} - -//============================================================================= - -int parseTerm() -/* -** Purpose: -** parses an input line containing an intermediate expression term . -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int i, j; - int k; - char s[MAXLINE+1] = ""; - MathExpr *expr; - -// --- get term's name - - if ( Ntokens < 2 ) return 0; - i = MSXproj_findObject(TERM, Tok[0]); - MSX.Term[i].id = MSXproj_findID(TERM, Tok[0]); - -// --- reconstruct the expression string from its tokens - - for (j=1; j 0 ) TermArray[i][k] = 1.0; - } - -// --- convert expression into a postfix stack of op codes - - expr = mathexpr_create(s, getVariableCode); - if ( expr == NULL ) return ERR_MATH_EXPR; - -// --- assign the expression to a Term object - - MSX.Term[i].expr = expr; - return 0; -} - -//============================================================================= - -int parseExpression(int classType) -/* -** Purpose: -** parses an input line containing a math expression. -** -** Input: -** classType = either LINK or TANK -** -** Returns: -** an error code (0 if no error) -*/ -{ - int i, j, k; - char s[MAXLINE+1] = ""; - MathExpr *expr; - -// --- determine expression type - - if ( Ntokens < 3 ) return ERR_ITEMS; - k = MSXutils_findmatch(Tok[0], ExprTypeWords); - if ( k < 0 ) return ERR_KEYWORD; - -// --- determine species associated with expression - - i = MSXproj_findObject(SPECIES, Tok[1]); - if ( i < 1 ) return ERR_NAME; - -// --- check that species does not already have an expression - - if ( classType == LINK ) - { - if ( MSX.Species[i].pipeExprType != NO_EXPR ) return ERR_DUP_EXPR; - } - if ( classType == TANK ) - { - if ( MSX.Species[i].tankExprType != NO_EXPR ) return ERR_DUP_EXPR; - } - -// --- reconstruct the expression string from its tokens - - for (j=2; j= 2 ) k = 2; - m = MSXproj_findObject(SPECIES, Tok[k]); - if ( m <= 0 ) return ERR_NAME; - -// --- get quality value - - if ( i >= 2 && Ntokens < 4 ) return ERR_ITEMS; - k = 2; - if ( i >= 2 ) k = 3; - if ( !MSXutils_getDouble(Tok[k], &x) ) return ERR_NUMBER; - -// --- for global specification, set initial quality either for -// all nodes or links depending on type of species - - if ( i == 1) - { - MSX.C0[m] = x; - if ( MSX.Species[m].type == BULK ) - { - for (j=1; j<=MSX.Nobjects[NODE]; j++) MSX.Node[j].c0[m] = x; - } - for (j=1; j<=MSX.Nobjects[LINK]; j++) MSX.Link[j].c0[m] = x; - } - -// --- for a specific node, get its index & set its initial quality - - else if ( i == 2 ) - { - err = ENgetnodeindex(Tok[1], &j); - if ( err ) return ERR_NAME; - if ( MSX.Species[m].type == BULK ) MSX.Node[j].c0[m] = x; - } - -// --- for a specific link, get its index & set its initial quality - - else if ( i == 3 ) - { - err = ENgetlinkindex(Tok[1], &j); - if ( err ) return ERR_NAME; - MSX.Link[j].c0[m] = x; - } - return 0; -} - -//============================================================================= - -int parseParameter() -/* -** Purpose: -** parses an input line containing a parameter data. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int err, i, j; - double x; - -// --- get parameter name - - if ( Ntokens < 4 ) return 0; - i = MSXproj_findObject(PARAMETER, Tok[2]); - -// --- get parameter value - - if ( !MSXutils_getDouble(Tok[3], &x) ) return ERR_NUMBER; - -// --- for pipe parameter, get pipe index and update parameter's value - - if ( MSXutils_match(Tok[0], "PIPE") ) - { - err = ENgetlinkindex(Tok[1], &j); - if ( err ) return ERR_NAME; - MSX.Link[j].param[i] = x; - } - -// --- for tank parameter, get tank index and update parameter's value - - else if ( MSXutils_match(Tok[0], "TANK") ) - { - err = ENgetnodeindex(Tok[1], &j); - if ( err ) return ERR_NAME; - j = MSX.Node[j].tank; - if ( j > 0 ) MSX.Tank[j].param[i] = x; - } - else return ERR_KEYWORD; - return 0; -} - -//============================================================================= - -int parseSource() -/* -** Purpose: -** parses an input line containing a source input data. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int err, i, j, k, m; - double x; - Psource source; - -// --- get source type - - if ( Ntokens < 4 ) return ERR_ITEMS; - k = MSXutils_findmatch(Tok[0], SourceTypeWords); - if ( k < 0 ) return ERR_KEYWORD; - -// --- get node index - - err = ENgetnodeindex(Tok[1], &j); - if ( err ) return ERR_NAME; - -// --- get species index - - m = MSXproj_findObject(SPECIES, Tok[2]); - if ( m <= 0 ) return ERR_NAME; - -// --- check that species is a BULK species - - if ( MSX.Species[m].type != BULK ) return 0; - -// --- get base strength - - if ( !MSXutils_getDouble(Tok[3], &x) ) return ERR_NUMBER; - -// --- get time pattern if present - - i = 0; - if ( Ntokens >= 5 ) - { - i = MSXproj_findObject(PATTERN, Tok[4]); - if ( i <= 0 ) return ERR_NAME; - } - -// --- check if a source for this species already exists - - source = MSX.Node[j].sources; - while ( source ) - { - if ( source->species == m ) break; - source = source->next; - } - -// --- otherwise create a new source object - - if ( source == NULL ) - { - source = (struct Ssource *) malloc(sizeof(struct Ssource)); - if ( source == NULL ) return 101; - source->next = MSX.Node[j].sources; - MSX.Node[j].sources = source; - } - -// --- save source's properties - - source->type = (char)k; - source->species = m; - source->c0 = x; - source->pat = i; - return 0; -} - -//============================================================================= - -int parsePattern() -/* -** Purpose: -** parses an input line containing a time pattern data. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int i, k; - double x; - SnumList *listItem; - -// --- get time pattern index - - if ( Ntokens < 2 ) return ERR_ITEMS; - i = MSXproj_findObject(PATTERN, Tok[0]); - if ( i <= 0 ) return ERR_NAME; - MSX.Pattern[i].id = MSXproj_findID(PATTERN, Tok[0]); - -// --- begin reading pattern multipliers - - k = 1; - while ( k < Ntokens ) - { - if ( !MSXutils_getDouble(Tok[k], &x) ) return ERR_NUMBER; - listItem = (SnumList *) malloc(sizeof(SnumList)); - if ( listItem == NULL ) return 101; - listItem->value = x; - listItem->next = NULL; - if ( MSX.Pattern[i].first == NULL ) - { - MSX.Pattern[i].current = listItem; - MSX.Pattern[i].first = listItem; - } - else - { - MSX.Pattern[i].current->next = listItem; - MSX.Pattern[i].current = listItem; - } - MSX.Pattern[i].length++; - k++; - } - return 0; -} - -//============================================================================= - -int parseReport() -{ - int i, j, k, err; - -// --- get keyword - - if ( Ntokens < 2 ) return 0; - k = MSXutils_findmatch(Tok[0], ReportWords); - if ( k < 0 ) return ERR_KEYWORD; - switch(k) - { - - // --- keyword is NODE; parse ID names of reported nodes - - case 0: - if ( MSXutils_strcomp(Tok[1], ALL) ) - { - for (j=1; j<=MSX.Nobjects[NODE]; j++) MSX.Node[j].rpt = 1; - } - else if ( MSXutils_strcomp(Tok[1], NONE) ) - { - for (j=1; j<=MSX.Nobjects[NODE]; j++) MSX.Node[j].rpt = 0; - } - else for (i=1; i= 3 ) - { - if ( MSXutils_strcomp(Tok[2], YES) ) MSX.Species[j].rpt = 1; - else if ( MSXutils_strcomp(Tok[2], NO) ) MSX.Species[j].rpt = 0; - else return ERR_KEYWORD; - } - if ( Ntokens >= 4 ) - { - if ( !MSXutils_getInt(Tok[3], &MSX.Species[j].precision) ) - return ERR_NUMBER; - } - break; - - // --- keyword is FILE: get name of report file - - case 3: - strcpy(MSX.RptFile.name, Tok[1]); - break; - - // --- keyword is PAGESIZE; - - case 4: - if ( !MSXutils_getInt(Tok[1], &MSX.PageSize) ) return ERR_NUMBER; - break; - } - return 0; -} - -int parseDiffu() -/* -** Purpose: -** parses an input line containing molecular diffusivity data. -** -** Input: -** none -** -** Returns: -** an error code (0 if no error) -*/ -{ - int m; - double x; - - // --- get source type - if (Ntokens < 2) return ERR_ITEMS; - - // --- get species index - m = MSXproj_findObject(SPECIES, Tok[0]); - if (m <= 0) return ERR_NAME; - - // --- check that species is a BULK species - if (MSX.Species[m].type != BULK) return 0; - - // --- get base strength - if (!MSXutils_getDouble(Tok[1], &x)) return ERR_NUMBER; - if (x < 0) return ERR_NUMBER; - - if (Ntokens > 2 && MSXutils_match(Tok[2], "FIXED")) - { - x = x * MSX.Dispersion.DIFFUS; - MSX.Dispersion.ld[m] = x; - } - else - { - x = x * MSX.Dispersion.DIFFUS; - MSX.Dispersion.md[m] = x; - } - MSX.DispersionFlag = 1; - return 0; -} - -//============================================================================= - -int getVariableCode(char *id) -/* -** Purpose: -** finds the index assigned to a species, intermediate term, -** parameter, or constant that appears in a math expression. -** -** Input: -** id = ID name being sought -** -** Returns: -** index of the symbolic variable or term named id. -** -** Note: -** Variables are assigned consecutive code numbers starting from 1 -** and proceeding through each Species, Term, Parameter and Constant. -*/ -{ - int j = MSXproj_findObject(SPECIES, id); - if ( j >= 1 ) return j; - j = MSXproj_findObject(TERM, id); - if ( j >= 1 ) return MSX.Nobjects[SPECIES] + j; - j = MSXproj_findObject(PARAMETER, id); - if ( j >= 1 ) return MSX.Nobjects[SPECIES] + MSX.Nobjects[TERM] + j; - j = MSXproj_findObject(CONSTANT, id); - if ( j >= 1 ) return MSX.Nobjects[SPECIES] + MSX.Nobjects[TERM] + - MSX.Nobjects[PARAMETER] + j; - j = MSXutils_findmatch(id, HydVarWords); - if ( j >= 1 ) return MSX.Nobjects[SPECIES] + MSX.Nobjects[TERM] + - MSX.Nobjects[PARAMETER] + MSX.Nobjects[CONSTANT] + j; - return -1; -} - -//============================================================================= - -int getTokens(char *s) -/* -** Purpose: -** scans a string for tokens, saving pointers to them -** in shared variable Tok[]. -** -** Input: -** s = a character string -** -** Returns: -** number of tokens found in s -** -** Notes: -** Tokens can be separated by the characters listed in SEPSTR -** (spaces, tabs, newline, carriage return) which is defined in -** MSXGLOBALS.H. Text between quotes is treated as a single token. -*/ -{ - int len, m, n; - char *c; - - // --- begin with no tokens - - for (n = 0; n < MAXTOKS; n++) Tok[n] = NULL; - n = 0; - - // --- truncate s at start of comment - - c = strchr(s,';'); - if (c) *c = '\0'; - len = (int)strlen(s); - - // --- scan s for tokens until nothing left - - while (len > 0 && n < MAXTOKS) - { - m = (int)strcspn(s,SEPSTR); // find token length - if (m == 0) s++; // no token found - else - { - if (*s == '"') // token begins with quote - { - s++; // start token after quote - len--; // reduce length of s - m = (int)strcspn(s,"\"\n"); // find end quote or new line - } - s[m] = '\0'; // null-terminate the token - Tok[n] = s; // save pointer to token - n++; // update token count - s += m+1; // begin next token - } - len -= m+1; // update length of s - } - return(n); -} - -//============================================================================= - -void writeInpErrMsg(int errcode, char *sect, char *line, int lineCount) -{ - char msg[MAXMSG+1]; - if ( errcode >= INP_ERR_LAST || errcode <= INP_ERR_FIRST ) - { - sprintf(msg, "Error Code = %d", errcode); - } - else - { - sprintf(msg, "%s at line %d of %s] section:", - InpErrorTxt[errcode-INP_ERR_FIRST], lineCount, sect); - } - ENwriteline(""); - ENwriteline(msg); - ENwriteline(line); -} - -//============================================================================= - -int checkCyclicTerms() -/* -** Purpose: -** checks for cyclic references in Term expressions (e.g., T1 = T2 + T3 -** and T3 = T2/T1) -** -** Input: -** none -** -** Returns: -** 1 if cyclic reference found or 0 if none found. -*/ -{ - int i, j, n; - char msg[MAXMSG+1]; - - n = MSX.Nobjects[TERM]; - for (i=1; i -#include -#include -#include - -#include "msxtypes.h" - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -// Local variables -//----------------- -static long ResultsOffset; // Offset byte where results begin -static long NodeBytesPerPeriod; // Bytes per time period used by all nodes -static long LinkBytesPerPeriod; // Bytes per time period used by all links - -// Imported functions -//-------------------- -double MSXqual_getNodeQual(int j, int m); -double MSXqual_getLinkQual(int k, int m); - -// Exported functions -//-------------------- -int MSXout_open(void); -int MSXout_saveInitialResults(void); -int MSXout_saveResults(void); -int MSXout_saveFinalResults(void); -float MSXout_getNodeQual(int k, int j, int m); -float MSXout_getLinkQual(int k, int j, int m); - -// Local functions -//----------------- -static int saveStatResults(void); -static void getStatResults(int objType, int m, double* stats1, - double* stats2, REAL4* x); - - -//============================================================================= - -int MSXout_open() -/* -** Purpose: -** opens an MSX binary output file. -** -** Input: -** none. -** -** Returns: -** an error code (or 0 if no error). -*/ -{ -// --- close output file if already opened - - if (MSX.OutFile.file != NULL) fclose(MSX.OutFile.file); - -// --- try to open the file - - if ( (MSX.OutFile.file = fopen(MSX.OutFile.name, "w+b")) == NULL) - { - return ERR_OPEN_OUT_FILE; - } - -// --- open a scratch output file for statistics - - if ( MSX.Statflag == SERIES ) MSX.TmpOutFile.file = MSX.OutFile.file; - else if ( (MSX.TmpOutFile.file = fopen(MSX.TmpOutFile.name, "w+b")) == NULL) - { - return ERR_OPEN_OUT_FILE; - } - -// --- write initial results to file - - MSX.Nperiods = 0; - MSXout_saveInitialResults(); - return 0; -} - -//============================================================================= - -int MSXout_saveInitialResults() -/* -** Purpose: -** saves general information to beginning of MSX binary output file. -** -** Input: -** none. -** -** Returns: -** an error code (or 0 if no error). -*/ -{ - int m; - INT4 n; - INT4 magic = MAGICNUMBER; - INT4 version = VERSION; - FILE* f = MSX.OutFile.file; - - rewind(f); - fwrite(&magic, sizeof(INT4), 1, f); //Magic number - fwrite(&version, sizeof(INT4), 1, f); //Version number - n = (INT4)MSX.Nobjects[NODE]; - fwrite(&n, sizeof(INT4), 1, f); //Number of nodes - n = (INT4)MSX.Nobjects[LINK]; - fwrite(&n, sizeof(INT4), 1, f); //Number of links - n = (INT4)MSX.Nobjects[SPECIES]; - fwrite(&n, sizeof(INT4), 1, f); //Number of species - n = (INT4)MSX.Rstep; - fwrite(&n, sizeof(INT4), 1, f); //Reporting step size - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - { - n = (INT4)strlen(MSX.Species[m].id); - fwrite(&n, sizeof(INT4), 1, f); //Length of species ID - fwrite(MSX.Species[m].id, sizeof(char), n, f); //Species ID string - fwrite(&MSX.Species[m].units, sizeof(char), MAXUNITS, f); //Species mass units - } - ResultsOffset = ftell(f); - NodeBytesPerPeriod = MSX.Nobjects[NODE]*MSX.Nobjects[SPECIES]*sizeof(REAL4); - LinkBytesPerPeriod = MSX.Nobjects[LINK]*MSX.Nobjects[SPECIES]*sizeof(REAL4); - return 0; -} - - -//============================================================================= - -int MSXout_saveResults() -/* -** Purpose: -** saves computed species concentrations for each node and link at the -** current time period to the temporary MSX binary output file (which -** will be the same as the permanent MSX binary file if time series -** values were specified as the reported statistic, which is the -** default case). -** -** Input: -** none. -** -** Returns: -** an error code (or 0 if no error). -*/ -{ - int m, j; - REAL4 x; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - { - for (j=1; j<=MSX.Nobjects[NODE]; j++) - { - x = (REAL4)MSXqual_getNodeQual(j, m); - fwrite(&x, sizeof(REAL4), 1, MSX.TmpOutFile.file); - } - } - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - { - for (j=1; j<=MSX.Nobjects[LINK]; j++) - { - x = (REAL4)MSXqual_getLinkQual(j, m); - fwrite(&x, sizeof(REAL4), 1, MSX.TmpOutFile.file); - } - } - return 0; -} - -//============================================================================= - -int MSXout_saveFinalResults() -/* -** Purpose: -** saves any statistical results plus the following information to the end -** of the MSX binary output file: -** - byte offset into file where WQ results for each time period begins, -** - total number of time periods written to the file, -** - any error code generated by the analysis (0 if there were no errors), -** - the Magic Number to indicate that the file is complete. -** -** Input: -** none. -** -** Returns: -** an error code (or 0 if no error). -*/ -{ - INT4 n; - INT4 magic = MAGICNUMBER; - int err = 0; - -// --- save statistical results to the file - - if ( MSX.Statflag != SERIES ) err = saveStatResults(); - if ( err > 0 ) return err; - -// --- write closing records to the file - - n = (INT4)ResultsOffset; - fwrite(&n, sizeof(INT4), 1, MSX.OutFile.file); - n = (INT4)MSX.Nperiods; - fwrite(&n, sizeof(INT4), 1, MSX.OutFile.file); - n = (INT4)MSX.ErrCode; - fwrite(&n, sizeof(INT4), 1, MSX.OutFile.file); - fwrite(&magic, sizeof(INT4), 1, MSX.OutFile.file); - return 0; -} - -//============================================================================= - -float MSXout_getNodeQual(int k, int j, int m) -/* -** Purpose: -** retrieves a result for a specific node from the MSX binary output file. -** -** Input: -** k = time period index -** j = node index -** m = species index. -** -** Returns: -** the requested species concentration. -*/ -{ - REAL4 c; - long bp = ResultsOffset + k * (NodeBytesPerPeriod + LinkBytesPerPeriod); - bp += ((m-1)*MSX.Nobjects[NODE] + (j-1)) * sizeof(REAL4); - fseek(MSX.OutFile.file, bp, SEEK_SET); - fread(&c, sizeof(REAL4), 1, MSX.OutFile.file); - return (float)c; -} - -//============================================================================= - -float MSXout_getLinkQual(int k, int j, int m) -/* -** Purpose: -** retrieves a result for a specific link from the MSX binary output file. -** -** Input: -** k = time period index -** j = link index -** m = species index. -** -** Returns: -** the requested species concentration. -*/ -{ - REAL4 c; - long bp = ResultsOffset + ((k+1)*NodeBytesPerPeriod) + (k*LinkBytesPerPeriod); - bp += ((m-1)*MSX.Nobjects[LINK] + (j-1)) * sizeof(REAL4); - fseek(MSX.OutFile.file, bp, SEEK_SET); - fread(&c, sizeof(REAL4), 1, MSX.OutFile.file); - return (float)c; -} - -//============================================================================= - -int saveStatResults() -/* -** Purpose: -** saves time statistic results (average, min., max., or range) for each -** node and link to the permanent binary output file. -** -** Input: -** none. -** -** Returns: -** an error code (or 0 if no error). -*/ -{ - int m, err = 0; - REAL4* x = NULL; - double* stats1 = NULL; - double* stats2 = NULL; - -// --- create arrays used to store statistics results - - if ( MSX.Nperiods <= 0 ) return err; - m = MAX(MSX.Nobjects[NODE], MSX.Nobjects[LINK]); - x = (REAL4 *) calloc(m+1, sizeof(REAL4)); - stats1 = (double *) calloc(m+1, sizeof(double)); - stats2 = (double *) calloc(m+1, sizeof(double)); - -// --- get desired statistic for each node & link and save to binary file - - if ( x && stats1 && stats2 ) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++ ) - { - getStatResults(NODE, m, stats1, stats2, x); - fwrite(x+1, sizeof(REAL4), MSX.Nobjects[NODE], MSX.OutFile.file); - } - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - getStatResults(LINK, m, stats1, stats2, x); - fwrite(x+1, sizeof(REAL4), MSX.Nobjects[LINK], MSX.OutFile.file); - } - MSX.Nperiods = 1; - } - else err = ERR_MEMORY; - -// --- free allocated arrays - - FREE(x); - FREE(stats1); - FREE(stats2); - return err; -} - -//============================================================================= - -void getStatResults(int objType, int m, double * stats1, double * stats2, - REAL4 * x) -/* -** Purpose: -** reads all results for a given type of object from the temporary -** binary output file and computes the required statistic (average, -** min., max., or range) for each object. -** -** Input: -** objType = type of object (nodes or links) -** m = species index -** stats1, stats2 = work arrays used to hold intermediate values -** x = array used to store results read from file. -** -** Output: -** x = array that contains computed statistic for each object. -*/ -{ - int j, k; - int n = MSX.Nobjects[objType]; - long bp; - -// --- initialize work arrays - - for (j = 1; j <= n; j++) - { - stats1[j] = 0.0; - stats2[j] = 0.0; - } - -// --- for all time periods - - for (k = 0; k < MSX.Nperiods; k++) - { - - // --- position file at start of time period - - bp = k*(NodeBytesPerPeriod + LinkBytesPerPeriod); - if ( objType == NODE ) - { - bp += (m-1) * MSX.Nobjects[NODE] * sizeof(REAL4); - } - if ( objType == LINK) - { - bp += NodeBytesPerPeriod + - (m-1) * MSX.Nobjects[LINK] * sizeof(REAL4); - } - fseek(MSX.TmpOutFile.file, bp, SEEK_SET); - - // --- read concentrations and update stats for all objects - - fread(x+1, sizeof(REAL4), n, MSX.TmpOutFile.file); - if ( MSX.Statflag == AVGERAGE ) - { - for (j = 1; j <= n; j++) stats1[j] += x[j]; - } - else for (j = 1; j <= n; j++) - { - stats1[j] = MIN(stats1[j], x[j]); - stats2[j] = MAX(stats2[j], x[j]); - } - } - -// --- place final stat value for each object in x - - if ( MSX.Statflag == AVGERAGE ) - { - for ( j = 1; j <= n; j++) stats1[j] /= (double)MSX.Nperiods; - } - if ( MSX.Statflag == RANGE ) - { - for ( j = 1; j <= n; j++) - stats1[j] = fabs(stats2[j] - stats1[j]); - } - if ( MSX.Statflag == MAXIMUM) - { - for ( j = 1; j <= MSX.Nobjects[NODE]; j++) stats1[j] = stats2[j]; - } - for (j = 1; j <= n; j++) x[j] = (REAL4)stats1[j]; -} diff --git a/Src/msxproj.c b/Src/msxproj.c deleted file mode 100644 index ae98e66..0000000 --- a/Src/msxproj.c +++ /dev/null @@ -1,791 +0,0 @@ -/****************************************************************************** -** MODULE: MSXPROJ.C -** PROJECT: EPANET-MSX -** DESCRIPTION: project data manager used by the EPANET Multi-Species -** Extension toolkit. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 08/30/2022 -******************************************************************************/ - -#include -#include -#include -#include - -#include "msxtypes.h" -#include "msxutils.h" -//#include "mempool.h" -#include "hash.h" -#include "smatrix.h" -#include "epanet2.h" -#include "dispersion.h" -// Exported variables -//-------------------- -MSXproject MSX; // MSX project data - -// Local variables -//----------------- -static alloc_handle_t *HashPool; // Memory pool for hash tables -static HTtable *Htable[MAX_OBJECTS]; // Hash tables for object ID names - -static char * Errmsg[] = - {"unknown error code.", - "Error 501 - insufficient memory available.", - "Error 502 - no EPANET data file supplied.", - "Error 503 - could not open MSX input file.", - "Error 504 - could not open hydraulic results file.", - "Error 505 - could not read hydraulic results file.", - "Error 506 - could not read MSX input file.", - "Error 507 - too few pipe reaction expressions.", - "Error 508 - too few tank reaction expressions.", - "Error 509 - could not open differential equation solver.", - "Error 510 - could not open algebraic equation solver.", - "Error 511 - could not open binary results file.", - "Error 512 - read/write error on binary results file.", - "Error 513 - could not integrate reaction rate expressions.", - "Error 514 - could not solve reaction equilibrium expressions.", - "Error 515 - reference made to an unknown type of object.", - "Error 516 - reference made to an illegal object index.", - "Error 517 - reference made to an undefined object ID.", - "Error 518 - invalid property values were specified.", - "Error 519 - an MSX project was not opened.", - "Error 520 - an MSX project is already opened.", - "Error 521 - could not open MSX report file.", //(LR-11/20/07) - - "Error 522 - could not compile chemistry functions.", - "Error 523 - could not load functions from compiled chemistry file.", - "Error 524 - illegal math operation."}; - -// Imported functions -//-------------------- -int MSXinp_countMsxObjects(void); -int MSXinp_countNetObjects(void); -int MSXinp_readNetData(void); -int MSXinp_readMsxData(void); - -// Exported functions -//-------------------- -int MSXproj_open(char *fname); -int MSXproj_addObject(int type, char *id, int n); -int MSXproj_findObject(int type, char *id); -char * MSXproj_findID(int type, char *id); -char * MSXproj_getErrmsg(int errcode); - -// Local functions -//----------------- -static void setDefaults(void); -static int convertUnits(void); -static int createObjects(void); -static void deleteObjects(void); -static int createHashTables(void); -static void deleteHashTables(void); - -static int openRptFile(void); //(LR-11/20/07) - -static int buildadjlists(); -static void freeadjlists(); - - -//============================================================================= - -int MSXproj_open(char *fname) -/* -** Purpose: -** opens an EPANET-MSX project. -** -** Input: -** fname = name of EPANET-MSX input file -** -** Returns: -** an error code (0 if no error) -*/ -{ -// --- initialize data to default values - - int errcode = 0; - MSX.ProjectOpened = FALSE; - MSX.QualityOpened = FALSE; - setDefaults(); - -// --- open the MSX input file - - strcpy(MSX.MsxFile.name, fname); - if ((MSX.MsxFile.file = fopen(fname,"rt")) == NULL) return ERR_OPEN_MSX_FILE; - -// --- create hash tables to look up object ID names - - CALL(errcode, createHashTables()); - -// --- allocate memory for the required number of objects - - CALL(errcode, MSXinp_countMsxObjects()); - CALL(errcode, MSXinp_countNetObjects()); - CALL(errcode, createObjects()); - - MSX.DispersionFlag = 0; //no dispersion by default, unless yes in msx file - -// --- read in the EPANET and MSX object data - - CALL(errcode, MSXinp_readNetData()); - CALL(errcode, MSXinp_readMsxData()); - - if (strcmp(MSX.RptFile.name, "")) - CALL(errcode, openRptFile()); - -// --- convert user's units to internal units - - CALL(errcode, convertUnits()); - - if (MSX.DispersionFlag != 0) - { - float relvis; - ENgetoption(13, &relvis); - MSX.Dispersion.viscosity = relvis * 1.1E-5; - - createsparse(); //symmetric matrix - } - - // Build nodal adjacency lists - if (errcode == 0 && MSX.Adjlist == NULL) - { - errcode = buildadjlists(); //parallel links are included - if (errcode) return errcode; - } - -// --- close input file - - if ( MSX.MsxFile.file ) fclose(MSX.MsxFile.file); - MSX.MsxFile.file = NULL; - if ( !errcode ) MSX.ProjectOpened = TRUE; - return errcode; -} - -//============================================================================= - -void MSXproj_close() -/* -** Purpose: -** closes the current EPANET-MSX project. -** -** Input: -** none -*/ -{ - // --- close all files - - if ( MSX.RptFile.file ) fclose(MSX.RptFile.file); //(LR-11/20/07, to fix bug 08) - if ( MSX.HydFile.file ) fclose(MSX.HydFile.file); - if ( MSX.TmpOutFile.file && MSX.TmpOutFile.file != MSX.OutFile.file ) - fclose(MSX.TmpOutFile.file); - if ( MSX.OutFile.file ) fclose(MSX.OutFile.file); - - // --- delete all temporary files - - if ( MSX.HydFile.mode == SCRATCH_FILE ) remove(MSX.HydFile.name); - if ( MSX.OutFile.mode == SCRATCH_FILE ) remove(MSX.OutFile.name); - remove(MSX.TmpOutFile.name); - - // --- free all allocated memory - - MSX.RptFile.file = NULL; //(LR-11/20/07, to fix bug 08) - MSX.HydFile.file = NULL; - MSX.OutFile.file = NULL; - MSX.TmpOutFile.file = NULL; - deleteObjects(); - deleteHashTables(); - MSX.ProjectOpened = FALSE; -} - -//============================================================================= - -int MSXproj_addObject(int type, char *id, int n) -/* -** Purpose: -** adds an object ID to the project's hash tables. -** -** Input: -** type = object type -** id = object ID string -** n = object index. -** -** Returns: -** 0 if object already added, 1 if not, -1 if hashing fails. -*/ -{ - int result; - int len; - char *newID; - -// --- do nothing if object already exists in a hash table - - if ( MSXproj_findObject(type, id) > 0 ) return 0; - -// --- use memory from the hash tables' common memory pool to store -// a copy of the object's ID string - - len = (int)strlen(id) + 1; - newID = (char *) Alloc(len*sizeof(char)); - strcpy(newID, id); - -// --- insert object's ID into the hash table for that type of object - - result = HTinsert(Htable[type], newID, n); - if ( result == 0 ) result = -1; - return result; -} - -//============================================================================= - -int MSXproj_findObject(int type, char *id) -/* -** Purpose: -** uses hash table to find index of an object with a given ID. -** -** Input: -** type = object type -** id = object ID. -** -** Returns: -** index of object with given ID, or -1 if ID not found. -*/ -{ - return HTfind(Htable[type], id); -} - -//============================================================================= - -char * MSXproj_findID(int type, char *id) -/* -** Purpose: -** uses hash table to find address of given string entry. -** -** Input: -** type = object type -** id = ID name being sought. -** -** Returns: -** pointer to location where object's ID string is stored. -*/ -{ - return HTfindKey(Htable[type], id); -} - -//============================================================================= - -char * MSXproj_getErrmsg(int errcode) -/* -** Purpose: -** gets the text of an error message. -** -** Input: -** errcode = error code. -** -** Returns: -** text of error message. -*/ -{ - if ( errcode <= ERR_FIRST || errcode >= ERR_MAX ) return Errmsg[0]; - else return Errmsg[errcode - ERR_FIRST]; -} - -//============================================================================= - -void setDefaults() -/* -** Purpose: -** assigns default values to project variables. -** -** Input: -** none. -*/ -{ - int i; - MSX.RptFile.file = NULL; //(LR-11/20/07) - MSX.HydFile.file = NULL; - MSX.HydFile.mode = USED_FILE; - MSX.OutFile.file = NULL; - MSX.OutFile.mode = SCRATCH_FILE; - MSX.TmpOutFile.file = NULL; - MSXutils_getTempName(MSX.OutFile.name); - MSXutils_getTempName(MSX.TmpOutFile.name); - strcpy(MSX.RptFile.name, ""); - strcpy(MSX.Title, ""); - MSX.Rptflag = 0; - for (i=0; inext; - FREE(p); - p=MSX.Node[i].sources; - } - } - } - if (MSX.Link) for (i=1; i<=MSX.Nobjects[LINK]; i++) - { - FREE(MSX.Link[i].c0); - FREE(MSX.Link[i].param); - FREE(MSX.Link[i].reacted); - } - if (MSX.Tank) for (i=1; i<=MSX.Nobjects[TANK]; i++) - { - FREE(MSX.Tank[i].param); - FREE(MSX.Tank[i].c); - FREE(MSX.Tank[i].reacted); - } - - freeadjlists(); - - // --- free memory used by time patterns - if (MSX.Pattern) for (i=1; i<=MSX.Nobjects[PATTERN]; i++) - { - listItem = MSX.Pattern[i].first; - while (listItem) - { - MSX.Pattern[i].first = listItem->next; - free(listItem); - listItem = MSX.Pattern[i].first; - } - } - FREE(MSX.Pattern); - -// --- free memory used for hydraulics results - - FREE(MSX.D); - FREE(MSX.H); - FREE(MSX.Q); - FREE(MSX.S); - FREE(MSX.C0); - -// --- delete all nodes, links, and tanks - - FREE(MSX.Node); - FREE(MSX.Link); - FREE(MSX.Tank); - -// --- free memory used by reaction rate & equilibrium expressions - - if (MSX.Species) for (i=1; i<=MSX.Nobjects[SPECIES]; i++) - { - // --- free the species tank expression only if it doesn't - // already point to the species pipe expression - if ( MSX.Species[i].tankExpr != MSX.Species[i].pipeExpr ) - { - mathexpr_delete(MSX.Species[i].tankExpr); - } - mathexpr_delete(MSX.Species[i].pipeExpr); - } - -// --- delete all species, parameters, and constants - - FREE(MSX.Species); - FREE(MSX.Param); - FREE(MSX.Const); - FREE(MSX.K); - -// --- free memory used by intermediate terms - - if (MSX.Term) for (i=1; i<=MSX.Nobjects[TERM]; i++) - mathexpr_delete(MSX.Term[i].expr); - FREE(MSX.Term); -} - -//============================================================================= - -int createHashTables() -/* -** Purpose: -** allocates memory for object ID hash tables. -** -** Input: -** none. -** -** Returns: -** an error code (0 if no error). -*/ -{ int j; - -// --- create a hash table for each type of object - - for (j = 0; j < MAX_OBJECTS ; j++) - { - Htable[j] = HTcreate(); - if ( Htable[j] == NULL ) return ERR_MEMORY; - } - -// --- initialize the memory pool used to store object ID's - - HashPool = AllocInit(); - if ( HashPool == NULL ) return ERR_MEMORY; - return 0; -} - -//============================================================================= - -void deleteHashTables() -/* -** Purpose: -** frees memory allocated for object ID hash tables. -** -** Input: -** none. -*/ -{ - int j; - -// --- free the hash tables - - for (j = 0; j < MAX_OBJECTS; j++) - { - if ( Htable[j] != NULL ) HTfree(Htable[j]); - } - -// --- free the object ID memory pool - - if ( HashPool ) - { - AllocSetPool(HashPool); - AllocFreePool(); - } -} - -// New function added (LR-11/20/07, to fix bug 08) -int openRptFile() -{ - if ( MSX.RptFile.file ) fclose(MSX.RptFile.file); - MSX.RptFile.file = fopen(MSX.RptFile.name, "wt"); - if ( MSX.RptFile.file == NULL ) return ERR_OPEN_RPT_FILE; - return 0; -} - -int buildadjlists() //from epanet for node sorting in WQ routing -/* -**-------------------------------------------------------------- -** Input: none -** Output: returns error code -** Purpose: builds linked list of links adjacent to each node -**-------------------------------------------------------------- -*/ -{ - int i, j, k; - int errcode = 0; - Padjlist alink; - - // Create an array of adjacency lists - freeadjlists(); - MSX.Adjlist = (Padjlist*)calloc(MSX.Nobjects[NODE]+1, sizeof(Padjlist)); - if (MSX.Adjlist == NULL) return 101; - for (i = 0; i <= MSX.Nobjects[NODE]; i++) - MSX.Adjlist[i] = NULL; - - // For each link, update adjacency lists of its end nodes - for (k = 1; k <= MSX.Nobjects[LINK]; k++) - { - i = MSX.Link[k].n1; - j = MSX.Link[k].n2; - - // Include link in start node i's list - alink = (struct Sadjlist*) malloc(sizeof(struct Sadjlist)); - if (alink == NULL) - { - errcode = 101; - break; - } - alink->node = j; - alink->link = k; - alink->next = MSX.Adjlist[i]; - MSX.Adjlist[i] = alink; - - // Include link in end node j's list - alink = (struct Sadjlist*) malloc(sizeof(struct Sadjlist)); - if (alink == NULL) - { - errcode = 101; - break; - } - alink->node = i; - alink->link = k; - alink->next = MSX.Adjlist[j]; - MSX.Adjlist[j] = alink; - } - if (errcode) freeadjlists(); - return errcode; -} - - -void freeadjlists() //from epanet for node sorting in WQ routing -/* -**-------------------------------------------------------------- -** Input: none -** Output: none -** Purpose: frees memory used for nodal adjacency lists -**-------------------------------------------------------------- -*/ -{ - int i; - Padjlist alink; - - if (MSX.Adjlist == NULL) return; - for (i = 0; i <= MSX.Nobjects[NODE]; i++) - { - for (alink = MSX.Adjlist[i]; alink != NULL; alink = MSX.Adjlist[i]) - { - MSX.Adjlist[i] = alink->next; - free(alink); - } - } - free(MSX.Adjlist); - MSX.Adjlist = NULL; -} - diff --git a/Src/msxqual.c b/Src/msxqual.c deleted file mode 100644 index 42684e9..0000000 --- a/Src/msxqual.c +++ /dev/null @@ -1,2009 +0,0 @@ -/****************************************************************************** -** MODULE: MSXQUAL.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Water quality routing routines. -** COPYRIGHT: Copyright (C) 2007 Feng Shang, Lewis Rossman, and James Uber. -** All Rights Reserved. See license information in LICENSE.TXT. -** AUTHORS: See AUTHORS -** VERSION: 2.0.00 -** LAST UPDATE: 08/30/2022 -******************************************************************************/ - -#include -#include -#include -#include - -#include "msxtypes.h" -//#include "mempool.h" -#include "msxutils.h" -#include "dispersion.h" - -// Macros to identify upstream & downstream nodes of a link -// under the current flow and to compute link volume -// -#define UP_NODE(x) ( (MSX.FlowDir[(x)]==POSITIVE) ? MSX.Link[(x)].n1 : MSX.Link[(x)].n2 ) -#define DOWN_NODE(x) ( (MSX.FlowDir[(x)]==POSITIVE) ? MSX.Link[(x)].n2 : MSX.Link[(x)].n1 ) -#define LINKVOL(k) ( 0.785398*MSX.Link[(k)].len*SQR(MSX.Link[(k)].diam) ) - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -// Local variables -//----------------- -//static Pseg FreeSeg; // pointer to unused pipe segment -//static Pseg *NewSeg; // new segment added to each pipe -//static char *FlowDir; // flow direction for each pipe -//static double *VolIn; // inflow flow volume to each node -//static double **MassIn; // mass inflow of each species to each node -//static double **X; // work matrix -//static char HasWallSpecies; // wall species indicator -//static char OutOfMemory; // out of memory indicator -//static alloc_handle_t *QualPool; // memory pool - -// Stagnant flow tolerance -const double Q_STAGNANT = 0.005 / GPMperCFS; // 0.005 gpm = 1.114e-5 cfs - -// Imported functions -//-------------------- -int MSXchem_open(void); -void MSXchem_close(void); -extern int MSXchem_react(double dt); -extern int MSXchem_equil(int zone, int k, double *c); - -extern void MSXtank_mix1(int i, double vin, double *massin, double vnet); -extern void MSXtank_mix2(int i, double vin, double *massin, double vnet); -extern void MSXtank_mix3(int i, double vin, double *massin, double vnet); -extern void MSXtank_mix4(int i, double vIn, double *massin, double vnet); - - - -int MSXout_open(void); -int MSXout_saveResults(void); -int MSXout_saveFinalResults(void); - -void MSXerr_clearMathError(void); -int MSXerr_mathError(void); -char* MSXerr_writeMathErrorMsg(void); - -// Exported functions -//-------------------- -int MSXqual_open(void); -int MSXqual_init(void); -int MSXqual_step(double *t, double *tleft); -int MSXqual_close(void); -double MSXqual_getNodeQual(int j, int m); -double MSXqual_getLinkQual(int k, int m); -int MSXqual_isSame(double c1[], double c2[]); -void MSXqual_removeSeg(Pseg seg); -Pseg MSXqual_getFreeSeg(double v, double c[]); -void MSXqual_addSeg(int k, Pseg seg); -void MSXqual_reversesegs(int k); - -// Local functions -//----------------- -static int getHydVars(void); -static int transport(int64_t tstep); -static void initSegs(void); -static int flowdirchanged(void); -static void advectSegs(double dt); -static void getNewSegWallQual(int k, double dt, Pseg seg); -static void shiftSegWallQual(int k, double dt); -static void sourceInput(int n, double vout, double dt); -static void addSource(int n, Psource source, double v, double dt); -static double getSourceQual(Psource source); -static void removeAllSegs(int k); - -static void topological_transport(double dt); -static void findnodequal(int n, double volin, double* massin, double volout, double tstep); -static void noflowqual(int n); -static void evalnodeinflow(int, double, double*, double*); -static void evalnodeoutflow(int k, double* upnodequal, double tstep); -static int sortNodes(); -static int selectnonstacknode(int numsorted, int* indegree); -static void findstoredmass(double* mass); - -static void evalHydVariables(int k); -//============================================================================= - -int MSXqual_open() -/* -** Purpose: -** opens the WQ routing system. -** -** Returns: -** an error code (0 if no errors). -*/ -{ - int errcode = 0; - int n; - - // --- set flags - - MSX.QualityOpened = FALSE; - MSX.Saveflag = 0; - MSX.OutOfMemory = FALSE; - MSX.HasWallSpecies = FALSE; - - // --- initialize array pointers to null - - MSX.C1 = NULL; - MSX.FirstSeg = NULL; - MSX.LastSeg = NULL; - MSX.NewSeg = NULL; - MSX.FlowDir = NULL; - MSX.MassIn = NULL; - - - // --- open the chemistry system - - errcode = MSXchem_open(); - if (errcode > 0) return errcode; - - // --- allocate a memory pool for pipe segments - - MSX.QualPool = AllocInit(); - if (MSX.QualPool == NULL) return ERR_MEMORY; - -// --- allocate memory used for species concentrations - - MSX.C1 = (double *) calloc(MSX.Nobjects[SPECIES]+1, sizeof(double)); - - MSX.MassBalance.initial = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); - MSX.MassBalance.inflow = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); - MSX.MassBalance.indisperse = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); - MSX.MassBalance.outflow = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); - MSX.MassBalance.reacted = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); - MSX.MassBalance.final = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); - MSX.MassBalance.ratio = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); - -// --- allocate memory used for pointers to the first, last, -// and new WQ segments in each link and tank - - n = MSX.Nobjects[LINK] + MSX.Nobjects[TANK] + 1; - MSX.FirstSeg = (Pseg *) calloc(n, sizeof(Pseg)); - MSX.LastSeg = (Pseg *) calloc(n, sizeof(Pseg)); - MSX.NewSeg = (Pseg *) calloc(n, sizeof(Pseg)); - -// --- allocate memory used for flow direction in each link - - MSX.FlowDir = (FlowDirection *) calloc(n, sizeof(FlowDirection)); - -// --- allocate memory used to accumulate mass and volume -// inflows to each node - - n = MSX.Nobjects[NODE] + 1; - MSX.MassIn = (double *) calloc(MSX.Nobjects[SPECIES]+1, sizeof(double)); - MSX.SourceIn = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); - -// --- allocate memory for topologically sorted nodes - - MSX.SortedNodes = (int*)calloc(n, sizeof(int)); - -// --- check for successful memory allocation - - CALL(errcode, MEMCHECK(MSX.C1)); - CALL(errcode, MEMCHECK(MSX.FirstSeg)); - CALL(errcode, MEMCHECK(MSX.LastSeg)); - CALL(errcode, MEMCHECK(MSX.NewSeg)); - CALL(errcode, MEMCHECK(MSX.FlowDir)); - CALL(errcode, MEMCHECK(MSX.MassIn)); - CALL(errcode, MEMCHECK(MSX.SourceIn)); - CALL(errcode, MEMCHECK(MSX.SortedNodes)); - CALL(errcode, MEMCHECK(MSX.MassBalance.initial)); - CALL(errcode, MEMCHECK(MSX.MassBalance.inflow)); - CALL(errcode, MEMCHECK(MSX.MassBalance.indisperse)); - CALL(errcode, MEMCHECK(MSX.MassBalance.outflow)); - CALL(errcode, MEMCHECK(MSX.MassBalance.reacted)); - CALL(errcode, MEMCHECK(MSX.MassBalance.final)); - CALL(errcode, MEMCHECK(MSX.MassBalance.ratio)); - -// --- check if wall species are present - - for (n=1; n<=MSX.Nobjects[SPECIES]; n++) - { - if ( MSX.Species[n].type == WALL ) MSX.HasWallSpecies = TRUE; - } - if ( !errcode ) MSX.QualityOpened = TRUE; - return(errcode); -} - -//============================================================================= - -int MSXqual_init() -/* -** Purpose: -** re-initializes the WQ routing system. -** -** Input: -** none. -** -** Returns: -** an error code (or 0 if no errors). -*/ -{ - int i, n, m; - int errcode = 0; - -// --- initialize node concentrations, tank volumes, & source mass flows - - for (i=1; i<=MSX.Nobjects[NODE]; i++) - { - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - MSX.Node[i].c[m] = MSX.Node[i].c0[m]; - } - for (i = 1; i <= MSX.Nobjects[LINK]; i++) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.Link[i].reacted[m] = 0.0; - } - - for (i=1; i<=MSX.Nobjects[TANK]; i++) - { - MSX.Tank[i].hstep = 0.0; - MSX.Tank[i].v = MSX.Tank[i].v0; - n = MSX.Tank[i].node; - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - MSX.Tank[i].c[m] = MSX.Node[n].c0[m]; - MSX.Tank[i].reacted[m] = 0.0; - } - } - - for (i=1; i<=MSX.Nobjects[PATTERN]; i++) - { - MSX.Pattern[i].interval = 0; - MSX.Pattern[i].current = MSX.Pattern[i].first; - } - -// --- copy expression constants to vector MSX.K[] - - for (i=1; i<=MSX.Nobjects[CONSTANT]; i++) - { - MSX.K[i] = MSX.Const[i].value; - } - -// --- check if a separate WQ report is required - - MSX.Rptflag = 0; - n = 0; - for (i=1; i<=MSX.Nobjects[NODE]; i++) n += MSX.Node[i].rpt; - for (i=1; i<=MSX.Nobjects[LINK]; i++) n += MSX.Link[i].rpt; - if ( n > 0 ) - { - n = 0; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) n += MSX.Species[m].rpt; - } - if ( n > 0 ) MSX.Rptflag = 1; - if ( MSX.Rptflag ) MSX.Saveflag = 1; - -// --- reset memory pool - - AllocSetPool(MSX.QualPool); - MSX.FreeSeg = NULL; - AllocReset(); - -// --- re-position hydraulics file - - fseek(MSX.HydFile.file, MSX.HydOffset, SEEK_SET); - -// --- set elapsed times to zero - - MSX.Htime = 0; //Hydraulic solution time - MSX.Qtime = 0; //Quality routing time - MSX.Rtime = MSX.Rstart * 1000; //Reporting time - MSX.Nperiods = 0; //Number fo reporting periods - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - MSX.MassBalance.initial[m] = 0.0; - MSX.MassBalance.final[m] = 0.0; - MSX.MassBalance.inflow[m] = 0.0; - MSX.MassBalance.indisperse[m] = 0.0; - MSX.MassBalance.outflow[m] = 0.0; - MSX.MassBalance.reacted[m] = 0.0; - MSX.MassBalance.ratio[m] = 0.0; - } - -// --- open binary output file if results are to be saved - - if ( MSX.Saveflag ) errcode = MSXout_open(); - return errcode; -} - -//============================================================================= - -int MSXqual_step(double *t, double *tleft) -/* -** Purpose: -** updates WQ conditions over a single WQ time step. -** -** Input: -** none. -** -** Output: -** *t = current simulation time (sec) -** *tleft = time left in simulation (sec) -** -** Returns: -** an error code: -** 0 = no error -** 501 = memory error -** 307 = can't read hydraulics file -** 513 = can't integrate reaction rates -*/ -{ - int k, errcode = 0, flowchanged; - int m; - double smassin, smassout, sreacted; - int64_t hstep, tstep, dt; - -// --- set the shared memory pool to the water quality pool -// and the overall time step to nominal WQ time step - - AllocSetPool(MSX.QualPool); - tstep = MSX.Qstep; - if (MSX.Qtime + tstep > MSX.Dur) tstep = MSX.Dur - MSX.Qtime; - -// --- repeat until the end of the time step - - do - { - // --- find the time until the next hydraulic event occurs - dt = tstep; - hstep = MSX.Htime - MSX.Qtime; - - // --- check if next hydraulic event occurs within the current time step - - if (hstep <= dt) - { - - // --- reduce current time step to end at next hydraulic event - dt = hstep; - - // --- route WQ over this time step - if ( dt > 0 ) CALL(errcode, transport(dt)); - MSX.Qtime += dt; - - // --- retrieve new hydraulic solution - if (MSX.Qtime == MSX.Htime) - { - CALL(errcode, getHydVars()); - - for (int kl = 1; kl <= MSX.Nobjects[LINK]; kl++) - { - // --- skip non-pipe links - - if (MSX.Link[kl].len == 0.0) continue; - - // --- evaluate hydraulic variables - - evalHydVariables(kl); - } - - if (MSX.Qtime < MSX.Dur) - { - // --- initialize pipe segments (at time 0) or else re-orient segments - // to accommodate any flow reversals - if (MSX.Qtime == 0) - { - flowchanged = 1; - initSegs(); - } - else - flowchanged = flowdirchanged(); - - if (flowchanged) - { - CALL(errcode, sortNodes()); - } - } - } - - // --- report results if its time to do so - if (MSX.Saveflag && MSX.Qtime == MSX.Rtime) - { - CALL(errcode, MSXout_saveResults()); - MSX.Rtime += MSX.Rstep * 1000; - MSX.Nperiods++; - } - } - - // --- otherwise just route WQ over the current time step - - else - { - CALL(errcode, transport(dt)); - MSX.Qtime += dt; - } - - // --- reduce overall time step by the size of the current time step - - tstep -= dt; - if (MSX.OutOfMemory) errcode = ERR_MEMORY; - } while (!errcode && tstep > 0); - -// --- update the current time into the simulation and the amount remaining - - *t = MSX.Qtime / 1000.; - *tleft = (MSX.Dur - MSX.Qtime) / 1000.; - -// --- if there's no time remaining, then save the final records to output file - - if ( *tleft <= 0 && MSX.Saveflag ) - { - findstoredmass(MSX.MassBalance.final); - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - sreacted = 0.0; - for (k = 1; k <= MSX.Nobjects[LINK]; k++) - sreacted += MSX.Link[k].reacted[m]; - for (k = 1; k <= MSX.Nobjects[TANK]; k++) - sreacted += MSX.Tank[k].reacted[m]; - - MSX.MassBalance.reacted[m] = sreacted; - smassin = MSX.MassBalance.initial[m] + MSX.MassBalance.inflow[m] + MSX.MassBalance.indisperse[m]; - smassout = MSX.MassBalance.outflow[m]+MSX.MassBalance.final[m]; - if (sreacted < 0) //loss - smassout -= sreacted; - else - smassin += sreacted; - - if (smassin == 0) - MSX.MassBalance.ratio[m] = 1.0; - else - MSX.MassBalance.ratio[m] = smassout / smassin; - } - CALL(errcode, MSXout_saveFinalResults()); - } - return errcode; -} - -//============================================================================= - -double MSXqual_getNodeQual(int j, int m) -/* -** Purpose: -** retrieves WQ for species m at node n. -** -** Input: -** j = node index -** m = species index. -** -** Returns: -** WQ value of node. -*/ -{ - int k; - -// --- return 0 for WALL species - - if ( MSX.Species[m].type == WALL ) return 0.0; - -// --- if node is a tank, return its internal concentration - - k = MSX.Node[j].tank; - if (k > 0 && MSX.Tank[k].a > 0.0) - { - return MSX.Tank[k].c[m]; - } - -// --- otherwise return node's concentration (which includes -// any contribution from external sources) - - return MSX.Node[j].c[m]; -} - -//============================================================================= - -double MSXqual_getLinkQual(int k, int m) -/* -** Purpose: -** computes average quality in link k. -** -** Input: -** k = link index -** m = species index. -** -** Returns: -** WQ value of link. -*/ -{ - double vsum = 0.0, - msum = 0.0; - Pseg seg; - - seg = MSX.FirstSeg[k]; - while (seg != NULL) - { - vsum += seg->v; - msum += (seg->c[m])*(seg->v); - seg = seg->prev; - } - if (vsum > 0.0) return(msum/vsum); - else - { - return (MSXqual_getNodeQual(MSX.Link[k].n1, m) + - MSXqual_getNodeQual(MSX.Link[k].n2, m)) / 2.0; - } -} - -//============================================================================= - -int MSXqual_close() -/* -** Purpose: -** closes the WQ routing system. -** -** Input: -** none. -** -** Returns: -** error code (0 if no error). -*/ -{ - int errcode = 0; - if (!MSX.ProjectOpened) return 0; - MSXchem_close(); - - FREE(MSX.C1); - FREE(MSX.FirstSeg); - FREE(MSX.LastSeg); - FREE(MSX.NewSeg); - FREE(MSX.FlowDir); - FREE(MSX.SortedNodes); - FREE(MSX.MassIn); - FREE(MSX.SourceIn); - if ( MSX.QualPool) - { - AllocSetPool(MSX.QualPool); - AllocFreePool(); - } - FREE(MSX.MassBalance.initial); - FREE(MSX.MassBalance.inflow); - FREE(MSX.MassBalance.indisperse); - FREE(MSX.MassBalance.outflow); - FREE(MSX.MassBalance.reacted); - FREE(MSX.MassBalance.final); - FREE(MSX.MassBalance.ratio); - - MSX.QualityOpened = FALSE; - return errcode; -} - -//============================================================================= - -int MSXqual_isSame(double c1[], double c2[]) -/* -** Purpose: -** checks if two sets of concentrations are the same -** -** Input: -** c1[] = first set of species concentrations -** c2[] = second set of species concentrations -** -** Returns: -** 1 if the concentrations are all within a specific tolerance of each -** other or 0 if they are not. -*/ -{ - int m; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - { - if (fabs(c1[m] - c2[m]) >= MSX.Species[m].aTol ) return 0; - } - return 1; -} - - -//============================================================================= - -int getHydVars() -/* -** Purpose: -** retrieves hydraulic solution and time step for next hydraulic event -** from a hydraulics file. -** -** Input: -** none. -** -** Returns: -** error code -** -** NOTE: -** A hydraulic solution consists of the current time -** (hydtime), nodal demands (D) and heads (H), link -** flows (Q), and link status values and settings (which are not used). -*/ -{ - int errcode = 0; - long hydtime, hydstep; - INT4 n; - -// --- read hydraulic time, demands, heads, and flows from the file - - if (fread(&n, sizeof(INT4), 1, MSX.HydFile.file) < 1) - return ERR_READ_HYD_FILE; - hydtime = (long)n; - n = MSX.Nobjects[NODE]; - if (fread(MSX.D+1, sizeof(REAL4), n, MSX.HydFile.file) < (unsigned)n) - return ERR_READ_HYD_FILE; - if (fread(MSX.H+1, sizeof(REAL4), n, MSX.HydFile.file) < (unsigned)n) - return ERR_READ_HYD_FILE; - n = MSX.Nobjects[LINK]; - if (fread(MSX.Q+1, sizeof(REAL4), n, MSX.HydFile.file) < (unsigned)n) - return ERR_READ_HYD_FILE; - if (fread(MSX.S + 1, sizeof(REAL4), n, MSX.HydFile.file) < (unsigned)n) //03/17/2022 - return ERR_READ_HYD_FILE; - - for (int pi = 1; pi <= n; pi++) //06/10/2021 Shang - if (fabs(MSX.Q[pi]) < Q_STAGNANT) - MSX.Q[pi] = 0.0; - -// --- skip over link settings - - fseek(MSX.HydFile.file, 1*n*sizeof(REAL4), SEEK_CUR); - -// --- read time step until next hydraulic event - - if (fread(&n, sizeof(INT4), 1, MSX.HydFile.file) < 1) - return ERR_READ_HYD_FILE; - hydstep = (long)n; - -// --- update elapsed time until next hydraulic event - - MSX.Htime = hydtime + hydstep; - MSX.Htime *= 1000; - -/* - if (MSX.Qtime < MSX.Dur) - { - if (MSX.Qtime == 0) - { - flowchanged = 1; - initSegs(); - } - else flowchanged = flowdirchanged(); - } - return flowchanged;*/ - - return errcode; -} - -//============================================================================= - -int transport(int64_t tstep) -/* -** Purpose: -** transports constituent mass through pipe network -** under a period of constant hydraulic conditions. -** -** Input: -** tstep = length of current time step (sec). -** -** Returns: -** an error code or 0 if no error. -*/ -{ - int64_t qtime, dt64; - double dt; - int errcode = 0; - -// --- repeat until time step is exhausted - - MSXerr_clearMathError(); // clear math error flag - qtime = 0; - while (!MSX.OutOfMemory && - !errcode && - qtime < tstep) - { // Qstep is nominal quality time step - dt64 = MIN(MSX.Qstep, tstep-qtime); // get actual time step - qtime += dt64; // update amount of input tstep taken - dt = dt64 / 1000.; // time step as fractional seconds - - errcode = MSXchem_react(dt); // react species in each pipe & tank - if ( errcode ) return errcode; - advectSegs(dt); // advect segments in each pipe - - topological_transport(dt); //replace accumulate, updateNodes, sourceInput and release - - if (MSXerr_mathError()) // check for any math error - { - MSXerr_writeMathErrorMsg(); - errcode = ERR_ILLEGAL_MATH; - } - } - return errcode; -} - -//============================================================================= - -void initSegs() -/* -** Purpose: -** initializes water quality in pipe segments. -** -** Input: -** none. -*/ -{ - int j, k, m; - double v; - -// --- examine each link - - for (k=1; k<=MSX.Nobjects[LINK]; k++) - { - // --- establish flow direction - - if (fabs(MSX.Q[k]) < Q_STAGNANT) - MSX.FlowDir[k] = ZERO_FLOW; - else if (MSX.Q[k] > 0.0) - MSX.FlowDir[k] = POSITIVE; - else - MSX.FlowDir[k] = NEGATIVE; - - // --- start with no segments - - MSX.LastSeg[k] = NULL; - MSX.FirstSeg[k] = NULL; - MSX.NewSeg[k] = NULL; - - // --- use quality of downstream node for BULK species - // if no initial link quality supplied - -// j = DOWN_NODE(k); - j = MSX.Link[k].n2; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - { - if ( MSX.Link[k].c0[m] != MISSING ) - MSX.C1[m] = MSX.Link[k].c0[m]; - else if ( MSX.Species[m].type == BULK ) - MSX.C1[m] = MSX.Node[j].c0[m]; - else MSX.C1[m] = 0.0; - } - - // --- fill link with a single segment of this quality - - MSXchem_equil(LINK, k, MSX.C1); - v = LINKVOL(k); - if (v > 0.0) - { - int ninitsegs = MIN(100, MSX.MaxSegments); - - for (int ns = 0; ns < ninitsegs; ns++) - MSXqual_addSeg(k, MSXqual_getFreeSeg(v / (1.0*ninitsegs), MSX.C1)); - } - } - -// --- initialize segments in tanks - - for (j=1; j<=MSX.Nobjects[TANK]; j++) - { - // --- skip reservoirs - - if ( MSX.Tank[j].a == 0.0 ) continue; - - // --- tank segment pointers are stored after those for links - - k = MSX.Tank[j].node; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - MSX.C1[m] = MSX.Node[k].c0[m]; - k = MSX.Nobjects[LINK] + j; - MSX.LastSeg[k] = NULL; - MSX.FirstSeg[k] = NULL; - - MSXchem_equil(NODE, j, MSX.C1); - - // --- add 2 segments for 2-compartment model - - if (MSX.Tank[j].mixModel == MIX2) - { - v = MAX(0, MSX.Tank[j].v - MSX.Tank[j].vMix); - MSXqual_addSeg(k, MSXqual_getFreeSeg(v, MSX.C1)); - v = MSX.Tank[j].v - v; - MSXqual_addSeg(k, MSXqual_getFreeSeg(v, MSX.C1)); - } - - // --- add one segment for all other models - - else - { - v = MSX.Tank[j].v; - MSXqual_addSeg(k, MSXqual_getFreeSeg(v, MSX.C1)); - } - } - - findstoredmass(MSX.MassBalance.initial); // initial mass -} - -//============================================================================= - -int flowdirchanged() -/* -** Purpose: -** re-orients pipe segments (if flow reverses). -** -** Input: -** none. -*/ -{ - int k, flowchanged=0; - FlowDirection newdir; - - -// --- examine each link - - for (k=1; k<=MSX.Nobjects[LINK]; k++) - { - // --- find new flow direction - - newdir = POSITIVE; - if (fabs(MSX.Q[k]) < Q_STAGNANT) - newdir = ZERO_FLOW; - else if (MSX.Q[k] < 0.0) newdir = NEGATIVE; - - // --- if direction changes, then reverse the order of segments - // (first to last) and save new direction - - if (newdir*MSX.FlowDir[k] < 0) - { - MSXqual_reversesegs(k); - } - if (newdir != MSX.FlowDir[k]) - { - flowchanged = 1; - } - MSX.FlowDir[k] = newdir; - } - return flowchanged; -} - - -//============================================================================= - -void advectSegs(double dt) -/* -** Purpose: -** advects WQ segments within each pipe. -** -** Input: -** dt = current WQ time step (sec). -*/ -{ - int k, m; - -// --- examine each link - - for (k=1; k<=MSX.Nobjects[LINK]; k++) - { - // --- zero out WQ in new segment to be added at entrance of link - - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) MSX.C1[m] = 0.0; - - // --- get a free segment to add to entrance of link - - MSX.NewSeg[k] = MSXqual_getFreeSeg(0.0, MSX.C1); - - // --- skip zero-length links (pumps & valves) & no-flow links - - if ( MSX.NewSeg[k] == NULL || - MSX.Link[(k)].len == 0.0 || MSX.Q[k] == 0.0 ) continue; - - // --- find conc. of wall species in new segment to be added - // and adjust conc. of wall species to reflect shifted - // positions of existing segments - - if ( MSX.HasWallSpecies ) - { - getNewSegWallQual(k, dt, MSX.NewSeg[k]); - shiftSegWallQual(k, dt); - } - } -} - -//============================================================================= - -void getNewSegWallQual(int k, double dt, Pseg newseg) -/* -** Purpose: -** computes wall species concentrations for a new WQ segment that -** enters a pipe from its upstream node. -** -** Input: -** k = link index -** dt = current WQ time step (sec) -** newseg = pointer to a new, unused WQ segment -** -** Output: -** newseg->c[] = wall species concentrations in the new WQ segment -*/ -{ - Pseg seg; - int m; - double v, vin, vsum, vadded, vleft; - -// --- get volume of inflow to link - - if ( newseg == NULL ) return; - v = LINKVOL(k); - vin = ABS(MSX.Q[k])*dt; - if (vin > v) vin = v; - -// --- start at last (most upstream) existing WQ segment - - seg = MSX.LastSeg[k]; - vsum = 0.0; - vleft = vin; - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if ( MSX.Species[m].type == WALL ) newseg->c[m] = 0.0; - } - -// --- repeat while some inflow volume still remains - - while ( vleft > 0.0 && seg != NULL ) - { - - // --- find volume added by this segment - - vadded = seg->v; - if ( vadded > vleft ) vadded = vleft; - - // --- update total volume added and inflow volume remaining - - vsum += vadded; - vleft -= vadded; - - // --- add wall species mass contributed by this segment to new segment - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if ( MSX.Species[m].type == WALL ) newseg->c[m] += vadded*seg->c[m]; - } - - // --- move to next downstream WQ segment - - seg = seg->next; - } - -// --- convert mass of wall species in new segment to concentration - - if ( vsum > 0.0 ) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if ( MSX.Species[m].type == WALL ) newseg->c[m] /= vsum; - } - } -} - -//============================================================================= - -void shiftSegWallQual(int k, double dt) -/* -** Purpose: -** recomputes wall species concentrations in segments that remain -** within a pipe after flow is advected over current time step. -** -** Input: -** k = link index -** dt = current WQ time step (sec) -*/ -{ - Pseg seg1, seg2; - int m; - double v, vin, vstart, vend, vcur, vsum; - -// --- find volume of water displaced in pipe - - v = LINKVOL(k); - vin = ABS((double)MSX.Q[k])*dt; - if (vin > v) vin = v; - -// --- set future start position (measured by pipe volume) of original last segment - - vstart = vin; - -// --- examine each segment, from upstream to downstream - - for( seg1 = MSX.LastSeg[k]; seg1 != NULL; seg1 = seg1->next ) - { - - // --- initialize a "mixture" WQ - // if vstart >= v the segment seg1 will be out of the pipe, - // so no need to track wall concentration of this segment - if (vstart >= v) break; //2020 moved up - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) MSX.C1[m] = 0.0; - - // --- find the future end position of this segment - - vend = vstart + seg1->v; // - if (vend > v) vend = v; - vcur = vstart; - vsum = 0; - - // --- find volume taken up by the segment after it moves down the pipe - - for (seg2 = MSX.LastSeg[k]; seg2 != NULL; seg2 = seg2->next) - { - if ( seg2->v == 0.0 ) continue; - vsum += seg2->v; - if ( vsum >= vstart && vsum <= vend ) //DS end of seg2 is between vstart and vend - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if ( MSX.Species[m].type == WALL ) - MSX.C1[m] += (vsum - vcur) * seg2->c[m]; - } - vcur = vsum; - } - if ( vsum >= vend ) break; //DS of seg2 is at DS of vend - } - - // --- update the wall species concentrations in the segment - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if ( MSX.Species[m].type != WALL ) continue; - if (seg2 != NULL) MSX.C1[m] += (vend - vcur) * seg2->c[m]; //only part of seg2 - seg1->c[m] = MSX.C1[m] / (vend - vstart); - if ( seg1->c[m] < 0.0 ) seg1->c[m] = 0.0; - } - - // --- re-start at the current end location - - vstart = vend; - // if ( vstart >= v ) break; //2020 moved up - } -} - - -//============================================================================= - -void sourceInput(int n, double volout, double dt) -/* -** Purpose: -** computes contribution (if any) of mass additions from WQ -** sources at each node. -** -** Input: -** n = nodeindex -** dt = current WQ time step (sec) -*/ -{ - int m; - double qout, qcutoff; - Psource source; - -// --- establish a flow cutoff which indicates no outflow from a node - - qcutoff = 10.0*TINY; - -// --- consider each node - - // --- skip node if no WQ source - - source = MSX.Node[n].sources; - if (source == NULL) return; - - - qout = volout / dt; - - // --- evaluate source input only if node outflow > cutoff flow - if (qout <= qcutoff) return; - - // --- add contribution of each source species - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.SourceIn[m] = 0.0; - while (source) - { - addSource(n, source, volout, dt); - source = source->next; - } - - // --- compute a new chemical equilibrium at the source node - MSXchem_equil(NODE, 0, MSX.Node[n].c); - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - MSX.MassBalance.inflow[m] += MSX.SourceIn[m] * LperFT3; - } -} - -//============================================================================= - -void addSource(int n, Psource source, double volout, double dt) -/* -** Purpose: -** updates concentration of particular species leaving a node -** that receives external source input. -** -** Input: -** n = index of source node -** source = pointer to WQ source data -** volout = volume of water leaving node during current time step -** dt = current WQ time step (sec) -*/ -{ - int m; - double massadded, s; - -// --- only analyze bulk species - - m = source->species; - massadded = 0.0; - if (source->c0 > 0.0 && MSX.Species[m].type == BULK) - { - - // --- mass added depends on type of source - - s = getSourceQual(source); - switch(source->type) - { - // Concen. Source: - // Mass added = source concen. * -(demand) - - case CONCEN: - - // Only add source mass if demand is negative - if (MSX.Node[n].tank <=0 && MSX.D[n] < 0.0) massadded = -s*MSX.D[n]*dt; - - // If node is a tank then set concen. to 0. - // (It will be re-set to true value later on) - - // if (MSX.Node[n].tank > 0) MSX.Node[n].c[m] = 0.0; - break; - - // Mass Inflow Booster Source: - - case MASS: - massadded = s*dt/LperFT3; - break; - - // Setpoint Booster Source: - // Mass added is difference between source - // & node concen. times outflow volume - - case SETPOINT: - if (s > MSX.Node[n].c[m]) - massadded = (s - MSX.Node[n].c[m])*volout; - break; - - // Flow-Paced Booster Source: - // Mass added = source concen. times outflow volume - - case FLOWPACED: - massadded = s*volout; - break; - } - - // --- adjust nodal concentration to reflect source addition - MSX.Node[n].c[m] += massadded / volout; - MSX.SourceIn[m] += massadded; - } -} - - -//============================================================================= - -double getSourceQual(Psource source) -/* -** Input: j = source index -** Output: returns source WQ value -** Purpose: determines source concentration in current time period -*/ -{ - int i; - long k; - double c, f = 1.0; - -// --- get source concentration (or mass flow) in original units - c = source->c0; - -// --- convert mass flow rate from min. to sec. - if (source->type == MASS) c /= 60.0; - -// --- apply time pattern if assigned - i = source->pat; - if (i == 0) return(c); - k = (int)((MSX.Qtime + MSX.Pstart*1000) / (MSX.Pstep*1000)) % MSX.Pattern[i].length; - if (k != MSX.Pattern[i].interval) - { - if ( k < MSX.Pattern[i].interval ) - { - MSX.Pattern[i].current = MSX.Pattern[i].first; - MSX.Pattern[i].interval = 0; - } - while (MSX.Pattern[i].current && MSX.Pattern[i].interval < k) - { - MSX.Pattern[i].current = MSX.Pattern[i].current->next; - MSX.Pattern[i].interval++; - } - } - if (MSX.Pattern[i].current) f = MSX.Pattern[i].current->value; - return c*f; -} - -//============================================================================= - -void removeAllSegs(int k) -/* -** Purpose: -** removes all segments in a pipe link. -** -** Input: -** k = link index. -*/ -{ - Pseg seg; - seg = MSX.FirstSeg[k]; - while (seg != NULL) - { - MSX.FirstSeg[k] = seg->prev; - MSXqual_removeSeg(seg); - seg = MSX.FirstSeg[k]; - } - MSX.LastSeg[k] = NULL; - if (k <= MSX.Nobjects[LINK]) - MSX.Link[k].nsegs = 0; -} - -void topological_transport(double dt) -{ - int j, n, k, m; - double volin, volout; - Padjlist alink; - - - // Analyze each node in topological order - for (j = 1; j <= MSX.Nobjects[NODE]; j++) - { - // ... index of node to be processed - n = MSX.SortedNodes[j]; - - // ... zero out mass & flow volumes for this node - volin = 0.0; - volout = 0.0; - memset(MSX.MassIn, 0, (MSX.Nobjects[SPECIES] + 1) * sizeof(double)); - memset(MSX.SourceIn, 0, (MSX.Nobjects[SPECIES] + 1) * sizeof(double)); - - // ... examine each link with flow into the node - for (alink = MSX.Adjlist[n]; alink != NULL; alink = alink->next) - { - // ... k is index of next link incident on node n - k = alink->link; - - // ... link has flow into node - add it to node's inflow - // (m is index of link's downstream node) - m = MSX.Link[k].n2; - if (MSX.FlowDir[k] < 0) m = MSX.Link[k].n1; - if (m == n) - { - evalnodeinflow(k, dt, &volin, MSX.MassIn); - } - - // ... link has flow out of node - add it to node's outflow - else volout += fabs(MSX.Q[k]); - } - - // ... if node is a junction, add on any external outflow (e.g., demands) - if (MSX.Node[n].tank == 0) - { - volout += fmax(0.0, MSX.D[n]); - } - - // ... convert from outflow rate to volume - volout *= dt; - - // ... find the concentration of flow leaving the node - findnodequal(n, volin, MSX.MassIn, volout, dt); - - // ... examine each link with flow out of the node - for (alink = MSX.Adjlist[n]; alink != NULL; alink = alink->next) - { - // ... link k incident on node n has upstream node m equal to n - k = alink->link; - m = MSX.Link[k].n1; - if (MSX.FlowDir[k] < 0) m = MSX.Link[k].n2; - if (m == n) - { - // ... send flow at new node concen. into link - evalnodeoutflow(k, MSX.Node[n].c, dt); - } - } - - } - /*Advection-Reaction Done, Dispersion Starts*/ - //1. Linear relationship for each pipe - //2. Compose the nodal equations - //3. Solve the matrix to update nodal concentration - //4. Update segment concentration - for (int m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Dispersion.md[m] > 0 || MSX.Dispersion.ld[m] > 0) - { - dispersion_pipe(m, dt); - solve_nodequal(m, dt); - segqual_update(m, dt); - } - } -} - - -void evalnodeoutflow(int k, double * upnodequal, double tstep) -/* -**-------------------------------------------------------------- -** Input: k = link index -** c = quality from upstream node -** tstep = time step -** Output: none -** Purpose: releases flow volume and mass from the upstream -** node of a link over a time step. -**-------------------------------------------------------------- -*/ -{ - - double v; - Pseg seg; - int m; - int useNewSeg = 0; - - // Find flow volume (v) released over time step - v = fabs(MSX.Q[k]) * tstep; - if (v == 0.0) return; - - // Release flow and mass into upstream end of the link - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type == BULK) - MSX.NewSeg[k]->c[m] = upnodequal[m]; - } - - // ... case where link has a last (most upstream) segment - seg = MSX.LastSeg[k]; - - if (seg) - { - if (!MSXqual_isSame(seg->c, upnodequal) && MSX.Link[k].nsegs < MSX.MaxSegments) - { - useNewSeg = 1; - } - else - useNewSeg = 0; - -// if (MSX.DispersionFlag == 1 && MSX.Link[k].nsegs >= MSX.MaxSegments) -// useNewSeg = 0; - - if (useNewSeg == 0) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type == BULK) - seg->c[m] = (seg->c[m]*seg->v+upnodequal[m]*v)/(seg->v+v); - } - seg->v += v; - MSXqual_removeSeg(MSX.NewSeg[k]); - } - - // --- otherwise add the new seg to the end of the link - - else - { - MSX.NewSeg[k]->v = v; - MSXqual_addSeg(k, MSX.NewSeg[k]); - } - } - - // ... link has no segments so add one - else - { - MSX.NewSeg[k]->v = v; - MSXqual_addSeg(k, MSX.NewSeg[k]); - } - -} - - -void evalnodeinflow(int k, double tstep, double* volin, double* massin) - /* - **-------------------------------------------------------------- - ** Input: k = link index - ** tstep = quality routing time step - ** Output: volin = flow volume entering a node - ** massin = constituent mass entering a node - ** Purpose: adds the contribution of a link's outflow volume - ** and constituent mass to the total inflow into its - ** downstream node over a time step. - **-------------------------------------------------------------- - */ -{ - - double q, v, vseg; - int sindex; - Pseg seg; - - // Get flow rate (q) and flow volume (v) through link - q = MSX.Q[k]; - v = fabs(q) * tstep; - - // Transport flow volume v from link's leading segments into downstream - // node, removing segments once their full volume is consumed - while (v > 0.0) - { - seg = MSX.FirstSeg[k]; - if (!seg) break; - - // ... volume transported from first segment is smaller of - // remaining flow volume & segment volume - vseg = seg->v; - vseg = MIN(vseg, v); - - // ... update total volume & mass entering downstream node - *volin += vseg; - for (sindex = 1; sindex <= MSX.Nobjects[SPECIES]; sindex++) - massin[sindex] += vseg * seg->c[sindex] * LperFT3; - - // ... reduce remaining flow volume by amount transported - v -= vseg; - - // ... if all of segment's volume was transferred - if (v >= 0.0 && vseg >= seg->v) - { - // ... replace this leading segment with the one behind it - MSX.FirstSeg[k] = seg->prev; - MSX.Link[k].nsegs--; - if (MSX.FirstSeg[k] == NULL) MSX.LastSeg[k] = NULL; - - // ... recycle the used up segment - seg->prev = MSX.FreeSeg; - MSX.FreeSeg = seg; - } - - // ... otherwise just reduce this segment's volume - else seg->v -= vseg; - } -} - - -void findnodequal(int n, double volin, double* massin, double volout, double tstep) - /* - **-------------------------------------------------------------- - ** Input: n = node index - ** volin = flow volume entering node - ** massin = mass entering node - ** volout = flow volume leaving node - ** tstep = length of current time step - ** Output: returns water quality in a node's outflow - ** Purpose: computes a node's new quality from its inflow - ** volume and mass, including any source contribution. - **-------------------------------------------------------------- - */ -{ - int m, j; - // Node is a junction - update its water quality - j = MSX.Node[n].tank; - if (j <= 0) - { - // ... dilute inflow with any external negative demand - volin -= fmin(0.0, MSX.D[n]) * tstep; - - // ... new concen. is mass inflow / volume inflow - if (volin > 0.0) - { - for(m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.Node[n].c[m] = massin[m] / volin / LperFT3; - } - - // ... if no inflow adjust quality for reaction in connecting pipes - else - noflowqual(n); - - MSXchem_equil(NODE, 0, MSX.Node[n].c); - - } - else - { - // --- use initial quality for reservoirs - - if (MSX.Tank[j].a == 0.0) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - MSX.Node[n].c[m] = MSX.Node[n].c0[m]; - } - MSXchem_equil(NODE, 0, MSX.Node[n].c); - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - - MSX.MassBalance.inflow[m] += MSX.Node[n].c[m] * volout * LperFT3; - MSX.MassBalance.outflow[m] += massin[m]; - } - } - - // --- otherwise update tank WQ based on mixing model - - else - { - if (volin > 0.0) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - MSX.C1[m] = massin[m] / volin / LperFT3; - } - } - else for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.C1[m] = 0.0; - switch (MSX.Tank[j].mixModel) - { - case MIX1: MSXtank_mix1(j, volin, massin, volin-volout); - break; - case MIX2: MSXtank_mix2(j, volin, massin, volin-volout); - break; - case FIFO: MSXtank_mix3(j, volin, massin, volin-volout); - break; - case LIFO: MSXtank_mix4(j, volin, massin, volin-volout); - break; - } - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - MSX.Node[n].c[m] = MSX.Tank[j].c[m]; - } - MSX.Tank[j].v += (double)MSX.D[n] * tstep; - } - } - - // Find quality contribued by any external chemical source - sourceInput(n, volout, tstep); - if (MSX.Node[n].tank == 0) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - if(MSX.Species[m].type == BULK) - MSX.MassBalance.outflow[m] += MAX(0.0, MSX.D[n]) * tstep * MSX.Node[n].c[m]*LperFT3; - } -} - - -int sortNodes() -/* -**-------------------------------------------------------------- -** Input: none -** Output: returns an error code -** Purpose: topologically sorts nodes from upstream to downstream. -** Note: links with negligible flow are ignored since they can -** create spurious cycles that cause the sort to fail. -**-------------------------------------------------------------- -*/ -{ - - int i, j, k, n; - int* indegree = NULL; - int* stack = NULL; - int stacksize = 0; - int numsorted = 0; - int errcode = 0; - FlowDirection dir; - Padjlist alink; - - // Allocate an array to count # links with inflow to each node - // and for a stack to hold nodes waiting to be processed - indegree = (int*)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); - stack = (int*)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); - if (indegree && stack) - { - // Count links with "non-negligible" inflow to each node - for (k = 1; k <= MSX.Nobjects[LINK]; k++) - { - dir = MSX.FlowDir[k]; - if (dir == POSITIVE) n = MSX.Link[k].n2; - else if (dir == NEGATIVE) n = MSX.Link[k].n1; - else continue; - indegree[n]++; - } - - // Place nodes with no inflow onto a stack - for (i = 1; i <= MSX.Nobjects[NODE]; i++) - { - if (indegree[i] == 0) - { - stacksize++; - stack[stacksize] = i; - } - } - - // Examine each node on the stack until none are left - while (numsorted < MSX.Nobjects[NODE]) - { - // ... if stack is empty then a cycle exists - if (stacksize == 0) - { - // ... add a non-sorted node connected to a sorted one to stack - j = selectnonstacknode(numsorted, indegree); - if (j == 0) break; // This shouldn't happen. - indegree[j] = 0; - stacksize++; - stack[stacksize] = j; - } - - // ... make the last node added to the stack the next - // in sorted order & remove it from the stack - i = stack[stacksize]; - stacksize--; - numsorted++; - MSX.SortedNodes[numsorted] = i; - - // ... for each outflow link from this node reduce the in-degree - // of its downstream node - for (alink = MSX.Adjlist[i]; alink != NULL; alink = alink->next) - { - // ... k is the index of the next link incident on node i - k = alink->link; - - // ... skip link if flow is negligible - if (MSX.FlowDir[k] == 0) continue; - - // ... link has flow out of node (downstream node n not equal to i) - n = MSX.Link[k].n2; - if (MSX.FlowDir[k] < 0) n = MSX.Link[k].n1; - - // ... reduce degree of node n - if (n != i && indegree[n] > 0) - { - indegree[n]--; - - // ... no more degree left so add node n to stack - if (indegree[n] == 0) - { - stacksize++; - stack[stacksize] = n; - } - } - } - } - } - else errcode = 101; - if (numsorted < MSX.Nobjects[NODE]) errcode = 120; - FREE(indegree); - FREE(stack); - return errcode; -} - -int selectnonstacknode(int numsorted, int* indegree) -/* -**-------------------------------------------------------------- -** Input: numsorted = number of nodes that have been sorted -** indegree = number of inflow links to each node -** Output: returns a node index -** Purpose: selects a next node for sorting when a cycle exists. -**-------------------------------------------------------------- -*/ -{ - - int i, m, n; - Padjlist alink; - - // Examine each sorted node in last in - first out order - for (i = numsorted; i > 0; i--) - { - // For each link connected to the sorted node - m = MSX.SortedNodes[i]; - for (alink = MSX.Adjlist[m]; alink != NULL; alink = alink->next) - { - // ... n is the node of link k opposite to node m - n = alink->node; - - // ... select node n if it still has inflow links - if (indegree[n] > 0) return n; - } - } - - // If no node was selected by the above process then return the - // first node that still has inflow links remaining - for (i = 1; i <= MSX.Nobjects[NODE]; i++) - { - if (indegree[i] > 0) return i; - } - - // If all else fails return 0 indicating that no node was selected - return 0; -} - -void noflowqual(int n) -/* -**-------------------------------------------------------------- -** Input: n = node index -** Output: quality for node n -** Purpose: sets the quality for a junction node that has no -** inflow to the average of the quality in its -** adjoining link segments. -** Note: this function is only used for reactive substances. -**-------------------------------------------------------------- -*/ -{ - - int k, m, inflow, kount = 0; - double c = 0.0; - FlowDirection dir; - Padjlist alink; - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.Node[n].c[m] = 0.0; - // Examine each link incident on the node - for (alink = MSX.Adjlist[n]; alink != NULL; alink = alink->next) - { - // ... index of an incident link - k = alink->link; - dir = MSX.FlowDir[k]; - - // Node n is link's downstream node - add quality - // of link's first segment to average - if (MSX.Link[k].n2 == n && dir >= 0) inflow = TRUE; - else if (MSX.Link[k].n1 == n && dir < 0) inflow = TRUE; - else inflow = FALSE; - if (inflow == TRUE && MSX.FirstSeg[k] != NULL) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.Node[n].c[m] += MSX.FirstSeg[k]->c[m]; - kount++; - } - - // Node n is link's upstream node - add quality - // of link's last segment to average - else if (inflow == FALSE && MSX.LastSeg[k] != NULL) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.Node[n].c[m] += MSX.LastSeg[k]->c[m]; - kount++; - } - } - if (kount > 0) - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.Node[n].c[m] = MSX.Node[n].c[m] / (double)kount; -} - -void findstoredmass(double * mass) -/* -**-------------------------------------------------------------- -** Input: none -** Output: returns total constituent mass stored in the network -** Purpose: finds the current mass stored in -** all pipes and tanks. -**-------------------------------------------------------------- -*/ -{ - - int i, k, m; - Pseg seg; - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - mass[m] = 0; - } - - // Mass residing in each pipe - for (k = 1; k <= MSX.Nobjects[LINK]; k++) - { - // Sum up the quality and volume in each segment of the link - seg = MSX.FirstSeg[k]; - while (seg != NULL) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type == BULK) - mass[m] += seg->c[m] * seg->v * LperFT3; //M/L * ft3 * L/Ft3 = M - else - mass[m] += seg->c[m] * seg->v * 4.0 / MSX.Link[k].diam * MSX.Ucf[AREA_UNITS]; //Mass per area unit * ft3 / ft * area unit per ft2; - } - seg = seg->prev; - } - } - - // Mass residing in each tank - for (i = 1; i <= MSX.Nobjects[TANK]; i++) - { - // ... skip reservoirs - if (MSX.Tank[i].a == 0.0) continue; - - // ... add up mass in each volume segment - else - { - k = MSX.Nobjects[LINK] + i; - seg = MSX.FirstSeg[k]; - while (seg != NULL) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type == BULK) - mass[m] += seg->c[m] * seg->v * LperFT3; - } - seg = seg->prev; - } - } - } -} - -void MSXqual_reversesegs(int k) -/* -**-------------------------------------------------------------- -** Input: k = link index -** Output: none -** Purpose: re-orients a link's segments when flow reverses. -**-------------------------------------------------------------- -*/ -{ - Pseg seg, cseg, pseg; - - seg = MSX.FirstSeg[k]; - MSX.FirstSeg[k] = MSX.LastSeg[k]; - MSX.LastSeg[k] = seg; - pseg = NULL; - while (seg != NULL) - { - cseg = seg->prev; - seg->prev = pseg; - seg->next = cseg; - pseg = seg; - seg = cseg; - } -} - - - -//============================================================================= - -void MSXqual_removeSeg(Pseg seg) -/* -** Purpose: -** places a WQ segment back into the memory pool of segments. -** -** Input: -** seg = pointer to a WQ segment. -*/ -{ - if ( seg == NULL ) return; - seg->prev = MSX.FreeSeg; - seg->next = NULL; - MSX.FreeSeg = seg; -} - -//============================================================================= - -Pseg MSXqual_getFreeSeg(double v, double c[]) -/* -** Purpose: -** retrieves an unused water quality volume segment from the memory pool. -** -** Input: -** v = segment volume (ft3) -** c[] = segment quality -** -** Returns: -** a pointer to an unused water quality segment. -*/ -{ - Pseg seg; - int m; - -// --- try using the last discarded segment if one is available - - if (MSX.FreeSeg != NULL) - { - seg = MSX.FreeSeg; - MSX.FreeSeg = seg->prev; - } - -// --- otherwise create a new segment from the memory pool - - else - { - seg = (struct Sseg *) Alloc(sizeof(struct Sseg)); - if (seg == NULL) - { - MSX.OutOfMemory = TRUE; - return NULL; - } - seg->c = (double *) Alloc((MSX.Nobjects[SPECIES]+1)*sizeof(double)); - seg->lastc = (double *)Alloc((MSX.Nobjects[SPECIES] + 1) * sizeof(double)); - if ( seg->c == NULL||seg->lastc == NULL) - { - MSX.OutOfMemory = TRUE; - return NULL; - } - } - -// --- assign volume, WQ, & integration time step to the new segment - - seg->v = v; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) seg->c[m] = c[m]; - seg->hstep = 0.0; - return seg; -} - -//============================================================================= - -void MSXqual_addSeg(int k, Pseg seg) -/* -** Purpose: -** adds a new segment to the upstream end of a link. -** -** Input: -** k = link index -** seg = pointer to a free WQ segment. -*/ - -{ - seg->prev = NULL; - seg->next = NULL; - if (MSX.FirstSeg[k] == NULL) MSX.FirstSeg[k] = seg; - if (MSX.LastSeg[k] != NULL) - { - MSX.LastSeg[k]->prev = seg; - seg->next = MSX.LastSeg[k]; - } - MSX.LastSeg[k] = seg; - if (k <= MSX.Nobjects[LINK]) - MSX.Link[k].nsegs++; -} - -void evalHydVariables(int k) -/* -** Purpose: -** retrieves current values of hydraulic variables for the -** current link being analyzed. -** -** Input: -** k = link index -** -** Output: -** updates values stored in vector HydVar[] -*/ -{ - double dh; // headloss in ft - double diam = MSX.Link[k].diam; // diameter in ft - double length = MSX.Link[k].len; // length in ft - double av; // area per unit volume - -// --- pipe diameter and length in user's units (ft or m) - MSX.Link[k].HydVar[DIAMETER] = diam * MSX.Ucf[LENGTH_UNITS]; - MSX.Link[k].HydVar[LENGTH] = length * MSX.Ucf[LENGTH_UNITS]; - - // --- flow rate in user's units - MSX.Link[k].HydVar[FLOW] = fabs(MSX.Q[k]) * MSX.Ucf[FLOW_UNITS]; - - // --- flow velocity in ft/sec - if (diam == 0.0) MSX.Link[k].HydVar[VELOCITY] = 0.0; - else MSX.Link[k].HydVar[VELOCITY] = fabs(MSX.Q[k]) * 4.0 / PI / SQR(diam); - - // --- Reynolds number - MSX.Link[k].HydVar[REYNOLDS] = MSX.Link[k].HydVar[VELOCITY] * diam / VISCOS; - - // --- flow velocity in user's units (ft/sec or m/sec) - MSX.Link[k].HydVar[VELOCITY] *= MSX.Ucf[LENGTH_UNITS]; - - // --- Darcy Weisbach friction factor - if (MSX.Link[k].len == 0.0) MSX.Link[k].HydVar[FRICTION] = 0.0; - else - { - dh = ABS(MSX.H[MSX.Link[k].n1] - MSX.H[MSX.Link[k].n2]); - MSX.Link[k].HydVar[FRICTION] = 39.725 * dh * pow(diam, 5.0) / - MSX.Link[k].len / SQR((double)MSX.Q[k]); - } - - // --- shear velocity in user's units (ft/sec or m/sec) - MSX.Link[k].HydVar[SHEAR] = MSX.Link[k].HydVar[VELOCITY] * sqrt(MSX.Link[k].HydVar[FRICTION] / 8.0); - - // --- pipe surface area / volume in area_units/L - MSX.Link[k].HydVar[AREAVOL] = 1.0; - if (diam > 0.0) - { - av = 4.0 / diam; // ft2/ft3 - av *= MSX.Ucf[AREA_UNITS]; // area_units/ft3 - av /= LperFT3; // area_units/L - MSX.Link[k].HydVar[AREAVOL] = av; - } - - MSX.Link[k].HydVar[ROUGHNESS] = MSX.Link[k].roughness; -} diff --git a/Src/msxrpt.c b/Src/msxrpt.c deleted file mode 100644 index c71a3e1..0000000 --- a/Src/msxrpt.c +++ /dev/null @@ -1,400 +0,0 @@ -/****************************************************************************** -** MODULE: MSXRPT.C -** PROJECT: EPANET-MSX -** DESCRIPTION: report writing routines for the EPANET Multi-Species -** Extension toolkit. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -******************************************************************************/ - -#include -#include -#include -#include - -#include "msxtypes.h" -#include "epanet2.h" - -// Constants -//---------- -#define SERIES_TABLE 0 -#define STATS_TABLE 1 - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -// Local variables -//----------------- -static char *Logo[] = - {"******************************************************************", - "* E P A N E T - M S X *", - "* Multi-Species Water Quality *", - "* Analysis for Pipe Networks *", - "* Version 2.0.0 *", //2.0.00 - "******************************************************************"}; - -static char PageHdr[] = " Page %d "; -static char *StatsHdrs[] = - {"", "Average Values ", "Minimum Values ", - "Maximum Values ", "Range of Values "}; -static char Line[MAXLINE+1]; -static long LineNum; -static long PageNum; -static int *RptdSpecies; -static struct TableHdrStruct -{ - char Line1[MAXLINE+1]; - char Line2[MAXLINE+1]; - char Line3[MAXLINE+1]; - char Line4[MAXLINE+1]; - char Line5[MAXLINE+1]; -} TableHdr; -static char IDname[MAXLINE+1]; - -// Imported functions -//-------------------- -void MSXinp_getSpeciesUnits(int m, char *units); -float MSXout_getNodeQual(int k, int j, int m); -float MSXout_getLinkQual(int k, int j, int m); - -// Exported functions -//-------------------- -int MSXrpt_write(void); -void MSXrpt_writeLine(char *line); - -// Local functions -//----------------- -static void createSeriesTables(void); -static void createStatsTables(void); -static void createTableHdr(int objType, int tableType); -static void writeTableHdr(void); -static void writeNodeTable(int j, int tableType); -static void writeLinkTable(int j, int tableType); -static void getHrsMins(int k, int *hrs, int *mins); -static void newPage(void); -static void writeLine(char *line); - -static void writemassbalance(); - -//============================================================================= - -int MSXrpt_write() -{ - INT4 magic = 0; - int j; - int recordsize = sizeof(INT4); - -// --- check that results are available - - if ( MSX.Nperiods < 1 ) return 0; - if ( MSX.OutFile.file == NULL ) return ERR_OPEN_OUT_FILE; - fseek(MSX.OutFile.file, -recordsize, SEEK_END); - fread(&magic, sizeof(INT4), 1, MSX.OutFile.file); - if ( magic != MAGICNUMBER ) return ERR_IO_OUT_FILE; - -// --- write program logo & project title - - PageNum = 1; - LineNum = 1; - newPage(); - for (j=0; j<=5; j++) writeLine(Logo[j]); - writeLine(""); - writeLine(MSX.Title); - -// --- generate the appropriate type of table - - if ( MSX.Statflag == SERIES ) createSeriesTables(); - else createStatsTables(); - - writemassbalance(); - - writeLine(""); - return 0; -} - -//============================================================================= - -void MSXrpt_writeLine(char *line) -{ - writeLine(line); -} - -//============================================================================= - -void createSeriesTables() -{ - int j; - -// --- report on all requested nodes - - for (j=1; j<=MSX.Nobjects[NODE]; j++) - { - if ( !MSX.Node[j].rpt ) continue; - ENgetnodeid(j, IDname); - createTableHdr(NODE, SERIES_TABLE); - writeNodeTable(j, SERIES_TABLE); - } - -// --- report on all requested links - - for (j=1; j<=MSX.Nobjects[LINK]; j++) - { - if ( !MSX.Link[j].rpt ) continue; - ENgetlinkid(j, IDname); - createTableHdr(LINK, SERIES_TABLE); - writeLinkTable(j, SERIES_TABLE); - } -} - -//============================================================================= - -void createStatsTables() -{ - int j; - int count; - -// --- check if any nodes to be reported - - count = 0; - for (j = 1; j <= MSX.Nobjects[NODE]; j++) count += MSX.Node[j].rpt; - -// --- report on all requested nodes - - if ( count > 0 ) - { - createTableHdr(NODE, STATS_TABLE); - for (j = 1; j <= MSX.Nobjects[NODE]; j++) - { - if ( MSX.Node[j].rpt ) writeNodeTable(j, STATS_TABLE); - } - } - -// --- check if any links to be reported - - count = 0; - for (j = 1; j <= MSX.Nobjects[LINK]; j++) count += MSX.Link[j].rpt; - -// --- report on all requested links - - if ( count > 0 ) - { - createTableHdr(LINK, STATS_TABLE); - for (j = 1; j <= MSX.Nobjects[LINK]; j++) - { - if ( MSX.Link[j].rpt ) writeLinkTable(j, STATS_TABLE); - } - } -} - -//============================================================================= - -void createTableHdr(int objType, int tableType) -{ - int m; - char s1[MAXLINE+1]; - char s2[MAXLINE+1]; - - if ( tableType == SERIES_TABLE ) - { - if ( objType == NODE ) - sprintf(TableHdr.Line1, "<<< Node %s >>>", IDname); - else - sprintf(TableHdr.Line1, "<<< Link %s >>>", IDname); - strcpy(TableHdr.Line2, "Time "); - strcpy(TableHdr.Line3, "hr:min "); - strcpy(TableHdr.Line4, "-------"); - } - if ( tableType == STATS_TABLE ) - { - strcpy(TableHdr.Line1, ""); - sprintf(TableHdr.Line2, "%-16s", StatsHdrs[tableType]); - if ( objType == NODE ) strcpy(TableHdr.Line3, "for Node "); - else strcpy(TableHdr.Line3, "for Link "); - strcpy(TableHdr.Line4, "----------------"); - } - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - { - if ( !MSX.Species[m].rpt ) continue; - if ( objType == NODE && MSX.Species[m].type == WALL ) continue; - sprintf(s1, " %10s", MSX.Species[m].id); - strcat(TableHdr.Line2, s1); - strcat(TableHdr.Line4, " ----------"); - MSXinp_getSpeciesUnits(m, s1); - sprintf(s2, " %10s", s1); - strcat(TableHdr.Line3, s2); - } - if ( MSX.PageSize > 0 && MSX.PageSize - LineNum < 8 ) newPage(); - else writeTableHdr(); -} - -//============================================================================= - -void writeTableHdr() -{ - if ( MSX.PageSize > 0 && MSX.PageSize - LineNum < 6 ) newPage(); - writeLine(""); - writeLine(TableHdr.Line1); - writeLine(""); - writeLine(TableHdr.Line2); - writeLine(TableHdr.Line3); - writeLine(TableHdr.Line4); -} - -//============================================================================= - -void writeNodeTable(int j, int tableType) -{ - int k, m, hrs, mins; - char s[MAXLINE+1]; - float c; - - for (k=0; k 1 ) writeTableHdr(); - PageNum++; -} - -//============================================================================= - -void writeLine(char *line) -{ - if ( LineNum == MSX.PageSize ) newPage(); - if ( MSX.RptFile.file ) fprintf(MSX.RptFile.file, " %s\n", line); //(modified, FS-01/07/2008) - else ENwriteline(line); - LineNum++; -} - - -void writemassbalance() -/* -**------------------------------------------------------------- -** Input: none -** Output: none -** Purpose: writes water quality mass balance ratio -** (Outflow + Final Storage) / Inflow + Initial Storage) -** to report file. -**------------------------------------------------------------- -*/ -{ - - char s1[MAXMSG + 1]; - int kunits = 0; - - for (int m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].pipeExprType != RATE) - continue; - - snprintf(s1, MAXMSG, "\n"); - writeLine(s1); - snprintf(s1, MAXMSG, "Water Quality Mass Balance: %s (%s)", MSX.Species[m].id, MSX.Species[m].units); - writeLine(s1); - snprintf(s1, MAXMSG, "================================"); - writeLine(s1); - snprintf(s1, MAXMSG, "Initial Mass: %12.5e", MSX.MassBalance.initial[m]); - writeLine(s1); - snprintf(s1, MAXMSG, "Mass Inflow: %12.5e", MSX.MassBalance.inflow[m]+ MSX.MassBalance.indisperse[m]); - writeLine(s1); - // snprintf(s1, MAXMSG, "Mass Dispersed Inflow: %12.5e", MSX.MassBalance.indisperse[m]); - // writeLine(s1); - snprintf(s1, MAXMSG, "Mass Outflow: %12.5e", MSX.MassBalance.outflow[m]); - writeLine(s1); - snprintf(s1, MAXMSG, "Mass Reacted: %12.5e", MSX.MassBalance.reacted[m]); - writeLine(s1); - snprintf(s1, MAXMSG, "Final Mass: %12.5e", MSX.MassBalance.final[m]); - writeLine(s1); - snprintf(s1, MAXMSG, "Mass Ratio: %-.5f", MSX.MassBalance.ratio[m]); - writeLine(s1); - snprintf(s1, MAXMSG, "================================\n"); - writeLine(s1); - } -} - - - - - - - - diff --git a/Src/msxtank.c b/Src/msxtank.c deleted file mode 100644 index 2e9e0eb..0000000 --- a/Src/msxtank.c +++ /dev/null @@ -1,422 +0,0 @@ -/****************************************************************************** -** MODULE: MSXTANK.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Storage tank mixing routines. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -******************************************************************************/ - -#include -#include - -#include "msxtypes.h" - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -// Imported functions -//-------------------- -extern void MSXqual_removeSeg(Pseg seg); -extern Pseg MSXqual_getFreeSeg(double v, double c[]); -extern void MSXqual_addSeg(int k, Pseg seg); -extern int MSXqual_isSame(double c1[], double c2[]); -extern int MSXchem_equil(int zone, int k, double *c); -extern void MSXqual_reversesegs(int k); - -// Exported functions -//-------------------- -void MSXtank_mix1(int i, double vin, double *massin, double vnet); -void MSXtank_mix2(int i, double vin, double *massin, double vnet); -void MSXtank_mix3(int i, double vin, double *massin, double vnet); -void MSXtank_mix4(int i, double vin, double *massin, double vnet); - - -//============================================================================= - -void MSXtank_mix1(int i, double vin, double *massin, double vnet) -/* -** Purpose: -** computes new WQ at end of time step in a completely mixed tank -** (after contents have been reacted). -** -** Input: -** i = tank index -** vin = volume of inflow to tank (ft3) -** massin = massinflow -** vnet = inflow - outflow -*/ -{ - int k, m, n; - double c; - double vnew; - Pseg seg; - -// --- blend inflow with contents - - n = MSX.Tank[i].node; - k = MSX.Nobjects[LINK] + i; - seg = MSX.FirstSeg[k]; - if (seg) - { - vnew = seg->v + vin; - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type != BULK) continue; - c = seg->c[m]; - if (vnew > 0.0) - c = (c*seg->v*LperFT3+massin[m])/(vnew*LperFT3); - - c = MAX(0.0, c); - seg->c[m] = c; - MSX.Tank[i].c[m] = c; - } - seg->v += vnet; - seg->v = MAX(0, seg->v); - } - -// --- update species equilibrium - - if ( vin > 0.0 ) MSXchem_equil(NODE, i, MSX.Tank[i].c); -} - -//============================================================================= - -void MSXtank_mix2(int i, double vin, double *massin, double vnet) -/* -** Purpose: 2-compartment tank model -** -** Input: i = tank index -** vIn = volume of inflow to tank (ft3) -** massin = massinflow -** vnet = inflow - outflow -*/ -{ - int k, m, n; - double vt, //transferred volume - vmz; //full mixing zone volume - Pseg mixzone, // Mixing zone segment - stagzone; // Stagnant zone segment - -// --- find inflows & outflows - - n = MSX.Tank[i].node; - -// --- get segments for each zone - - k = MSX.Nobjects[LINK] + i; - mixzone = MSX.LastSeg[k]; - stagzone = MSX.FirstSeg[k]; - if (mixzone == NULL || stagzone == NULL) return; - - - // Full mixing zone volume - vmz = MSX.Tank[i].vMix; - - vt = 0.0; - - -// --- case of net filling (vnet > 0) - - if (vnet > 0.0) - { - vt = MAX(0.0, (mixzone->v + vnet - vmz)); - if (vin > 0) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type != BULK) continue; - - // --- new quality in mixing zone - mixzone->c[m] = (mixzone->c[m] * mixzone->v * LperFT3 + massin[m]) / ((mixzone->v + vin)*LperFT3); - mixzone->c[m] = MAX(0.0, mixzone->c[m]); - } - } - if (vt > 0) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type != BULK) continue; - - // --- new quality in stagnant zone - - stagzone->c[m] = (stagzone->c[m] * stagzone->v + mixzone->c[m] * vt) / (stagzone->v + vt); - stagzone->c[m] = MAX(0.0, stagzone->c[m]); - } - - - - } - } - else if (vnet < 0) //tank is draining - { - if (stagzone->v > 0.0) vt = MIN(stagzone->v, (-vnet)); - if (vin + vt > 0.0) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - if (MSX.Species[m].type != BULK) continue; - - // --- new quality in mixing zone - mixzone->c[m] = (mixzone->c[m] * mixzone->v * LperFT3 + massin[m] + stagzone->c[m]*vt*LperFT3) / ((mixzone->v + vin + vt)*LperFT3); - mixzone->c[m] = MAX(0.0, mixzone->c[m]); - } - } - } - - // Update segment volumes - if (vt > 0.0) - { - mixzone->v = vmz; - if (vnet > 0.0) stagzone->v += vt; - else stagzone->v = MAX(0.0, ((stagzone->v) - vt)); - } - else - { - mixzone->v += vnet; - mixzone->v = MIN(mixzone->v, vmz); - mixzone->v = MAX(0.0, mixzone->v); - stagzone->v = 0.0; - } - - if (mixzone->v > 0.0) MSXchem_equil(NODE, i, mixzone->c); - if (stagzone->v > 0.0) MSXchem_equil(NODE, i, stagzone->c); - -// --- use quality of mixed compartment (mixzone) to represent quality -// of tank since this is where outflow begins to flow from - - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) MSX.Tank[i].c[m] = mixzone->c[m]; -} - -//============================================================================= - -void MSXtank_mix3(int i, double vin, double *massin, double vnet) -/* -** Purpose: computes concentrations in the segments that form a -** first-in-first-out (FIFO) tank model. -** -** Input: i = tank index -** vIn = volume of inflow to tank (ft3) -** massin = mass inflow -** vnet = inflow - outflow -*/ -{ - int k, m, n; - double vout, vseg, vsum; - Pseg seg; - -// --- find inflows & outflows - - k = MSX.Nobjects[LINK] + i; - n = MSX.Tank[i].node; - vout = vin - vnet; - - if (MSX.LastSeg[k] == NULL || MSX.FirstSeg[k] == NULL) return; - - if (vin > 0.0) - { - - // --- quality is the same, so just add flow volume to last seg - seg = MSX.LastSeg[k]; - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - { - MSX.C1[m] = massin[m] / (vin*LperFT3); - } - if (seg != NULL && MSXqual_isSame(seg->c, MSX.C1)) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - seg->c[m] = (seg->c[m] * seg->v + MSX.C1[m] * vin) / (seg->v + vin); - seg->v += vin; - } - // --- Otherwise add a new seg to tank - else - { - seg = MSXqual_getFreeSeg(vin, MSX.C1); - MSXqual_addSeg(k, seg); - } - } - - -// --- initialize outflow volume & concentration - - vsum = 0.0; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - MSX.C1[m] = 0.0; -// --- withdraw flow from first segment - - while (vout > 0.0) - { - // --- get volume of current first segment - seg = MSX.FirstSeg[k]; - if (seg == NULL) break; - vseg = seg->v; - vseg = MIN(vseg, vout); - if ( seg == MSX.LastSeg[k] ) vseg = vout; - - // --- update mass & volume removed - vsum += vseg; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - { - MSX.C1[m] += (seg->c[m]) * vseg * LperFT3; - } - - // --- decrease vOut by volume of first segment - vout -= vseg; - - // --- remove segment if all its volume is consumed - if (vout >= 0.0 && vseg >= seg->v) - { - if (seg->prev) - { - MSX.FirstSeg[k] = seg->prev; - // MSXqual_removeSeg(seg); - seg->prev = MSX.FreeSeg; - MSX.FreeSeg = seg; - - } - } - - // --- otherwise just adjust volume of first segment - else seg->v -= vseg; - } - -// --- use quality from first segment to represent overall -// quality of tank since this is where outflow flows from - - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - { - if (vsum > 0.0) MSX.Tank[i].c[m] = MSX.C1[m]/(vsum * LperFT3); - else if (MSX.FirstSeg[k] == NULL) MSX.Tank[i].c[m] = 0.0; - else MSX.Tank[i].c[m] = MSX.FirstSeg[k]->c[m]; - } -// --- add new last segment for new flow entering tank -} - -//============================================================================= - -void MSXtank_mix4(int i, double vin, double *massin, double vnet) -/* -**---------------------------------------------------------- -** Input: i = tank index -** vin = volume of inflow to tank (ft3) -** massin = mass inflow -** vnet = vin - vout -** Output: none -** Purpose: Last In-First Out (LIFO) tank model -**---------------------------------------------------------- -*/ -{ - int k, m, n; - double vsum, vseg; - Pseg seg; - -// --- find inflows & outflows - - k = MSX.Nobjects[LINK] + i; - n = MSX.Tank[i].node; - - if (MSX.LastSeg[k] == NULL || MSX.FirstSeg[k] == NULL) return; - -// --- keep track of total volume & mass removed from tank - - vsum = 0.0; - if (vin > 0) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.C1[m] = massin[m] / (vin*LperFT3); - } - else - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.C1[m] = 0; - } - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.Tank[i].c[m] = MSX.LastSeg[k]->c[m]; - - seg = MSX.LastSeg[k]; -// --- if tank filling, then create a new last segment - if ( vnet > 0.0 ) - { - - // --- inflow quality = last segment quality so just expand last segment - if (seg != NULL && MSXqual_isSame(seg->c, MSX.C1)) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - seg->c[m] = (seg->c[m] * seg->v + MSX.C1[m] * vnet) / (seg->v + vnet); - seg->v += vnet; - } - - // --- otherwise add a new last segment to tank - - else - { - seg = MSXqual_getFreeSeg(vnet, MSX.C1); - MSXqual_addSeg(k, seg); - } - - // --- quality of tank is that of inflow - - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.Tank[i].c[m] = MSX.LastSeg[k]->c[m]; - - } - -// --- if tank emptying then remove last segments until vNet consumed - - else if (vnet < 0.0) - { - for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) - MSX.C1[m] = 0; - // --- keep removing volume from last segments until vNet is removed - vsum = 0; - vnet = -vnet; - MSXqual_reversesegs(k); - while (vnet > 0.0) - { - - // --- get volume of current last segment - seg = MSX.FirstSeg[k]; - if ( seg == NULL ) break; - vseg = seg->v; - vseg = MIN(vseg, vnet); - if ( seg == MSX.LastSeg[k] ) vseg = vnet; - - // --- update mass & volume removed - vsum += vseg; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - MSX.C1[m] += (seg->c[m])*vseg*LperFT3; - - // --- reduce vNet by volume of last segment - vnet -= vseg; - - // --- remove segment if all its volume is used up - if (vnet >= 0.0 && vseg >= seg->v) - { - if (seg->prev) - { - MSX.FirstSeg[k] = seg->prev; - MSXqual_removeSeg(seg); - - } - } - // --- otherwise just reduce volume of last segment - else - { - seg->v -= vseg; - } - } - MSXqual_reversesegs(k); - // --- tank quality is mixture of flow released and any inflow - - vsum = vsum + vin; - for (m=1; m<=MSX.Nobjects[SPECIES]; m++) - { - if (vsum > 0.0) - MSX.Tank[i].c[m] = (MSX.C1[m] + massin[m]) / (vsum*LperFT3); - } - } -} diff --git a/Src/msxtoolkit.c b/Src/msxtoolkit.c deleted file mode 100644 index e8f7732..0000000 --- a/Src/msxtoolkit.c +++ /dev/null @@ -1,1132 +0,0 @@ -/******************************************************************************* -** MODULE: MSXTOOLKIT.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Contains the exportable set of functions that comprise the -** EPANET Multi-Species Extension toolkit. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -** -** These functions can be used in conjunction with the original EPANET -** toolkit functions to model water quality fate and transport of -** multiple interacting chemcial species within piping networks. See the -** MSXMAIN.C module for an example of how these functions were used to -** extend the original command line version of EPANET to include multiple -** chemical species. Consult the EPANET and EPANET-MSX Users Manuals for -** detailed descriptions of the input data file formats required by both -** the original EPANET and its multi-species extension. -*******************************************************************************/ - -#include -#include -#include -#include - -#include "msxtypes.h" -#include "msxutils.h" -#include "epanet2.h" -#include "epanetmsx.h" - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data - -// Imported functions -//-------------------- -int MSXproj_open(char *fname); -int MSXproj_close(void); -int MSXproj_addObject(int type, char *id, int n); -int MSXproj_findObject(int type, char *id); -char * MSXproj_findID(int type, char *id); -char * MSXproj_getErrmsg(int errcode); -int MSXqual_open(void); -int MSXqual_init(void); -int MSXqual_step(double *t, double *tleft); -int MSXqual_close(void); -double MSXqual_getNodeQual(int j, int m); -double MSXqual_getLinkQual(int k, int m); -int MSXrpt_write(void); -int MSXfile_save(FILE *f); - -//============================================================================= - -int MSXDLLEXPORT MSXopen(char *fname) -/* -** Purpose: -** opens the EPANET-MSX toolkit system. -** -** Input: -** fname = name of an MSX input file. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int err = 0; - if (MSX.ProjectOpened) return(ERR_MSX_OPENED); - CALL(err, MSXproj_open(fname)); - CALL(err, MSXqual_open()); - - if ( err ) - { - ENwriteline(MSXproj_getErrmsg(err)); - ENwriteline(""); - } - - return err; -} - -//============================================================================= - -int MSXDLLEXPORT MSXsolveH() -/* -** Purpose: -** solves for system hydraulics which are written to a temporary file. -** -** Input: -** none. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int err = 0; - -// --- check that an MSX project was opened - - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - -// --- close & remove any existing hydraulics file - - if ( MSX.HydFile.file ) - { - fclose(MSX.HydFile.file); - MSX.HydFile.file = NULL; - } - if ( MSX.HydFile.mode == SCRATCH_FILE ) remove(MSX.HydFile.name); - -// --- create a temporary hydraulics file - - MSXutils_getTempName(MSX.HydFile.name); - MSX.HydFile.mode = SCRATCH_FILE; //(LR-10/05/08) - -// --- use EPANET to solve for & save hydraulics results - - CALL(err, ENsolveH()); - CALL(err, ENsavehydfile(MSX.HydFile.name)); - CALL(err, MSXusehydfile(MSX.HydFile.name)); - return err; -} - -//============================================================================= - -int MSXDLLEXPORT MSXusehydfile(char *fname) -/* -** Purpose: -** registers a hydraulics solution file with the MSX system. -** -** Input: -** fname = name of binary hydraulics results file. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - INT4 magic; - INT4 version; - INT4 n; - -// --- check that an MSX project was opened - - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - -// --- close any existing hydraulics file - - if ( MSX.HydFile.file ) - { - fclose(MSX.HydFile.file); - if ( MSX.HydFile.mode == SCRATCH_FILE ) remove(MSX.HydFile.name); //(LR-10/05/08) - } - - -// --- open hydraulics file - - //MSX.HydFile.mode = USED_FILE; - MSX.HydFile.file = fopen(fname, "rb"); - if (!MSX.HydFile.file) return ERR_OPEN_HYD_FILE; - -// --- check that file is really a hydraulics file for current project - - fread(&magic, sizeof(INT4), 1, MSX.HydFile.file); - if ( magic != MAGICNUMBER ) return ERR_READ_HYD_FILE; - fread(&version, sizeof(INT4), 1, MSX.HydFile.file); - fread(&n, sizeof(INT4), 1, MSX.HydFile.file); - if ( n != MSX.Nobjects[NODE] ) return ERR_READ_HYD_FILE; - fread(&n, sizeof(INT4), 1, MSX.HydFile.file); - if ( n != MSX.Nobjects[LINK] ) return ERR_READ_HYD_FILE; - fseek(MSX.HydFile.file, 3*sizeof(INT4), SEEK_CUR); - -// --- read length of simulation period covered by file - - fread(&n, sizeof(INT4), 1, MSX.HydFile.file); - MSX.Dur = 1000 * n; - MSX.HydOffset = ftell(MSX.HydFile.file); - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXsolveQ() -/* -** Purpose: -** runs a MSX water quality analysis over the entire simulation period. -** -** Input: -** none. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - double t, tleft = 0; - int err = 0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - CALL(err, MSXinit(1)); - do CALL(err, MSXstep(&t, &tleft)); - while (tleft > 0 && err == 0); - return err; -} - -//============================================================================= - -int MSXDLLEXPORT MSXinit(int saveFlag) -/* -** Purpose: -** initializes a MSX water quality analysis. -** -** Input: -** saveFlag = 1 if results saved to binary file, 0 if not. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int err= 0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - MSX.Saveflag = saveFlag; - err = MSXqual_init(); - return err; -} - -//============================================================================= - -int MSXDLLEXPORT MSXstep(double *t, double *tleft) -/* -** Purpose: -** advances the WQ simulation over a single time step. -** -** Input: -** none -** -** Output: -** *t = current simulation time at the end of the step (sec) -** *tleft = time left in the simulation (sec) -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - return MSXqual_step(t, tleft); -} - -//============================================================================= - -int MSXDLLEXPORT MSXsaveoutfile(char *fname) -/* -** Purpose: -** saves all results of the WQ simulation to a binary file. -** -** Input: -** fname = name of the binary results file. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - FILE *f; - int c; - - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( !MSX.OutFile.file ) return ERR_OPEN_OUT_FILE; - if ( (f = fopen(fname,"w+b") ) == NULL) return ERR_OPEN_OUT_FILE; - fseek(MSX.OutFile.file, 0, SEEK_SET); - while ( (c = fgetc(MSX.OutFile.file)) != EOF) fputc(c, f); - fclose(f); - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXreport() -/* -** Purpose: -** writes requested WQ simulation results to a text file. -** -** Input: -** none -** -** Returns: -** an error code (or 0 for no error). -** -** Notes: -** Results are written to the EPANET report file unless a specific -** water quality report file is named in the [REPORT] section of -** the MSX input file. -*/ -{ - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( MSX.Rptflag ) return MSXrpt_write(); - else return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXclose() -/* -** Purpose: -** closes the EPANET-MSX toolkit system. -** -** Input: -** none -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - MSXqual_close(); - MSXproj_close(); - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetindex(int type, char *id, int *index) -/* -** Purpose: -** retrieves the index of a named MSX object. -** -** Input: -** type = object type code -** id = name of water quality species. -** -** Output: -** index = index (base 1) in the list of all objects of the given type. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int i; - *index = 0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - switch(type) - { - case MSX_SPECIES: i = MSXproj_findObject(SPECIES, id); break; - case MSX_CONSTANT: i = MSXproj_findObject(CONSTANT, id); break; - case MSX_PARAMETER: i = MSXproj_findObject(PARAMETER, id); break; - case MSX_PATTERN: i = MSXproj_findObject(PATTERN, id); break; - default: return ERR_INVALID_OBJECT_TYPE; - } - if ( i < 1 ) return ERR_UNDEFINED_OBJECT_ID; - *index = i; - return 0; -} -//============================================================================= - -int MSXDLLEXPORT MSXgetIDlen(int type, int index, int *len) -/* -** Purpose: -** retrieves the number of characters in the ID name of an MSX object. -** -** Input: -** type = object type code -** index = index (base 1) of the object in list of all objects of the -** given type. -** -** Output: -** len = number of characters in the object's ID name. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int i; - *len = 0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - switch(type) - { - case MSX_SPECIES: i = SPECIES; break; - case MSX_CONSTANT: i = CONSTANT; break; - case MSX_PARAMETER: i = PARAMETER; break; - case MSX_PATTERN: i = PATTERN; break; - default: return ERR_INVALID_OBJECT_TYPE; - } - if ( index < 1 || index > MSX.Nobjects[i] ) return ERR_INVALID_OBJECT_INDEX; - switch(i) - { - case SPECIES: *len = (int) strlen(MSX.Species[index].id); break; - case CONSTANT: *len = (int) strlen(MSX.Const[index].id); break; - case PARAMETER: *len = (int) strlen(MSX.Param[index].id); break; - case PATTERN: *len = (int) strlen(MSX.Pattern[index].id); break; - } - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetID(int type, int index, char *id, int len) -/* -** Purpose: -** retrieves the name of an object given its index. -** -** Input: -** type = object type code -** index = index (base 1) of the object in list of all objects of the -** given type -** len = maximum number of characters that id can hold. -** -** Output: -** id = name of the object. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int i; - strcpy(id, ""); - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - switch(type) - { - case MSX_SPECIES: i = SPECIES; break; - case MSX_CONSTANT: i = CONSTANT; break; - case MSX_PARAMETER: i = PARAMETER; break; - case MSX_PATTERN: i = PATTERN; break; - default: return ERR_INVALID_OBJECT_TYPE; - } - if ( index < 1 || index > MSX.Nobjects[i] ) return ERR_INVALID_OBJECT_INDEX; - switch(i) - { - case SPECIES: strncpy(id, MSX.Species[index].id, len); break; - case CONSTANT: strncpy(id, MSX.Const[index].id, len); break; - case PARAMETER: strncpy(id, MSX.Param[index].id, len); break; - case PATTERN: strncpy(id, MSX.Pattern[index].id, len); break; - } - id[len] = '\0'; //(L. Rossman - 11/01/10) - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetcount(int type, int *count) -/* -** Purpose: -** retrieves the number of objects of a specific type. -** -** Input: -** type = object type code -** -** Output: -** count = number of objects of the given type. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - *count = 0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - switch(type) - { - case MSX_SPECIES: *count = MSX.Nobjects[SPECIES]; break; - case MSX_CONSTANT: *count = MSX.Nobjects[CONSTANT]; break; - case MSX_PARAMETER: *count = MSX.Nobjects[PARAMETER]; break; - case MSX_PATTERN: *count = MSX.Nobjects[PATTERN]; break; - default: return ERR_INVALID_OBJECT_TYPE; - } - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetspecies(int index, int *type, char *units, - double *aTol, double * rTol) -/* -** Purpose: -** retrieves the attributes of a chemical species. -** -** Input: -** index = index (base 1) of the species in the list of all species. -** -** Output: -** type = MSX_BULK (0) for a bulk flow species or MSX_WALL (1) for a -** surface species; -** units = character string containing the mass units defined for the species - -** must be sized in the calling program to accept up to 15 bytes -** plus a null termination character -** aTol = absolute concentration tolerance (concentration units); -** rTol = relative concentration tolerance (unitless) -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - *type = 0; - strcpy(units, ""); - *aTol = 0.0; - *rTol = 0.0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( index < 1 || index > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; - *type = MSX.Species[index].type; - strncpy(units, MSX.Species[index].units, MAXUNITS); - *aTol = MSX.Species[index].aTol; - *rTol = MSX.Species[index].rTol; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetconstant(int index, double *value) -/* -** Purpose: -** retrieves the value of a particular reaction constant. -** -** Input: -** index = index (base 1) of the constant in the list of all constants. -** -** Output: -** value = value assigned to the constant. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - *value = 0.0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( index < 1 || index > MSX.Nobjects[CONSTANT] ) return ERR_INVALID_OBJECT_INDEX; - *value = MSX.Const[index].value; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetparameter(int type, int index, int param, double *value) -/* -** Purpose: -** retrieves the value of a particular reaction parameter for a given pipe -** or tank within the pipe network. -** -** Input: -** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; -** index = index (base 1) assigned to the node or link; -** param = index (base 1) assigned to the reaction parameter. -** -** Output: -** value = value assigned to the parameter. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int j; - *value = 0.0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( param < 1 || param > MSX.Nobjects[PARAMETER] ) return ERR_INVALID_OBJECT_INDEX; - if ( type == MSX_NODE ) - { - if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; - j = MSX.Node[index].tank; - if ( j > 0 ) *value = MSX.Tank[j].param[param]; - } - else if ( type == MSX_LINK ) - { - if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; - *value = MSX.Link[index].param[param]; - } - else return ERR_INVALID_OBJECT_TYPE; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetsource(int node, int species, int *type, double *level, - int *pat) -/* -** Purpose: -** retrieves information on any external source of a particular chemical -** species assigned to a specific node of the pipe network. -** -** Input: -** node = index number (base 1) assigned to the node of interest; -** species = index number (base 1) of the species of interest; -** -** Output: -** type = one of the following of external source type codes: -** MSX_NOSOURCE = -1 for no source, -** MSX_CONCEN = 0 for a concentration source, -** MSX_MASS = 1 for a mass booster source, -** MSX_SETPOINT = 2 for a setpoint source, -** MSX_FLOWPACED = 3 for a flow paced source; -** level = the baseline concentration (or mass flow rate) of the species -** in the source; -** pat = the index of the time pattern assigned to the species at the source -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - Psource source; - *type = MSX_NOSOURCE; - *level = 0.0; - *pat = 0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( node < 1 || node > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; - if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; - source = MSX.Node[node].sources; - while ( source ) - { - if ( source->species == species ) - { - *type = source->type; - *level = source->c0; - *pat = source->pat; - break; - } - source = source->next; - } - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetpatternlen(int pat, int *len) -/* -** Purpose: -** retrieves the number of time periods within a source time pattern. -** -** Input: -** pat = the index number (base 1) of the time pattern; -** -** Output: -** len = the number of time periods that appear in the pattern. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - *len = 0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( pat < 1 || pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; - *len = MSX.Pattern[pat].length; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetpatternvalue(int pat, int period, double *value) -/* -** Purpose: -** retrieves the multiplier at a specific time period for a given -** source time pattern. -** -** Input: -** pat = the index number (base 1) of the time pattern; -** period = the index of the time period (starting from 1) whose -** multiplier is being sought; -** -** Output: -** value = the value of the pattern's multiplier in the desired period. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int n = 1; - *value = 0.0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( pat < 1 || pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; - if ( period <= MSX.Pattern[pat].length ) - { - MSX.Pattern[pat].current = MSX.Pattern[pat].first; - while ( MSX.Pattern[pat].current ) - { - if ( n == period ) - { - *value = MSX.Pattern[pat].current->value; - return 0; - } - MSX.Pattern[pat].current = MSX.Pattern[pat].current->next; - n++; - } - } - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetinitqual(int type, int index, int species, double *value) -/* -** Purpose: -** retrieves the initial concentration of a particular chemical species -** assigned to a specific node or link of the pipe network. -** -** Input: -** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; -** index = index (base 1) of the node or link of interest; -** species = index (base 1) of the species of interest. -** -** Output: -** value = initial concentration of the species at the node or link. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - *value = 0.0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; - if ( type == MSX_NODE ) - { - if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; - *value = MSX.Node[index].c0[species]; - } - else if ( type == MSX_LINK ) - { - if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; - *value = MSX.Link[index].c0[species]; - } - else return ERR_INVALID_OBJECT_TYPE; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgetqual(int type, int index, int species, double *value) -/* -** Purpose: -** retrieves the current concentration of a species at a particular node -** or link of the pipe network. -** -** Input: -** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; -** index = index (base 1) of the node or link of interest;. -** species = index (base 1) of the species of interest. -** -** Output: -** value = species concentration at the node or link. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - *value = 0.0; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; - if ( type == MSX_NODE ) - { - if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; - *value = MSXqual_getNodeQual(index, species); - } - else if ( type == MSX_LINK ) - { - if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; - *value = MSXqual_getLinkQual(index, species); - } - else return ERR_INVALID_OBJECT_TYPE; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXgeterror(int code, char *msg, int len) -/* -** Purpose: -** retrieves text of an error message. -** -** Input: -** code = error code number -** len = maximum length of string errmsg. -** -** Output: -** msg = text of error message. -** -** Returns: -** an error code which is always 0. -*/ -{ - strncpy(msg, MSXproj_getErrmsg(code), len); - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXsetconstant(int index, double value) -/* -** Purpose: -** assigns a new value to a specific reaction constant. -** -** Input: -** index = index (base 1) of the constant in the list of all constants; -** value = the new value to be assigned to the constant. -** -** Output: -** none. -** -** Returns: -** an error code or 0 for no error. -*/ -{ - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( index < 1 || index > MSX.Nobjects[CONSTANT] ) return ERR_INVALID_OBJECT_INDEX; - MSX.Const[index].value = value; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXsetparameter(int type, int index, int param, double value) -/* -** Purpose: -** assigns a value to a particular reaction parameter for a given pipe -** or tank within the pipe network. -** -** Input: -** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; -** index = index (base 1) assigned to the node or link; -** param = index (base 1) assigned to the reaction parameter; -** value = value to be assigned to the parameter. -** -** Output: -** none. -** -** Returns: -** an error code or 0 for no error. -*/ -{ - int j; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( param < 1 || param > MSX.Nobjects[PARAMETER] ) return ERR_INVALID_OBJECT_INDEX; - if ( type == MSX_NODE ) - { - if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; - j = MSX.Node[index].tank; - if ( j > 0 ) MSX.Tank[j].param[param] = value; - } - else if ( type == MSX_LINK ) - { - if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; - MSX.Link[index].param[param] = value; - } - else return ERR_INVALID_OBJECT_TYPE; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXsetinitqual(int type, int index, int species, double value) -/* -** Purpose: -** assigns an initial concentration of a particular chemical species -** to a specific node or link of the pipe network. -** -** Input: -** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; -** index = index (base 1) of the node or link of interest; -** species = index (base 1) of the species of interest. -** value = initial concentration of the species at the node or link. -** -** Output: -** none. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; - if ( type == MSX_NODE ) - { - if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; - if ( MSX.Species[species].type == BULK ) - MSX.Node[index].c0[species] = value; - } - else if ( type == MSX_LINK ) - { - if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; - MSX.Link[index].c0[species] = value; - } - else return ERR_INVALID_OBJECT_TYPE; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXsetsource(int node, int species, int type, double level, - int pat) -/* -** Purpose: -** sets the attributes of an external source of a particular chemical -** species to a specific node of the pipe network. -** -** Input: -** node = index number (base 1) assigned to the node of interest; -** species = index number (base 1) of the species of interest; -** type = one of the following of external source type codes: -** MSX_NOSOURCE = -1 for no source, -** MSX_CONCEN = 0 for a concentration source, -** MSX_MASS = 1 for a mass booster source, -** MSX_SETPOINT = 2 for a setpoint source, -** MSX_FLOWPACED = 3 for a flow paced source; -** level = the baseline concentration (or mass flow rate) of the species -** in the source; -** pat = the index of the time pattern assigned to the species at the source -** -** Output: -** none. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - Psource source; - -// --- check for valid source parameters - - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( node < 1 || node > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; - if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; - if ( pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; - if ( pat < 0 ) pat = 0; - if ( type < MSX_NOSOURCE || - type > MSX_FLOWPACED ) return ERR_INVALID_OBJECT_PARAMS; - if ( MSX.Species[species].type != BULK ) return ERR_INVALID_OBJECT_PARAMS; - if ( level < 0.0 ) return ERR_INVALID_OBJECT_PARAMS; - -// --- check if a source for this species already exists at the node - - source = MSX.Node[node].sources; - while ( source ) - { - if ( source->species == species ) break; - source = source->next; - } - -// --- if no current source exists then create a new one - - if ( source == NULL ) - { - source = (struct Ssource *) malloc(sizeof(struct Ssource)); - if ( source == NULL ) return ERR_MEMORY; - source->next = MSX.Node[node].sources; - MSX.Node[node].sources = source; - } - -// --- assign parameters to the source - - source->type = (char)type; - source->species = species; - source->c0 = level; - source->pat = pat; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXsetpatternvalue(int pat, int period, double value) -/* -** Purpose: -** assigns a new value to the multiplier for a specific time period in -** a given time pattern. -** -** Input: -** pat = the index number (base 1) of the time pattern; -** period = the time period (starting from 1) whose multiplier is -** being replaced; -** value = the new value of the pattern's multiplier in the desired period. -** -** Output: -** none. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int n = 1; - -// --- check that pattern & period exists - - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( pat < 1 || pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; - if ( period <= 0 || period > MSX.Pattern[pat].length ) - return ERR_INVALID_OBJECT_PARAMS; - -// --- find desired time period in the pattern - - MSX.Pattern[pat].current = MSX.Pattern[pat].first; - while ( MSX.Pattern[pat].current ) - { - if ( n == period ) - { - MSX.Pattern[pat].current->value = value; - return 0; - } - MSX.Pattern[pat].current = MSX.Pattern[pat].current->next; - n++; - } - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXaddpattern(char *id) -/* -** Purpose: -** adds a new MSX time pattern to the project. -** -** Input: -** id = C-style character string with the ID name of the new pattern. -** -** Output: -** none. -** -** Returns: -** an error code (or 0 for no error). -** -** Notes: -** the new pattern is appended to the end of the existing patterns. -*/ -{ - int i, n; - Spattern *tmpPat; - -// --- check if a pattern with same id already exists - - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( MSXproj_findObject(PATTERN, id) >= 1 ) return ERR_INVALID_OBJECT_PARAMS; - -// --- allocate memory for a new array of patterns - - n = MSX.Nobjects[PATTERN] + 1; - tmpPat = (Spattern *) calloc((size_t)n+1, sizeof(Spattern)); - if ( tmpPat == NULL ) return ERR_MEMORY; - -// --- copy contents of old pattern array to new one - - for (i=1; i<=MSX.Nobjects[PATTERN]; i++) - { - tmpPat[i].id = MSX.Pattern[i].id; - tmpPat[i].length = MSX.Pattern[i].length; - tmpPat[i].first = MSX.Pattern[i].first; - tmpPat[i].current = MSX.Pattern[i].current; - } - -// --- add info for the new pattern - - if ( MSXproj_addObject(PATTERN, id, n) < 0 ) - { - free(tmpPat); - return ERR_MEMORY; - } - tmpPat[n].id = MSXproj_findID(PATTERN, id); - tmpPat[n].length = 0; - tmpPat[n].first = NULL; - tmpPat[n].current = NULL; - -// --- replace old pattern array with new one - - FREE(MSX.Pattern); - MSX.Pattern = tmpPat; - MSX.Nobjects[PATTERN]++; - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXsetpattern(int pat, double mult[], int len) -/* -** Purpose: -** Assigns a new set of multipliers to a given time pattern. -** -** Input: -** pat = the index number (base 1) of the time pattern; -** mult[] = an array of multiplier values (base 0) to replace those -** previously used by the pattern; -** len = the number of entries in the multiplier array mult. -** -** Output: -** none. -** -** Returns: -** an error code (or 0 for no error). -*/ -{ - int i; - SnumList *listItem; - -// --- check that pattern exists - - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ( pat < 1 || pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; - if ( len < 0) len = 0; - -// --- delete current multipliers - - listItem = MSX.Pattern[pat].first; - while (listItem) - { - MSX.Pattern[pat].first = listItem->next; - free(listItem); - listItem = MSX.Pattern[pat].first; - } - MSX.Pattern[pat].first = NULL; - -// --- create a new set of multipliers - - MSX.Pattern[pat].length = 0; - for ( i = 0; i < len; i++ ) - { - listItem = (SnumList *) malloc(sizeof(SnumList)); - if ( listItem == NULL ) return ERR_MEMORY; - listItem->value = mult[i]; - listItem->next = NULL; - if ( MSX.Pattern[pat].first == NULL ) - { - MSX.Pattern[pat].current = listItem; - MSX.Pattern[pat].first = listItem; - } - else - { - MSX.Pattern[pat].current->next = listItem; - MSX.Pattern[pat].current = listItem; - } - MSX.Pattern[pat].length++; - } - - MSX.Pattern[pat].interval = 0; //Feng Shang 04/17/2008 - MSX.Pattern[pat].current = MSX.Pattern[pat].first; //Feng Shang 04/17/2008 - return 0; -} - -//============================================================================= - -int MSXDLLEXPORT MSXsavemsxfile(char *fname) -{ - int errcode; - FILE *f; - if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; - if ((f = fopen(fname,"wt")) == NULL) return ERR_OPEN_OUT_FILE; - errcode = MSXfile_save(f); - fclose(f); - return errcode; -} diff --git a/Src/msxtypes.h b/Src/msxtypes.h deleted file mode 100644 index 67f1803..0000000 --- a/Src/msxtypes.h +++ /dev/null @@ -1,547 +0,0 @@ -/************************************************************************ -** MODULE: TYPES.H -** PROJECT: EPANET-MSX -** DESCRIPTION: Global constants and data types used by the EPANET -** Multi-Species Extension toolkit. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 08/30/2022 -***********************************************************************/ - -#include "mathexpr.h" -#include "mempool.h" -#include - -//----------------------------------------------------------------------------- -// Definition of 4-byte integers & reals -//----------------------------------------------------------------------------- -typedef int INT4; -typedef float REAL4; - -//----------------------------------------------------------------------------- -// Macros for memory allocation -//----------------------------------------------------------------------------- -#define MEMCHECK(x) (((x) == NULL) ? ERR_MEMORY : 0 ) -#define FREE(x) { if (x) { free(x); x = NULL; } } - -//----------------------------------------------------------------------------- -// Conversion macros to be used in place of functions -//----------------------------------------------------------------------------- -#define INT(x) ((int)(x)) // integer portion of x -#define FRAC(x) ((x)-(int)(x)) // fractional part of x -#define ABS(x) (((x)<0) ? -(x) : (x)) // absolute value of x -#define MIN(x,y) (((x)<=(y)) ? (x) : (y)) // minimum of x and y -#define MAX(x,y) (((x)>=(y)) ? (x) : (y)) // maximum of x and y -#define ROUND(x) (((x)>=0) ? (int)((x)+.5) : (int)((x)-.5)) - // round-off of x -#define MOD(x,y) ((x)%(y)) // x modulus y -#define SQR(x) ((x)*(x)) // x-squared -#define SGN(x) (((x)<0) ? (-1) : (1)) // sign of x -#define UCHAR(x) (((x) >= 'a' && (x) <= 'z') ? ((x)&~32) : (x)) - // uppercase char of x -//----------------------------------------------------------------------------- -// Macro to evaluate function f with error checking -// (Fatal errors are numbered higher than 100) -//----------------------------------------------------------------------------- -#define CALL(err, f) (err = ( (err>100) ? (err) : (f) )) - - -//----------------------------------------------------------------------------- -// Defined Constants -//----------------------------------------------------------------------------- -#define MAGICNUMBER 516114521 -#define VERSION 200000 -#define MAXMSG 1024 // Max. # characters in message text -#define MAXLINE 1024 // Max. # characters in input line -#define TRUE 1 -#define FALSE 0 -#define BIG 1.E10 -#define TINY 1.E-6 -#define MISSING -1.E10 -#define PI 3.141592654 -#define VISCOS 1.1E-5 // Kinematic viscosity of water - // @ 20 deg C (sq ft/sec) - -//----------------------------------------------------------------------------- -// Various conversion factors -//----------------------------------------------------------------------------- -#define M2perFT2 0.09290304 -#define CM2perFT2 929.0304 -#define DAYperSEC 1.1574E-5 -#define HOURperSEC 2.7778E-4 -#define MINUTEperSEC 0.016667 -#define GPMperCFS 448.831 -#define AFDperCFS 1.9837 -#define MGDperCFS 0.64632 -#define IMGDperCFS 0.5382 -#define LPSperCFS 28.317 -#define LPMperCFS 1699.0 -#define CMHperCFS 101.94 -#define CMDperCFS 2446.6 -#define MLDperCFS 2.4466 -#define M3perFT3 0.028317 -#define LperFT3 28.317 -#define MperFT 0.3048 -#define PSIperFT 0.4333 -#define KPAperPSI 6.895 -#define KWperHP 0.7457 -#define SECperDAY 86400 - - -//----------------------------------------------------------------------------- -// Enumerated Types -//----------------------------------------------------------------------------- - enum ObjectTypes // Object types - {NODE, - LINK, - TANK, - SPECIES, - TERM, - PARAMETER, - CONSTANT, - PATTERN, - MAX_OBJECTS}; - - enum SourceType // Type of source quality input - {CONCEN, // inflow concentration - MASS, // mass inflow booster - SETPOINT, // setpoint booster - FLOWPACED}; // flow paced booster - - enum UnitSystemType // Unit system: - {US, // US - SI}; // SI (metric) - - enum FlowUnitsType // Flow units: - {CFS, // cubic feet per second - GPM, // gallons per minute - MGD, // million gallons per day - IMGD, // imperial million gal. per day - AFD, // acre-feet per day - LPS, // liters per second - LPM, // liters per minute - MLD, // megaliters per day - CMH, // cubic meters per hour - CMD}; // cubic meters per day - - enum MixType // Tank mixing regimes - {MIX1, // 1-compartment model - MIX2, // 2-compartment model - FIFO, // First in, first out model - LIFO}; // Last in, first out model - - enum SpeciesType // Types of water quality species - {BULK, // bulk flow species - WALL}; // pipe wall attached species - - enum ExpressionType // Types of math expressions - {NO_EXPR, // no expression - RATE, // reaction rate - FORMULA, // simple formula - EQUIL}; // equilibrium expression - - enum SolverType // ODE solver options - {EUL, // Euler - RK5, // 5th order Runge-Kutta - ROS2}; // 2nd order Rosenbrock - - enum CouplingType // Degree of coupling for solving DAE's - {NO_COUPLING, // no coupling between alg. & diff. eqns. - FULL_COUPLING}; // full coupling between alg. &diff. eqns. - - enum MassUnitsType // Concentration mass units - {MG, // milligram - UG, // microgram - MOLE, // mole - MMOLE}; // millimole - - enum AreaUnitsType // Pipe surface area units - {FT2, // square feet - M2, // square meters - CM2}; // square centimeters - - enum RateUnitsType // Reaction rate time units - {SECONDS, // seconds - MINUTES, // minutes - HOURS, // hours - DAYS}; // days - - enum UnitsType // Measurement unit types - {LENGTH_UNITS, // length - DIAM_UNITS, // pipe diameter - AREA_UNITS, // surface area - VOL_UNITS, // volume - FLOW_UNITS, // flow - CONC_UNITS, // concentration volume - RATE_UNITS, // reaction rate time units - MAX_UNIT_TYPES}; - - enum HydVarType // Hydraulic variables - {DIAMETER = 1, // link diameter - FLOW, // link flow rate - VELOCITY, // link flow velocity - REYNOLDS, // Reynolds number - SHEAR, // link shear velocity - FRICTION, // friction factor - AREAVOL, // area/volume - ROUGHNESS, // roughness /*Feng Shang 01/29/2008*/ - LENGTH, // pipe length /*Feng Shang 01/27/2023 - MAX_HYD_VARS}; - - enum TstatType // Time series statistics - {SERIES, // full time series - AVGERAGE, // time-averages - MINIMUM, // minimum values - MAXIMUM, // maximum values - RANGE}; // max - min values - - enum OptionType // Analysis options - {AREA_UNITS_OPTION, - RATE_UNITS_OPTION, - SOLVER_OPTION, - COUPLING_OPTION, - TIMESTEP_OPTION, - RTOL_OPTION, - ATOL_OPTION, - COMPILER_OPTION, - MAXSEGMENT_OPTION, - PECLETNUMER_OPTION}; - - enum CompilerType // C compiler type - {NO_COMPILER, - VC, // MS Visual C compiler - GC}; // Gnu C compiler - - enum FileModeType // File modes - {SCRATCH_FILE, - SAVED_FILE, - USED_FILE}; - - enum SectionType // Input data file sections - {s_TITLE, - s_SPECIES, - s_COEFF, - s_TERM, - s_PIPE, - s_TANK, - s_SOURCE, - s_QUALITY, - s_PARAMETER, - s_PATTERN, - s_OPTION, - s_REPORT, - s_Diffu, - }; - - enum ErrorCodeType // Error codes (501-525) - {ERR_FIRST = 500, - ERR_MEMORY, // 501 - ERR_NO_EPANET_FILE, // 502 - ERR_OPEN_MSX_FILE, // 503 - ERR_OPEN_HYD_FILE, // 504 - ERR_READ_HYD_FILE, // 505 - ERR_MSX_INPUT, // 506 - ERR_NUM_PIPE_EXPR, // 507 - ERR_NUM_TANK_EXPR, // 508 - ERR_INTEGRATOR_OPEN, // 509 - ERR_NEWTON_OPEN, // 510 - ERR_OPEN_OUT_FILE, // 511 - ERR_IO_OUT_FILE, // 512 - ERR_INTEGRATOR, // 513 - ERR_NEWTON, // 514 - ERR_INVALID_OBJECT_TYPE, // 515 - ERR_INVALID_OBJECT_INDEX, // 516 - ERR_UNDEFINED_OBJECT_ID, // 517 - ERR_INVALID_OBJECT_PARAMS, // 518 - ERR_MSX_NOT_OPENED, // 519 - ERR_MSX_OPENED, // 520 - ERR_OPEN_RPT_FILE, // 521 - ERR_COMPILE_FAILED, // 522 - ERR_COMPILED_LOAD, // 523 - ERR_ILLEGAL_MATH, // 524 - ERR_MAX}; - - -//----------------------------------------------------------------------------- -// Data Structures -//----------------------------------------------------------------------------- -struct NumList // List of numerical values -{ - double value; - struct NumList *next; -}; -typedef struct NumList SnumList; - - -typedef struct // TIME PATTERN OBJECT -{ - char *id; // pattern ID - long length; // number of pattern factors - long interval; // current time interval - SnumList *first; // first mutiplier - SnumList *current; // current multiplier -} Spattern; - - -struct Ssource // WATER QUALITY SOURCE OBJECT -{ - char type; // sourceType - int species; // species index - double c0; // base concentration - int pat; // time pattern index - double massRate; // actual mass flow rate - struct Ssource *next; // next bulk species source -}; -typedef struct Ssource *Psource; - - -typedef struct // NODE OBJECT -{ - Psource sources; // ptr. to WQ source list - double *c; // current species concentrations - double *c0; // initial species concentrations - int tank; // tank index - char rpt; // reporting flag -} Snode; - - -typedef struct // LINK OBJECT -{ - int nsegs; // number of active segments - int n1; // start node index - int n2; // end node index - double diam; // diameter - double len; // length - char rpt; // reporting flag - double *c0; // initial species concentrations - double *reacted; - double *param; // kinetic parameter values - double roughness; // roughness - double areasquare; - double HydVar[MAX_HYD_VARS]; // hydraulic variables -} Slink; - - -typedef struct // TANK OBJECT -{ - int node; // node index of tank - double hstep; // integration time step - double a; // tank area - double v0; // initial volume - double v; // tank volume - int mixModel; // type of mixing model - double vMix; // mixing compartment size - double *param; // kinetic parameter values - double *c; // current species concentrations - double *reacted; -} Stank; - - -struct Sseg // PIPE SEGMENT OBJECT -{ - double hstep; // integration time step - double v; // segment volume - double *c; // species concentrations - double * lastc; // species concentrations of previous step - struct Sseg *prev; // ptr. to previous segment - struct Sseg *next; // ptr. to next segment - double hresponse, // for dispersion response of initial, - uresponse, // upstream and downstream condition - dresponse; -}; -typedef struct Sseg *Pseg; - - -#define MAXUNITS 16 -typedef struct // CHEMICAL SPECIES OBJECT -{ - char *id; // name - char units[MAXUNITS]; // mass units code - double aTol; // absolute tolerance - double rTol; // relative tolerance - int type; // BULK or WALL - int pipeExprType; // type of pipe chemistry - int tankExprType; // type of tank chemistry - int precision; // reporting precision - char rpt; // reporting flag - MathExpr *pipeExpr; // pipe chemistry expression - MathExpr *tankExpr; // tank chemistry expression -} Sspecies; - - -typedef struct // INTERMEDIATE TERM OBJECT -{ - char *id; // name - MathExpr *expr; // math expression for term -} Sterm; - - -typedef struct // REACTION RATE PARAMETER OBJECT -{ - char *id; // name - double value; // value -} Sparam; - - -typedef struct // MATH EXPRESSION CONSTANT OBJECT -{ - char *id; // name - double value; // value -} Sconst; - - -#define MAXFNAME 259 // Max. # characters in file name -typedef struct // FILE OBJECT -{ - char name[MAXFNAME]; // file name - char mode; // see FileModeType enumeration below - FILE* file; // FILE structure pointer -} TFile; - - - -struct Sadjlist // Node Adjacency List Item -{ - int node; // index of connecting node - int link; // index of connecting link - struct Sadjlist* next; // next item in list -}; - -typedef struct Sadjlist* Padjlist; // Pointer to adjacency list - -typedef enum { - NEGATIVE = -1, // flow in reverse of pre-assigned direction - ZERO_FLOW = 0, // zero flow - POSITIVE = 1 // flow in pre-assigned direction -} FlowDirection; - -typedef struct // Mass Balance Components -{ - double * initial; // initial mass in system - double * inflow; // mass inflow to system - double * indisperse; // mass dispersed into the system - double * outflow; // mass outflow from system - double * reacted; // mass reacted in system - double * final; // final mass in system - double * ratio; // ratio of mass added to mass lost -} SmassBalance; - - -typedef struct -{ - - double viscosity; - double DIFFUS; // Diffusivity of chlorine 1.3E-8 @ 20 deg C (sq ft/sec) - double PecletLimit; // The Pectlet number below which the dispersion in a pipe is considered - - int* Order; // Node-to-row of re-ordered matrix - int* Row; // Row-to-node of re-ordered matrix - int* Ndx; // Index of link's coeff. in Aij - int* XLNZ; // Start position of each column in NZSUB - int* NZSUB; // Row index of each coeff.in each column - int* LNZ; // Position of each coeff. in Aij array - int* Degree; // Number of links adjacent to each node - int Ncoeffs; // Number of non-zero matrix coeffs - - int* link; // Array used by linear eqn. solver - int* first; // Array used by linear eqn. solver - double* temp; // Array used by linear eqn. solver - double* Aii; // Diagonal matrix coeffs. - double* Aij; // Non-zero, off-diagonal matrix coeffs. - double* F; // Right hand side vector - - Padjlist* Adjlist; // Node adjacency lists - - - double* md; // molecular diffusion - double* ld; // fixed longitudinal dispersion coefficient - double* pipeDispersionCoeff; //effective longitudinal dispersion coefficient -} Sdispersion; - - -typedef struct // MSX PROJECT VARIABLES -{ - TFile HydFile, // EPANET hydraulics file - MsxFile, // MSX input file - OutFile, // MSX binary output file - TmpOutFile, // Scratch MSX binary output file - RptFile; // MSX report file - - char Title[MAXLINE+1], // Project title - Msg[MAXLINE+1]; // Message string - - int Nobjects[MAX_OBJECTS], // Numbers of each type of object - Unitsflag, // Unit system flag - Flowflag, // Flow units flag - Saveflag, // Save results flag - Rptflag, // Report results flag - Coupling, // Degree of coupling for solving DAE's - Compiler, // chemistry function compiler code - AreaUnits, // Surface area units - RateUnits, // Reaction rate time units - Solver, // Choice of ODE solver - PageSize, // Lines per page in report - Nperiods, // Number of reporting periods - ErrCode, // Error code - ProjectOpened, // Project opened flag - QualityOpened; // Water quality system opened flag - int MaxSegments; // Maximum number of segments in a link - long HydOffset, // Hydraulics file byte offset - Pstep, // Time pattern time step (sec) - Pstart, // Starting pattern time (sec) - Rstep, // Reporting time step (sec) - Rstart, // Time when reporting starts - Statflag; // Reporting statistic flag - - int64_t Qstep, // Quality time step (millisec) - Qtime, // Current quality time (millisec) - Htime, // Current hydraulic time (millisec) - Rtime, // Next reporting time (millisec) - Dur; // Duration of simulation (millisec) - - REAL4 *D, // Node demands - *H, // Node heads - *Q, // Link flows - *S; // Link status - - double Ucf[MAX_UNIT_TYPES], // Unit conversion factors - DefRtol, // Default relative error tolerance - DefAtol, // Default absolute error tolerance - *K, // Vector of expression constants - *C0, // Species initial quality vector - *C1; // Species concentration vector - - Pseg *FirstSeg, // First WQ segment in each pipe/tank - *LastSeg; // Last WQ segment in each pipe/tank - - Sspecies *Species; // WQ species data - Sparam *Param; // Expression parameters - Sconst *Const; // Expression constants - Sterm *Term; // Intermediate terms - Snode *Node; // Node data - Slink *Link; // Link data - Stank *Tank; // Tank data - Spattern *Pattern; // Pattern data - - char HasWallSpecies; // wall species indicator - char OutOfMemory; // out of memory indicator - Padjlist* Adjlist; // Node adjacency lists - Pseg* NewSeg; // new segment added to each pipe - Pseg FreeSeg; // pointer to unused segment - FlowDirection *FlowDir; // flow direction for each pipe - SmassBalance MassBalance; - alloc_handle_t* QualPool; // memory pool - - int DispersionFlag; // 1 if dispersion modeling - - double* MassIn; // mass inflow of each species to each node - double* SourceIn; // external mass inflow of each species from WQ source; - int* SortedNodes; - - Sdispersion Dispersion; - -} MSXproject; - - diff --git a/Src/msxutils.c b/Src/msxutils.c deleted file mode 100644 index 76bd208..0000000 --- a/Src/msxutils.c +++ /dev/null @@ -1,525 +0,0 @@ -/******************************************************************************* -** MODULE: MSXUTILS.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Utility functions used by the EPANET Multi-Species Extension -** toolkit. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 2/8/11 -*******************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include "msxutils.h" -// --- define WINDOWS - -#undef WINDOWS -#ifdef _WIN32 - #define WINDOWS -#endif -#ifdef __WIN32__ - #define WINDOWS -#endif - -#define UCHAR(x) (((x) >= 'a' && (x) <= 'z') ? ((x)&~32) : (x)) -#define TINY1 1.0e-20 - -//============================================================================= - -char * MSXutils_getTempName(char *s) -/* -** Purpose: -** gets the name of a temporary file with path name and periods stripped -** -** Input: -** s = character string (must be of size L_tmpnam) -** -** Returns: -** a pointer to the file name. -*/ -{ -#ifdef WINDOWS - char *ptr; - char fname[L_tmpnam]; - unsigned int i; - - // --- use tmpnam() function to create a temporary file name - tmpnam(fname); - - // --- replace any '.' characters (they cause problems for some compilers) - for (i=0; i 0) return(0); - return(1); -} - -//============================================================================= - -int MSXutils_getDouble(char *s, double *y) -/* -** Purpose: -** converts a string to a double precision floating point number. -** -** Input: -** s = a character string. -** -** Output: -** y = converted value of s. -** -** Returns: -** 1 if conversion successful, 0 if not. -*/ -{ - char *endptr; - *y = strtod(s, &endptr); - if (*endptr > 0) return(0); - return(1); -} - -//============================================================================= - -double ** createMatrix(int nrows, int ncols) -/* -** Purpose: -** allocates memory for a 2-dimensional array of doubles. -** -** Input: -** nrows = number of rows (0-based) -** ncols = number of columns (0-based). -** -** Returns: -** a pointer to the matrix (a = matrix(nr, nc)). -*/ -{ - int i,j; - double **a; - -// --- allocate pointers to rows - - a = (double **) malloc(nrows * sizeof(double *)); - if ( !a ) return NULL; - -// --- allocate rows and set pointers to them - - a[0] = (double *) malloc (nrows * ncols * sizeof(double)); - if ( !a[0] ) return NULL; - for ( i = 1; i < nrows; i++ ) a[i] = a[i-1] + ncols; - - for ( i = 0; i < nrows; i++) - { - for ( j = 0; j < ncols; j++) a[i][j] = 0.0; - } - -// --- return pointer to array of pointers to rows - - return a; -} - -//============================================================================= - -void freeMatrix(double **a) -/* -** Purpose: -** frees the memory allocated for a matrix of doubles. -** -** Input: -** a = pointer to a matrix of doubles. -*/ -{ - if ( a != NULL ) - { - if ( a[0] != NULL ) free( a[0] ); - free( a ); - } -} - -//============================================================================= - -int factorize(double **a, int n, double *w, int *indx) -/* -** Purpose: -** performs an LU decomposition of a matrix. -** -** Input: -** a[1..n][1..n] = a square matrix of doubles -** n = matrix size (1-based) -** w[1..n] = work array of doubles. -** -** Output: -** a[][] = matrix that contains elements of L and U matrices -** indx[1..n] = vector that records the row permutation -** effected by the partial pivoting. -** -** Returns: -** 1 if successful, 0 if matrix is singular. -** -** Note: -** The arrays and matrices used in this function are 1-based, so -** they must have been sized to n+1 when first created. -*/ -{ - int i, imax, j, k; - double big, dum, sum, temp; - - for (i = 1; i <= n; i++) - { - /*Loop over rows to get the implicit scaling information.*/ - big = 0.0; - for (j = 1;j <= n;j++) - if ((temp = fabs(a[i][j])) > big) big = temp; - if (big == 0.0) - return 0; /* Warning for singular matrix*/ - /*No nonzero largest element.*/ - w[i] = 1.0/big; /*Save the scaling.*/ - } - for (j = 1;j <= n;j++) /**for each column*/ - { - /*This is the loop over columns of Crout’s method.*/ - for (i = 1; i < j; i++) - { - /*Up from the diagonal*/ - sum = a[i][j]; - for (k = 1;k < i;k++) sum -= a[i][k]*a[k][j]; - a[i][j] = sum; - } - big = 0.0; /*Initialize for the search for largest pivot element.*/ - imax = j; - for (i = j; i <= n; i++) - { - sum = a[i][j]; - for (k = 1; k < j; k++) sum -= a[i][k]*a[k][j]; - a[i][j] = sum; - if ( (dum = w[i]*fabs(sum)) >= big) - { - big = dum; - imax = i; - } - } - if (j != imax) - { - /*Do we need to interchange rows?*/ - for (k = 1; k <= n; k++) - { - /*Yes,do so...*/ - dum = a[imax][k]; - a[imax][k] = a[j][k]; - a[j][k] = dum; - } - w[imax] = w[j]; /* interchange the scale factor.*/ - } - indx[j] = imax; - if (a[j][j] == 0.0) a[j][j] = TINY1; - if (j != n) /* divide by the pivot element.*/ - { - dum = 1.0/(a[j][j]); - for (i = j+1;i <= n;i++) a[i][j] *= dum; - } - } - return 1; -} - -//============================================================================= - -void solve(double **a, int n, int *indx, double b[]) -/* -** Purpose: -** solves linear equations AX = B after LU decomposition of A. -** -** Input: -** a[1..n][1..n] = LU decomposed square matrix A returned by factorize -** n = matrix size -** indx[1..n] = permutation vector returned by factorize -** b[1..n] = right-hand side vector B. -** -** Output: -** b[1..n] = solution vector X. -** -** Note: -** The arrays and matrices used in this function are 1-based, so -** they must have been sized to n+1 when first created. -*/ -{ - int i, ii=0, ip, j; - double sum; - - /*forward substitution */ - for (i=1; i<=n; i++) - { - ip=indx[i]; - sum=b[ip]; - b[ip]=b[i]; - if (ii) - for (j=ii; j<=i-1; j++) - sum -= a[i][j]*b[j]; - else if (sum) ii=i; - b[i]=sum; - } - - /* back substitution */ - for (i=n; i>=1; i--) - { - sum=b[i]; - for (j=i+1; j<=n; j++) - sum -= a[i][j]*b[j]; - b[i]=sum/a[i][i]; - } -} - -//============================================================================= - -void jacobian(double *x, int n, double *f, double *w, double **a, - void (*func)(double, double*, int, double*)) -/* -** Purpose: -** computes Jacobian matrix of F(t,X) at given X -** -** Input: -** x[1..n] = vector of function variables -** n = number of variables -** f[1..n] = a work vector -** w[1..n] = a work vector -** func = user supplied routine that computes the function -** values at x. -** -** Output: -** f[1..n] = function values at x -** a[1..n][1..n] = coeffs. of the Jacobian matrix. -** -** Notes: -** 1. Arguments for func() are: -** t = independent variable (not used) -** x[1..n] = vector of dependent variables -** n = number of functions -** f[1..n] = function values at x. -** -** 2. The arrays and matrices used in this function are 1-based, so -** they must have been sized to n+1 when first created. -*/ -{ - - int i, j; - double temp, eps = 1.0e-7, eps2; - - for (j=1; j<=n; j++) - { - temp = x[j]; - x[j] = temp + eps; - func(0.0, x, n, f); - if ( temp == 0.0 ) - { - x[j] = temp; - eps2 = eps; - } - else - { - x[j] = temp - eps; - eps2 = 2.0*eps; - } - func(0.0, x, n, w); - for (i=1; i<=n; i++) a[i][j] = (f[i] - w[i]) / eps2; - x[j] = temp; - } - - -/* --- An alternative method that uses forward differencing - int i,j; - double temp, h; - double eps = sqrt(DBL_EPSILON); - - func(0.0, x, n, f); - for (j=1; j<=n; j++) - { - temp = x[j]; - h = eps*fabs(temp); - if (h == 0.0) h = eps; - x[j] = temp + h; - func(0.0, x, n, w); - for (i=1; i<=n; i++) a[i][j] = (w[i] - f[i]) / h; - x[j] = temp; - } -*/ - -} diff --git a/Src/msxutils.h b/Src/msxutils.h deleted file mode 100644 index e1b984b..0000000 --- a/Src/msxutils.h +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* -** MODULE: MSXUTILS.H -** PROJECT: EPANET-MSX -** DESCRIPTION: Header file for the utility functions used by the EPANET -** Multi-Species Extension toolkit. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 2/8/11 -*******************************************************************************/ - -// Gets the name of a temporary file -char * MSXutils_getTempName(char *s); - -// Case insentive comparison of two strings -int MSXutils_strcomp(char *s1, char *s2); - -// Matches a string against an array of keywords -int MSXutils_findmatch(char *s, char *keyword[]); - -// Case insensitive search of a string for a substring -int MSXutils_match(char *str, char *substr); - -// Converts a 24-hr clocktime to number of seconds -int MSXutils_strToSeconds(char *s, long *t); - -// Converts a string to an integer -int MSXutils_getInt(char *s, int *y); - -// Converts a string to a float -int MSXutils_getFloat(char *s, float *y); - -// Converts a string to a double -int MSXutils_getDouble(char *s, double *y); - -// Creates a two dimensional array -double ** createMatrix(int nrows, int ncols); - -// Deletes a two dimensional array -void freeMatrix(double **a); - -// Applies L-D factorization to a square matrix -int factorize(double **a, int n, double *w, int *indx); - -// Solves a factorized, linear system of equations -void solve(double **a, int n, int *indx, double b[]); - -// Computes the Jacobian matrix of a set of functions -void jacobian(double *x, int n, double *f, double *w, double **a, - void (*func)(double, double*, int, double*)); diff --git a/Src/newton.c b/Src/newton.c deleted file mode 100644 index 43eea49..0000000 --- a/Src/newton.c +++ /dev/null @@ -1,158 +0,0 @@ -/****************************************************************************** -** MODULE: NEWTON.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Newton-Raphson algorithm used to solve a set of nonlinear -** algebraic equations. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -******************************************************************************/ - -#include -#include -#include -#include -#include "msxutils.h" -#include "newton.h" - -// Local declarations -//------------------- -MSXNewton MSXNewtonSolver; - -#pragma omp threadprivate(MSXNewtonSolver) - -//============================================================================= - -int newton_open(int n) -/* -** Purpose: -** opens the algebraic solver to handle a system of n equations. -** -** Input: -** n = number of equations -** -** Returns: -** 1 if successful, 0 if not. -** -** Note: -** All arrays are 1-based so an extra memory location -** must be allocated for the unused 0-th position. -*/ -{ - int errorcode = 1; - -#pragma omp parallel -{ - MSXNewtonSolver.Nmax = 0; - MSXNewtonSolver.Indx = NULL; - MSXNewtonSolver.F = NULL; - MSXNewtonSolver.W = NULL; - MSXNewtonSolver.Indx = (int*)calloc(n + 1, sizeof(int)); - MSXNewtonSolver.F = (double*)calloc(n + 1, sizeof(double)); - MSXNewtonSolver.W = (double*)calloc(n + 1, sizeof(double)); - MSXNewtonSolver.J = createMatrix(n + 1, n + 1); -#pragma omp critical - { - if (!MSXNewtonSolver.Indx || !MSXNewtonSolver.F || !MSXNewtonSolver.W || !MSXNewtonSolver.J) - errorcode = 0; - } - MSXNewtonSolver.Nmax = n; -} - - return errorcode; -} - -//============================================================================= - -void newton_close() -/* -** Purpose: -** closes the algebraic solver. -** -** Input: -** none -*/ -{ - -#pragma omp parallel -{ - if (MSXNewtonSolver.Indx) { free(MSXNewtonSolver.Indx); MSXNewtonSolver.Indx = NULL; } - if (MSXNewtonSolver.F) { free(MSXNewtonSolver.F); MSXNewtonSolver.F = NULL; } - if (MSXNewtonSolver.W) { free(MSXNewtonSolver.W); MSXNewtonSolver.W = NULL; } - freeMatrix(MSXNewtonSolver.J); - MSXNewtonSolver.J = NULL; -} - -} - -//============================================================================= - -int newton_solve(double x[], int n, int maxit, int numsig, - void (*func)(double, double*, int, double*)) -/* -** Purpose: -** uses newton-raphson iterations to solve n nonlinear eqns. -** -** Input: -** x[] = solution vector -** n = number of equations -** maxit = max. number of iterations allowed -** numsig = number of significant digits in error -** func = pointer to the function that returns the function values at x. -** -** Returns: -** number of iterations if successful, -1 if Jacobian is singular, -** -2 if it didn't converge, or -3 if n exceeds allowable size. -** -** Note: -** the arguments to the function func are: -** t = a time value (not used here) -** x = vector of unknowns being solved for -** n = number of unknowns -** f = vector of function values evaluated at x. -*/ -{ - int i, k; - double errx, errmax, cscal, relconvg = pow(10.0, -numsig); - - // --- check that system was sized adequetely - - if ( n > MSXNewtonSolver.Nmax ) return -3; - - // --- use up to maxit iterations to find a solution - - for (k=1; k<=maxit; k++) - { - // --- evaluate the Jacobian matrix - - jacobian(x, n, MSXNewtonSolver.F, MSXNewtonSolver.W, MSXNewtonSolver.J, func); - - // --- factorize the Jacobian - - if ( !factorize(MSXNewtonSolver.J, n, MSXNewtonSolver.W, MSXNewtonSolver.Indx) ) return -1; - - // --- solve for the updates to x (returned in F) - - for (i=1; i<=n; i++) MSXNewtonSolver.F[i] = -MSXNewtonSolver.F[i]; - solve(MSXNewtonSolver.J, n, MSXNewtonSolver.Indx, MSXNewtonSolver.F); - - // --- update solution x & check for convergence - - errmax = 0.0; - for (i=1; i<=n; i++) - { - cscal = x[i]; - if (cscal < relconvg) cscal = relconvg; - x[i] += MSXNewtonSolver.F[i]; - errx = fabs(MSXNewtonSolver.F[i]/cscal); - if (errx > errmax) errmax = errx; - } - if (errmax <= relconvg) return k; - } - - // --- return error code if no convergence - - return -2; -} diff --git a/Src/newton.h b/Src/newton.h deleted file mode 100644 index 8902f60..0000000 --- a/Src/newton.h +++ /dev/null @@ -1,29 +0,0 @@ -/****************************************************************************** -** MODULE: NEWTON.H -** PROJECT: EPANET-MSX -** DESCRIPTION: header file for the equation solver contained in newton.c. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -******************************************************************************/ - -typedef struct -{ - int Nmax; // max. number of equations - int* Indx; // permutation vector of row indexes - double* F; // function & adjustment vector - double* W; // work vector - double** J; // Jacobian matrix -}MSXNewton; - -// Opens the equation solver system -int newton_open(int n); - -// Closes the equation solver system -void newton_close(void); - -// Applies the solver to a specific system of equations -int newton_solve(double x[], int n, int maxit, int numsig, - void (*func)(double, double*, int, double*)); diff --git a/Src/rk5.c b/Src/rk5.c deleted file mode 100644 index dc81574..0000000 --- a/Src/rk5.c +++ /dev/null @@ -1,287 +0,0 @@ -/************************************************************************ -** MODULE: RK5.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Numerical solution of a system of first order -** ordinary differential equations dY/dt = F(t,Y). -** AUTHOR: L. Rossman, US EPA - NRMRL -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -** -** This is an explicit Runge-Kutta method of order (4)5 -** due to Dormand & Prince (with optional stepsize control). -** The code was adapted from the DOPRI5 code of E. Hairer -** and G. Wanner as described in: -** E. HAIRER, S.P. NORSETT AND G. WANNER, SOLVING ORDINARY -** DIFFERENTIAL EQUATIONS I. NONSTIFF PROBLEMS. 2ND EDITION. -** SPRINGER SERIES IN COMPUTATIONAL MATHEMATICS, -** SPRINGER-VERLAG (1993) -***********************************************************************/ - -#include -#include -#include "rk5.h" - -#define fmin(x,y) (((x)<=(y)) ? (x) : (y)) /* minimum of x and y */ -#define fmax(x,y) (((x)>=(y)) ? (x) : (y)) /* maximum of x and y */ - -// Local variables -//----------------- -MSXRungeKutta MSXRungeKuttaSolver; - -#pragma omp threadprivate(MSXRungeKuttaSolver) -//============================================================================= - -int rk5_open(int n, int itmax, int adjust) -/* -** Purpose: -** Opens the RK5 solver to solve system of n equations -** -** Input: -** n = number of equtions -** itmax = maximum iterations allowed -** adjust = 1 if time step adjustment used, 0 if not -** -** Returns: -** 1 if successful and 0 if not. -*/ -{ - int n1 = n+1; - int errorcode = 1; - MSXRungeKuttaSolver.Report = NULL; - -#pragma omp parallel -{ - MSXRungeKuttaSolver.Nmax = 0; - MSXRungeKuttaSolver.Itmax = itmax; - MSXRungeKuttaSolver.Adjust = adjust; - MSXRungeKuttaSolver.Ynew = (double*)calloc(n1, sizeof(double)); - MSXRungeKuttaSolver.Ak = (double*)calloc(6 * n1, sizeof(double)); -#pragma omp critical - { - if (!MSXRungeKuttaSolver.Ynew || !MSXRungeKuttaSolver.Ak) errorcode = 0; - } - - MSXRungeKuttaSolver.Nmax = n; - MSXRungeKuttaSolver.K1 = (MSXRungeKuttaSolver.Ak); - MSXRungeKuttaSolver.K2 = ((MSXRungeKuttaSolver.Ak)+(n1)); - MSXRungeKuttaSolver.K3 = ((MSXRungeKuttaSolver.Ak)+(2 * n1)); - MSXRungeKuttaSolver.K4 = ((MSXRungeKuttaSolver.Ak)+(3 * n1)); - MSXRungeKuttaSolver.K5 = ((MSXRungeKuttaSolver.Ak)+(4 * n1)); - MSXRungeKuttaSolver.K6 = ((MSXRungeKuttaSolver.Ak)+(5 * n1)); -} - - return errorcode; -} - -//============================================================================= - -void rk5_close() -/* -** Purpose: -** Closes the RK5 solver. -*/ -{ - -#pragma omp parallel -{ - if (MSXRungeKuttaSolver.Ynew) free(MSXRungeKuttaSolver.Ynew); - MSXRungeKuttaSolver.Ynew = NULL; - if (MSXRungeKuttaSolver.Ak) free(MSXRungeKuttaSolver.Ak); - MSXRungeKuttaSolver.Ak = NULL; - MSXRungeKuttaSolver.Nmax = 0; - MSXRungeKuttaSolver.Report = NULL; -} - -} - -//============================================================================= - -int rk5_integrate(double y[], int n, double t, double tnext, - double* htry, double atol[], double rtol[], - void (*func)(double, double*, int, double*)) -/* -** Purpose: -** Integrates system of equations dY/dt = F(t,Y) over a -** given interval. -** -** Input: -** y[] = values of dependent variables at start of interval -** n = number of dependent variables -** t = value of independent variable at start of interval -** tnext = value of independent variable at end of interval -** htry = initial step size -** atol[] = absolute error tolerance on each dependent variable -** rtol[] = relative error tolerance on each dependent variable -** func = pointer to function that evaluates dY/dt at given -** values of t and Y. -** -** Output: -** y[] = values of dependent variables at end of interval -** htry = last step size used -** -** Returns: -** number of function evaluations if successful, -1 if not -** successful within Itmax iterations or -2 if step size -** shrinks to 0. -*/ -{ - double c2=0.20, c3=0.30, c4=0.80, c5=8.0/9.0; - double a21=0.20, a31=3.0/40.0, a32=9.0/40.0, - a41=44.0/45.0, a42=-56.0/15.0, a43=32.0/9.0, - a51=19372.0/6561.0, a52=-25360.0/2187.0, a53=64448.0/6561.0, - a54=-212.0/729.0, a61=9017.0/3168.0, a62=-355.0/33.0, - a63=46732.0/5247.0, a64=49.0/176.0, a65=-5103.0/18656.0, - a71=35.0/384.0, a73=500.0/1113.0, a74=125.0/192.0, - a75=-2187.0/6784.0, a76=11.0/84.0; - double e1=71.0/57600.0, e3=-71.0/16695.0, e4=71.0/1920.0, - e5=-17253.0/339200.0, e6=22.0/525.0, e7=-1.0/40.0; - - double tnew, h, hmax, hnew, ytol, err, sk, fac, fac11 = 1.0; - int i; - -// --- parameters for step size control - - double UROUND = 2.3e-16; - double SAFE = 0.90; - double fac1 = 0.2; - double fac2 = 10.0; - double beta = 0.04; - double facold = 1.e-4; - double expo1 = 0.2 - beta*0.75; - double facc1 = 1.0/fac1; - double facc2 = 1.0/fac2; - -// --- various counters - - int nstep = 1; - int nfcn = 0; - int naccpt = 0; - int nrejct = 0; - int reject = 0; - int adjust = MSXRungeKuttaSolver.Adjust; - -// --- initial function evaluation - - func(t, y, n, MSXRungeKuttaSolver.K1); - nfcn++; - -// --- initial step size - h = *htry; - hmax = tnext - t; - if (h == 0.0) - { - adjust = 1; - h = tnext - t; - for (i=1; i<=n; i++) - { - ytol = atol[i] + rtol[i]*fabs(y[i]); - if (MSXRungeKuttaSolver.K1[i] != 0.0) - h = fmin(h, (ytol/fabs(MSXRungeKuttaSolver.K1[i]))); - } - } - h = fmax(1.e-8, h); - -// --- while not at end of time interval - - while (t < tnext) - { - // --- check for zero step size - if (0.10*fabs(h) <= fabs(t)*UROUND) return -2; - - // --- adjust step size if interval exceeded - if ((t + 1.01*h - tnext) > 0.0) h = tnext - t; - - tnew = t + c2*h; - for (i=1; i<=n; i++) - MSXRungeKuttaSolver.Ynew[i] = y[i] + h*a21* MSXRungeKuttaSolver.K1[i]; - func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K2); - - tnew = t + c3*h; - for (i=1; i<=n; i++) - MSXRungeKuttaSolver.Ynew[i] = y[i] + h*(a31* MSXRungeKuttaSolver.K1[i] + a32* MSXRungeKuttaSolver.K2[i]); - func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K3); - - tnew = t + c4*h; - for (i=1; i<=n; i++) - MSXRungeKuttaSolver.Ynew[i]=y[i] + h*(a41* MSXRungeKuttaSolver.K1[i] + a42* MSXRungeKuttaSolver.K2[i] + a43* MSXRungeKuttaSolver.K3[i]); - func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K4); - - tnew = t + c5*h; - for (i=1; i<=n; i++) - MSXRungeKuttaSolver.Ynew[i] = y[i] + h*(a51* MSXRungeKuttaSolver.K1[i] + a52* MSXRungeKuttaSolver.K2[i] + a53* MSXRungeKuttaSolver.K3[i]+a54* MSXRungeKuttaSolver.K4[i]); - func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K5); - - tnew = t + h; - for (i=1; i<=n; i++) - MSXRungeKuttaSolver.Ynew[i] = y[i] + h*(a61* MSXRungeKuttaSolver.K1[i] + a62* MSXRungeKuttaSolver.K2[i] + - a63* MSXRungeKuttaSolver.K3[i] + a64* MSXRungeKuttaSolver.K4[i] + a65* MSXRungeKuttaSolver.K5[i]); - func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K6); - - for (i=1; i<=n; i++) - MSXRungeKuttaSolver.Ynew[i] = y[i] + h*(a71* MSXRungeKuttaSolver.K1[i] + a73* MSXRungeKuttaSolver.K3[i] + - a74* MSXRungeKuttaSolver.K4[i] + a75* MSXRungeKuttaSolver.K5[i] + a76* MSXRungeKuttaSolver.K6[i]); - func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K2); - nfcn += 6; - - // --- step size adjustment - - err = 0.0; - hnew = h; - if (adjust) - { - for (i=1; i<=n; i++) - MSXRungeKuttaSolver.K4[i] = (e1* MSXRungeKuttaSolver.K1[i] + e3* MSXRungeKuttaSolver.K3[i] + e4* MSXRungeKuttaSolver.K4[i] + e5* MSXRungeKuttaSolver.K5[i] + - e6* MSXRungeKuttaSolver.K6[i] + e7* MSXRungeKuttaSolver.K2[i])*h; - - for (i=1; i<=n; i++) - { - sk = atol[i] + rtol[i]*fmax(fabs(y[i]), fabs(MSXRungeKuttaSolver.Ynew[i])); - sk = MSXRungeKuttaSolver.K4[i]/sk; - err = err + (sk*sk); - } - err = sqrt(err/n); - - // --- computation of hnew - fac11 = pow(err, expo1); - fac = fac11/pow(facold, beta); // LUND-stabilization - fac = fmax(facc2, fmin(facc1, (fac/SAFE))); // must have FAC1 <= HNEW/H <= FAC2 - hnew = h/fac; - } - - // --- step is accepted - - if( err <= 1.0 ) - { - facold = fmax(err, 1.0e-4); - naccpt++; - for (i=1; i<=n; i++) - { - MSXRungeKuttaSolver.K1[i] = MSXRungeKuttaSolver.K2[i]; - y[i] = MSXRungeKuttaSolver.Ynew[i]; - } - t = t + h; - if ( adjust && t <= tnext ) *htry = h; - if (fabs(hnew) > hmax) hnew = hmax; - if (reject) hnew = fmin(fabs(hnew), fabs(h)); - reject = 0; - if (MSXRungeKuttaSolver.Report) MSXRungeKuttaSolver.Report(t, y, n); - } - - // --- step is rejected - - else - { - if ( adjust ) hnew = h/fmin(facc1, (fac11/SAFE)); - reject = 1; - if (naccpt >= 1) nrejct++; - } - - // --- take another step - - h = hnew; - if ( adjust ) *htry = h; - nstep++; - if (nstep >= MSXRungeKuttaSolver.Itmax) return -1; - } - return nfcn; -} diff --git a/Src/rk5.h b/Src/rk5.h deleted file mode 100644 index f20f9f8..0000000 --- a/Src/rk5.h +++ /dev/null @@ -1,34 +0,0 @@ -/************************************************************************ -** MODULE: RK5.H -** PROJECT: EPANET-MSX -** DESCRIPTION: Header file for the ODE solver contained in RK5.C. -** AUTHOR: L. Rossman, US EPA - NRMRL -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -***********************************************************************/ - -typedef struct -{ - int Nmax; // max. number of equations - int Itmax; // max. number of integration steps - int Adjust; // use adjustable step size - double* Ak; // work arrays - double* K1; - double* K2; - double* K3; - double* K4; - double* K5; - double* K6; - double* Ynew; // updated solution - void (*Report) (double, double*, int); -}MSXRungeKutta; -// Opens the ODE solver system -int rk5_open(int n, int itmax, int adjust); - -// Closes the ODE solver system -void rk5_close(void); - -// Applies the solver to integrate a specific system of ODEs -int rk5_integrate(double y[], int n, double t, double tnext, - double* htry, double atol[], double rtol[], - void (*func)(double, double*, int, double*)); diff --git a/Src/ros2.c b/Src/ros2.c deleted file mode 100644 index 9647032..0000000 --- a/Src/ros2.c +++ /dev/null @@ -1,293 +0,0 @@ -/******************************************************************************* -** MODULE: ROS2.C -** PROJECT: EPANET-MSX -** DESCRIPTION: a second order Rosenbrock 2(1) method for solving stiff sets of -** ordinary differential equations. -** AUTHOR: L. Rossman, US EPA - NRMRL -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -** -** This code is based on material presented in: -** Verwer, J.G., Spee, E.J., Blom, J.G. and Hundsdorfer, W.H., -** "A second order Rosenbrock method applied to photochemical dispersion -** problems", SIAM J. Sci. Comput., 20:1456-1480, July 1999. -*******************************************************************************/ - -#include -#include -#include "msxutils.h" -#include "ros2.h" - -#define fmin(x,y) (((x)<=(y)) ? (x) : (y)) /* minimum of x and y */ -#define fmax(x,y) (((x)>=(y)) ? (x) : (y)) /* maximum of x and y */ - -// Local variables -//----------------- -MSXRosenbrock MSXRosenbrockSolver; - -#pragma omp threadprivate(MSXRosenbrockSolver) - -//============================================================================= - -int ros2_open(int n, int adjust) -/* -** Purpose: -** Opens the ROS2 integrator. -** -** Input: -** n = number of equations to be solved -** adjust = 1 if step size adjustment used, 0 if not -** -** Returns: -** 1 if successful, 0 if not. -*/ -{ - int errorcode = 1; - int n1 = n + 1; - -#pragma omp parallel -{ - MSXRosenbrockSolver.Nmax = n; - MSXRosenbrockSolver.Adjust = adjust; - MSXRosenbrockSolver.K1 = NULL; - MSXRosenbrockSolver.K2 = NULL; - MSXRosenbrockSolver.Jindx = NULL; - MSXRosenbrockSolver.Ynew = NULL; - MSXRosenbrockSolver.A = NULL; - MSXRosenbrockSolver.K1 = (double*)calloc(n1, sizeof(double)); - MSXRosenbrockSolver.K2 = (double*)calloc(n1, sizeof(double)); - MSXRosenbrockSolver.Jindx = (int*)calloc(n1, sizeof(int)); - MSXRosenbrockSolver.Ynew = (double*)calloc(n1, sizeof(double)); - MSXRosenbrockSolver.A = createMatrix(n1, n1); -#pragma omp critical - { - if (!MSXRosenbrockSolver.Jindx || !MSXRosenbrockSolver.Ynew || - !MSXRosenbrockSolver.K1 || !MSXRosenbrockSolver.K2) errorcode = 0; - if (!MSXRosenbrockSolver.A) errorcode = 0; - } -} - - return errorcode; -} - -//============================================================================= - -void ros2_close() -/* -** Purpose: -** closes the ROS2 integrator. -** -** Input: -** none. -*/ -{ - -#pragma omp parallel -{ - - if (MSXRosenbrockSolver.Jindx) { free(MSXRosenbrockSolver.Jindx); MSXRosenbrockSolver.Jindx = NULL; } - if (MSXRosenbrockSolver.Ynew) { free(MSXRosenbrockSolver.Ynew); MSXRosenbrockSolver.Ynew = NULL; } - if (MSXRosenbrockSolver.K1) { free(MSXRosenbrockSolver.K1); MSXRosenbrockSolver.K1 = NULL; } - if (MSXRosenbrockSolver.K2) { free(MSXRosenbrockSolver.K2); MSXRosenbrockSolver.K2 = NULL; } - freeMatrix(MSXRosenbrockSolver.A); - MSXRosenbrockSolver.A = NULL; -} - -} - -//============================================================================= - -int ros2_integrate(double y[], int n, double t, double tnext, - double* htry, double atol[], double rtol[], - void (*func)(double, double*, int, double*)) -/* -** Purpose: -** integrates a system of ODEs over a specified time interval. -** -** Input: -** y[1..n] = vector of dependent variable values at the start -** of the integration interval -** n = number of dependent variables -** t = time value at the start of the interval -** tnext = time value at the end of the interval -** htry = initial step size to be taken -** atol[1..n] = vector of absolute tolerances on the variables y -** rtol[1..n] = vector of relative tolerances on the variables y -** func = name of the function that computes dy/dt for each y -** -** Output: -** htry = size of the last full time step taken. -** -** Returns: -** the number of times that func() was called, -1 if -** the Jacobian is singular, or -2 if the step size -** shrinks to 0. -** -** Notes: -** 1. The arguments to the function func() are: -** t = current time -** y[1..n] = vector of dependent variable values -** n = number of dependent variables -** dfdy[1..n] = vector of derivative values computed. -** -** 2. The arrays used in this function are 1-based, so -** they must have been sized to n+1 when first created. -*/ -{ - double UROUND = 2.3e-16; - double g, ghinv, ghinv1, dghinv, ytol; - double h, hold, hmin, hmax, tplus; - double ej, err, factor, facmax; - int nfcn, njac, naccept, nreject, j; - int isReject; - int adjust = MSXRosenbrockSolver.Adjust; - -// --- Initialize counters, etc. - - g = 1.0 + 1.0 / sqrt(2.0); - ghinv1 = 0.0; - tplus = t; - isReject = 0; - naccept = 0; - nreject = 0; - nfcn = 0; - njac = 0; - -// --- Initial step size - - hmax = tnext - t; - hmin = 1.e-8; - h = *htry; - if ( h == 0.0 ) - { - func(t, y, n, MSXRosenbrockSolver.K1); - nfcn += 1; - adjust = 1; - h = tnext - t; - for (j=1; j<=n; j++) - { - ytol = atol[j] + rtol[j]*fabs(y[j]); - if (MSXRosenbrockSolver.K1[j] != 0.0) h = fmin(h, (ytol/fabs(MSXRosenbrockSolver.K1[j]))); - } - } - h = fmax(hmin, h); - h = fmin(hmax, h); - -// --- Start the time loop - - while ( t < tnext ) - { - // --- check for zero step size - - if (0.10*fabs(h) <= fabs(t)*UROUND) return -2; - - // --- adjust step size if interval exceeded - - tplus = t + h; - if ( tplus > tnext ) - { - h = tnext - t; - tplus = tnext; - } - - // --- Re-compute the Jacobian if step size accepted - - if ( isReject == 0 ) - { - jacobian(y, n, MSXRosenbrockSolver.K1, MSXRosenbrockSolver.K2, MSXRosenbrockSolver.A, func); - njac++; - nfcn += 2*n; - ghinv1 = 0.0; - } - - // --- Update the Jacobian to reflect new step size - - ghinv = -1.0 / (g*h); - dghinv = ghinv - ghinv1; - for (j=1; j<=n; j++) - { - MSXRosenbrockSolver.A[j][j] += dghinv; - } - ghinv1 = ghinv; - if ( !factorize(MSXRosenbrockSolver.A, n, MSXRosenbrockSolver.K1, MSXRosenbrockSolver.Jindx) ) return -1; - - // --- Stage 1 solution - - func(t, y, n, MSXRosenbrockSolver.K1); - nfcn += 1; - for (j=1; j<=n; j++) MSXRosenbrockSolver.K1[j] *= ghinv; - solve(MSXRosenbrockSolver.A, n, MSXRosenbrockSolver.Jindx, MSXRosenbrockSolver.K1); - - // --- Stage 2 solution - - for (j=1; j<=n; j++) - { - MSXRosenbrockSolver.Ynew[j] = y[j] + h* MSXRosenbrockSolver.K1[j]; - } - func(t, MSXRosenbrockSolver.Ynew, n, MSXRosenbrockSolver.K2); - nfcn += 1; - for (j=1; j<=n; j++) - { - MSXRosenbrockSolver.K2[j] = (MSXRosenbrockSolver.K2[j] - 2.0* MSXRosenbrockSolver.K1[j])*ghinv; - } - solve(MSXRosenbrockSolver.A, n, MSXRosenbrockSolver.Jindx, MSXRosenbrockSolver.K2); - - // --- Overall solution - - for (j=1; j<=n; j++) - { - MSXRosenbrockSolver.Ynew[j] = y[j] + 1.5*h* MSXRosenbrockSolver.K1[j] + 0.5*h* MSXRosenbrockSolver.K2[j]; - } - - // --- Error estimation - - hold = h; - err = 0.0; - if ( adjust ) - { - for (j=1; j<=n; j++) - { - ytol = atol[j] + rtol[j]*fabs(MSXRosenbrockSolver.Ynew[j]); - ej = fabs(MSXRosenbrockSolver.Ynew[j] - y[j] - h* MSXRosenbrockSolver.K1[j])/ytol; - err = err + ej*ej; - } - err = sqrt(err/n); - err = fmax(UROUND, err); - - // --- Choose the step size - - factor = 0.9 / sqrt(err); - if (isReject) facmax = 1.0; - else facmax = 10.0; - factor = fmin(factor, facmax); - factor = fmax(factor, 1.0e-1); - h = factor*h; - h = fmin(hmax, h); - } - - // --- Reject/accept the step - - if ( err > 1.0 ) - { - isReject = 1; - nreject++; - h = 0.5*h; - } - else - { - isReject = 0; - for (j=1; j<=n; j++) - { - y[j] = MSXRosenbrockSolver.Ynew[j]; - if ( y[j] <= UROUND ) y[j] = 0.0; - } - if ( adjust ) *htry = h; - t = tplus; - naccept++; - } - -// --- End of the time loop - - } - return nfcn; -} diff --git a/Src/ros2.h b/Src/ros2.h deleted file mode 100644 index bc36871..0000000 --- a/Src/ros2.h +++ /dev/null @@ -1,30 +0,0 @@ -/************************************************************************ -** MODULE: ROS2.H -** PROJECT: EPANET-MSX -** DESCRIPTION: Header file for the stiff ODE solver ROS2.C. -** AUTHOR: L. Rossman, US EPA - NRMRL -** VERSION: 2.0.00 -** LAST UPDATE: 04/14/2021 -***********************************************************************/ - -typedef struct { - - double** A; // Jacobian matrix - double* K1; // Intermediate solutions - double* K2; - double* Ynew; // Updated function values - int* Jindx; // Jacobian column indexes - int Nmax; // Max. number of equations - int Adjust; // use adjustable step size -}MSXRosenbrock; - -// Opens the ODE solver system -int ros2_open(int n, int adjust); - -// Closes the ODE solver system -void ros2_close(void); - -// Applies the solver to integrate a specific system of ODEs -int ros2_integrate(double y[], int n, double t, double tnext, - double* htry, double atol[], double rtol[], - void (*func)(double, double*, int, double*)); diff --git a/Src/smatrix.c b/Src/smatrix.c deleted file mode 100644 index c0f110c..0000000 --- a/Src/smatrix.c +++ /dev/null @@ -1,815 +0,0 @@ -/* -******************************************************************* -Modified from: - -SMATRIX.C -- Sparse matrix routines for EPANET program, VERSION: 2.0.0. - - -DATE: 5/8/00 -AUTHOR: L. Rossman - US EPA - NRMRL - -This module contains the sparse matrix routines used to solve -a network's hydraulic equations. The entry points into this -module are: - createsparse() -- called from openhyd() in HYDRAUL.C - freesparse() -- called from closehyd() in HYDRAUL.C - linsolve() -- called from netsolve() in HYDRAUL.C - -Createsparse() does the following: - 1. for each node, builds an adjacency list that identifies - all links connected to the node (see buildlists()) - 2. re-orders the network's nodes to minimize the number - of non-zero entries in the hydraulic solution matrix - (see reorder()) - 3. converts the adjacency lists into a compact scheme - for storing the non-zero coeffs. in the lower diagonal - portion of the solution matrix (see storesparse()) -Freesparse() frees the memory used for the sparse matrix. -Linsolve() solves the linearized system of hydraulic equations. - -******************************************************************** -*/ - -#include -#include -#include -#include -#include "hash.h" -#include "msxtypes.h" -#include "smatrix.h" -#include "dispersion.h" -#define EXTERN extern - - - -// External variables -//-------------------- -extern MSXproject MSX; // MSX project data -#define ERRCODE(x) (errcode = ((errcode>100) ? (errcode) : (x))) - - - - -int createsparse() -/* -**-------------------------------------------------------------- -** Input: none -** Output: returns error code -** Purpose: creates sparse representation of coeff. matrix -**-------------------------------------------------------------- -*/ -{ - int errcode = 0; - int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; - - /* Allocate data structures */ - ERRCODE(allocsparse()); - if (errcode) return(errcode); - - /* Build node-link adjacency lists with parallel links removed. */ - - ERRCODE(buildlists(TRUE)); //TRUE localadjlists in 2.2 - if (!errcode) - { - xparalinks(); /* Remove parallel links */ - countdegree(); /* Find degree of each junction */ - } /* (= # of adjacent links) */ - - /* Re-order nodes to minimize number of non-zero coeffs. */ - /* in factorized solution matrix. At same time, adjacency */ - /* list is updated with links representing non-zero coeffs. */ - MSX.Dispersion.Ncoeffs = MSX.Nobjects[LINK]; - ERRCODE(reordernodes()); - - /* Allocate memory for sparse storage of positions of non-zero */ - /* coeffs. and store these positions in vector NZSUB. */ - ERRCODE(storesparse(njuncs)); - - /* Free memory used for adjacency lists and sort */ - /* row indexes in NZSUB to optimize linsolve(). */ - if (!errcode) freelists(); - ERRCODE(ordersparse(njuncs)); - - MSX.Dispersion.Aij = (double*)calloc(MSX.Dispersion.Ncoeffs + 1, sizeof(double)); - MSX.Dispersion.Aii = (double*)calloc(MSX.Nobjects[NODE]+1, sizeof(double)); - MSX.Dispersion.F = (double*)calloc(MSX.Nobjects[NODE]+1, sizeof(double)); - MSX.Dispersion.temp = (double*)calloc(MSX.Nobjects[NODE] + 1, sizeof(double)); - MSX.Dispersion.link = (int*)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); - MSX.Dispersion.first = (int*)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); - ERRCODE(MEMCHECK(MSX.Dispersion.Aij)); - ERRCODE(MEMCHECK(MSX.Dispersion.Aii)); - ERRCODE(MEMCHECK(MSX.Dispersion.F)); - ERRCODE(MEMCHECK(MSX.Dispersion.temp)); - ERRCODE(MEMCHECK(MSX.Dispersion.link)); - ERRCODE(MEMCHECK(MSX.Dispersion.first)); - - // MSX.Dispersion.md = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); - - MSX.Dispersion.pipeDispersionCoeff = (double*)calloc(MSX.Nobjects[LINK] + 1, sizeof(double)); - - - - ERRCODE(MEMCHECK(MSX.Dispersion.ld)); - ERRCODE(MEMCHECK(MSX.Dispersion.md)); - - - dispersion_open(); - - /* Re-build adjacency lists without removing parallel */ - /* links for use in future connectivity checking. */ - ERRCODE(buildlists(FALSE)); //FALSE buildadjlists in 2.2 - - /* Free allocated memory */ - free(MSX.Dispersion.Degree); - return(errcode); -} /* End of createsparse */ - - -int allocsparse() -/* -**-------------------------------------------------------------- -** Input: none -** Output: returns error code -** Purpose: allocates memory for indexing the solution matrix -**-------------------------------------------------------------- -*/ -{ - int errcode = 0; - int nnodes = MSX.Nobjects[NODE]; - int nlinks = MSX.Nobjects[LINK]; - MSX.Dispersion.Aii = NULL; - MSX.Dispersion.Aij = NULL; - MSX.Dispersion.F = NULL; - MSX.Dispersion.temp = NULL; - MSX.Dispersion.link = NULL; - MSX.Dispersion.first = NULL; - - MSX.Dispersion.Adjlist = (Padjlist *) calloc(nnodes+1, sizeof(Padjlist)); - MSX.Dispersion.Order = (int *) calloc(nnodes+1, sizeof(int)); - MSX.Dispersion.Row = (int *) calloc(nnodes+1, sizeof(int)); - MSX.Dispersion.Ndx = (int *) calloc(nlinks+1, sizeof(int)); - ERRCODE(MEMCHECK(MSX.Dispersion.Adjlist)); - ERRCODE(MEMCHECK(MSX.Dispersion.Order)); - ERRCODE(MEMCHECK(MSX.Dispersion.Row)); - ERRCODE(MEMCHECK(MSX.Dispersion.Ndx)); - return(errcode); -} - - -void freesparse() -/* -**---------------------------------------------------------------- -** Input: None -** Output: None -** Purpose: Frees memory used for sparse matrix storage -**---------------------------------------------------------------- -*/ -{ - freelists(); - FREE(MSX.Dispersion.Adjlist); - FREE(MSX.Dispersion.Order); - FREE(MSX.Dispersion.Row); - FREE(MSX.Dispersion.Ndx); - FREE(MSX.Dispersion.XLNZ); - FREE(MSX.Dispersion.NZSUB); - FREE(MSX.Dispersion.LNZ); - FREE(MSX.Dispersion.Aii); - FREE(MSX.Dispersion.Aij); - FREE(MSX.Dispersion.F); - FREE(MSX.Dispersion.link); - FREE(MSX.Dispersion.first); - FREE(MSX.Dispersion.temp); - - FREE(MSX.Dispersion.md); - - FREE(MSX.Dispersion.pipeDispersionCoeff); - dispersion_close(); - - - - -} /* End of freesparse */ - - -int buildlists(int paraflag) -/* -**-------------------------------------------------------------- -** Input: paraflag = TRUE if list marks parallel links -** Output: returns error code -** Purpose: builds linked list of links adjacent to each node -**-------------------------------------------------------------- -*/ -{ - int i,j,k; - int pmark = 0; - int errcode = 0; - int nlinks = MSX.Nobjects[LINK]; - Padjlist alink; - - freelists(); - MSX.Dispersion.Adjlist = (Padjlist*)calloc(MSX.Nobjects[NODE] + 1, sizeof(Padjlist)); - if (MSX.Dispersion.Adjlist == NULL) return 101; - for (i = 0; i <= MSX.Nobjects[NODE]; i++) - MSX.Dispersion.Adjlist[i] = NULL; - - /* For each link, update adjacency lists of its end nodes */ - for (k=1; k<=nlinks; k++) - { - i = MSX.Link[k].n1; - j = MSX.Link[k].n2; - if (paraflag) pmark = paralink(i,j,k); /* Parallel link check */ - - /* Include link in start node i's list */ - alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist)); - if (alink == NULL) return(101); - if (!pmark) alink->node = j; - else alink->node = 0; /* Parallel link marker */ - alink->link = k; - alink->next = MSX.Dispersion.Adjlist[i]; - MSX.Dispersion.Adjlist[i] = alink; - - /* Include link in end node j's list */ - alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist)); - if (alink == NULL) return(101); - if (!pmark) alink->node = i; - else alink->node = 0; /* Parallel link marker */ - alink->link = k; - alink->next = MSX.Dispersion.Adjlist[j]; - MSX.Dispersion.Adjlist[j] = alink; - } - if (errcode)freelists(); - return(errcode); -} /* End of buildlists */ - - -int paralink(int i, int j, int k) -/* -**-------------------------------------------------------------- -** Input: i = index of start node of link -** j = index of end node of link -** k = link index -** Output: returns 1 if link k parallels another link, else 0 -** Purpose: checks for parallel links between nodes i and j -** -**-------------------------------------------------------------- -*/ -{ - Padjlist alink; - for (alink = MSX.Dispersion.Adjlist[i]; alink != NULL; alink = alink->next) - { - if (alink->node == j) /* Link || to k (same end nodes) */ - { - MSX.Dispersion.Ndx[k] = alink->link; /* Assign Ndx entry to this link */ - return(1); - } - } - MSX.Dispersion.Ndx[k] = k; /* Ndx entry if link not parallel */ - return(0); -} /* End of paralink */ - - -void xparalinks() -/* -**-------------------------------------------------------------- -** Input: none -** Output: none -** Purpose: removes parallel links from nodal adjacency lists -**-------------------------------------------------------------- -*/ -{ - int i; - Padjlist alink, /* Current item in adjacency list */ - blink; /* Previous item in adjacency list */ - int nnodes = MSX.Nobjects[NODE]; - - /* Scan adjacency list of each node */ - for (i=1; i<=nnodes; i++) - { - alink = MSX.Dispersion.Adjlist[i]; /* First item in list */ - blink = NULL; - while (alink != NULL) - { - if (alink->node == 0) /* Parallel link marker found */ - { - if (blink == NULL) /* This holds at start of list */ - { - MSX.Dispersion.Adjlist[i] = alink->next; - free(alink); /* Remove item from list */ - alink = MSX.Dispersion.Adjlist[i]; - } - else /* This holds for interior of list */ - { - blink->next = alink->next; - free(alink); /* Remove item from list */ - alink = blink->next; - } - } - else - { - blink = alink; /* Move to next item in list */ - alink = alink->next; - } - } - } -} /* End of xparalinks */ - - -void freelists() -/* -**-------------------------------------------------------------- -** Input: none -** Output: none -** Purpose: frees memory used for nodal adjacency lists -**-------------------------------------------------------------- -*/ -{ - int i; - Padjlist alink; - int nnodes = MSX.Nobjects[NODE]; - - if (MSX.Dispersion.Adjlist == NULL) - return; - for (i=0; i<=nnodes; i++) - { - for (alink = MSX.Dispersion.Adjlist[i]; alink != NULL; alink = MSX.Dispersion.Adjlist[i]) - { - MSX.Dispersion.Adjlist[i] = alink->next; - free(alink); - } - } - free(MSX.Dispersion.Adjlist); - MSX.Dispersion.Adjlist = NULL; -} /* End of freelists */ - - -void countdegree() -/* -**---------------------------------------------------------------- -** Input: none -** Output: none -** Purpose: counts number of nodes directly connected to each node -**---------------------------------------------------------------- -*/ -{ - int i; - Padjlist alink; - - int nnodes = MSX.Nobjects[NODE]; - int njuncs = MSX.Nobjects[NODE]-MSX.Nobjects[TANK]; - int errcode; - - errcode = 0; - - MSX.Dispersion.Degree = (int *)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); - ERRCODE(MEMCHECK(MSX.Dispersion.Degree)); - memset(MSX.Dispersion.Degree,0,(nnodes+1)*sizeof(int)); - - /* NOTE: For purposes of node re-ordering, Tanks (nodes with */ - /* indexes above Njuncs) have zero degree of adjacency. */ - - for (i=1; i<=njuncs; i++) - for (alink = MSX.Dispersion.Adjlist[i]; alink != NULL; alink = alink->next) - if (alink->node > 0) MSX.Dispersion.Degree[i]++; -} - - -int reordernodes() -/* -**-------------------------------------------------------------- -** Input: none -** Output: returns 1 if successful, 0 if not -** Purpose: re-orders nodes to minimize # of non-zeros that -** will appear in factorized solution matrix -**-------------------------------------------------------------- -*/ -{ - int k, knode, m, n; - int nnodes = MSX.Nobjects[NODE]; - int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; - for (k=1; k<=nnodes; k++) - { - MSX.Dispersion.Row[k] = k; - MSX.Dispersion.Order[k] = k; - } - n = njuncs; - for (k=1; k<=n; k++) /* Examine each junction */ - { - m = mindegree(k,n); /* Node with lowest degree */ - knode = MSX.Dispersion.Order[m]; /* Node's index */ - if (!growlist(knode)) return(101); /* Augment adjacency list */ - MSX.Dispersion.Order[m] = MSX.Dispersion.Order[k]; /* Switch order of nodes */ - MSX.Dispersion.Order[k] = knode; - MSX.Dispersion.Degree[knode] = 0; /* In-activate node */ - } - for (k=1; k<=n; k++) /* Assign nodes to rows of */ - MSX.Dispersion.Row[MSX.Dispersion.Order[k]] = k; /* coeff. matrix */ - return(0); -} /* End of reordernodes */ - - -int mindegree(int k, int n) -/* -**-------------------------------------------------------------- -** Input: k = first node in list of active nodes -** n = total number of junction nodes -** Output: returns node index with fewest direct connections -** Purpose: finds active node with fewest direct connections -**-------------------------------------------------------------- -*/ -{ - int i, m; - int min = n, - imin = n; - - for (i=k; i<=n; i++) - { - m = MSX.Dispersion.Degree[MSX.Dispersion.Order[i]]; - if (m < min) - { - min = m; - imin = i; - } - } - return(imin); -} /* End of mindegree */ - - -int growlist(int knode) -/* -**-------------------------------------------------------------- -** Input: knode = node index -** Output: returns 1 if successful, 0 if not -** Purpose: creates new entries in knode's adjacency list for -** all unlinked pairs of active nodes that are -** adjacent to knode -**-------------------------------------------------------------- -*/ -{ - int node; - Padjlist alink; - - /* Iterate through all nodes connected to knode */ - for (alink = MSX.Dispersion.Adjlist[knode]; alink != NULL; alink = alink -> next) - { - node = alink->node; /* End node of connecting link */ - if (MSX.Dispersion.Degree[node] > 0) /* End node is active */ - { - MSX.Dispersion.Degree[node]--; /* Reduce degree of adjacency */ - if (!newlink(alink)) /* Add to adjacency list */ - return(0); - } - } - return(1); -} /* End of growlist */ - - -int newlink(Padjlist alink) -/* -**-------------------------------------------------------------- -** Input: alink = element of node's adjacency list -** Output: returns 1 if successful, 0 if not -** Purpose: links end of current adjacent link to end nodes of -** all links that follow it on adjacency list -**-------------------------------------------------------------- -*/ -{ - int inode, jnode; - Padjlist blink; - - /* Scan all entries in adjacency list that follow anode. */ - inode = alink->node; /* End node of connection to anode */ - for (blink = alink->next; blink != NULL; blink = blink->next) - { - jnode = blink->node; /* End node of next connection */ - - /* If jnode still active, and inode not connected to jnode, */ - /* then add a new connection between inode and jnode. */ - if (MSX.Dispersion.Degree[jnode] > 0) /* jnode still active */ - { - if (!linked(inode,jnode)) /* inode not linked to jnode */ - { - - /* Since new connection represents a non-zero coeff. */ - /* in the solution matrix, update the coeff. count. */ - MSX.Dispersion.Ncoeffs++; - - /* Update adjacency lists for inode & jnode to */ - /* reflect the new connection. */ - if (!addlink(inode,jnode,MSX.Dispersion.Ncoeffs)) return(0); - if (!addlink(jnode,inode,MSX.Dispersion.Ncoeffs)) return(0); - MSX.Dispersion.Degree[inode]++; - MSX.Dispersion.Degree[jnode]++; - } - } - } - return(1); -} /* End of newlink */ - - -int linked(int i, int j) -/* -**-------------------------------------------------------------- -** Input: i = node index -** j = node index -** Output: returns 1 if nodes i and j are linked, 0 if not -** Purpose: checks if nodes i and j are already linked. -**-------------------------------------------------------------- -*/ -{ - Padjlist alink; - for (alink = MSX.Dispersion.Adjlist[i]; alink != NULL; alink = alink->next) - if (alink->node == j) return(1); - return(0); -} /* End of linked */ - - -int addlink(int i, int j, int n) -/* -**-------------------------------------------------------------- -** Input: i = node index -** j = node index -** n = link index -** Output: returns 1 if successful, 0 if not -** Purpose: augments node i's adjacency list with node j -**-------------------------------------------------------------- -*/ -{ - Padjlist alink; - alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist)); - if (alink == NULL) return(0); - alink->node = j; - alink->link = n; - alink->next = MSX.Dispersion.Adjlist[i]; - MSX.Dispersion.Adjlist[i] = alink; - return(1); -} /* End of addlink */ - - -int storesparse(int n) -/* -**-------------------------------------------------------------- -** Input: n = number of rows in solution matrix -** Output: returns error code -** Purpose: stores row indexes of non-zeros of each column of -** lower triangular portion of factorized matrix -**-------------------------------------------------------------- -*/ -{ - Padjlist alink; - int i, ii, j, k, l, m; - int errcode = 0; - - /* Allocate sparse matrix storage */ - MSX.Dispersion.XLNZ = (int *) calloc(n+2, sizeof(int)); - MSX.Dispersion.NZSUB = (int *) calloc(MSX.Dispersion.Ncoeffs+2, sizeof(int)); - MSX.Dispersion.LNZ = (int *) calloc(MSX.Dispersion.Ncoeffs+2, sizeof(int)); - ERRCODE(MEMCHECK(MSX.Dispersion.XLNZ)); - ERRCODE(MEMCHECK(MSX.Dispersion.NZSUB)); - ERRCODE(MEMCHECK(MSX.Dispersion.LNZ)); - if (errcode) return(errcode); - - /* Generate row index pointers for each column of matrix */ - k = 0; - MSX.Dispersion.XLNZ[1] = 1; - for (i=1; i<=n; i++) /* column */ - { - m = 0; - ii = MSX.Dispersion.Order[i]; - for (alink = MSX.Dispersion.Adjlist[ii]; alink != NULL; alink = alink->next) - { - j = MSX.Dispersion.Row[alink->node]; /* row */ - l = alink->link; - if (j > i && j <= n) - { - m++; - k++; - MSX.Dispersion.NZSUB[k] = j; - MSX.Dispersion.LNZ[k] = l; - } - } - MSX.Dispersion.XLNZ[i+1] = MSX.Dispersion.XLNZ[i] + m; - } - return(errcode); -} /* End of storesparse */ - - -int ordersparse(int n) -/* -**-------------------------------------------------------------- -** Input: n = number of rows in solution matrix -** Output: returns eror code -** Purpose: puts row indexes in ascending order in NZSUB -**-------------------------------------------------------------- -*/ -{ - int i, k; - int *xlnzt, *nzsubt, *lnzt, *nzt; - int errcode = 0; - - xlnzt = (int *) calloc(n+2, sizeof(int)); - nzsubt = (int *) calloc(MSX.Dispersion.Ncoeffs+2, sizeof(int)); - lnzt = (int *) calloc(MSX.Dispersion.Ncoeffs+2, sizeof(int)); - nzt = (int *) calloc(n+2, sizeof(int)); - ERRCODE(MEMCHECK(xlnzt)); - ERRCODE(MEMCHECK(nzsubt)); - ERRCODE(MEMCHECK(lnzt)); - ERRCODE(MEMCHECK(nzt)); - if (!errcode) - { - - /* Count # non-zeros in each row */ - for (i=1; i<=n; i++) nzt[i] = 0; - for (i=1; i<=n; i++) - { - for (k=MSX.Dispersion.XLNZ[i]; k= istrt) - { - - /* Before modification, update vectors 'first' */ - /* and 'link' for future modification steps. */ - MSX.Dispersion.first[k] = istrt; - isub = MSX.Dispersion.NZSUB[istrt]; - MSX.Dispersion.link[k] = MSX.Dispersion.link[isub]; - MSX.Dispersion.link[isub] = k; - - /* The actual mod is saved in vector 'temp'. */ - for (i=istrt; i<=istop; i++) - { - isub = MSX.Dispersion.NZSUB[i]; - MSX.Dispersion.temp[isub] += Aij[MSX.Dispersion.LNZ[i]]*ljk; - } - } - k = newk; - } - - /* Apply the modifications accumulated */ - /* in 'temp' to column L(*,j). */ - diagj = Aii[j] - diagj; - if (diagj <= 0.0) /* Check for ill-conditioning */ - { - errcode = j; - return errcode; - } - diagj = sqrt(diagj); - Aii[j] = diagj; - istrt = MSX.Dispersion.XLNZ[j]; - istop = MSX.Dispersion.XLNZ[j+1] - 1; - if (istop >= istrt) - { - MSX.Dispersion.first[j] = istrt; - isub = MSX.Dispersion.NZSUB[istrt]; - MSX.Dispersion.link[j] = MSX.Dispersion.link[isub]; - MSX.Dispersion.link[isub] = j; - for (i=istrt; i<=istop; i++) - { - isub = MSX.Dispersion.NZSUB[i]; - bj = (Aij[MSX.Dispersion.LNZ[i]] - MSX.Dispersion.temp[isub])/diagj; - Aij[MSX.Dispersion.LNZ[i]] = bj; - MSX.Dispersion.temp[isub] = 0.0; - } - } - } /* next j */ - - /* Foward substitution */ - for (j=1; j<=n; j++) - { - bj = B[j]/Aii[j]; - B[j] = bj; - istrt = MSX.Dispersion.XLNZ[j]; - istop = MSX.Dispersion.XLNZ[j+1] - 1; - if (istop >= istrt) - { - for (i=istrt; i<=istop; i++) - { - isub = MSX.Dispersion.NZSUB[i]; - B[isub] -= Aij[MSX.Dispersion.LNZ[i]]*bj; - } - } - } - - /* Backward substitution */ - for (j=n; j>=1; j--) - { - bj = B[j]; - istrt = MSX.Dispersion.XLNZ[j]; - istop = MSX.Dispersion.XLNZ[j+1] - 1; - if (istop >= istrt) - { - for (i=istrt; i<=istop; i++) - { - isub = MSX.Dispersion.NZSUB[i]; - bj -= Aij[MSX.Dispersion.LNZ[i]]*B[isub]; - } - } - B[j] = bj/Aii[j]; - } - - return(errcode); -} /* End of linsolve */ - - -/************************ END OF SMATRIX.C ************************/ - diff --git a/Src/smatrix.h b/Src/smatrix.h deleted file mode 100644 index 18b1b95..0000000 --- a/Src/smatrix.h +++ /dev/null @@ -1,21 +0,0 @@ -/* ----------- SMATRIX.C ---------------*/ -int createsparse(void); /* Creates sparse matrix */ -int allocsparse(void); /* Allocates matrix memory */ -void freesparse(void); /* Frees matrix memory */ -int buildlists(int); /* Builds adjacency lists */ -int paralink(int, int, int); /* Checks for parallel links */ -void xparalinks(void); /* Removes parallel links */ -void freelists(void); /* Frees adjacency lists */ -void countdegree(void); /* Counts links at each node */ -int reordernodes(void); /* Finds a node re-ordering */ -int mindegree(int, int); /* Finds min. degree node */ -int growlist(int); /* Augments adjacency list */ -int newlink(Padjlist); /* Adds fill-ins for a node */ -int linked(int, int); /* Checks if 2 nodes linked */ -int addlink(int, int, int); /* Creates new fill-in */ -int storesparse(int); /* Stores sparse matrix */ -int ordersparse(int); /* Orders matrix storage */ -void transpose(int, int*, int*, /* Transposes sparse matrix */ - int*, int*, int*, int*, int*); -int linsolve(int, double*, double*, /* Solution of linear eqns. */ - double*); /* via Cholesky factorization */ \ No newline at end of file diff --git a/readme.md b/readme.md index 4090421..88b8f44 100644 --- a/readme.md +++ b/readme.md @@ -3,6 +3,12 @@ The EPANET-MSX 2.0 is a free software program and can be used to model water quality problems involving multiple components. EPANET-MSX will only run correctly with release 2.2 or higher of the EPANET2 engine. +## Build Status +[![Build and Test](../../actions/workflows/build-and-test.yml/badge.svg)](../../actions/workflows/build-and-test.yml) + + +## Build Instructions + CMake (https://cmake.org/) can be used to build EPANETMSX applications. The project's CMake file (CMakeLists.txt) is located in its root directory and supports builds for Linux, Mac OS and Windows. To build the EPANETMSX library and its command line executable using CMake, first open a console window and navigate to the project's root directory. Then enter the following commands: @@ -15,4 +21,6 @@ cmake --build . --config Release Note: under Windows, the third command should be cmake .. -A Win32 for a 32-bit build or cmake .. -A x64 for a 64-bit build when Microsoft Visual Studio is the default compiler. 64-bit EPANETMSX application need to work with 64-bit EPANET2 engine. +# Documentation + EPANET-MSX manual can be found here: [MSX manual](https://github.com/USEPA/EPANETMSX/blob/master/Doc/EPANETMSX.pdf) diff --git a/run/CMakeLists.txt b/run/CMakeLists.txt deleted file mode 100644 index a980cd4..0000000 --- a/run/CMakeLists.txt +++ /dev/null @@ -1,43 +0,0 @@ -# EPANETMSX COMMAND LINE EXECUTABLE -cmake_minimum_required (VERSION 2.8.8) -# Sets for output directory for executables and libraries. -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -set(RELEASEVAR, "Release") -set(DEBUGVAR, "Debug") - -# Sets the position independent code property for all targets. -set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -# Link to multi-threaded static runtime library -IF (MSVC) - add_definitions(-D_CRT_SECURE_NO_DEPRECATE -MT) -ENDIF (MSVC) - - -# Set up file groups for exe target -set(MSX_CLI_SOURCES msxmain.c) -include_directories(include) - -source_group("CLI" FILES ${MSX_CLI_SOURCES}) - -# Creates the EPANET-MSX command line executable -add_executable(runepanetmsx ${MSX_CLI_SOURCES}) -target_compile_definitions(runepanetmsx PUBLIC FOO=1) - -IF(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)") - find_library(EPANET_LIB epanet2 NAMES epanet2 PATHS ${PROJECT_SOURCE_DIR}/include/x86 NO_DEFAULT_PATH) - target_link_libraries(runepanetmsx LINK_PUBLIC epanetmsx ${EPANET_LIB}) - add_custom_command( - TARGET runepanetmsx - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/x86/epanet2.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/epanet2.dll - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/runvc.bat ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/runvc.bat) -else(TRUE) - find_library(EPANET_LIB epanet2 NAMES epanet2 PATHS ${PROJECT_SOURCE_DIR}/include/x64 NO_DEFAULT_PATH) - target_link_libraries(runepanetmsx LINK_PUBLIC epanetmsx ${EPANET_LIB}) - add_custom_command( - TARGET runepanetmsx - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/x64/epanet2.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/epanet2.dll - COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/runvc.bat ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/runvc.bat) -endif(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)") diff --git a/run/msxmain.c b/run/msxmain.c deleted file mode 100644 index 138f3e3..0000000 --- a/run/msxmain.c +++ /dev/null @@ -1,177 +0,0 @@ -/******************************************************************************* -** MODULE: MSXMAIN.C -** PROJECT: EPANET-MSX -** DESCRIPTION: Main module of the EPANET Multi-Species Extension toolkit. -** AUTHORS: see AUTHORS -** Copyright: see AUTHORS -** License: see LICENSE -** VERSION: 2.0.00 -** LAST UPDATE: 08/30/2022 -** -** EPANET-MSX is an extension of the EPANET program for modeling the fate -** and transport of multiple interacting chemical species within a water -** distribution system over an extended period of operation. This module -** provides a main function for producing a stand-alone console -** application version of EPANET-MSX. It is not needed when compiling -** EPANET-MSX into a dynamic link library (DLL) of callable functions. -** -** To use either the console version or the DLL a user must prepare a -** regular EPANET input file that describes the pipe network layout -** and its hydraulic properties as well as a special EPANET-MSX input file -** that names the chemical species being modeled and specifies the reaction -** rate and equilbrium expressions that define their chemical behavior. The -** format of these files is described in the EPANET and EPANET-MSX Users -** Manuals, respectively. -*******************************************************************************/ - -#include -#include -#include -#include "epanet2.h" // EPANET toolkit header file -#include "epanetmsx.h" // EPANET-MSX toolkit header file -#include -int main(int argc, char* argv[]) -/* -** Purpose: -** main function for the console version of EPANET-MSX. -** -** Input: -** argc = number of command line arguments -** argv = array of command line arguments. -** -** Returns: -** an error code (or 0 for no error). -** -** Notes: -** The command line arguments are: -** - the name of the regular EPANET input data file -** - the name of the EPANET-MSX input file -** - the name of a report file that will contain status -** messages and output results -** - optionally, the name of an output file that will -** contain water quality results in binary format. -*/ -{ - int err, done = 1; - double t, tleft; - long oldHour, newHour; - char* inpFile, * repFile, * outFile; - - // --- check command line arguments - - if (argc < 4 || argc > 5) - { - printf("\nInvalid command line arguments:\n\n"); - printf("usage: runepanetmsx [binary_output_file]\n"); - return 0; - } - inpFile = argv[1]; - repFile = argv[3]; - if (argc == 5) { - outFile = argv[4]; - } - else { - outFile = ""; - } - - // --- open EPANET file - - printf("\n... EPANET-MSX Version 2.0.0\n"); - printf("\n o Processing EPANET input file"); - err = ENopen(inpFile, repFile, outFile); - do - { - if (err) - { - printf("\n\n... Cannot read EPANET file; error code = %d\n", err); - ENclose(); - return err; - } - - // --- open the MSX input file - - printf("\n o Processing MSX input file "); - err = MSXopen(argv[2]); - if (err) - { - printf("\n\n... Cannot read EPANET-MSX file; error code = %d\n", err); - break; - } - - //--- solve hydraulics - - printf("\n o Computing network hydraulics"); - err = MSXsolveH(); - if (err) - { - printf("\n\n... Cannot obtain network hydraulics; error code = %d\n", err); - break; - } - - //--- Initialize the multi-species analysis - - printf("\n o Initializing network water quality"); - err = MSXinit(1); - if (err) - { - printf("\n\n... Cannot initialize EPANET-MSX; error code = %d\n", err); - break; - } - t = 0; - oldHour = -1; - newHour = 0; - printf("\n"); - - //--- Run the multi-species analysis at each time step - - do - { - if (oldHour != newHour) - { - printf("\r o Computing water quality at hour %d", newHour); - oldHour = newHour; - } - err = MSXstep(&t, &tleft); - newHour = (long)(t / 3600.); - - } while (!err && tleft > 0); - if (err) - { - printf("\n\n... EPANET-MSX runtime error; error code = %d\n", err); - break; - } - else - printf("\r o Computing water quality at hour %d", (long)(t / 3600.)); - - // --- report results - - printf("\n o Reporting water quality results"); - err = MSXreport(); - if (err) - { - printf("\n\n... EPANET-MSX report writer error; error code = %d\n", err); - break; - } - - // --- save results to binary file if a file name was provided - - if (argc >= 5) - { - err = MSXsaveoutfile(argv[4]); - if (err > 0) - { - printf("\n\n... Cannot save EPANET-MSX results file; error code = %d\n", err); - break; - } - } - - } while (!done); - - //--- Close both the multi-species & EPANET systems - - MSXclose(); - ENclose(); - if (!err) printf("\n\n... EPANET-MSX completed successfully."); - printf("\n"); - return err; -} From dcdb003ff23d0f0d0e5f3da3556d40ae4828f46e Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 13:44:18 -0500 Subject: [PATCH 05/32] Configuring build --- src/run/CMakeLists.txt | 101 ++ src/run/msxmain.c | 177 ++++ src/solver/CMakeLists.txt | 123 +++ src/solver/dispersion.h | 22 + src/solver/hash.c | 106 ++ src/solver/hash.h | 24 + src/solver/mathexpr.c | 936 +++++++++++++++++ src/solver/mathexpr.h | 34 + src/solver/mempool.c | 204 ++++ src/solver/mempool.h | 19 + src/solver/msxchem.c | 1285 +++++++++++++++++++++++ src/solver/msxcompiler.c | 367 +++++++ src/solver/msxdict.h | 36 + src/solver/msxdispersion.c | 584 +++++++++++ src/solver/msxerr.c | 116 +++ src/solver/msxfile.c | 260 +++++ src/solver/msxfuncs.c | 165 +++ src/solver/msxfuncs.h | 35 + src/solver/msxinp.c | 1505 +++++++++++++++++++++++++++ src/solver/msxout.c | 398 +++++++ src/solver/msxproj.c | 791 ++++++++++++++ src/solver/msxqual.c | 2009 ++++++++++++++++++++++++++++++++++++ src/solver/msxrpt.c | 400 +++++++ src/solver/msxtank.c | 422 ++++++++ src/solver/msxtoolkit.c | 1132 ++++++++++++++++++++ src/solver/msxtypes.h | 547 ++++++++++ src/solver/msxutils.c | 525 ++++++++++ src/solver/msxutils.h | 51 + src/solver/newton.c | 158 +++ src/solver/newton.h | 29 + src/solver/rk5.c | 287 ++++++ src/solver/rk5.h | 34 + src/solver/ros2.c | 293 ++++++ src/solver/ros2.h | 30 + src/solver/smatrix.c | 815 +++++++++++++++ src/solver/smatrix.h | 21 + 36 files changed, 14041 insertions(+) create mode 100644 src/run/CMakeLists.txt create mode 100644 src/run/msxmain.c create mode 100644 src/solver/CMakeLists.txt create mode 100644 src/solver/dispersion.h create mode 100644 src/solver/hash.c create mode 100644 src/solver/hash.h create mode 100644 src/solver/mathexpr.c create mode 100644 src/solver/mathexpr.h create mode 100644 src/solver/mempool.c create mode 100644 src/solver/mempool.h create mode 100644 src/solver/msxchem.c create mode 100644 src/solver/msxcompiler.c create mode 100644 src/solver/msxdict.h create mode 100644 src/solver/msxdispersion.c create mode 100644 src/solver/msxerr.c create mode 100644 src/solver/msxfile.c create mode 100644 src/solver/msxfuncs.c create mode 100644 src/solver/msxfuncs.h create mode 100644 src/solver/msxinp.c create mode 100644 src/solver/msxout.c create mode 100644 src/solver/msxproj.c create mode 100644 src/solver/msxqual.c create mode 100644 src/solver/msxrpt.c create mode 100644 src/solver/msxtank.c create mode 100644 src/solver/msxtoolkit.c create mode 100644 src/solver/msxtypes.h create mode 100644 src/solver/msxutils.c create mode 100644 src/solver/msxutils.h create mode 100644 src/solver/newton.c create mode 100644 src/solver/newton.h create mode 100644 src/solver/rk5.c create mode 100644 src/solver/rk5.h create mode 100644 src/solver/ros2.c create mode 100644 src/solver/ros2.h create mode 100644 src/solver/smatrix.c create mode 100644 src/solver/smatrix.h diff --git a/src/run/CMakeLists.txt b/src/run/CMakeLists.txt new file mode 100644 index 0000000..765b78a --- /dev/null +++ b/src/run/CMakeLists.txt @@ -0,0 +1,101 @@ +# # EPANETMSX COMMAND LINE EXECUTABLE +# cmake_minimum_required (VERSION 2.8.8) +# # Sets for output directory for executables and libraries. +# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) +# set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +# set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) +# set(RELEASEVAR, "Release") +# set(DEBUGVAR, "Debug") + +# # Sets the position independent code property for all targets. +# set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +# # Link to multi-threaded static runtime library +# IF (MSVC) +# add_definitions(-D_CRT_SECURE_NO_DEPRECATE -MT) +# ENDIF (MSVC) + + +# # Set up file groups for exe target +# set(MSX_CLI_SOURCES msxmain.c) +# include_directories(include) + +# source_group("CLI" FILES ${MSX_CLI_SOURCES}) + +# # Creates the EPANET-MSX command line executable +# add_executable(runepanetmsx ${MSX_CLI_SOURCES}) + +# target_compile_definitions(runepanetmsx PUBLIC FOO=1) + +# IF(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)") +# find_library(EPANET_LIB epanet2 NAMES epanet2 PATHS ${PROJECT_SOURCE_DIR}/include/x86 NO_DEFAULT_PATH) +# target_link_libraries(runepanetmsx LINK_PUBLIC epanetmsx ${EPANET_LIB}) +# add_custom_command( +# TARGET runepanetmsx +# COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/x86/epanet2.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/epanet2.dll +# COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/runvc.bat ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/runvc.bat) +# else(TRUE) +# find_library(EPANET_LIB epanet2 NAMES epanet2 PATHS ${PROJECT_SOURCE_DIR}/include/x64 NO_DEFAULT_PATH) +# target_link_libraries(runepanetmsx LINK_PUBLIC epanetmsx ${EPANET_LIB}) +# add_custom_command( +# TARGET runepanetmsx +# COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/x64/epanet2.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/epanet2.dll +# COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/runvc.bat ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/runvc.bat) +# endif(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)") + + +# CMakeLists.txt - CMake configuration file for EPANET MSX runner +# +# Created: Nov 13, 2023 +# Updated: Nov 13, 2023 +# +# Author: Caleb Buahin +# US EPA ORD/CESER +# + +if(APPLE) + set(RPATH_ROOT "@loader_path") +else() + set(RPATH_ROOT "$ORIGIN") +endif() + +set(PACKAGE_RPATH "${RPATH_ROOT}/../lib;${RPATH_ROOT}/../extern") + + +# Creates the EPANET command line executable +add_executable(runepanetmsx + msxmain.c +) + +target_include_directories(runepanetmsx + PUBLIC + ${PROJECT_SOURCE_DIR}/include +) + +target_link_libraries(runepanetmsx + LINK_PUBLIC + epanet2 + epanetmsx +) + +# Set up rpath for runswmm inside install package +set_target_properties(runepanetmsx + PROPERTIES + MACOSX_RPATH TRUE + SKIP_BUILD_RPATH FALSE + BUILD_WITH_INSTALL_RPATH FALSE + INSTALL_RPATH "${PACKAGE_RPATH}" + INSTALL_RPATH_USE_LINK_PATH TRUE +) + +install(TARGETS runepanetmsx + DESTINATION "${TOOL_DIST}" +) + + +# # copy runswmm to build tree for testing +# add_custom_command(TARGET runepanet POST_BUILD +# COMMAND ${CMAKE_COMMAND} -E copy +# $ +# ${CMAKE_BINARY_DIR}/bin/$/$ +# ) \ No newline at end of file diff --git a/src/run/msxmain.c b/src/run/msxmain.c new file mode 100644 index 0000000..138f3e3 --- /dev/null +++ b/src/run/msxmain.c @@ -0,0 +1,177 @@ +/******************************************************************************* +** MODULE: MSXMAIN.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Main module of the EPANET Multi-Species Extension toolkit. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 08/30/2022 +** +** EPANET-MSX is an extension of the EPANET program for modeling the fate +** and transport of multiple interacting chemical species within a water +** distribution system over an extended period of operation. This module +** provides a main function for producing a stand-alone console +** application version of EPANET-MSX. It is not needed when compiling +** EPANET-MSX into a dynamic link library (DLL) of callable functions. +** +** To use either the console version or the DLL a user must prepare a +** regular EPANET input file that describes the pipe network layout +** and its hydraulic properties as well as a special EPANET-MSX input file +** that names the chemical species being modeled and specifies the reaction +** rate and equilbrium expressions that define their chemical behavior. The +** format of these files is described in the EPANET and EPANET-MSX Users +** Manuals, respectively. +*******************************************************************************/ + +#include +#include +#include +#include "epanet2.h" // EPANET toolkit header file +#include "epanetmsx.h" // EPANET-MSX toolkit header file +#include +int main(int argc, char* argv[]) +/* +** Purpose: +** main function for the console version of EPANET-MSX. +** +** Input: +** argc = number of command line arguments +** argv = array of command line arguments. +** +** Returns: +** an error code (or 0 for no error). +** +** Notes: +** The command line arguments are: +** - the name of the regular EPANET input data file +** - the name of the EPANET-MSX input file +** - the name of a report file that will contain status +** messages and output results +** - optionally, the name of an output file that will +** contain water quality results in binary format. +*/ +{ + int err, done = 1; + double t, tleft; + long oldHour, newHour; + char* inpFile, * repFile, * outFile; + + // --- check command line arguments + + if (argc < 4 || argc > 5) + { + printf("\nInvalid command line arguments:\n\n"); + printf("usage: runepanetmsx [binary_output_file]\n"); + return 0; + } + inpFile = argv[1]; + repFile = argv[3]; + if (argc == 5) { + outFile = argv[4]; + } + else { + outFile = ""; + } + + // --- open EPANET file + + printf("\n... EPANET-MSX Version 2.0.0\n"); + printf("\n o Processing EPANET input file"); + err = ENopen(inpFile, repFile, outFile); + do + { + if (err) + { + printf("\n\n... Cannot read EPANET file; error code = %d\n", err); + ENclose(); + return err; + } + + // --- open the MSX input file + + printf("\n o Processing MSX input file "); + err = MSXopen(argv[2]); + if (err) + { + printf("\n\n... Cannot read EPANET-MSX file; error code = %d\n", err); + break; + } + + //--- solve hydraulics + + printf("\n o Computing network hydraulics"); + err = MSXsolveH(); + if (err) + { + printf("\n\n... Cannot obtain network hydraulics; error code = %d\n", err); + break; + } + + //--- Initialize the multi-species analysis + + printf("\n o Initializing network water quality"); + err = MSXinit(1); + if (err) + { + printf("\n\n... Cannot initialize EPANET-MSX; error code = %d\n", err); + break; + } + t = 0; + oldHour = -1; + newHour = 0; + printf("\n"); + + //--- Run the multi-species analysis at each time step + + do + { + if (oldHour != newHour) + { + printf("\r o Computing water quality at hour %d", newHour); + oldHour = newHour; + } + err = MSXstep(&t, &tleft); + newHour = (long)(t / 3600.); + + } while (!err && tleft > 0); + if (err) + { + printf("\n\n... EPANET-MSX runtime error; error code = %d\n", err); + break; + } + else + printf("\r o Computing water quality at hour %d", (long)(t / 3600.)); + + // --- report results + + printf("\n o Reporting water quality results"); + err = MSXreport(); + if (err) + { + printf("\n\n... EPANET-MSX report writer error; error code = %d\n", err); + break; + } + + // --- save results to binary file if a file name was provided + + if (argc >= 5) + { + err = MSXsaveoutfile(argv[4]); + if (err > 0) + { + printf("\n\n... Cannot save EPANET-MSX results file; error code = %d\n", err); + break; + } + } + + } while (!done); + + //--- Close both the multi-species & EPANET systems + + MSXclose(); + ENclose(); + if (!err) printf("\n\n... EPANET-MSX completed successfully."); + printf("\n"); + return err; +} diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt new file mode 100644 index 0000000..893851e --- /dev/null +++ b/src/solver/CMakeLists.txt @@ -0,0 +1,123 @@ +# +# CMakeLists.txt - CMake configuration file for s +# Created: 11-13-2023 +# Updated: 11-13-2023 +# +# Author: Caleb Buahin +# US EPA ORD/CESER +# + +find_package(OpenMP) + + +set(EPANET_PUBLIC_HEADERS + ${PROJECT_SOURCE_DIR}/include/epanetmsx.h +) + +file(GLOB + EPANETMSX_SOURCES + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c *.h *.dat +) + +if(BUILD_DEF) + # Builds library with def file interface for backward compatibility + set_source_files_properties(${PROJECT_SOURCE_DIR}/include/epanetmsx.def + PROPERTIES_HEADER_FILE_ONLY TRUE + ) + + add_library(epanetmsx + ${EPANETMSX_SOURCES} + ${PROJECT_SOURCE_DIR}/include/epanetmsx.def + ) + +else() + # Performs standard library build + add_library(epanetmsx + ${EPANETMSX_SOURCES} + ) + +endif() + +target_link_libraries(epanetmsx + PUBLIC + epanet2 +) + +# Sets MSVC compiler flags +target_compile_options(epanetmsx + PUBLIC + "$<$:" + "$<$:/GL>" + "$<$:/fp:fast>" + "$<$:/Zi>" + ">" + $<$: + $<$:-O3> + > +) + +target_link_options(epanetmsx + PUBLIC + "$<$:" + "$<$:/LTCG:incremental>" + ">" +) + +if(UNIX) + target_link_libraries(epanetmsx + PRIVATE + m + ) +endif() + +target_include_directories(epanetmsx + PUBLIC + $ + $ + $ +) + +# include(GenerateExportHeader) +# generate_export_header(epanet2 +# STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC +# ) + +# if(APPLE) +# set(LIB_ROOT "@loader_path") +# else() +# set(LIB_ROOT "$ORIGIN") +# endif() + +# set_target_properties(epanet2 +# PROPERTIES +# MACOSX_RPATH TRUE +# SKIP_BUILD_RPATH FALSE +# BUILD_WITH_INSTALL_RPATH FALSE +# INSTALL_RPATH "${LIB_ROOT};${PACKAGE_RPATH};" +# INSTALL_RPATH_USE_LINK_PATH TRUE +# ) + + +install(TARGETS epanetmsx EXPORT epanetmsxTargets + RUNTIME DESTINATION "${TOOL_DIST}" + LIBRARY DESTINATION "${LIBRARY_DIST}" + ARCHIVE DESTINATION "${LIBRARY_DIST}" + FRAMEWORK DESTINATION "${TOOL_DIST}" +) + +# Create target import scripts so other cmake projects can use swmm libraries +install( + EXPORT + epanetmsxTargets + DESTINATION + "${CONFIG_DIST}" + FILE + epanetmsx-config.cmake +) + +install( + FILES + ${EPANETMSX_PUBLIC_HEADERS} + DESTINATION + "${INCLUDE_DIST}" +) diff --git a/src/solver/dispersion.h b/src/solver/dispersion.h new file mode 100644 index 0000000..ceae365 --- /dev/null +++ b/src/solver/dispersion.h @@ -0,0 +1,22 @@ +#define MAXSEGMENTS 5000 + +typedef enum { + XHEAD, // pump cannot deliver head (closed) + TEMPCLOSED, // temporarily closed + CLOSED, // closed + OPEN, // open + ACTIVE, // valve active (partially open) + XFLOW, // pump exceeds maximum flow + XFCV, // FCV cannot supply flow + XPRESSURE, // valve cannot supply pressure + FILLING, // tank filling + EMPTYING, // tank emptying + OVERFLOWING // tank overflowing +} StatusType; + +int dispersion_open(); +int dispersion_close(); +void dispersion_pipe(int m, double tstep); //effective dispersion coefficient and upstream/downstream node impact calculation +void solve_nodequal(int m, double tstep); //solve nodal concentration +void segqual_update(int m, double tstep); //update pipe segment concentration +void tridiag(int n, double *a, double *b, double *c, double *r, double *y); \ No newline at end of file diff --git a/src/solver/hash.c b/src/solver/hash.c new file mode 100644 index 0000000..dce691e --- /dev/null +++ b/src/solver/hash.c @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// hash.c +// +// Implementation of a simple Hash Table for string storage & retrieval +// / +// Written by L. Rossman +// Last Updated on 6/19/03 +// +// The hash table data structure (HTable) is defined in "hash.h". +// Interface Functions: +// HTcreate() - creates a hash table +// HTinsert() - inserts a string & its index value into a hash table +// HTfind() - retrieves the index value of a string from a table +// HTfree() - frees a hash table +//----------------------------------------------------------------------------- + +#include +#include +#include "hash.h" + +/* Use Fletcher's checksum to compute 2-byte hash of string */ +unsigned int hash(char *str) +{ + unsigned int sum1= 0, check1; + unsigned long sum2= 0L; + while( '\0' != *str ) + { + sum1 += (*str); + str++; + if ( 255 <= sum1 ) sum1 -= 255; + sum2 += sum1; + } + check1= sum2; + check1 %= 255; + check1= 255 - (sum1+check1) % 255; + sum1= 255 - (sum1+check1) % 255; + return( ( ( check1 << 8 ) | sum1 ) % HTMAXSIZE); +} + +HTtable *HTcreate() +{ + int i; + HTtable *ht = (HTtable *) calloc(HTMAXSIZE, sizeof(HTtable)); + if (ht != NULL) for (i=0; i= HTMAXSIZE ) return(0); + entry = (struct HTentry *) malloc(sizeof(struct HTentry)); + if (entry == NULL) return(0); + entry->key = key; + entry->data = data; + entry->next = ht[i]; + ht[i] = entry; + return(1); +} + +int HTfind(HTtable *ht, char *key) +{ + unsigned int i = hash(key); + struct HTentry *entry; + if ( i >= HTMAXSIZE ) return(NOTFOUND); + entry = ht[i]; + while (entry != NULL) + { + if ( strcmp(entry->key,key) == 0 ) return(entry->data); + entry = entry->next; + } + return(NOTFOUND); +} + +char *HTfindKey(HTtable *ht, char *key) +{ + unsigned int i = hash(key); + struct HTentry *entry; + if ( i >= HTMAXSIZE ) return(NULL); + entry = ht[i]; + while (entry != NULL) + { + if ( strcmp(entry->key,key) == 0 ) return(entry->key); + entry = entry->next; + } + return(NULL); +} + +void HTfree(HTtable *ht) +{ + struct HTentry *entry, + *nextentry; + int i; + for (i=0; inext; + free(entry); + entry = nextentry; + } + } + free(ht); +} diff --git a/src/solver/hash.h b/src/solver/hash.h new file mode 100644 index 0000000..a6b0433 --- /dev/null +++ b/src/solver/hash.h @@ -0,0 +1,24 @@ +/* HASH.H +** +** Header file for Hash Table module HASH.C +** +*/ + +#define HTMAXSIZE 1999 +#define NOTFOUND 0 + +struct HTentry +{ + char *key; + int data; + struct HTentry *next; +}; + +typedef struct HTentry *HTtable; + +HTtable *HTcreate(void); +int HTinsert(HTtable *, char *, int); +int HTfind(HTtable *, char *); +char *HTfindKey(HTtable *, char *); +void HTfree(HTtable *); + diff --git a/src/solver/mathexpr.c b/src/solver/mathexpr.c new file mode 100644 index 0000000..f09baa3 --- /dev/null +++ b/src/solver/mathexpr.c @@ -0,0 +1,936 @@ +/****************************************************************************** +** MODULE: MATHEXPR.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Evaluates symbolic mathematical expression consisting +** of numbers, variable names, math functions & arithmetic +** operators. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 09/02/2022 +******************************************************************************/ +/* +** Operand codes: +** 1 = ( +** 2 = ) +** 3 = + +** 4 = - (subtraction) +** 5 = * +** 6 = / +** 7 = number +** 8 = user-defined variable +** 9 = - (negative) +** 10 = cos +** 11 = sin +** 12 = tan +** 13 = cot +** 14 = abs +** 15 = sgn +** 16 = sqrt +** 17 = log +** 18 = exp +** 19 = asin +** 20 = acos +** 21 = atan +** 22 = acot +** 23 = sinh +** 24 = cosh +** 25 = tanh +** 26 = coth +** 27 = log10 +** 28 = step (x<=0 ? 0 : 1) +** 31 = ^ +******************************************************************************/ +#define _CRT_SECURE_NO_WARNINGS + +#include +#include +#include +#include +#include +#include "mathexpr.h" + +#define MAX_STACK_SIZE 1024 + +//*************************************************** +#define MAX_TERM_SIZE 1024 +struct MathTerm +{ + char s[MAX_TERM_SIZE]; +}; +typedef struct MathTerm Term; +//*************************************************** + + +// Local declarations +//-------------------- +// Structure for binary tree representation of math expression +struct TreeNode +{ + int opcode; // operator code + int ivar; // variable index + double fvalue; // numerical value + struct TreeNode* left; // left sub-tree of tokenized formula + struct TreeNode* right; // right sub-tree of tokenized formula +}; +typedef struct TreeNode ExprTree; + +// Local variables +//---------------- +static int Err; +static int Bc; +static int PrevLex, CurLex; +static int Len, Pos; +static char* S; +static char Token[255]; +static int Ivar; +static double Fvalue; + +// math function names +char* MathFunc[] = { "COS", "SIN", "TAN", "COT", "ABS", "SGN", + "SQRT", "LOG", "EXP", "ASIN", "ACOS", "ATAN", + "ACOT", "SINH", "COSH", "TANH", "COTH", "LOG10", + "STEP", NULL }; + +// Local functions +//---------------- +static int sametext(char*, char*); +static int isDigit(char); +static int isLetter(char); +static void getToken(void); +static int getMathFunc(void); +static int getVariable(void); +static int getOperand(void); +static int getLex(void); +static double getNumber(void); +static ExprTree* newNode(void); +static ExprTree* getSingleOp(int*); +static ExprTree* getOp(int*); +static ExprTree* getTree(void); +static void traverseTree(ExprTree*, MathExpr**); +static void deleteTree(ExprTree*); + +// Callback functions +static int (*getVariableIndex) (char*); // return index of named variable +static double (*getVariableValue) (int); // return value of indexed variable + +//============================================================================= + +int sametext(char* s1, char* s2) +/* +** Purpose: +** performs case insensitive comparison of two strings. +** +** Input: +** s1 = character string +** s2 = character string. +** +** Returns: +** 1 if strings are the same, 0 otherwise. +*/ +{ + int i; + for (i = 0; toupper(s1[i]) == toupper(s2[i]); i++) + if (!s1[i + 1] && !s2[i + 1]) return(1); + return(0); +} + +//============================================================================= + +int isDigit(char c) +{ + if (c >= '1' && c <= '9') return 1; + if (c == '0') return 1; + return 0; +} + +//============================================================================= + +int isLetter(char c) +{ + if (c >= 'a' && c <= 'z') return 1; + if (c >= 'A' && c <= 'Z') return 1; + if (c == '_') return 1; + return 0; +} + +//============================================================================= + +void getToken() +{ + char c[] = " "; + Token[0] = '\0'; + while (Pos <= Len && + (isLetter(S[Pos]) || isDigit(S[Pos]))) + { + c[0] = S[Pos]; + strcat(Token, c); + Pos++; + } + Pos--; +} + +//============================================================================= + +int getMathFunc() +{ + int i = 0; + while (MathFunc[i] != NULL) + { + if (sametext(MathFunc[i], Token)) return i + 10; + i++; + } + return(0); +} + +//============================================================================= + +int getVariable() +{ + if (!getVariableIndex) return 0; + Ivar = getVariableIndex(Token); + if (Ivar >= 0) return 8; + return 0; +} + +//============================================================================= + +double getNumber() +{ + char c[] = " "; + char sNumber[255]; + int errflag = 0; + int decimalCount = 0; + + /* --- get whole number portion of number */ + sNumber[0] = '\0'; + while (Pos < Len && isDigit(S[Pos])) + { + c[0] = S[Pos]; + strcat(sNumber, c); + Pos++; + } + + /* --- get fractional portion of number */ + if (Pos < Len) + { + if (S[Pos] == '.') + { + decimalCount++; + if (decimalCount > 1) Err = 1; + strcat(sNumber, "."); + Pos++; + while (Pos < Len && isDigit(S[Pos])) + { + c[0] = S[Pos]; + strcat(sNumber, c); + Pos++; + } + } + + /* --- get exponent */ + if (Pos < Len && (S[Pos] == 'e' || S[Pos] == 'E')) + { + strcat(sNumber, "E"); + Pos++; + if (Pos >= Len) errflag = 1; + else + { + if (S[Pos] == '-' || S[Pos] == '+') + { + c[0] = S[Pos]; + strcat(sNumber, c); + Pos++; + } + if (Pos >= Len || !isDigit(S[Pos])) errflag = 1; + else while (Pos < Len && isDigit(S[Pos])) + { + c[0] = S[Pos]; + strcat(sNumber, c); + Pos++; + } + } + } + } + Pos--; + if (errflag) return 0; + else return atof(sNumber); +} + +//============================================================================= + +int getOperand() +{ + int code; + switch (S[Pos]) + { + case '(': code = 1; break; + case ')': code = 2; break; + case '+': code = 3; break; + case '-': code = 4; + if (Pos < Len - 1 && + isDigit(S[Pos + 1]) && + (CurLex <= 6 || CurLex == 31)) + { + Pos++; + Fvalue = -getNumber(); + code = 7; + } + break; + case '*': code = 5; break; + case '/': code = 6; break; + case '^': code = 31; break; + default: code = 0; + } + return code; +} + +//============================================================================= + +int getLex() +{ + int n; + + /* --- skip spaces */ + while (Pos < Len && S[Pos] == ' ') Pos++; + if (Pos >= Len) return 0; + + /* --- check for operand */ + n = getOperand(); + + /* --- check for function/variable/number */ + if (n == 0) + { + if (isLetter(S[Pos])) + { + getToken(); + n = getMathFunc(); + if (n == 0) n = getVariable(); + } + else if (S[Pos] == '.' || isDigit(S[Pos])) + { + n = 7; + Fvalue = getNumber(); + } + } + Pos++; + PrevLex = CurLex; + CurLex = n; + return n; +} + +//============================================================================= + +ExprTree* newNode() +{ + ExprTree* node; + node = (ExprTree*)malloc(sizeof(ExprTree)); + if (!node) Err = 2; + else + { + node->opcode = 0; + node->ivar = -1; + node->fvalue = 0.; + node->left = NULL; + node->right = NULL; + } + return node; +} + +//============================================================================= + +ExprTree* getSingleOp(int* lex) +{ + int opcode; + ExprTree* left; + ExprTree* node; + + /* --- open parenthesis, so continue to grow the tree */ + if (*lex == 1) + { + Bc++; + left = getTree(); + } + + else + { + /* --- Error if not a singleton operand */ + if (*lex < 7 || *lex == 9 || *lex > 30) + { + Err = 1; + return NULL; + } + + opcode = *lex; + + /* --- simple number or variable name */ + if (*lex == 7 || *lex == 8) + { + left = newNode(); + left->opcode = opcode; + if (*lex == 7) left->fvalue = Fvalue; + if (*lex == 8) left->ivar = Ivar; + } + + /* --- function which must have a '(' after it */ + else + { + *lex = getLex(); + if (*lex != 1) + { + Err = 1; + return NULL; + } + Bc++; + left = newNode(); + left->left = getTree(); + left->opcode = opcode; + } + } + *lex = getLex(); + + /* --- exponentiation */ + if (*lex == 31) + { + node = newNode(); + node->left = left; + node->opcode = *lex; + *lex = getLex(); + node->right = getSingleOp(lex); + left = node; + } + return left; +} + +//============================================================================= + +ExprTree* getOp(int* lex) +{ + int opcode; + ExprTree* left; + ExprTree* right; + ExprTree* node; + int neg = 0; + + *lex = getLex(); + if (PrevLex == 0 || PrevLex == 1) + { + if (*lex == 4) + { + neg = 1; + *lex = getLex(); + } + else if (*lex == 3) *lex = getLex(); + } + left = getSingleOp(lex); + while (*lex == 5 || *lex == 6) + { + opcode = *lex; + *lex = getLex(); + right = getSingleOp(lex); + node = newNode(); + if (Err) return NULL; + node->left = left; + node->right = right; + node->opcode = opcode; + left = node; + } + if (neg) + { + node = newNode(); + if (Err) return NULL; + node->left = left; + node->right = NULL; + node->opcode = 9; + left = node; + } + return left; +} + +//============================================================================= + +ExprTree* getTree() +{ + int lex; + int opcode; + ExprTree* left; + ExprTree* right; + ExprTree* node; + + left = getOp(&lex); + for (;;) + { + if (lex == 0 || lex == 2) + { + if (lex == 2) Bc--; + break; + } + + if (lex != 3 && lex != 4) + { + Err = 1; + break; + } + + opcode = lex; + right = getOp(&lex); + node = newNode(); + if (Err) break; + node->left = left; + node->right = right; + node->opcode = opcode; + left = node; + } + return left; +} + +//============================================================================= + +void traverseTree(ExprTree* tree, MathExpr** expr) +// Converts binary tree to linked list (postfix format) +{ + MathExpr* node; + if (tree == NULL) return; + traverseTree(tree->left, expr); + traverseTree(tree->right, expr); + node = (MathExpr*)malloc(sizeof(MathExpr)); + if (node) + { + node->fvalue = tree->fvalue; + node->opcode = tree->opcode; + node->ivar = tree->ivar; + node->next = NULL; + node->prev = (*expr); + } + if (*expr) (*expr)->next = node; + (*expr) = node; +} + +//============================================================================= + +void deleteTree(ExprTree* tree) +{ + if (tree) + { + if (tree->left) deleteTree(tree->left); + if (tree->right) deleteTree(tree->right); + free(tree); + } +} + +//============================================================================= + +// Turn on "precise" floating point option +#pragma float_control(precise, on, push) + +double mathexpr_eval(MathExpr* expr, double (*getVariableValue) (int)) +// Mathematica expression evaluation using a stack +{ + + // --- Note: the exprStack array must be declared locally and not globally + // since this function can be called recursively. + + double exprStack[MAX_STACK_SIZE]; + MathExpr* node = expr; + double r1, r2; + int stackindex = 0; + + exprStack[0] = 0.0; + while (node != NULL) + { + switch (node->opcode) + { + case 3: + r1 = exprStack[stackindex]; + stackindex--; + r2 = exprStack[stackindex]; + exprStack[stackindex] = r2 + r1; + break; + + case 4: + r1 = exprStack[stackindex]; + stackindex--; + r2 = exprStack[stackindex]; + exprStack[stackindex] = r2 - r1; + break; + + case 5: + r1 = exprStack[stackindex]; + stackindex--; + r2 = exprStack[stackindex]; + exprStack[stackindex] = r2 * r1; + break; + + case 6: + r1 = exprStack[stackindex]; + stackindex--; + r2 = exprStack[stackindex]; + exprStack[stackindex] = r2 / r1; + break; + + case 7: + stackindex++; + exprStack[stackindex] = node->fvalue; + break; + + case 8: + if (getVariableValue != NULL) + r1 = getVariableValue(node->ivar); + else r1 = 0.0; + stackindex++; + exprStack[stackindex] = r1; + break; + + case 9: + exprStack[stackindex] = -exprStack[stackindex]; + break; + + case 10: + r1 = exprStack[stackindex]; + r2 = cos(r1); + exprStack[stackindex] = r2; + break; + + case 11: + r1 = exprStack[stackindex]; + r2 = sin(r1); + exprStack[stackindex] = r2; + break; + + case 12: + r1 = exprStack[stackindex]; + r2 = tan(r1); + exprStack[stackindex] = r2; + break; + + case 13: + r1 = exprStack[stackindex]; + r2 = 1.0 / tan(r1); + exprStack[stackindex] = r2; + break; + + case 14: + r1 = exprStack[stackindex]; + r2 = fabs(r1); + exprStack[stackindex] = r2; + break; + + case 15: + r1 = exprStack[stackindex]; + if (r1 < 0.0) r2 = -1.0; + else if (r1 > 0.0) r2 = 1.0; + else r2 = 0.0; + exprStack[stackindex] = r2; + break; + + case 16: + r1 = exprStack[stackindex]; + r2 = sqrt(r1); + exprStack[stackindex] = r2; + break; + + case 17: + r1 = exprStack[stackindex]; + r2 = log(r1); + exprStack[stackindex] = r2; + break; + + case 18: + r1 = exprStack[stackindex]; + r2 = exp(r1); + exprStack[stackindex] = r2; + break; + + case 19: + r1 = exprStack[stackindex]; + r2 = asin(r1); + exprStack[stackindex] = r2; + break; + + case 20: + r1 = exprStack[stackindex]; + r2 = acos(r1); + exprStack[stackindex] = r2; + break; + + case 21: + r1 = exprStack[stackindex]; + r2 = atan(r1); + exprStack[stackindex] = r2; + break; + + case 22: + r1 = exprStack[stackindex]; + r2 = 1.57079632679489661923 - atan(r1); + exprStack[stackindex] = r2; + break; + + case 23: + r1 = exprStack[stackindex]; + r2 = (exp(r1) - exp(-r1)) / 2.0; + exprStack[stackindex] = r2; + break; + + case 24: + r1 = exprStack[stackindex]; + r2 = (exp(r1) + exp(-r1)) / 2.0; + exprStack[stackindex] = r2; + break; + + case 25: + r1 = exprStack[stackindex]; + r2 = (exp(r1) - exp(-r1)) / (exp(r1) + exp(-r1)); + exprStack[stackindex] = r2; + break; + + case 26: + r1 = exprStack[stackindex]; + r2 = (exp(r1) + exp(-r1)) / (exp(r1) - exp(-r1)); + exprStack[stackindex] = r2; + break; + + case 27: + r1 = exprStack[stackindex]; + r2 = log10(r1); + exprStack[stackindex] = r2; + break; + + case 28: + r1 = exprStack[stackindex]; + if (r1 <= 0.0) r2 = 0.0; + else r2 = 1.0; + exprStack[stackindex] = r2; + break; + + case 31: + r1 = exprStack[stackindex]; + stackindex--; + if (stackindex < 0) break; + r2 = exprStack[stackindex]; + if (r2 <= 0.0) r2 = 0.0; + else r2 = pow(r2, r1); + exprStack[stackindex] = r2; + break; + } + node = node->next; + } + if (stackindex >= 0) + r1 = exprStack[stackindex]; + else + r1 = 0.0; + + // Set result to 0 if it is NaN due to an illegal math op + if (r1 != r1) r1 = 0.0; + + return r1; +} + +// Turn off "precise" floating point option +#pragma float_control(pop) + +//============================================================================= + +void mathexpr_delete(MathExpr* expr) +{ + if (expr) mathexpr_delete(expr->next); + free(expr); +} + +//============================================================================= + +MathExpr* mathexpr_create(char* formula, int (*getVar) (char*)) +{ + ExprTree* tree; + MathExpr* expr = NULL; + MathExpr* result = NULL; + getVariableIndex = getVar; + Err = 0; + PrevLex = 0; + CurLex = 0; + S = formula; + Len = (int)strlen(S); + Pos = 0; + Bc = 0; + tree = getTree(); + if (Bc == 0 && Err == 0) + { + traverseTree(tree, &expr); + while (expr) + { + result = expr; + expr = expr->prev; + } + } + deleteTree(tree); + return result; +} + + +//============================================================================= + +char* mathexpr_getStr(MathExpr* expr, char* exprStr, + char* (*getVariableStr) (int, char*)) +{ + Term TermStack[50]; + MathExpr* node = expr; + char r1[MAX_TERM_SIZE], r2[MAX_TERM_SIZE]; + int stackindex = 0; + + strcpy(TermStack[0].s, ""); + while (node != NULL) + { + switch (node->opcode) + { + case 3: + strcpy(r1, TermStack[stackindex].s); + stackindex--; + strcpy(r2, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "(%s) + (%s)", r2, r1); + break; + + case 4: + strcpy(r1, TermStack[stackindex].s); + stackindex--; + strcpy(r2, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "(%s) - (%s)", r2, r1); + break; + + case 5: + strcpy(r1, TermStack[stackindex].s); + stackindex--; + strcpy(r2, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "(%s) * (%s)", r2, r1); + break; + + case 6: + strcpy(r1, TermStack[stackindex].s); + stackindex--; + strcpy(r2, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "(%s) / (%s)", r2, r1); + break; + + case 7: + stackindex++; + sprintf(TermStack[stackindex].s, "%.6g", node->fvalue); + break; + + case 8: + if (getVariableStr != NULL)strcpy(r1, getVariableStr(node->ivar, r2)); + else strcpy(r1, ""); + stackindex++; + strcpy(TermStack[stackindex].s, r1); + break; + + case 9: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "-(%s)", r1); + break; + + case 10: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "cos(%s)", r1); + break; + + case 11: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "sin(%s)", r1); + break; + + case 12: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "tan(%s)", r1); + break; + + case 13: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "cot(%s)", r1); + break; + + case 14: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "abs(%s)", r1); + break; + + case 15: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "sgn(%s)", r1); + break; + + case 16: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "sqrt(%s)", r1); + break; + + case 17: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "log(%s)", r1); + break; + + case 18: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "exp(%s)", r1); + break; + + case 19: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "asin(%s)", r1); + break; + + case 20: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "acos(%s)", r1); + break; + + case 21: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "atan(%s)", r1); + break; + + case 22: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "acot(%s)", r1); + break; + + case 23: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "sinh(%s)", r1); + break; + + case 24: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "cosh(%s)", r1); + break; + + case 25: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "tanh(%s)", r1); + break; + + case 26: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "coth(%s)", r1); + break; + + case 27: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "log10(%s)", r1); + break; + + case 28: + strcpy(r1, TermStack[stackindex].s); + sprintf(TermStack[stackindex].s, "step(%s)", r1); + break; + + case 31: + strcpy(r1, TermStack[stackindex].s); + strcpy(r2, TermStack[stackindex - 1].s); + sprintf(TermStack[stackindex - 1].s, "pow(%s,%s)", r2, r1); + stackindex--; + break; + } + node = node->next; + } + strcpy(exprStr, TermStack[stackindex].s); + return exprStr; +} diff --git a/src/solver/mathexpr.h b/src/solver/mathexpr.h new file mode 100644 index 0000000..71e0fb3 --- /dev/null +++ b/src/solver/mathexpr.h @@ -0,0 +1,34 @@ +/****************************************************************************** +** MODULE: MATHEXPR.H +** PROJECT: EPANET-MSX +** DESCRIPTION: header file for the math expression parser in mathexpr.c. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 2/8/11 +******************************************************************************/ + +// Node in a tokenized math expression list +struct ExprNode +{ + int opcode; // operator code + int ivar; // variable index + double fvalue; // numerical value + struct ExprNode *prev; // previous node + struct ExprNode *next; // next node +}; +typedef struct ExprNode MathExpr; + +// Creates a tokenized math expression from a string +MathExpr* mathexpr_create(char* s, int (*getVar) (char *)); + +// Evaluates a tokenized math expression +double mathexpr_eval(MathExpr* expr, double (*getVal) (int)); + +// Deletes a tokenized math expression +void mathexpr_delete(MathExpr* expr); + +// Returns reconstructed string version of a tokenized expression +char * mathexpr_getStr(MathExpr* expr, char* exprStr, + char * (*getVariableStr) (int, char *)); diff --git a/src/solver/mempool.c b/src/solver/mempool.c new file mode 100644 index 0000000..f2cc2ee --- /dev/null +++ b/src/solver/mempool.c @@ -0,0 +1,204 @@ +/* mempool.c +** +** A simple fast memory allocation package. +** +** By Steve Hill in Graphics Gems III, David Kirk (ed.), +** Academic Press, Boston, MA, 1992 +** +** Modified by Lew Rossman, 8/13/94. +** +** AllocInit() - create an alloc pool, returns the old pool handle +** Alloc() - allocate memory +** AllocReset() - reset the current pool +** AllocSetPool() - set the current pool +** AllocFree() - free the memory used by the current pool. +** +*/ + +#include +#include +#include "mempool.h" + +/* +** ALLOC_BLOCK_SIZE - adjust this size to suit your installation - it +** should be reasonably large otherwise you will be mallocing a lot. +*/ + +#define ALLOC_BLOCK_SIZE 64000 /*(62*1024)*/ + +/* +** alloc_hdr_t - Header for each block of memory. +*/ + +typedef struct alloc_hdr_s +{ + struct alloc_hdr_s *next; /* Next Block */ + char *block, /* Start of block */ + *free, /* Next free in block */ + *end; /* block + block size */ +} alloc_hdr_t; + +/* +** alloc_root_t - Header for the whole pool. +*/ + +typedef struct alloc_root_s +{ + alloc_hdr_t *first, /* First header in pool */ + *current; /* Current header */ +} alloc_root_t; + +/* +** root - Pointer to the current pool. +*/ + +static alloc_root_t *root; + + +/* +** AllocHdr() +** +** Private routine to allocate a header and memory block. +*/ + +static alloc_hdr_t *AllocHdr(void); + +static alloc_hdr_t * AllocHdr() +{ + alloc_hdr_t *hdr; + char *block; + + block = (char *) malloc(ALLOC_BLOCK_SIZE); + hdr = (alloc_hdr_t *) malloc(sizeof(alloc_hdr_t)); + + if (hdr == NULL || block == NULL) return(NULL); + hdr->block = block; + hdr->free = block; + hdr->next = NULL; + hdr->end = block + ALLOC_BLOCK_SIZE; + + return(hdr); +} + + +/* +** AllocInit() +** +** Create a new memory pool with one block. +** Returns pointer to the new pool. +*/ + +alloc_handle_t * AllocInit() +{ + alloc_handle_t *newpool; + + root = (alloc_root_t *) malloc(sizeof(alloc_root_t)); + if (root == NULL) return(NULL); + if ( (root->first = AllocHdr()) == NULL) return(NULL); + root->current = root->first; + newpool = (alloc_handle_t *) root; + return(newpool); +} + + +/* +** Alloc() +** +** Use as a direct replacement for malloc(). Allocates +** memory from the current pool. +*/ + +char * Alloc(long size) +{ + alloc_hdr_t *hdr = root->current; + char *ptr; + + /* + ** Align to 4 byte boundary - should be ok for most machines. + ** Change this if your machine has weird alignment requirements. + */ + size = (size + 3) & 0xfffffffc; + + ptr = hdr->free; + hdr->free += size; + + /* Check if the current block is exhausted. */ + + if (hdr->free >= hdr->end) + { + /* Is the next block already allocated? */ + + if (hdr->next != NULL) + { + /* re-use block */ + hdr->next->free = hdr->next->block; + root->current = hdr->next; + } + else + { + /* extend the pool with a new block */ + if ( (hdr->next = AllocHdr()) == NULL) return(NULL); + root->current = hdr->next; + } + + /* set ptr to the first location in the next block */ + ptr = root->current->free; + root->current->free += size; + } + + /* Return pointer to allocated memory. */ + + return(ptr); +} + + +/* +** AllocSetPool() +** +** Change the current pool. Return the old pool. +*/ + +alloc_handle_t * AllocSetPool(alloc_handle_t *newpool) +{ + alloc_handle_t *old = (alloc_handle_t *) root; + root = (alloc_root_t *) newpool; + return(old); +} + + +/* +** AllocReset() +** +** Reset the current pool for re-use. No memory is freed, +** so this is very fast. +*/ + +void AllocReset() +{ + root->current = root->first; + root->current->free = root->current->block; +} + + +/* +** AllocFreePool() +** +** Free the memory used by the current pool. +** Don't use where AllocReset() could be used. +*/ + +void AllocFreePool() +{ + alloc_hdr_t *tmp, + *hdr = root->first; + + while (hdr != NULL) + { + tmp = hdr->next; + free((char *) hdr->block); + free((char *) hdr); + hdr = tmp; + } + free((char *) root); + root = NULL; +} diff --git a/src/solver/mempool.h b/src/solver/mempool.h new file mode 100644 index 0000000..bed1787 --- /dev/null +++ b/src/solver/mempool.h @@ -0,0 +1,19 @@ +/* +** mempool.h +** +** Header for mempool.c +** +** The type alloc_handle_t provides an opaque reference to the +** alloc pool - only the alloc routines know its structure. +*/ + +typedef struct +{ + long dummy; +} alloc_handle_t; + +alloc_handle_t *AllocInit(void); +char *Alloc(long); +alloc_handle_t *AllocSetPool(alloc_handle_t *); +void AllocReset(void); +void AllocFreePool(void); diff --git a/src/solver/msxchem.c b/src/solver/msxchem.c new file mode 100644 index 0000000..11cc3fb --- /dev/null +++ b/src/solver/msxchem.c @@ -0,0 +1,1285 @@ +/******************************************************************************* +** MODULE: MSXCHEM.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Water quality chemistry functions. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +*******************************************************************************/ + +#include +#include +#include +#include + +#include "msxtypes.h" +#include "rk5.h" +#include "ros2.h" +#include "newton.h" +#include "msxfuncs.h" + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + + +// Constants +//----------- +int MAXIT = 20; // Max. number of iterations used + // in nonlinear equation solver +int NUMSIG = 3; // Number of significant digits in + // nonlinear equation solver error + +// Local variables +//----------------- +static Pseg TheSeg; // Current water quality segment +static int TheLink; // Index of current link +static int TheNode; // Index of current node +static int TheTank; // Index of current tank +static int NumSpecies; // Total number of species +static int NumPipeRateSpecies; // Number of species with pipe rates +static int NumTankRateSpecies; // Number of species with tank rates +static int NumPipeFormulaSpecies; // Number of species with pipe formulas +static int NumTankFormulaSpecies; // Number of species with tank formulas +static int NumPipeEquilSpecies; // Number of species with pipe equilibria +static int NumTankEquilSpecies; // Number of species with tank equilibria +static int *PipeRateSpecies; // Species governed by pipe reactions +static int *TankRateSpecies; // Species governed by tank reactions +static int *PipeEquilSpecies; // Species governed by pipe equilibria +static int *TankEquilSpecies; // Species governed by tank equilibria +static int LastIndex[MAX_OBJECTS]; // Last index of given type of variable +static double *Atol; // Absolute concentration tolerances +static double *Rtol; // Relative concentration tolerances +static double *Yrate; // Rate species concentrations +static double *Yequil; // Equilibrium species concentrations +static double HydVar[MAX_HYD_VARS]; // Values of hydraulic variables +static double *F; // Function values +static double *ChemC1; + +#pragma omp threadprivate(TheSeg, TheLink, TheNode, TheTank, Yrate, Yequil, HydVar, F, ChemC1) + +// Exported functions +//-------------------- +int MSXchem_open(void); +int MSXchem_react(double dt); +int MSXchem_equil(int zone, int k, double *c); +char* MSXchem_getVariableStr(int i, char *s); +void MSXchem_close(void); + +// Imported functions +//------------------- +int MSXcompiler_open(void); +void MSXcompiler_close(void); +double MSXerr_validate(double x, int index, int element, int exprType); + +// Local functions +//----------------- +static void setSpeciesChemistry(void); +static void setTankChemistry(void); +//static void evalHydVariables(int k); +static int evalPipeReactions(int k, double dt); +static int evalTankReactions(int k, double dt); +static int evalPipeEquil(double *c); +static int evalTankEquil(double *c); +static void evalPipeFormulas(double *c); +static void evalTankFormulas(double *c); +static double getPipeVariableValue(int i); +static double getTankVariableValue(int i); +static void getPipeDcDt(double t, double y[], int n, double deriv[]); +static void getTankDcDt(double t, double y[], int n, double deriv[]); +static void getPipeEquil(double t, double y[], int n, double f[]); +static void getTankEquil(double t, double y[], int n, double f[]); +static int isValidNumber(double x); //(L.Rossman - 11/03/10) + + +//============================================================================= + +int MSXchem_open() +/* +** Purpose: +** opens the multi-species chemistry system. +** +** Input: +** none. +** +** Returns: +** an error code (0 if no error). +*/ +{ + int m; + int numWallSpecies; + int numBulkSpecies; + int numTankExpr; + int numPipeExpr; + int errcode = 0; + + // --- allocate memory + + PipeRateSpecies = NULL; + TankRateSpecies = NULL; + PipeEquilSpecies = NULL; + TankEquilSpecies = NULL; + Atol = NULL; + Rtol = NULL; + Yrate = NULL; + Yequil = NULL; + NumSpecies = MSX.Nobjects[SPECIES]; + m = NumSpecies + 1; + PipeRateSpecies = (int*)calloc(m, sizeof(int)); + TankRateSpecies = (int*)calloc(m, sizeof(int)); + PipeEquilSpecies = (int*)calloc(m, sizeof(int)); + TankEquilSpecies = (int*)calloc(m, sizeof(int)); + Atol = (double*)calloc(m, sizeof(double)); + Rtol = (double*)calloc(m, sizeof(double)); + CALL(errcode, MEMCHECK(PipeRateSpecies)); + CALL(errcode, MEMCHECK(TankRateSpecies)); + CALL(errcode, MEMCHECK(PipeEquilSpecies)); + CALL(errcode, MEMCHECK(TankEquilSpecies)); + CALL(errcode, MEMCHECK(Atol)); + CALL(errcode, MEMCHECK(Rtol)); + +#pragma omp parallel +{ + Yrate = (double*)calloc(m, sizeof(double)); + Yequil = (double*)calloc(m, sizeof(double)); + F = (double*)calloc(m, sizeof(double)); + ChemC1 = (double*)calloc(m, sizeof(double)); +#pragma omp critical + { + CALL(errcode, MEMCHECK(Yrate)); + CALL(errcode, MEMCHECK(Yequil)); + CALL(errcode, MEMCHECK(F)); + CALL(errcode, MEMCHECK(ChemC1)); + } +} + if ( errcode ) return errcode; + +// --- assign species to each type of chemical expression + + setSpeciesChemistry(); + numPipeExpr = NumPipeRateSpecies + NumPipeFormulaSpecies + NumPipeEquilSpecies; + numTankExpr = NumTankRateSpecies + NumTankFormulaSpecies + NumTankEquilSpecies; + +// --- use pipe chemistry for tanks if latter was not supplied + + if ( numTankExpr == 0 ) + { + setTankChemistry(); + numTankExpr = numPipeExpr; + } + +// --- check if enough equations were specified + + numWallSpecies = 0; + numBulkSpecies = 0; + for (m=1; m<=NumSpecies; m++) + { + if ( MSX.Species[m].type == WALL ) numWallSpecies++; + if ( MSX.Species[m].type == BULK ) numBulkSpecies++; + } + if ( numPipeExpr != NumSpecies ) return ERR_NUM_PIPE_EXPR; + if ( numTankExpr != numBulkSpecies ) return ERR_NUM_TANK_EXPR; + +// --- open the ODE solver; +// arguments are max. number of ODE's, +// max. number of steps to be taken, +// 1 if automatic step sizing used (or 0 if not used) + + if ( MSX.Solver == RK5 ) + { + if ( rk5_open(NumSpecies, 1000, 1) == FALSE ) + return ERR_INTEGRATOR_OPEN; + } + if ( MSX.Solver == ROS2 ) + { + if ( ros2_open(NumSpecies, 1) == FALSE ) + return ERR_INTEGRATOR_OPEN; + } + +// --- open the algebraic eqn. solver + + m = MAX(NumPipeEquilSpecies, NumTankEquilSpecies); + if ( newton_open(m) == FALSE ) return ERR_NEWTON_OPEN; + +// --- assign entries to LastIndex array + + LastIndex[SPECIES] = MSX.Nobjects[SPECIES]; + LastIndex[TERM] = LastIndex[SPECIES] + MSX.Nobjects[TERM]; + LastIndex[PARAMETER] = LastIndex[TERM] + MSX.Nobjects[PARAMETER]; + LastIndex[CONSTANT] = LastIndex[PARAMETER] + MSX.Nobjects[CONSTANT]; + +// --- compile chemistry function dynamic library if specified + + if ( MSX.Compiler ) + { + errcode = MSXcompiler_open(); + if ( errcode ) return errcode; + } + return 0; +} + +//============================================================================= + +void MSXchem_close() +/* +** Purpose: +** closes the multi-species chemistry system. +** +** Input: +** none. +*/ +{ + if (MSX.Compiler) MSXcompiler_close(); + if (MSX.Solver == RK5) rk5_close(); + if (MSX.Solver == ROS2) ros2_close(); + newton_close(); + FREE(PipeRateSpecies); + FREE(TankRateSpecies); + FREE(PipeEquilSpecies); + FREE(TankEquilSpecies); + FREE(Atol); + FREE(Rtol); + +#pragma omp parallel +{ + FREE(ChemC1); + FREE(Yrate); + FREE(Yequil); + FREE(F); +} + +} + +//============================================================================= + +int MSXchem_react(double dt) +/* +** Purpose: +** computes reactions in all pipes and tanks. +** +** Input: +** dt = current WQ time step (sec). +** +** Returns: +** an error code or 0 if no error. +*/ +{ + int k, m; + int errcode = 0; + +// --- save tolerances of pipe rate species + + for (k=1; k<=NumPipeRateSpecies; k++) + { + m = PipeRateSpecies[k]; + Atol[k] = MSX.Species[m].aTol; + Rtol[k] = MSX.Species[m].rTol; + } + +// --- examine each link +#pragma omp parallel +{ + #pragma omp for private(k) + for (k = 1; k <= MSX.Nobjects[LINK]; k++) + { + // --- skip non-pipe links + + if (MSX.Link[k].len == 0.0) continue; + + // --- evaluate hydraulic variables + + //evalHydVariables(k); + for (int hi = 1; hi < MAX_HYD_VARS; hi++) + HydVar[hi] = MSX.Link[k].HydVar[hi]; + // --- compute pipe reactions + + errcode = evalPipeReactions(k, dt); + //if (errcode) return errcode; + } +} + if (errcode) return errcode; + +// --- save tolerances of tank rate species + + for (k=1; k<=NumTankRateSpecies; k++) + { + m = TankRateSpecies[k]; + Atol[k] = MSX.Species[m].aTol; + Rtol[k] = MSX.Species[m].rTol; + } + +// --- examine each tank + + for (k=1; k<=MSX.Nobjects[TANK]; k++) + { + // --- skip reservoirs + + if (MSX.Tank[k].a == 0.0) continue; + + // --- compute tank reactions + + errcode = evalTankReactions(k, dt); + if ( errcode ) return errcode; + } + return errcode; +} + +//============================================================================= + +int MSXchem_equil(int zone, int k, double *c) +/* +** Purpose: +** computes equilibrium concentrations for a set of chemical species. +** +** Input: +** zone = reaction zone (NODE or LINK) +** k = pipe or tank index +** c[] = array of species concentrations +** +** Output: +** updated value of c[]. +** +** Returns: +** an error code or 0 if no errors. +*/ +{ + int errcode = 0; + if ( zone == LINK ) + { + TheLink = k; + for (int vi = 1; vi < MAX_HYD_VARS; vi++) + HydVar[vi] = MSX.Link[k].HydVar[vi]; + if ( NumPipeEquilSpecies > 0 ) errcode = evalPipeEquil(c); + evalPipeFormulas(c); + } + if ( zone == NODE ) + { + TheTank = k; + TheNode = MSX.Tank[k].node; + if ( NumTankEquilSpecies > 0 ) errcode = evalTankEquil(c); + evalTankFormulas(c); + } + return errcode; +} + +//============================================================================= + +char* MSXchem_getVariableStr(int i, char *s) +/* +** Purpose: +** returns a string representation of a variable used in the chemistry +** functions appearing in the C source code file used to compile +** these functions +** +** Input: +** i = variable's index in the LastIndex array +** s = string to hold variable's symbol +** +** Output: +** returns a pointer to s +*/ +{ +// --- WQ species have index between 1 & # of species + + if ( i <= LastIndex[SPECIES] ) sprintf(s, "c[%d]", i); + +// --- intermediate term expressions come next + + else if ( i <= LastIndex[TERM] ) + { + i -= LastIndex[TERM-1]; + sprintf(s, "term(%d, c, k, p, h)", i); + } + +// --- reaction parameter indexes come after that + + else if ( i <= LastIndex[PARAMETER] ) + { + i -= LastIndex[PARAMETER-1]; + sprintf(s, "p[%d]", i); + } + +// --- followed by constants + + else if ( i <= LastIndex[CONSTANT] ) + { + i -= LastIndex[CONSTANT-1]; + sprintf(s, "k[%d]", i); + } + +// --- and finally by hydraulic variables + + else + { + i -= LastIndex[CONSTANT]; + sprintf(s, "h[%d]", i); + } + return s; +} + +//============================================================================= + +void setSpeciesChemistry() +/* +** Purpose: +** determines which species are described by reaction rate +** expressions, equilibrium expressions, or simple formulas. +** +** Input: +** none. +** +** Output: +** updates arrays of different chemistry types. +*/ +{ + int m; + NumPipeRateSpecies = 0; + NumPipeFormulaSpecies = 0; + NumPipeEquilSpecies = 0; + NumTankRateSpecies = 0; + NumTankFormulaSpecies = 0; + NumTankEquilSpecies = 0; + for (m=1; m<=NumSpecies; m++) + { + switch ( MSX.Species[m].pipeExprType ) + { + case RATE: + NumPipeRateSpecies++; + PipeRateSpecies[NumPipeRateSpecies] = m; + break; + + case FORMULA: + NumPipeFormulaSpecies++; + break; + + case EQUIL: + NumPipeEquilSpecies++; + PipeEquilSpecies[NumPipeEquilSpecies] = m; + break; + } + switch ( MSX.Species[m].tankExprType ) + { + case RATE: + NumTankRateSpecies++; + TankRateSpecies[NumTankRateSpecies] = m; + break; + + case FORMULA: + NumTankFormulaSpecies++; + break; + + case EQUIL: + NumTankEquilSpecies++; + TankEquilSpecies[NumTankEquilSpecies] = m; + break; + } + } +} + +//============================================================================= + +void setTankChemistry() +/* +** Purpose: +** assigns pipe chemistry expressions to tank chemistry for +** each chemical species. +** +** Input: +** none. +** +** Output: +** updates arrays of different tank chemistry types. +*/ +{ + int m; + for (m=1; m<=NumSpecies; m++) + { + MSX.Species[m].tankExpr = MSX.Species[m].pipeExpr; + MSX.Species[m].tankExprType = MSX.Species[m].pipeExprType; + } + NumTankRateSpecies = NumPipeRateSpecies; + for (m=1; m<=NumTankRateSpecies; m++) + { + TankRateSpecies[m] = PipeRateSpecies[m]; + } + NumTankFormulaSpecies = NumPipeFormulaSpecies; + NumTankEquilSpecies = NumPipeEquilSpecies; + for (m=1; m<=NumTankEquilSpecies; m++) + { + TankEquilSpecies[m] = PipeEquilSpecies[m]; + } +} + + + +//============================================================================= + +int evalPipeReactions(int k, double dt) +/* +** Purpose: +** updates species concentrations in each WQ segment of a pipe +** after reactions occur over time step dt. +** +** Input: +** k = link index +** dt = time step (sec). +** +** Output: +** updates values in the concentration vector C[] associated +** with a pipe's WQ segments. +** +** Returns: +** an error code or 0 if no error. +** +** Re-written to accommodate compiled functions (1.1) +*/ +{ + int i, m; + int errcode = 0, ierr = 0; + double tstep = (double)dt / MSX.Ucf[RATE_UNITS]; + double c, dh; + +// --- start with the most downstream pipe segment + + TheLink = k; + TheSeg = MSX.FirstSeg[TheLink]; + while ( TheSeg ) + { + for (m = 1; m <= NumSpecies; m++) + { + ChemC1[m] = TheSeg->c[m]; + TheSeg->lastc[m] = TheSeg->c[m]; + } + ierr = 0; + + // --- react each reacting species over the time step + + if ( dt > 0.0 ) + { + + // --- place current concentrations of species that react in vector Yrate + + for (i=1; i<=NumPipeRateSpecies; i++) + { + m = PipeRateSpecies[i]; + Yrate[i] = TheSeg->c[m]; + } + + // --- Euler integrator + + if ( MSX.Solver == EUL ) + { + getPipeDcDt(0, Yrate, NumPipeRateSpecies, Yrate); + for (i=1; i<=NumPipeRateSpecies; i++) + { + m = PipeRateSpecies[i]; + c = TheSeg->c[m] + Yrate[i]*tstep; + TheSeg->c[m] = MAX(c, 0.0); + } + } + + // --- other integrators + else + { + dh = TheSeg->hstep; + + // --- Runge-Kutta integrator + + if ( MSX.Solver == RK5 ) + ierr = rk5_integrate(Yrate, NumPipeRateSpecies, 0, tstep, + &dh, Atol, Rtol, getPipeDcDt); + + // --- Rosenbrock integrator + + if ( MSX.Solver == ROS2 ) + ierr = ros2_integrate(Yrate, NumPipeRateSpecies, 0, tstep, + &dh, Atol, Rtol, getPipeDcDt); + + // --- save new concentration values of the species that reacted + + for (m=1; m<=NumSpecies; m++) TheSeg->c[m] = ChemC1[m]; + for (i=1; i<=NumPipeRateSpecies; i++) + { + m = PipeRateSpecies[i]; + TheSeg->c[m] = MAX(Yrate[i], 0.0); + } + TheSeg->hstep = dh; + } + if ( ierr < 0 ) return + ERR_INTEGRATOR; + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type == BULK) + { + MSX.Link[k].reacted[m] += TheSeg->v * (TheSeg->c[m] - TheSeg->lastc[m]) * LperFT3; + } + else if (MSX.Link[k].diam > 0) + { + MSX.Link[k].reacted[m] += TheSeg->v * 4.0 / MSX.Link[k].diam * MSX.Ucf[AREA_UNITS] * (TheSeg->c[m] - TheSeg->lastc[m]); + } + TheSeg->lastc[m] = TheSeg->c[m]; + } + } + + // --- compute new equilibrium concentrations within segment + + errcode = MSXchem_equil(LINK, k, TheSeg->c); + if ( errcode ) return errcode; + + // --- move to the segment upstream of the current one + TheSeg = TheSeg->prev; + } + return errcode; +} + +//============================================================================= + +int evalTankReactions(int k, double dt) +/* +** Purpose: +** updates species concentrations in a given storage tank +** after reactions occur over time step dt. +** +** Input: +** k = tank index +** dt = time step (sec). +** +** Output: +** updates values in the concentration vector Tank[k].c[] +** for tank k. +** +** Returns: +** an error code or 0 if no error. +** +** Re-written to accommodate compiled functions (1.1) +*/ +{ + int i, m; + int errcode = 0, ierr = 0; + double tstep = (double)dt / MSX.Ucf[RATE_UNITS]; + double c, dh; + +// --- evaluate each volume segment in the tank + + TheTank = k; + TheNode = MSX.Tank[k].node; + i = MSX.Nobjects[LINK] + k; + TheSeg = MSX.FirstSeg[i]; + while ( TheSeg ) + { + for (m = 1; m <= NumSpecies; m++) + { + ChemC1[m] = TheSeg->c[m]; + TheSeg->lastc[m] = TheSeg->c[m]; + } + ierr = 0; + + // --- react each reacting species over the time step + + if ( dt > 0.0 ) + { + + // --- place current concentrations of species that react in vector Yrate + for (i=1; i<=NumTankRateSpecies; i++) + { + m = TankRateSpecies[i]; + // Yrate[i] = MSX.Tank[k].c[m]; + Yrate[i] = TheSeg->c[m]; + } + + // --- Euler integrator + + if ( MSX.Solver == EUL ) + { + getTankDcDt(0, Yrate, NumTankRateSpecies, Yrate); + for (i=1; i<=NumTankRateSpecies; i++) + { + m = TankRateSpecies[i]; + c = TheSeg->c[m] + Yrate[i]*tstep; + TheSeg->c[m] = MAX(c, 0.0); + } + } + + // --- other integrators + else + { + dh = MSX.Tank[k].hstep; + + // --- Runge-Kutta integrator + + if ( MSX.Solver == RK5 ) + ierr = rk5_integrate(Yrate, NumTankRateSpecies, 0, tstep, + &dh, Atol, Rtol, getTankDcDt); + + // --- Rosenbrock integrator + + if ( MSX.Solver == ROS2 ) + ierr = ros2_integrate(Yrate, NumTankRateSpecies, 0, tstep, + &dh, Atol, Rtol, getTankDcDt); + + // --- save new concentration values of the species that reacted + + for (m=1; m<=NumSpecies; m++) TheSeg->c[m] = ChemC1[m]; + for (i=1; i<=NumTankRateSpecies; i++) + { + m = TankRateSpecies[i]; + TheSeg->c[m] = MAX(Yrate[i], 0.0); + } + TheSeg->hstep = dh; + } + if ( ierr < 0 ) return + ERR_INTEGRATOR; + } + + // --- compute new equilibrium concentrations within segment + + errcode = MSXchem_equil(NODE, k, TheSeg->c); + if ( errcode ) return errcode; + + // --- move to the next tank segment + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type == BULK) + { + MSX.Tank[k].reacted[m] += TheSeg->v * (TheSeg->c[m] - TheSeg->lastc[m]) * LperFT3; + } + TheSeg->lastc[m] = TheSeg->c[m]; + } + + TheSeg = TheSeg->prev; + } + return errcode; +} + +//============================================================================= + +int evalPipeEquil(double *c) +/* +** Purpose: +** computes equilibrium concentrations for water in a pipe segment. +** +** Input: +** c[] = array of starting species concentrations +** +** Output: +** c[] = array of equilibrium concentrations. +** +** Returns: +** an error code or 0 if no error. +*/ +{ + int i, m; + int errcode; + for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m]; + for (i=1; i<=NumPipeEquilSpecies; i++) + { + m = PipeEquilSpecies[i]; + Yequil[i] = c[m]; + } + errcode = newton_solve(Yequil, NumPipeEquilSpecies, MAXIT, NUMSIG, + getPipeEquil); + if ( errcode < 0 ) return ERR_NEWTON; + for (i=1; i<=NumPipeEquilSpecies; i++) + { + m = PipeEquilSpecies[i]; + c[m] = Yequil[i]; + ChemC1[m] = c[m]; + } + return 0; +} + + +//============================================================================= + +int evalTankEquil(double *c) +/* +** Purpose: +** computes equilibrium concentrations for water in a tank. +** +** Input: +** c[] = array of starting species concentrations +** +** Output: +** c[] = array of equilibrium concentrations. +** +** Returns: +** an error code or 0 if no error. +*/ +{ + int i, m; + int errcode; + for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m]; + for (i=1; i<=NumTankEquilSpecies; i++) + { + m = TankEquilSpecies[i]; + Yequil[i] = c[m]; + } + errcode = newton_solve(Yequil, NumTankEquilSpecies, MAXIT, NUMSIG, + getTankEquil); + if ( errcode < 0 ) return ERR_NEWTON; + for (i=1; i<=NumTankEquilSpecies; i++) + { + m = TankEquilSpecies[i]; + c[m] = Yequil[i]; + ChemC1[m] = c[m]; + } + return 0; +} + +//============================================================================= + +void evalPipeFormulas(double *c) +/* +** Purpose: +** evaluates species concentrations in a pipe segment that are simple +** formulas involving other known species concentrations. +** +** Input: +** c[] = array of current species concentrations. +** +** Output: +** c[] = array of updated concentrations. +** +** Re-written to accommodate compiled functions (1.1) +*/ +{ + int m; + double x; + + for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m]; +// --- use compiled functions if available + + if ( MSX.Compiler ) + { + MSXgetPipeFormulas(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar); + for (m=1; m<=NumSpecies; m++) + { + if (MSX.Species[m].pipeExprType == FORMULA) + c[m] = MSXerr_validate(ChemC1[m], m, LINK, FORMULA); + } + return; + } + + for (m=1; m<=NumSpecies; m++) + { + if ( MSX.Species[m].pipeExprType == FORMULA ) + { + x = mathexpr_eval(MSX.Species[m].pipeExpr, getPipeVariableValue); + c[m] = MSXerr_validate(x, m, LINK, FORMULA); + } + } +} + +//============================================================================= + +void evalTankFormulas(double *c) +/* +** Purpose: +** evaluates species concentrations in a tank that are simple +** formulas involving other known species concentrations. +** +** Input: +** c[] = array of current species concentrations. +** +** Output: +** c[] = array of updated concentrations. +** +** Re-written to accommodate compiled functions (1.1) +*/ +{ + int m; + double x; + + for (m=1; m<=NumSpecies; m++) ChemC1[m] = c[m]; + +// --- use compiled functions if available + + if ( MSX.Compiler ) + { + MSXgetTankFormulas(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar); + for (m=1; m<=NumSpecies; m++) + { + if (MSX.Species[m].tankExprType == FORMULA) + c[m] = MSXerr_validate(ChemC1[m], m, TANK, FORMULA); + } + return; + } + + for (m=1; m<=NumSpecies; m++) + { + if ( MSX.Species[m].tankExprType == FORMULA ) + { + x = mathexpr_eval(MSX.Species[m].tankExpr, getTankVariableValue); + c[m] = MSXerr_validate(x, m, TANK, FORMULA); + } + } +} + +//============================================================================= + +double getPipeVariableValue(int i) +/* +** Purpose: +** finds the value of a species, a parameter, or a constant for +** the pipe link being analyzed. +** +** Input: +** i = variable index. +** +** Returns: +** the current value of the indexed variable. +*/ +{ + double x; + +// --- WQ species have index i between 1 & # of species +// and their current values are stored in vector ChemC1 + + if ( i <= LastIndex[SPECIES] ) + { + // --- if species represented by a formula then evaluate it + + if ( MSX.Species[i].pipeExprType == FORMULA ) + { + x = mathexpr_eval(MSX.Species[i].pipeExpr, getPipeVariableValue); + return MSXerr_validate(x, i, LINK, FORMULA); + } + + // --- otherwise return the current concentration + + else return ChemC1[i]; + } + +// --- intermediate term expressions come next + + else if ( i <= LastIndex[TERM] ) + { + i -= LastIndex[TERM-1]; + x = mathexpr_eval(MSX.Term[i].expr, getPipeVariableValue); + return MSXerr_validate(x, i, 0, TERM); + } + +// --- reaction parameter indexes come after that + + else if ( i <= LastIndex[PARAMETER] ) + { + i -= LastIndex[PARAMETER-1]; + return MSX.Link[TheLink].param[i]; + } + +// --- followed by constants + + else if ( i <= LastIndex[CONSTANT] ) + { + i -= LastIndex[CONSTANT-1]; + return MSX.Const[i].value; + } + +// --- and finally by hydraulic variables + else + { + i -= LastIndex[CONSTANT]; + if (i < MAX_HYD_VARS) return HydVar[i]; + else return 0.0; + } +} + +//============================================================================= + +double getTankVariableValue(int i) +/* +** Purpose: +** finds the value of a species, a parameter, or a constant for +** the current node being analyzed. +** +** Input: +** i = variable index. +** +** Returns: +** the current value of the indexed variable. +** +** Modified to check for NaN values (L.Rossman - 11/03/10). +*/ +{ + int j; + double x; + +// --- WQ species have index i between 1 & # of species +// and their current values are stored in vector ChemC1 + + if ( i <= LastIndex[SPECIES] ) + { + // --- if species represented by a formula then evaluate it + + if ( MSX.Species[i].tankExprType == FORMULA ) + { + x = mathexpr_eval(MSX.Species[i].tankExpr, getTankVariableValue); + return MSXerr_validate(x, i, TANK, FORMULA); + } + + // --- otherwise return the current concentration + + else return ChemC1[i]; + } + +// --- intermediate term expressions come next + + else if ( i <= LastIndex[TERM] ) + { + i -= LastIndex[TERM-1]; + x = mathexpr_eval(MSX.Term[i].expr, getTankVariableValue); + return MSXerr_validate(x, i, 0, TERM); + } + +// --- next come reaction parameters associated with Tank nodes + + else if (i <= LastIndex[PARAMETER] ) + { + i -= LastIndex[PARAMETER-1]; + j = MSX.Node[TheNode].tank; + if ( j > 0 ) + { + return MSX.Tank[j].param[i]; + } + else return 0.0; + } + +// --- and then come constants + + else if (i <= LastIndex[CONSTANT] ) + { + i -= LastIndex[CONSTANT-1]; + return MSX.Const[i].value; + } + else return 0.0; +} + +//============================================================================= + +void getPipeDcDt(double t, double y[], int n, double deriv[]) +/* +** Purpose: +** finds reaction rate (dC/dt) for each reacting species in a pipe. +** +** Input: +** t = current time (not used) +** y[] = vector of reacting species concentrations +** n = number of reacting species. +** +** Output: +** deriv[] = vector of reaction rates of each reacting species. +*/ +{ + int i, m; + double x; + +// --- assign species concentrations to their proper positions in the global +// concentration vector ChemC1 + + for (i=1; i<=n; i++) + { + m = PipeRateSpecies[i]; + ChemC1[m] = y[i]; + } + +// --- update equilibrium species if full coupling in use + + if ( MSX.Coupling == FULL_COUPLING ) + { + if ( MSXchem_equil(LINK, TheLink, ChemC1) > 0 ) // check for error condition + { + for (i=1; i<=n; i++) deriv[i] = 0.0; + return; + } + } + +// --- use compiled functions if available + + if ( MSX.Compiler ) + { + MSXgetPipeRates(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar, F); + for (i=1; i<=n; i++) + { + m = PipeRateSpecies[i]; + deriv[i] = MSXerr_validate(F[m], m, LINK, RATE); + } + return; + } + +// --- evaluate each pipe reaction expression + + for (i=1; i<=n; i++) + { + m = PipeRateSpecies[i]; + x = mathexpr_eval(MSX.Species[m].pipeExpr, getPipeVariableValue); + deriv[i] = MSXerr_validate(x, m, LINK, RATE); + } +} + +//============================================================================= + +void getTankDcDt(double t, double y[], int n, double deriv[]) +/* +** Purpose: +** finds reaction rate (dC/dt) for each reacting species in a tank. +** +** Input: +** t = current time (not used) +** y[] = vector of reacting species concentrations +** n = number of reacting species. +** +** Output: +** deriv[] = vector of reaction rates of each reacting species. +*/ +{ + int i, m; + double x; + +// --- assign species concentrations to their proper positions in the global +// concentration vector ChemC1 + + for (i=1; i<=n; i++) + { + m = TankRateSpecies[i]; + ChemC1[m] = y[i]; + } + +// --- update equilibrium species if full coupling in use + + if ( MSX.Coupling == FULL_COUPLING ) + { + if ( MSXchem_equil(NODE, TheTank, ChemC1) > 0 ) // check for error condition + { + for (i=1; i<=n; i++) deriv[i] = 0.0; + return; + } + } + +// --- use compiled functions if available + + if ( MSX.Compiler ) + { + MSXgetTankRates(ChemC1, MSX.K, MSX.Tank[TheTank].param, HydVar, F); + for (i=1; i<=n; i++) + { + m = TankRateSpecies[i]; + deriv[i] = MSXerr_validate(F[m], m, TANK, RATE); + } + return; + } + +// --- evaluate each tank reaction expression + + for (i=1; i<=n; i++) + { + m = TankRateSpecies[i]; + x = mathexpr_eval(MSX.Species[m].tankExpr, getTankVariableValue); + deriv[i] = MSXerr_validate(x, m, TANK, RATE); + } +} + +//============================================================================= + +void getPipeEquil(double t, double y[], int n, double f[]) +/* +** Purpose: +** evaluates equilibrium expressions for pipe chemistry. +** +** Input: +** t = current time (not used) +** y[] = vector of equilibrium species concentrations +** n = number of equilibrium species. +** +** Output: +** f[] = vector of equilibrium function values. +*/ +{ + int i, m; + double x; + +// --- assign species concentrations to their proper positions in the global +// concentration vector ChemC1 + + for (i=1; i<=n; i++) + { + m = PipeEquilSpecies[i]; + ChemC1[m] = y[i]; + } + +// --- use compiled functions if available + + if ( MSX.Compiler ) + { + MSXgetPipeEquil(ChemC1, MSX.K, MSX.Link[TheLink].param, HydVar, F); + for (i=1; i<=n; i++) + { + m = PipeEquilSpecies[i]; + f[i] = MSXerr_validate(F[m], m, LINK, EQUIL); + } + return; + } + +// --- evaluate each pipe equilibrium expression + + for (i=1; i<=n; i++) + { + m = PipeEquilSpecies[i]; + x = mathexpr_eval(MSX.Species[m].pipeExpr, getPipeVariableValue); + f[i] = MSXerr_validate(x, m, LINK, EQUIL); + } +} + +//============================================================================= + +void getTankEquil(double t, double y[], int n, double f[]) +/* +** Purpose: +** evaluates equilibrium expressions for tank chemistry. +** +** Input: +** t = current time (not used) +** y[] = vector of equilibrium species concentrations +** n = number of equilibrium species +** +** Output: +** f[] = vector of equilibrium function values. +*/ +{ + int i, m; + double x; + +// --- assign species concentrations to their proper positions in the global +// concentration vector ChemC1 + + for (i=1; i<=n; i++) + { + m = TankEquilSpecies[i]; + ChemC1[m] = y[i]; + } + +// --- use compiled functions if available + + if ( MSX.Compiler ) + { + MSXgetTankEquil(ChemC1, MSX.K, MSX.Tank[TheTank].param, HydVar, F); + for (i=1; i<=n; i++) + { + m = TankEquilSpecies[i]; + f[i] = MSXerr_validate(F[m], m, TANK, EQUIL); + } + return; + } + +// --- evaluate each tank equilibrium expression + + for (i=1; i<=n; i++) + { + m = TankEquilSpecies[i]; + x = mathexpr_eval(MSX.Species[m].tankExpr, getTankVariableValue); + f[i] = MSXerr_validate(x, m, TANK, EQUIL); + } +} + diff --git a/src/solver/msxcompiler.c b/src/solver/msxcompiler.c new file mode 100644 index 0000000..c98de10 --- /dev/null +++ b/src/solver/msxcompiler.c @@ -0,0 +1,367 @@ +/******************************************************************************* +** MODULE: MSXCOMPILER.C +** PROJECT: EPANET-MSX +** DESCRIPTION: compiles chemistry functions to a dynamic library file. +** COPYRIGHT: Copyright (C) 2006 Feng Shang, Lewis Rossman, and James Uber. +** All Rights Reserved. See license information in LICENSE.TXT. +** AUTHORS: L. Rossman, US EPA - NRMRL +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +*******************************************************************************/ + +#include +#include +#include +#include "msxtypes.h" +#include "msxfuncs.h" +#include "msxutils.h" + +// --- define WINDOWS + +#undef WINDOWS +#ifdef _WIN32 + #define WINDOWS +#endif +#ifdef __WIN32__ + #define WINDOWS +#endif +#ifdef WIN32 + #define WINDOWS +#endif + +// Local variables +//----------------- +char *Fname; // Prefix used for all file names +char TempName[L_tmpnam]; +char srcFile[MAXFNAME]; // Name of source code file +char objFile[MAXFNAME]; // Name of object file +char libFile[MAXFNAME]; // Name of library file +int Compiled; // Flag for compilation step + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +// Imported functions +//-------------------- +char * MSXchem_getVariableStr(int i, char *s); +//void MSXrpt_writeLine(char *line); + +// Exported functions +//-------------------- +int MSXcompiler_open(void); +void MSXcompiler_close(void); + +// Local functions +//----------------- +static void writeSrcFile(FILE* f); + +//============================================================================= + +int MSXcompiler_open() +/* +** Purpose: +** compiles MSX chemistry functions into a dynamic link library +** and loads the functions into the running application +** +** Input: +** none +** +** Returns: +** an error code (0 if no error). +*/ +{ + char cmd[256]; + char arch[100]; + FILE* f; + int err; + +// --- initialize + + Fname = NULL; + Compiled = FALSE; + +// --- get the name of a temporary file with directory path stripped from it +// and replace any '.' characters in it (for the Borland compiler to work) + + Fname = MSXutils_getTempName(TempName) ; + +// --- assign names to source code and compiled files + + strcpy(srcFile, Fname); + strcat(srcFile, ".c"); + strcpy(objFile, Fname); + strcat(objFile, ".o"); +#ifdef WINDOWS + strcpy(libFile, Fname); + strcat(libFile, ".dll"); +#else + strcpy(libFile, "lib"); + strcat(libFile, Fname); + strcat(libFile, ".so"); +#endif + +// --- write the chemistry functions to the source code file + + f = fopen(srcFile, "wt"); + if ( f == NULL ) return ERR_COMPILE_FAILED; + writeSrcFile(f); + fclose(f); + +// --- compile the source code file to a dynamic link library file + +#ifdef WINDOWS +#ifdef _WIN64 + strcpy(arch, "x64"); +#else + strcpy(arch, "x86"); +#endif + if ( MSX.Compiler == VC ) + { + sprintf(cmd, "runvc.bat %s %s", srcFile, arch); + err = MSXfuncs_run(cmd); + } + + else if ( MSX.Compiler == GC ) + { + sprintf(cmd, "gcc -c -O3 %s", srcFile); + err = MSXfuncs_run(cmd); + sprintf(cmd, "gcc -lm -shared -o %s %s", libFile, objFile); + err = MSXfuncs_run(cmd); + } + else return ERR_COMPILE_FAILED; +#else + if ( MSX.Compiler == GC ) + { + sprintf(cmd, "gcc -c -fPIC -O3 %s", srcFile); + err = system(cmd); + sprintf(cmd, "gcc -lm -shared -o %s %s", libFile, objFile); + err = system(cmd); + } + else return ERR_COMPILE_FAILED; +#endif + Compiled = (err == 0); // ttaxon - 9/7/10 + +// --- load the compiled chemistry functions from the library file + + if(Compiled) + { + err = MSXfuncs_load(libFile); + if ( err == 1 ) return ERR_COMPILE_FAILED; + if ( err == 2 ) return ERR_COMPILED_LOAD; + } + else + { + MSXcompiler_close(); + return ERR_COMPILE_FAILED; + } + return 0; +} + +//============================================================================= + +void MSXcompiler_close() +/* +** Purpose: +** frees resources used to load chemistry functions from the shared +** library and deletes all files used to compile and link the library. +** +** Input: +** none +** +** Returns: +** none. +*/ +{ + char cmd[256]; + if ( Compiled ) MSXfuncs_free(); + if ( Fname ) + { +#ifdef WINDOWS + // --- delete all files created from compilation + // (VC++ creates more than just an obj and dll file) + sprintf(cmd, "cmd /c del %s.*", Fname); + MSXfuncs_run(cmd); +#else + remove(TempName); + remove(srcFile); + remove(objFile); + remove(libFile); +#endif + } +} +//============================================================================= + +void writeSrcFile(FILE* f) +/* +** Purpose: +** writes C statements to the chemistry function source code file +** +** Input: +** f = pointer to the source code file +** +** Returns: +** none. +** +** Note: this function uses mathexpr_getStr() from mathexpr.c to +** reconstruct math expressions that were previously parsed +** into a stack of atomic terms by mathexpr_create(). The +** mathexpr_getStr function calls MSXchem_getVariableStr (in +** msxchem.c) to return a symbol for a particular variable that +** is used in the reconstucted expression in place of the +** variable's original name. For example, if NH3 were the name +** of the 2nd chemical species, then in the source code written +** here it would be denoted as c[2]; the third hydraulic variable, +** Velocity, would appear as h[3]. Similar notation is used for +** constants (k[]) and parameters (p[]). +*/ +{ + int i; + char e[1024]; + char headers[] = + +" /* Machine Generated EPANET-MSX File - Do Not Edit */ \n\n" +" #include \n" +" \n" +" #undef WINDOWS \n" +" #ifdef _WIN32 \n" +" #define WINDOWS \n" +" #endif \n" +" #ifdef __WIN32__ \n" +" #define WINDOWS \n" +" #endif \n" +" #ifdef WIN32 \n" +" #define WINDOWS \n" +" #endif \n" +" \n" +" #ifdef WINDOWS \n" +" #define DLLEXPORT __declspec(dllexport) \n" +" #else \n" +" #define DLLEXPORT \n" +" #endif \n" +" \n" +" void DLLEXPORT MSXgetPipeRates(double *, double *, double *, double *, double *); \n" +" void DLLEXPORT MSXgetTankRates(double *, double *, double *, double *, double *); \n" +" void DLLEXPORT MSXgetPipeEquil(double *, double *, double *, double *, double *); \n" +" void DLLEXPORT MSXgetTankEquil(double *, double *, double *, double *, double *); \n" +" void DLLEXPORT MSXgetPipeFormulas(double *, double *, double *, double *); \n" +" void DLLEXPORT MSXgetTankFormulas(double *, double *, double *, double *); \n" +" double term(int, double *, double *, double *, double *); \n"; + + char mathFuncs[] = + + " double coth(double); \n" + " double cot(double); \n" + " double acot(double); \n" + " double step(double); \n" + " double sgn(double); \n" + " \n" + " double coth(double x) { \n" + " return (exp(x) + exp(-x)) / (exp(x) - exp(-x)); } \n" + " double cot(double x) { \n" + " return 1.0 / tan(x); } \n" + " double acot(double x) { \n" + " return 1.57079632679489661923 - atan(x); } \n" + " double step(double x) { \n" + " if (x <= 0.0) return 0.0; \n" + " return 1.0; } \n" + " double sgn(double x) { \n" + " if (x < 0.0) return -1.0; \n" + " if (x > 0.0) return 1.0; \n" + " return 0.0; } \n"; + + +// --- write headers & non-intrinsic math functions to file + + fprintf(f, "%s", headers); + fprintf(f, "%s", mathFuncs); + +// --- write term functions + + fprintf(f, +"\n double term(int i, double c[], double k[], double p[], double h[])\n { \n"); + if ( MSX.Nobjects[TERM] > 0 ) + { + fprintf(f, " switch(i) { \n"); + for (i=1; i<=MSX.Nobjects[TERM]; i++) + { + fprintf(f, " case %d: return %s; \n", + i, mathexpr_getStr(MSX.Term[i].expr, e, MSXchem_getVariableStr)); + } + fprintf(f, " } \n"); + } + fprintf(f, " return 0.0; \n }\n"); + +// --- write pipe rate functions + + fprintf(f, +"\n void DLLEXPORT MSXgetPipeRates(double c[], double k[], double p[], double h[], double f[])\n { \n"); + for (i=1; i<=MSX.Nobjects[SPECIES]; i++) + { + if ( MSX.Species[i].pipeExprType == RATE ) + fprintf(f, " f[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].pipeExpr, e, + MSXchem_getVariableStr)); + } + fprintf(f, " }\n"); + +// --- write tank rate functions + + fprintf(f, +"\n void DLLEXPORT MSXgetTankRates(double c[], double k[], double p[], double h[], double f[])\n { \n"); + for (i=1; i<=MSX.Nobjects[SPECIES]; i++) + { + if ( MSX.Species[i].tankExprType == RATE ) + fprintf(f, " f[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].tankExpr, e, + MSXchem_getVariableStr)); + } + fprintf(f, " }\n"); + +// --- write pipe equilibrium functions + + fprintf(f, +"\n void DLLEXPORT MSXgetPipeEquil(double c[], double k[], double p[], double h[], double f[])\n { \n"); + for (i=1; i<=MSX.Nobjects[SPECIES]; i++) + { + if ( MSX.Species[i].pipeExprType == EQUIL ) + fprintf(f, " f[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].pipeExpr, e, + MSXchem_getVariableStr)); + } + fprintf(f, " }\n"); + +// --- write tank equilibrium functions + + fprintf(f, +"\n void DLLEXPORT MSXgetTankEquil(double c[], double k[], double p[], double h[], double f[])\n { \n"); + for (i=1; i<=MSX.Nobjects[SPECIES]; i++) + { + if ( MSX.Species[i].tankExprType == EQUIL ) + fprintf(f, " f[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].tankExpr, e, + MSXchem_getVariableStr)); + } + fprintf(f, " }\n"); + +// --- write pipe formula functions + + fprintf(f, +"\n void DLLEXPORT MSXgetPipeFormulas(double c[], double k[], double p[], double h[])\n { \n"); + for (i=1; i<=MSX.Nobjects[SPECIES]; i++) + { + if ( MSX.Species[i].pipeExprType == FORMULA ) + fprintf(f, " c[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].pipeExpr, e, + MSXchem_getVariableStr)); + } + fprintf(f, " }\n"); + +// --- write tank formula functions + + fprintf(f, +"\n void DLLEXPORT MSXgetTankFormulas(double c[], double k[], double p[], double h[])\n { \n"); + for (i=1; i<=MSX.Nobjects[SPECIES]; i++) + { + if ( MSX.Species[i].tankExprType == FORMULA ) + fprintf(f, " c[%d] = %s; \n", i, mathexpr_getStr(MSX.Species[i].tankExpr, e, + MSXchem_getVariableStr)); + } + fprintf(f, " }\n"); + fprintf(f, "\n"); +} diff --git a/src/solver/msxdict.h b/src/solver/msxdict.h new file mode 100644 index 0000000..b68e97a --- /dev/null +++ b/src/solver/msxdict.h @@ -0,0 +1,36 @@ +/************************************************************************ +** MODULE: MSXDICT.H +** PROJECT: EPANET-MSX +** DESCRIPTION: Dictionary of key words used by the +** EPANET Multi-Species Extension toolkit. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 09/29/08 +***********************************************************************/ + +// NOTE: the entries in MsxsectWords must match the entries in the enumeration +// variable SectionType defined in msxtypes.h. +static char *MsxSectWords[] = {"[TITLE", "[SPECIE", "[COEFF", "[TERM", + "[PIPE", "[TANK", "[SOURCE", "[QUALITY", + "[PARAM", "[PATTERN", "[OPTION", + "[REPORT", "[DIFFU", NULL}; +static char *ReportWords[] = {"NODE", "LINK", "SPECIE", "FILE", "PAGESIZE", NULL}; +static char *OptionTypeWords[] = {"AREA_UNITS", "RATE_UNITS", "SOLVER", "COUPLING", + "TIMESTEP", "RTOL", "ATOL", "COMPILER", "SEGMENTS","PECLET",NULL}; +static char *CompilerWords[] = {"NONE", "VC", "GC", NULL}; +static char *SourceTypeWords[] = {"CONC", "MASS", "SETPOINT", "FLOW", NULL}; +static char *MixingTypeWords[] = {"MIXED", "2COMP", "FIFO", "LIFO", NULL}; +static char *MassUnitsWords[] = {"MG", "UG", "MOLE", "MMOL", NULL}; +static char *AreaUnitsWords[] = {"FT2", "M2", "CM2", NULL}; +static char *TimeUnitsWords[] = {"SEC", "MIN", "HR", "DAY", NULL}; +static char *SolverTypeWords[] = {"EUL", "RK5", "ROS2", NULL}; +static char *CouplingWords[] = {"NONE", "FULL", NULL}; +static char *ExprTypeWords[] = {"", "RATE", "FORMULA", "EQUIL", NULL}; +static char *HydVarWords[] = {"", "D", "Q", "U", "Re", + "Us", "Ff", "Av", "Kc", "Len", NULL}; /*Len added Feng Shang 01/27/2023*/ +static char YES[] = "YES"; +static char NO[] = "NO"; +static char ALL[] = "ALL"; +static char NONE[] = "NONE"; diff --git a/src/solver/msxdispersion.c b/src/solver/msxdispersion.c new file mode 100644 index 0000000..2282539 --- /dev/null +++ b/src/solver/msxdispersion.c @@ -0,0 +1,584 @@ +/****************************************************************************** +** MODULE: MSXDISPERSION.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Dispersion solver for Lagrangian ADR +******************************************************************************/ + +#include +#include +#include +#include +#include +#include "msxtypes.h" +#include "dispersion.h" +#include "smatrix.h" +#define ERRCODE(x) (errcode = ((errcode>100) ? (errcode) : (x))) +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +static double* al; //vector helping solve tridaigonal system of eqns. +static double* bl; //vector helping solve tridaigonal system of eqns. +static double* cl; //vector helping solve tridaigonal system of eqns. +static double* rl; //vector helping solve tridaigonal system of eqns. +static double* sol; //vector helping solve tridaigonal system of eqns. + +static double* gam; + +#pragma omp threadprivate(al, bl, cl, rl, sol, gam) + +int dispersion_open() +{ + int errcode=0; +#pragma omp parallel + { + al = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); + bl = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); + cl = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); + rl = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); + sol = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); + gam = (double*)calloc(MSX.MaxSegments + 2, sizeof(double)); + #pragma omp critical + { + ERRCODE(MEMCHECK(al)); + ERRCODE(MEMCHECK(bl)); + ERRCODE(MEMCHECK(cl)); + ERRCODE(MEMCHECK(rl)); + ERRCODE(MEMCHECK(sol)); + ERRCODE(MEMCHECK(gam)); + } + } + return errcode; + +} + +int dispersion_close() +{ + int errcode = 0; +#pragma omp parallel + { + FREE(al); + FREE(bl); + FREE(cl); + FREE(rl); + FREE(sol); + FREE(gam); + } + return errcode; +} + +void dispersion_pipe(int m, double tstep) +{ + + double cons = 0.0; + double ldispersion = 0.0; + double flowrate = 0.0, velocity = 0.0, area = 0.0; + int nseg = 0, k; + double diam = 0.0; + double vd = 0.0, vu = 0.0, vself = 0.0, asquare = 0.0, dh = 0.0, frictionfactor = 0.0; + double reynolds=0, shearvelocity=0; + Pseg seg = NULL; + + double elpt = 0.0; + double d0 = 1.292e-8; //molecular diffusivity 1.292e-8 ft^2/s 1.2e-9 m^2/s + + d0 = MSX.Dispersion.md[m]; + #pragma omp parallel + { + #pragma omp for private(seg, cons, vd, vu, vself, k, nseg, asquare, velocity, diam, area, flowrate, reynolds, dh, frictionfactor, shearvelocity, ldispersion, elpt) + for (k = 1; k <= MSX.Nobjects[LINK]; k++) + { + + velocity = 0; + if (MSX.FirstSeg[k] == NULL) + continue; + diam = MSX.Link[k].diam; + // Compute Reynolds No. + flowrate = (MSX.S[k] <= CLOSED) ? 0.0 : MSX.Q[k]; + area = PI * diam * diam / 4.0; // pipe area + if (area > 0.0 && MSX.Link[k].len > 0.0 && ABS(flowrate) > 0.0) + { + velocity = fabs(flowrate) / area; // flow velocity + reynolds = velocity * diam / MSX.Dispersion.viscosity; // Reynolds number //#define VISCOS 1.1E-5 // Kinematic viscosity of water // @ 20 deg C (sq ft/sec) + dh = ABS(MSX.H[MSX.Link[k].n1] - MSX.H[MSX.Link[k].n2]); + if (dh > 0.00001) + frictionfactor = 39.725 * dh * pow(diam, 5) / (MSX.Link[k].len * SQR(flowrate)); + else + frictionfactor = 0.0; + shearvelocity = velocity * sqrt(frictionfactor / 8); + + if (d0 < 0) + { + ldispersion = MSX.Dispersion.ld[m]; + } + else if (reynolds > 2300) //Basha 2007 + { + ldispersion = 0.5 * diam * shearvelocity * (10.1 + 577 * pow(reynolds / 1000.0, -2.2)); + + } + /* else //Basha 2007 + { + ldispersion = SQR(0.5 * diam * velocity) / (48 * d0); + elpt = MSX.Link[k].len / velocity; + ldispersion = ldispersion * (1 - exp(-12.425 * d0 * elpt / SQR(0.5 * diam))); + ldispersion += d0; + }*/ + else //Lee 2004 averaged + { + ldispersion = SQR(0.5 * diam * velocity) / (48 * d0); + elpt = MSX.Link[k].len / velocity; + double interv = 16.0 * d0 * elpt / (0.25 * diam * diam); + ldispersion = ldispersion * (1 - (1 - exp(-interv))/interv); + ldispersion += d0; + + } + + } + else + { + ldispersion = 0; + } + + if (ldispersion < 0.0) + { + ldispersion = 0; + MSX.Dispersion.pipeDispersionCoeff[k] = 0; + continue; + } + + double domi; + + if (velocity > 0) + domi = ldispersion / (velocity * velocity * tstep); + else + domi = 1000; + if (domi >= 0.000 && MSX.Link[k].len*velocity/ldispersion < MSX.Dispersion.PecletLimit) //Peclet numer + { + MSX.Dispersion.pipeDispersionCoeff[k] = ldispersion; + } + else + { + MSX.Dispersion.pipeDispersionCoeff[k] = 0; + continue; + } + asquare = area * area; + seg = MSX.FirstSeg[k]; //downstream + cons = 2.0 * ldispersion * asquare * tstep; + vd = 0.0; + bl[0] = 1.0; + cl[0] = 0.0; + rl[0] = 0.0; + nseg = 0; + + while (seg != NULL) + { + nseg++; + vself = seg->v; + rl[nseg] = seg->c[m]; + seg = seg->prev; + if (seg) + vu = seg->v; + else + vu = 0.0; + al[nseg] = -cons / (vself * vself + vself * vd); + cl[nseg] = -cons / (vself * vself + vself * vu); + bl[nseg] = 1 - al[nseg] - cl[nseg]; + + vd = vself; + } + if (nseg == 0) + continue; + + + al[nseg + 1] = 0.0; + bl[nseg + 1] = 1.0; + rl[nseg + 1] = 0.0; + + if (reynolds >= 0) + tridiag(nseg + 2, al, bl, cl, rl, sol); //nseg+2 <= 1000 here + else + { + for (int p = 0; p <= nseg + 1; p++) + sol[p] = rl[p]; + } + + seg = MSX.FirstSeg[k]; //downstream segment + int segindex = 1; + while (seg != NULL) + { + seg->hresponse = sol[segindex]; + seg = seg->prev; + segindex++; + } + /*clear initial condition*/ + for (int p = 1; p < nseg + 1; p++) + rl[p] = 0.0; + + /*downstream unit boundary condition*/ + rl[0] = 1.0; + if (reynolds >= 0) + tridiag(nseg + 2, al, bl, cl, rl, sol); + else + { + for (int p = 0; p <= nseg + 1; p++) + sol[p] = rl[p]; + } + + seg = MSX.FirstSeg[k]; //downstream + segindex = 1; + while (seg != NULL) + { + seg->dresponse = sol[segindex]; + seg = seg->prev; + segindex++; + } + + /*upstream unit boundary condition*/ + rl[0] = 0.0; + rl[nseg + 1] = 1.0; + if (reynolds >= 0) + tridiag(nseg + 2, al, bl, cl, rl, sol); //nseg+2 <= 100 here + else + { + for (int p = 0; p <= nseg + 1; p++) + sol[p] = rl[p]; + } + + seg = MSX.FirstSeg[k]; //downstream + segindex = 1; + while (seg != NULL) + { + seg->uresponse = sol[segindex]; + seg = seg->prev; + segindex++; + } + } + } +} + +void solve_nodequal(int m, double tstep) +{ + + Pseg firstseg; + Pseg lastseg; + Psource source; + int n1, n2; + double diam, area, asquare; + + // double dispersion = 147.25; + double ldispersion; + double coelastseg, coefirstseg; + + int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; + int found = 0; + + + //let's take a look of the matrix + + memset(MSX.Dispersion.Aii, 0, (MSX.Nobjects[NODE] + 1) * sizeof(double)); + memset(MSX.Dispersion.Aij, 0, (MSX.Dispersion.Ncoeffs + 1) * sizeof(double)); + memset(MSX.Dispersion.F, 0, (MSX.Nobjects[NODE] + 1) * sizeof(double)); + for (int k = 1; k <= MSX.Nobjects[LINK]; k++) + { + ldispersion = MSX.Dispersion.pipeDispersionCoeff[k]; + if (ldispersion <= 0) + continue; + n1 = MSX.Link[k].n1; //upstream + n2 = MSX.Link[k].n2; //downstream + if (MSX.FlowDir[k] < 0) + { + n1 = MSX.Link[k].n2; //upstream + n2 = MSX.Link[k].n1; //downstream + } + diam = MSX.Link[k].diam; + area = 0.25 * PI * diam * diam; + asquare = area * area; + firstseg = MSX.FirstSeg[k]; //downstream + lastseg = MSX.LastSeg[k]; //upstream + + + if (firstseg == NULL) + continue; + + coefirstseg = ldispersion * asquare / firstseg->v; //dispersion should be pipe by pipe + coelastseg = ldispersion * asquare / lastseg->v; //dispersion should be pipe by pipe + MSX.Dispersion.Aij[MSX.Dispersion.Ndx[k]] -= coefirstseg * firstseg->uresponse; //coefirstseg*firstseg->greenu = coelastseg*lastseg->greend + + found = 0; + source = MSX.Node[n2].sources; + while(source != NULL) + { + if (source->species == m) + { + found = 1; + break; + } + else + source = source->next; + } + + if (n2 <= njuncs) + { + if (source == NULL || source->c0 <= 0.0) + { + MSX.Dispersion.Aii[MSX.Dispersion.Row[n2]] += coefirstseg * (1.0 - firstseg->dresponse); + + MSX.Dispersion.F[MSX.Dispersion.Row[n2]] += coefirstseg * firstseg->hresponse; + } + else + { + MSX.Dispersion.Aij[MSX.Dispersion.Ndx[k]] = 0; + MSX.Dispersion.F[MSX.Dispersion.Row[n1]] += coelastseg * MSX.LastSeg[k]->dresponse * MSX.Node[n2].c[m]; + } + } + else + { + MSX.Dispersion.F[MSX.Dispersion.Row[n1]] += coelastseg * MSX.LastSeg[k]->dresponse * MSX.Node[n2].c[m]; + } + + + found = 0; + source = MSX.Node[n1].sources; + while (source != NULL) + { + if (source->species == m) + { + found = 1; + break; + } + else + source = source->next; + } + + if (n1 <= njuncs) + { + source = MSX.Node[n1].sources; + if (source == NULL || source->c0 <= 0.0) + { + MSX.Dispersion.Aii[MSX.Dispersion.Row[n1]] += coelastseg * (1.0 - lastseg->uresponse); + MSX.Dispersion.F[MSX.Dispersion.Row[n1]] += coelastseg * lastseg->hresponse; + } + else + { + MSX.Dispersion.Aij[MSX.Dispersion.Ndx[k]] = 0; //sure + MSX.Dispersion.F[MSX.Dispersion.Row[n2]] += coefirstseg * firstseg->uresponse * MSX.Node[n1].c[m]; + } + + } + else + { + MSX.Dispersion.F[MSX.Dispersion.Row[n2]] += coefirstseg * firstseg->uresponse * MSX.Node[n1].c[m]; + } + } + for (int i = 1; i <= njuncs; i++) + { + if (MSX.Dispersion.Aii[MSX.Dispersion.Row[i]] == 0.0) //no dispersion around the junction at all + { + MSX.Dispersion.Aii[MSX.Dispersion.Row[i]] = 1.0; + + MSX.Dispersion.F[MSX.Dispersion.Row[i]] = 1.0 * MSX.Node[i].c[m]; + } + } + + int errcode = linsolve(njuncs, MSX.Dispersion.Aii, MSX.Dispersion.Aij, MSX.Dispersion.F); + + for (int i = 1; i <= njuncs; i++) + { + MSX.Node[i].c[m] = MSX.Dispersion.F[MSX.Dispersion.Row[i]]; + } + +} + + +void segqual_update(int m, double tstep) +{ + + Pseg seg = NULL; + Psource source = NULL; + int n1 = 0, n2 = 0, k; + double mass1 = 0; + double mass2 = 0; + double dispersedin = 0; + double ldispersion = 0, massin = 0; + double area = 0.0; + int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; +#pragma omp parallel + { + #pragma omp for private(k, n1, n2, seg, source, mass1, mass2, ldispersion, massin, area) + for (k = 1; k <= MSX.Nobjects[LINK]; k++) + { + mass1 = 0; + mass2 = 0; + ldispersion = MSX.Dispersion.pipeDispersionCoeff[k]; + if (ldispersion <= 0.0) + continue; + area = 0.25 * PI * MSX.Link[k].diam * MSX.Link[k].diam; + n1 = MSX.Link[k].n1; + n2 = MSX.Link[k].n2; + if (MSX.FlowDir[k] < 0.0) + { + n1 = MSX.Link[k].n2; + n2 = MSX.Link[k].n1; + } + seg = MSX.FirstSeg[k]; + while (seg != NULL) //update segment concentration based on new up/down node quality + { + mass1 += seg->c[m] * seg->v; + seg->c[m] = seg->hresponse + MSX.Node[n2].c[m] * seg->dresponse + MSX.Node[n1].c[m] * seg->uresponse; + + mass2 += seg->c[m] * seg->v; + seg = seg->prev; + } + if (MSX.FirstSeg[k] == NULL) + continue; + + source = MSX.Node[n2].sources; + while (source != NULL) + { + if (source->species == m) + break; + source = source->next; + } + massin = 0; + if (source != NULL && source->c0 > 0) + { + massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n2].c[m] - MSX.FirstSeg[k]->c[m]) * LperFT3 / MSX.FirstSeg[k]->v; + } + else if (n2 > njuncs && MSX.Tank[n2 - njuncs].a == 0) //we assume constant tank and reservoir concentration during dispersion which may not be true for small tanks + { + massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n2].c[m] - MSX.FirstSeg[k]->c[m]) * LperFT3 / MSX.FirstSeg[k]->v; + } + else if (n2 > njuncs && MSX.Tank[n2 - njuncs].a > 0.0) + { + massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n2].c[m] - MSX.FirstSeg[k]->c[m]) * LperFT3 / MSX.FirstSeg[k]->v; + + } +#pragma omp critical + { + dispersedin += massin; + } + source = MSX.Node[n1].sources; + while (source != NULL) + { + if (source->species == m) + break; + source = source->next; + } + massin = 0; + if (source != NULL && source->c0 > 0) + { + massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n1].c[m] - MSX.LastSeg[k]->c[m]) * LperFT3 / MSX.LastSeg[k]->v; + } + else if (n1 > njuncs && MSX.Tank[n1 - njuncs].a == 0) + { + massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n1].c[m] - MSX.LastSeg[k]->c[m]) * LperFT3 / MSX.LastSeg[k]->v; + } + else if (n1 > njuncs && MSX.Tank[n1 - njuncs].a > 0.0) + { + + massin = 2.0 * ldispersion * tstep * area * area * (MSX.Node[n1].c[m] - MSX.LastSeg[k]->c[m]) * LperFT3 / MSX.LastSeg[k]->v; + + } +#pragma omp critical + { + dispersedin += massin; + } + } + } + MSX.MassBalance.indisperse[m] += dispersedin; + + +} + + +void disperse_tankqual(int n, int m, double massin) +{ + int j, tm, k; + Pseg seg; + double c, v; + + j = MSX.Node[n].tank; + if (j < 0) + return; + else if (MSX.Tank[j].a == 0) + return; + + k = MSX.Nobjects[LINK] + j; + tm = MSX.Tank[j].mixModel; + + if (tm == MIX1|| tm == MIX2) + { + seg = MSX.LastSeg[k]; + if (seg) + { + v = seg->v; + c = seg->c[m]; + if (v > 0) + c = (c * v * LperFT3 + massin) / (v * LperFT3); + + c = MAX(0, c); + seg->c[m] = c; + MSX.Tank[j].c[m] = c; + MSX.Node[n].c[m] = c; + } + } + else if (tm == FIFO) + { + seg = MSX.FirstSeg[k]; + if (seg) + { + v = seg->v; + c = seg->c[m]; + if (v > 0) + c = (c * v * LperFT3 + massin) / (v * LperFT3); + + if( c < 0) + c = MAX(0, c); + seg->c[m] = c; + + } + } + else if (tm == LIFO) + { + seg = MSX.FirstSeg[k]; + if (seg) + { + v = seg->v; + c = seg->c[m]; + if (v > 0) + c = (c * v * LperFT3 + massin) / (v * LperFT3); + + c = MAX(0, c); + seg->c[m] = c; + + } + + } + + +} + + + + + +// Solve tri-daigonal system of eqns. using Thomas' algorithm + +void tridiag(int n, double *a, double *b, double *c, double *r, double *y) +{ + int j; + double bet; + + bet = b[0]; + y[0] = r[0] / bet; + for (j = 1; j < n; j++) + { + gam[j] = c[j - 1] / bet; + bet = b[j] - a[j] * gam[j]; + y[j] = (r[j] - a[j] * y[j - 1]) / bet; + } + for (j = n - 2; j >= 0; j--) + { + y[j] -= gam[j + 1] * y[j + 1]; + } +} diff --git a/src/solver/msxerr.c b/src/solver/msxerr.c new file mode 100644 index 0000000..63dfa06 --- /dev/null +++ b/src/solver/msxerr.c @@ -0,0 +1,116 @@ +/****************************************************************************** +** MODULE: MSXERR.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Math error reporting routines. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +******************************************************************************/ + +#include +#include + +#include "msxtypes.h" +#include "epanet2.h" + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +// Local variables +//----------------- +static int mathError; // math error flag +static char mathErrorMsg[1024]; // math error message +static char* elementTxt[] = // see ObjectType in msxtypes.h + {"", "pipe", "tank"}; +static char* exprTypeTxt[] = // see ExpressionType in msxtypes.h + {"", "rate", "formula", "equilibrium"}; + +// Exported functions +//-------------------- +void MSXerr_clearMathError(void); +int MSXerr_mathError(void); +double MSXerr_validate(double x, int index, int element, int exprType); +void MSXerr_writeMathErrorMsg(void); + + +//============================================================================= + +void MSXerr_clearMathError() +/* +** Purpose: +** clears the math error flag. +*/ +{ + mathError = 0; + strcpy(mathErrorMsg, ""); +} + +//============================================================================= + +int MSXerr_mathError() +/* +** Purpose: +** returns the current state of the math error flag. +*/ +{ + return mathError; +} + +//============================================================================= + +void MSXerr_writeMathErrorMsg() +/* +** Purpose: +** writes math error message to EPANET report file. +*/ +{ + ENwriteline(mathErrorMsg); + ENwriteline(""); +} + +//============================================================================= + +double MSXerr_validate(double x, int index, int element, int exprType) +/* +** Purpose: +** checks if a number is valid or not. +** +** Input: +** x = the number to check +** index = array index of species or term that x was computed for +** element = LINK for a pipe element or TANK for a tank element +** exprType = type of expression that produced x +** +** Returns: +** the value of x if it's a valid number or 0 otherwise. +*/ +{ + // return x if it's a valid number + if (x == x) return x; + + // return 0 if the math error flag has previously been set + // (we only want the first math error identified since others + // may have propagated from it) + if (mathError) return 0.0; + + // construct a math error message + if ( exprType == TERM ) + { + sprintf(mathErrorMsg, + "Ilegal math operation occurred for term:\n %s", + MSX.Term[index].id); + } + else + { + sprintf(mathErrorMsg, + "Ilegal math operation occurred in %s %s expression for species:\n %s", + elementTxt[element], exprTypeTxt[exprType], MSX.Species[index].id); + } + + // set the math error flag and return 0 + mathError = 1; + return 0.0; +} diff --git a/src/solver/msxfile.c b/src/solver/msxfile.c new file mode 100644 index 0000000..26cc66d --- /dev/null +++ b/src/solver/msxfile.c @@ -0,0 +1,260 @@ +/******************************************************************************* +** MODULE: MSXFILE.C +** PROJECT: EPANET-MSX +** DESCRIPTION: writes MSX project data to a MSX input file. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +*******************************************************************************/ + +#include +#include + +#include "msxtypes.h" +#include "msxutils.h" +#include "msxdict.h" +#include "epanet2.h" + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +// Exported functions +//-------------------- +int MSXfile_save(FILE *f); + +// Local functions +//----------------- +static void saveSpecies(FILE *f); +static void saveCoeffs(FILE *f); +static int saveInpSections(FILE *f); +static void saveParams(FILE *f); +static void saveQuality(FILE *f); +static void saveSources(FILE *f); +static void savePatterns(FILE *f); + +//============================================================================= + +int MSXfile_save(FILE *f) +/* +** Purpose: +** saves current MSX project data to file. +** +** Input: +** f = pointer to MSX file where data are saved. +*/ +{ + int errcode; + fprintf(f, "[TITLE]"); + fprintf(f, "\n%s\n", MSX.Title); + saveSpecies(f); + saveCoeffs(f); + errcode = saveInpSections(f); + saveParams(f); + saveQuality(f); + saveSources(f); + savePatterns(f); + return errcode; +} + +//============================================================================= + +void saveSpecies(FILE *f) +{ + int i, n; + fprintf(f, "\n[SPECIES]"); + n = MSX.Nobjects[SPECIES]; + for (i=1; i<=n; i++) + { + if ( MSX.Species[i].type == BULK ) fprintf(f, "\nBULK "); + else fprintf(f, "\nWALL "); + fprintf(f, "%-32s %-15s %e %e", + MSX.Species[i].id, MSX.Species[i].units, + MSX.Species[i].aTol, MSX.Species[i].rTol); + } +} + +//============================================================================= + +void saveCoeffs(FILE *f) +{ + int i, n; + fprintf(f, "\n\n[COEFFICIENTS]"); + n = MSX.Nobjects[CONSTANT]; + for (i=1; i<=n; i++) + { + fprintf(f, "\nCONSTANT %-32s %e", + MSX.Const[i].id, MSX.Const[i].value); + } + n = MSX.Nobjects[PARAMETER]; + for (i=1; i<=n; i++) + { + fprintf(f, "\nPARAMETER %-32s %e", + MSX.Param[i].id, MSX.Param[i].value); + } +} + +//============================================================================= + +int saveInpSections(FILE *f) +{ + char line[MAXLINE+1]; + char writeLine; + int newsect; + + if ((MSX.MsxFile.file = fopen(MSX.MsxFile.name,"rt")) == NULL) return ERR_OPEN_MSX_FILE; + rewind(MSX.MsxFile.file); + + fprintf(f,"\n\n"); + writeLine = FALSE; + while ( fgets(line, MAXLINE, MSX.MsxFile.file) != NULL ) + { + if (*line == '[' ) + { + writeLine = TRUE; + newsect = MSXutils_findmatch(line, MsxSectWords); + if ( newsect >= 0 ) switch(newsect) + { + case s_OPTION: + case s_TERM: + case s_PIPE: + case s_TANK: + case s_REPORT: + break; + default: + writeLine = FALSE; + } + } + if ( writeLine) fprintf(f, "%s", line); + } + if ( MSX.MsxFile.file ) fclose(MSX.MsxFile.file); + MSX.MsxFile.file = NULL; + return 0; +} + +//============================================================================= + +void saveParams(FILE *f) +{ + int i, j, k; + double x; + char id[MAXLINE+1]; + + if ( MSX.Nobjects[PARAMETER] > 0 ) + { + fprintf(f, "\n\n[PARAMETERS]"); + for (j=1; j<=MSX.Nobjects[PARAMETER]; j++) + { + x = MSX.Param[j].value; + for (i=1; i<=MSX.Nobjects[LINK]; i++) + { + if ( MSX.Link[i].param[j] != x ) + { + ENgetlinkid(i, id); + fprintf(f, "\nPIPE %-32s %-32s %e", + id, MSX.Param[j].id, MSX.Link[i].param[j]); + } + } + for (i=1; i<=MSX.Nobjects[TANK]; i++) + { + if ( MSX.Tank[i].param[j] != x ) + { + k = MSX.Tank[i].node; + ENgetnodeid(k, id); + fprintf(f, "\nTANK %-32s %-32s %e", + id, MSX.Param[j].id, MSX.Tank[i].param[j]); + } + } + } + } +} + +//============================================================================= + +void saveQuality(FILE *f) +{ + int i, j; + char id[MAXLINE+1]; + + fprintf(f, "\n\n[QUALITY]"); + for (j=1; j<=MSX.Nobjects[SPECIES]; j++) + { + if (MSX.C0[j] > 0.0) + fprintf(f, "\nGLOBAL %-32s %e", + MSX.Species[j].id, MSX.C0[j]); + + for (i=1; i<=MSX.Nobjects[NODE]; i++) + { + if ( MSX.Node[i].c0[j] > 0.0 && MSX.Node[i].c0[j] != MSX.C0[j]) + { + ENgetnodeid(i, id); + fprintf(f, "\nNODE %-32s %-32s %e", + id, MSX.Species[j].id, MSX.Node[i].c0[j]); + } + } + for (i=1; i<=MSX.Nobjects[LINK]; i++) + { + if ( MSX.Link[i].c0[j] > 0.0 && MSX.Link[i].c0[j] != MSX.C0[j]) + { + ENgetlinkid(i, id); + fprintf(f, "\nLINK %-32s %-32s %e", + id, MSX.Species[j].id, MSX.Link[i].c0[j]); + } + } + } +} + +//============================================================================= + +void saveSources(FILE *f) +{ + int i; + Psource source; + char id[MAXLINE+1]; + + fprintf(f, "\n\n[SOURCES]"); + for (i=1; i<=MSX.Nobjects[NODE]; i++) + { + source = MSX.Node[i].sources; + while ( source ) + { + if ( source->c0 > 0.0 && source->type > -1) //Feng Shang 09/23/2008 + { + ENgetnodeid(i, id); + fprintf(f, "\n%-10s %-32s %-32s %e", + SourceTypeWords[source->type], id, + MSX.Species[source->species].id, source->c0); + if ( source->pat > 0 ) + fprintf(f, " %-32s", MSX.Pattern[source->pat].id); + } + source = source->next; + } + } +} + +//============================================================================= + +void savePatterns(FILE *f) +{ + int i, count; + SnumList *listItem; + + if ( MSX.Nobjects[PATTERN] > 0 ) fprintf(f, "\n\n[PATTERNS]"); + for (i=1; i<=MSX.Nobjects[PATTERN]; i++) + { + count = 0; + listItem = MSX.Pattern[i].first; + while (listItem) + { + if ( count % 6 == 0 ) + { + fprintf(f, "\n%-32s", MSX.Pattern[i].id); + } + fprintf(f, " %e", listItem->value); + count++; + listItem = listItem->next; + } + } +} diff --git a/src/solver/msxfuncs.c b/src/solver/msxfuncs.c new file mode 100644 index 0000000..7af0311 --- /dev/null +++ b/src/solver/msxfuncs.c @@ -0,0 +1,165 @@ +/******************************************************************************* +** MODULE: MSXFUNCS.C +** PROJECT: EPANET-MSX +** DESCRIPTION: compiles chemistry functions to a shared dynamic library. +** COPYRIGHT: Copyright (C) 2007 Feng Shang, Lewis Rossman, and James Uber. +** All Rights Reserved. See license information in LICENSE.TXT. +** AUTHORS: see AUTHORS +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2014 +*******************************************************************************/ + +#include + +// --- define WINDOWS + +#undef WINDOWS +#ifdef _WIN32 + #define WINDOWS +#endif +#ifdef __WIN32__ + #define WINDOWS +#endif +#ifdef WIN32 + #define WINDOWS +#endif + +#ifdef WINDOWS +#include +HMODULE hDLL; +#else + #include + void *hDLL; +#endif + +#include "msxfuncs.h" + +//============================================================================= + +int MSXfuncs_load(char * libName) +/* +** Purpose: +** loads compiled chemistry functions from a named library +** +** Input: +** libName = path to shared library +** +** Returns: +** an error code (0 if no error). +*/ +{ + +#ifdef WINDOWS + hDLL = LoadLibraryA(libName); + if (hDLL == NULL) return 1; + + MSXgetPipeRates = (MSXGETRATES) GetProcAddress(hDLL, "MSXgetPipeRates"); + MSXgetTankRates = (MSXGETRATES) GetProcAddress(hDLL, "MSXgetTankRates"); + MSXgetPipeEquil = (MSXGETEQUIL) GetProcAddress(hDLL, "MSXgetPipeEquil"); + MSXgetTankEquil = (MSXGETEQUIL) GetProcAddress(hDLL, "MSXgetTankEquil"); + MSXgetPipeFormulas = (MSXGETFORMULAS) GetProcAddress(hDLL, "MSXgetPipeFormulas"); + MSXgetTankFormulas = (MSXGETFORMULAS) GetProcAddress(hDLL, "MSXgetTankFormulas"); + +#else + hDLL = dlopen(libName, RTLD_LAZY); + if (hDLL == NULL) return 1; + + MSXgetPipeRates = (MSXGETRATES) dlsym(hDLL, "MSXgetPipeRates"); + MSXgetTankRates = (MSXGETRATES) dlsym(hDLL, "MSXgetTankRates"); + MSXgetPipeEquil = (MSXGETEQUIL) dlsym(hDLL, "MSXgetPipeEquil"); + MSXgetTankEquil = (MSXGETEQUIL) dlsym(hDLL, "MSXgetTankEquil"); + MSXgetPipeFormulas = (MSXGETFORMULAS) dlsym(hDLL, "MSXgetPipeFormulas"); + MSXgetTankFormulas = (MSXGETFORMULAS) dlsym(hDLL, "MSXgetTankFormulas"); +#endif + + if (NULL == MSXgetPipeRates || NULL == MSXgetTankRates || + NULL == MSXgetPipeEquil || NULL == MSXgetTankEquil || + NULL == MSXgetPipeFormulas || NULL == MSXgetTankFormulas) + { + MSXfuncs_free(); + hDLL = NULL; + return 2; + } + return 0; +} + +//============================================================================= + +void MSXfuncs_free() +/* +** Purpose: +** frees the handle to the shared function library +** +** Input: +** none +** +** Returns: +** none +*/ +{ +#ifdef WINDOWS + if (hDLL) FreeLibrary(hDLL); +#else + if (hDLL) dlclose(hDLL); +#endif +} + +//============================================================================= + +int MSXfuncs_run(char* cmdLine) +/* +** Purpose: +** executes a program and waits for it to end +** +** Input: +** cmdLine = command line string that executes the program +** +** Returns: +** the program's exit code (or -1 if the program was not run) +*/ +{ +#ifdef WINDOWS + + unsigned long exitCode; + STARTUPINFOA si; + PROCESS_INFORMATION pi; + + // --- initialize data structures + + memset(&si, 0, sizeof(si)); + memset(&pi, 0, sizeof(pi)); + si.cb = sizeof(si); + + // --- hide the window that the program runs in + + si.dwFlags = STARTF_USESHOWWINDOW; + si.wShowWindow = SW_HIDE; + + // --- execute the command line in a new console window + exitCode = CreateProcess(NULL, cmdLine, NULL, NULL, 0, + CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi); + if (exitCode == 0) + { + exitCode = GetLastError(); + return exitCode; + } + + // --- wait for program to end + + exitCode = WaitForSingleObject(pi.hProcess, INFINITE); + + // --- retrieve the error code produced by the program + + BOOL rt = GetExitCodeProcess(pi.hProcess, &exitCode); + + // --- release handles + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return exitCode; + +#else + return -1; +#endif +} + diff --git a/src/solver/msxfuncs.h b/src/solver/msxfuncs.h new file mode 100644 index 0000000..4cb7d19 --- /dev/null +++ b/src/solver/msxfuncs.h @@ -0,0 +1,35 @@ +/************************************************************************ +** MODULE: MSXFUNCS.H +** PROJECT: EPANET-MSX +** DESCRIPTION: Definitions of functions loaded from compiled chemistry file. +** COPYRIGHT: Copyright (C) 2007 Feng Shang, Lewis Rossman, and James Uber. +** All Rights Reserved. See license information in LICENSE.TXT. +** AUTHORS: See Authors +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +***********************************************************************/ + +#ifndef MSXFUNCS_H +#define MSXFUNCS_H + +// Define pointers for each group of chemistry functions +typedef void (*MSXGETRATES)(double *, double *, double * , double *, double *); +typedef void (*MSXGETEQUIL)(double *, double *, double * , double *, double *); +typedef void (*MSXGETFORMULAS)(double *, double *, double *, double *); + +// Declare each chemistry function +MSXGETRATES MSXgetPipeRates; +MSXGETRATES MSXgetTankRates; +MSXGETEQUIL MSXgetPipeEquil; +MSXGETEQUIL MSXgetTankEquil; +MSXGETFORMULAS MSXgetPipeFormulas; +MSXGETFORMULAS MSXgetTankFormulas; + +// Functions that load and free the chemistry functions +int MSXfuncs_load(char *); +void MSXfuncs_free(void); + +// Function that executes a command line program +int MSXfuncs_run(char * ); + +#endif diff --git a/src/solver/msxinp.c b/src/solver/msxinp.c new file mode 100644 index 0000000..01d6a1f --- /dev/null +++ b/src/solver/msxinp.c @@ -0,0 +1,1505 @@ +/******************************************************************************* +** MODULE: MSXINP.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Input data processor for the EPANET Multi-Species Extension +** toolkit. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 08/20/2022 +*******************************************************************************/ + +#include +#include +#include +#include +#include + +#include "msxtypes.h" +#include "msxutils.h" +#include "msxdict.h" +#include "epanet2.h" + +// Constants +//----------- +#define MAXERRS 100 // Max. input errors reported +#define MAXTOKS 40 // Max. items per line of input +#define SEPSTR " \t\n\r" // Token separator characters + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +// Local variables +//----------------- +static char *Tok[MAXTOKS]; // String tokens from line of input +static int Ntokens; // Number of tokens in line of input +static double **TermArray; // Incidence array used to check Terms + +enum InpErrorCodes { // Error codes (401 - 409) + INP_ERR_FIRST = 400, + ERR_LINE_LENGTH, + ERR_ITEMS, + ERR_KEYWORD, + ERR_NUMBER, + ERR_NAME, + ERR_RESERVED_NAME, + ERR_DUP_NAME, + ERR_DUP_EXPR, + ERR_MATH_EXPR, + ERR_UNSUPPORTED_OPTION, + INP_ERR_LAST}; + +static char *InpErrorTxt[INP_ERR_LAST-INP_ERR_FIRST] = { + "", + "Error 401 (too many characters)", + "Error 402 (too few input items)", + "Error 403 (invalid keyword)", + "Error 404 (invalid numeric value)", + "Error 405 (reference to undefined object)", + "Error 406 (illegal use of a reserved name)", + "Error 407 (name already used by another object)", + "Error 408 (species already assigned an expression)", + "Error 409 (illegal math expression)", + "Error 410 (option no longer supported)"}; + +// Imported functions +//-------------------- +int MSXproj_addObject(int type, char *id, int n); +int MSXproj_findObject(int type, char *id); +char * MSXproj_findID(int type, char *id); + +// Exported functions +//-------------------- +int MSXinp_countMsxObjects(void); +int MSXinp_countNetObjects(void); +int MSXinp_readNetData(void); +int MSXinp_readMsxData(void); +void MSXinp_getSpeciesUnits(int m, char *units); + +// Local functions +//----------------- +static int getLineLength(char *line); +static int getNewSection(char *tok, char *sectWords[], int *sect); +static int addSpecies(char *line); +static int addCoeff(char *line); +static int addTerm(char *id); +static int addPattern(char *id); +static int checkID(char *id); +static int parseLine(int sect, char *line); +static int parseOption(void); +static int parseSpecies(void); +static int parseCoeff(void); +static int parseTerm(void); +static int parseExpression(int classType); +static int parseTankData(void); +static int parseQuality(void); +static int parseParameter(void); +static int parseSource(void); +static int parsePattern(void); +static int parseReport(void); +static int parseDiffu(void); +static int getVariableCode(char *id); +static int getTokens(char *s); +static void writeInpErrMsg(int errcode, char *sect, char *line, int lineCount); + +static int checkCyclicTerms(void); +static int traceTermPath(int i, int istar, int n); + +//============================================================================= + +int MSXinp_countMsxObjects() +/* +** Purpose: +** reads multi-species input file to determine number of system objects. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + char line[MAXLINE+1]; // line from input data file + char wLine[MAXLINE+1]; // working copy of input line + char *tok; // first string token of line + int sect = -1; // input data sections + int errcode = 0; // error code + int errsum = 0; // number of errors found + long lineCount = 0; + +// --- write name of input file to EPANET report file + + strcpy(MSX.Msg, "Processing MSX input file "); + strcpy(line, MSX.MsxFile.name); + strcat(MSX.Msg, line); + ENwriteline(MSX.Msg); + ENwriteline(""); + +// --- make pass through EPANET-MSX data file counting number of each object + + while ( fgets(line, MAXLINE, MSX.MsxFile.file) != NULL ) + { + + // --- skip blank lines & those beginning with a comment + + errcode = 0; + lineCount++; + strcpy(wLine, line); // make working copy of line + tok = strtok(wLine, SEPSTR); // get first text token on line + if ( tok == NULL || *tok == ';' ) continue; + if ( getNewSection(tok, MsxSectWords, §) ) continue; + + // --- read id names from SPECIES, COEFFS, TERMS, & PATTERNS sections + + if ( sect == s_SPECIES ) errcode = addSpecies(line); + if ( sect == s_COEFF ) errcode = addCoeff(line); + if ( sect == s_TERM ) errcode = addTerm(tok); + if ( sect == s_PATTERN ) errcode = addPattern(tok); + + + // --- report any error found + + if ( errcode ) + { + writeInpErrMsg(errcode, MsxSectWords[sect], line, lineCount); + errsum++; + if (errsum >= MAXERRS ) break; + } + } + +// --- return error code + + if ( errsum > 0 ) return ERR_MSX_INPUT; + return errcode; +} + +//============================================================================= + +int MSXinp_countNetObjects() +/* +** Purpose: +** queries EPANET data base to determine number of network objects. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int errcode = 0; + +// --- retrieve number of network elements + + CALL(errcode, ENgetcount(EN_NODECOUNT, &MSX.Nobjects[NODE])); + CALL(errcode, ENgetcount(EN_TANKCOUNT, &MSX.Nobjects[TANK])); + CALL(errcode, ENgetcount(EN_LINKCOUNT, &MSX.Nobjects[LINK])); + return errcode; +} + +//============================================================================= + +int MSXinp_readNetData() +/* +** Purpose: +** retrieves required input data from the EPANET project data. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int errcode = 0; + int i, k, n, t = 0; + int n1 = 0, n2 = 0; + long qstep; + float diam = 0.0, len = 0.0, v0 = 0.0, xmix = 0.0, vmix = 0.0; + + float roughness = 0.0; + +// --- get flow units & time parameters + + CALL(errcode, ENgetflowunits(&MSX.Flowflag)); + if ( MSX.Flowflag >= EN_LPS ) MSX.Unitsflag = SI; + else MSX.Unitsflag = US; + CALL(errcode, ENgettimeparam(EN_QUALSTEP, &qstep)); + MSX.Qstep = qstep * 1000; + CALL(errcode, ENgettimeparam(EN_REPORTSTEP, &MSX.Rstep)); + CALL(errcode, ENgettimeparam(EN_REPORTSTART, &MSX.Rstart)); + CALL(errcode, ENgettimeparam(EN_PATTERNSTEP, &MSX.Pstep)); + CALL(errcode, ENgettimeparam(EN_PATTERNSTART, &MSX.Pstart)); + CALL(errcode, ENgettimeparam(EN_STATISTIC, &MSX.Statflag)); + +// --- read tank/reservoir data + + n = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; + for (i=1; i<=MSX.Nobjects[NODE]; i++) + { + k = i - n; + if ( k > 0 ) + { + CALL(errcode, ENgetnodetype(i, &t)); + CALL(errcode, ENgetnodevalue(i, EN_INITVOLUME, &v0)); + CALL(errcode, ENgetnodevalue(i, EN_MIXMODEL, &xmix)); + CALL(errcode, ENgetnodevalue(i, EN_MIXZONEVOL, &vmix)); + if ( !errcode ) + { + MSX.Node[i].tank = k; + MSX.Tank[k].node = i; + if ( t == EN_RESERVOIR ) MSX.Tank[k].a = 0.0; + else MSX.Tank[k].a = 1.0; + MSX.Tank[k].v0 = v0; + MSX.Tank[k].mixModel = (int)xmix; + MSX.Tank[k].vMix = vmix; + } + } + } + +// --- read link data + + for (i=1; i<=MSX.Nobjects[LINK]; i++) + { + CALL(errcode, ENgetlinknodes(i, &n1, &n2)); + CALL(errcode, ENgetlinkvalue(i, EN_DIAMETER, &diam)); + CALL(errcode, ENgetlinkvalue(i, EN_LENGTH, &len)); + CALL(errcode, ENgetlinkvalue(i, EN_ROUGHNESS, &roughness)); + if ( !errcode ) + { + MSX.Link[i].n1 = n1; + MSX.Link[i].n2 = n2; + MSX.Link[i].diam = diam; + MSX.Link[i].len = len; + MSX.Link[i].roughness = roughness; + } + } + return errcode; +} + +//============================================================================= + +int MSXinp_readMsxData() +/* +** Purpose: +** reads multi-species data from the EPANET-MSX input file. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + char line[MAXLINE+1]; // line from input data file + char wLine[MAXLINE+1]; // working copy of input line + int sect = -1; // input data sections + int errsum = 0; // number of errors found + int inperr = 0; // input error code + long lineCount = 0; // line count + +// --- create the TermArray for checking circular references in Terms + + TermArray = createMatrix(MSX.Nobjects[TERM]+1, MSX.Nobjects[TERM]+1); + if ( TermArray == NULL ) return ERR_MEMORY; + +// --- read each line from MSX input file + + rewind(MSX.MsxFile.file); + while ( fgets(line, MAXLINE, MSX.MsxFile.file) != NULL ) + { + // --- make copy of line and scan for tokens + + lineCount++; + strcpy(wLine, line); + Ntokens = getTokens(wLine); + + // --- skip blank lines and comments + + if ( Ntokens == 0 || *Tok[0] == ';' ) continue; + + // --- check if max. line length exceeded + + if ( getLineLength(line) >= MAXLINE ) + { + inperr = ERR_LINE_LENGTH; + writeInpErrMsg(inperr, MsxSectWords[sect], line, lineCount); + errsum++; + } + + // --- check if at start of a new input section + + if ( getNewSection(Tok[0], MsxSectWords, §) ) continue; + + // --- parse tokens from input line + + inperr = parseLine(sect, line); + if ( inperr > 0 ) + { + errsum++; + writeInpErrMsg(inperr, MsxSectWords[sect], line, lineCount); + } + + // --- stop if reach end of file or max. error count + + if (errsum >= MAXERRS) break; + } // End of while + +// --- check for errors + + if ( checkCyclicTerms() ) errsum++; + freeMatrix(TermArray); + if (errsum > 0) return ERR_MSX_INPUT; + return 0; +} + +//============================================================================= + +void MSXinp_getSpeciesUnits(int m, char *units) +/* +** Purpose: +** constructs the character string for a species concentration units. +** +** Input: +** m = species index +** +** Output: +** units = character string with species concentration units +*/ +{ + strcpy(units, MSX.Species[m].units); + strcat(units, "/"); + if ( MSX.Species[m].type == BULK ) strcat(units, "L"); + else strcat(units, AreaUnitsWords[MSX.AreaUnits]); +} + +//============================================================================= + +int getLineLength(char *line) +/* +** Purpose: +** determines number of characters of data in a line of input. +** +** Input: +** line = line of text from an input file +** +** Returns: +** number of characters in the line (with comment ignored). +*/ +{ + char *comment; + int lineLength = (int)strlen(line); + if ( lineLength >= MAXLINE ) + { + // --- don't count comment if present + comment = strchr(line, ';'); + if ( comment ) lineLength = (int)(comment - line); // Pointer math here + } + return lineLength; +} + +//============================================================================= + +int getNewSection(char *tok, char *sectWords[], int *sect) +/* +** Purpose: +** checks if a line begins a new section in the input file. +** +** Input: +** tok = a string token +** sectWords = array of input file section keywords +** +** Output: +** sect = index code of section matching tok (or -1 if no match) +** +** Returns: +** 1 if a section is found, 0 if not +*/ +{ + int newsect; + +// --- check if line begins with a new section heading + + if ( *tok == '[' ) + { + // --- look for section heading in list of section keywords + + newsect = MSXutils_findmatch(tok, sectWords); + if ( newsect >= 0 ) *sect = newsect; + else *sect = -1; + return 1; + } + return 0; +} + +//============================================================================= + +int addSpecies(char *line) +/* +** Purpose: +** adds a species ID name to the project. +** +** Input: +** line = line of input data +** +** Returns: +** an error code (0 if no error) +*/ +{ + int errcode = 0; + Ntokens = getTokens(line); + if ( Ntokens < 2 ) return ERR_ITEMS; + errcode = checkID(Tok[1]); + if ( errcode ) return errcode; + if ( MSXproj_addObject(SPECIES, Tok[1], MSX.Nobjects[SPECIES]+1) < 0 ) + errcode = 101; + else MSX.Nobjects[SPECIES]++; + return errcode; +} + +//============================================================================= + +int addCoeff(char *line) +/* +** Purpose: +** adds a coefficient ID name to the project. +** +** Input: +** line = line of input data +** +** Returns: +** an error code (0 if no error) +*/ +{ + int k; + int errcode = 0; + +// --- determine the type of coeff. + + Ntokens = getTokens(line); + if ( Ntokens < 2 ) return ERR_ITEMS; + if (MSXutils_match(Tok[0], "PARAM")) k = PARAMETER; + else if (MSXutils_match(Tok[0], "CONST")) k = CONSTANT; + else return ERR_KEYWORD; + +// --- check for valid id name + + errcode = checkID(Tok[1]); + if ( errcode ) return errcode; + if ( MSXproj_addObject(k, Tok[1], MSX.Nobjects[k]+1) < 0 ) + errcode = 101; + else MSX.Nobjects[k]++; + return errcode; +} + +//============================================================================= + +int addTerm(char *id) +/* +** Purpose: +** adds an intermediate expression term ID name to the project. +** +** Input: +** id = name of an intermediate expression term +** +** Returns: +** an error code (0 if no error) +*/ +{ + int errcode = checkID(id); + if ( !errcode ) + { + if ( MSXproj_addObject(TERM, id, MSX.Nobjects[TERM]+1) < 0 ) + errcode = 101; + else MSX.Nobjects[TERM]++; + } + return errcode; +} + +//============================================================================= + +int addPattern(char *id) +/* +** Purpose: +** adds a time pattern ID name to the project. +** +** Input: +** id = name of a time pattern +** +** Returns: +** an error code (0 if no error) +*/ +{ + int errcode = 0; + + // --- a time pattern can span several lines + + if ( MSXproj_findObject(PATTERN, id) <= 0 ) + { + if ( MSXproj_addObject(PATTERN, id, MSX.Nobjects[PATTERN]+1) < 0 ) + errcode = 101; + else MSX.Nobjects[PATTERN]++; + } + return errcode; +} + +//============================================================================= + +int checkID(char *id) +/* +** Purpose: +** checks that an object's name is unique +** +** Input: +** id = name of an object +** +** Returns: +** an error code (0 if successful) +*/ +{ +// --- check that id name is not a reserved word + int i = 1; + while (HydVarWords[i] != NULL) + { + if (MSXutils_strcomp(id, HydVarWords[i])) return ERR_RESERVED_NAME; + i++; + } + +// --- check that id name not used before + + if ( MSXproj_findObject(SPECIES, id) > 0 || + MSXproj_findObject(TERM, id) > 0 || + MSXproj_findObject(PARAMETER, id) > 0 || + MSXproj_findObject(CONSTANT, id) > 0 + ) return ERR_DUP_NAME; + return 0; +} + +//============================================================================= + +int parseLine(int sect, char *line) +/* +** Purpose: +** parses the contents of a line of input data. +** +** Input: +** sect = index of current input data section +** line = contents of current line of input data +** +** Returns: +** an error code (0 if no error) +*/ +{ + switch(sect) + { + case s_TITLE: + strcpy(MSX.Title, line); + break; + + case s_OPTION: + return parseOption(); + + case s_SPECIES: + return parseSpecies(); + + case s_COEFF: + return parseCoeff(); + + case s_TERM: + return parseTerm(); + + case s_PIPE: + return parseExpression(LINK); + + case s_TANK: + return parseExpression(TANK); + + case s_SOURCE: + return parseSource(); + + case s_QUALITY: + return parseQuality(); + + case s_PARAMETER: + return parseParameter(); + + case s_PATTERN: + return parsePattern(); + + case s_REPORT: + return parseReport(); + + case s_Diffu: + return parseDiffu(); + } + return 0; +} + +//============================================================================= + +int parseOption() +/* +** Purpose: +** parses an input line containing a project option. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int k; + double v; + +// --- determine which option is being read + + if ( Ntokens < 2 ) return 0; + k = MSXutils_findmatch(Tok[0], OptionTypeWords); + if ( k < 0 ) return ERR_KEYWORD; + +// --- parse the value for the given option + + switch ( k ) + { + case AREA_UNITS_OPTION: + k = MSXutils_findmatch(Tok[1], AreaUnitsWords); + if ( k < 0 ) return ERR_KEYWORD; + MSX.AreaUnits = k; + break; + + case RATE_UNITS_OPTION: + k = MSXutils_findmatch(Tok[1], TimeUnitsWords); + if ( k < 0 ) return ERR_KEYWORD; + MSX.RateUnits = k; + break; + + case SOLVER_OPTION: + k = MSXutils_findmatch(Tok[1], SolverTypeWords); + if ( k < 0 ) return ERR_KEYWORD; + MSX.Solver = k; + break; + + case COUPLING_OPTION: + k = MSXutils_findmatch(Tok[1], CouplingWords); + if ( k < 0 ) return ERR_KEYWORD; + MSX.Coupling = k; + break; + + case TIMESTEP_OPTION: + + // Read time step as a floating point value in seconds + if ( !MSXutils_getDouble(Tok[1], &v) ) return ERR_NUMBER; + if ( v < 0.001 ) return ERR_NUMBER; + + // Convert time step to integer milliseconds + v = round(v * 1000.); + MSX.Qstep = (int64_t)v; + break; + + case RTOL_OPTION: + if ( !MSXutils_getDouble(Tok[1], &MSX.DefRtol) ) return ERR_NUMBER; + break; + + case ATOL_OPTION: + if ( !MSXutils_getDouble(Tok[1], &MSX.DefAtol) ) return ERR_NUMBER; + break; + + case COMPILER_OPTION: + k = MSXutils_findmatch(Tok[1], CompilerWords); + if ( k < 0 ) return ERR_KEYWORD; + MSX.Compiler = k; + break; + + case PECLETNUMER_OPTION: + v = atof(Tok[1]); + if (v <= 0.0)return ERR_NUMBER; + MSX.Dispersion.PecletLimit = MAX(v, 1.0); + break; + + case MAXSEGMENT_OPTION: + k = atoi(Tok[1]); + if (k <= 0) return ERR_NUMBER; + MSX.MaxSegments = MAX(k, 50); //at least 50 segments + + } + return 0; +} + +//============================================================================= + +int parseSpecies() +/* +** Purpose: +** parses an input line containing a species variable. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int i; + +// --- get Species index + + if ( Ntokens < 3 ) return ERR_ITEMS; + i = MSXproj_findObject(SPECIES, Tok[1]); + if ( i <= 0 ) return ERR_NAME; + +// --- get pointer to Species name + + MSX.Species[i].id = MSXproj_findID(SPECIES, Tok[1]); + +// --- get Species type + + if ( MSXutils_match(Tok[0], "BULK") ) MSX.Species[i].type = BULK; + else if ( MSXutils_match(Tok[0], "WALL") ) MSX.Species[i].type = WALL; + else return ERR_KEYWORD; + +// --- get Species units + + strncpy(MSX.Species[i].units, Tok[2], MAXUNITS); + +// --- get Species error tolerance + + MSX.Species[i].aTol = 0.0; + MSX.Species[i].rTol = 0.0; + if ( Ntokens >= 4) + { + if ( !MSXutils_getDouble(Tok[3], &MSX.Species[i].aTol) ) + return ERR_NUMBER; + } + if ( Ntokens >= 5) + { + if ( !MSXutils_getDouble(Tok[4], &MSX.Species[i].rTol) ) + return ERR_NUMBER; + } + return 0; +} + +//============================================================================= + +int parseCoeff() +/* +** Purpose: +** parses an input line containing a coefficient definition. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int i, j; + double x; + +// --- check if variable is a Parameter + + if ( Ntokens < 2 ) return 0; + if ( MSXutils_match(Tok[0], "PARAM") ) + { + // --- get Parameter's index + + i = MSXproj_findObject(PARAMETER, Tok[1]); + if ( i <= 0 ) return ERR_NAME; + + // --- get Parameter's value + + MSX.Param[i].id = MSXproj_findID(PARAMETER, Tok[1]); + if ( Ntokens >= 3 ) + { + if ( !MSXutils_getDouble(Tok[2], &x) ) return ERR_NUMBER; + MSX.Param[i].value = x; + for (j=1; j<=MSX.Nobjects[LINK]; j++) MSX.Link[j].param[i] = x; + for (j=1; j<=MSX.Nobjects[TANK]; j++) MSX.Tank[j].param[i] = x; + } + return 0; + } + +// --- check if variable is a Constant + + else if ( MSXutils_match(Tok[0], "CONST") ) + { + // --- get Constant's index + + i = MSXproj_findObject(CONSTANT, Tok[1]); + if ( i <= 0 ) return ERR_NAME; + + // --- get Constant's value + + MSX.Const[i].id = MSXproj_findID(CONSTANT, Tok[1]); + MSX.Const[i].value = 0.0; + if ( Ntokens >= 3 ) + { + if ( !MSXutils_getDouble(Tok[2], &MSX.Const[i].value) ) + return ERR_NUMBER; + } + return 0; + } + else return ERR_KEYWORD; +} + +//============================================================================= + +int parseTerm() +/* +** Purpose: +** parses an input line containing an intermediate expression term . +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int i, j; + int k; + char s[MAXLINE+1] = ""; + MathExpr *expr; + +// --- get term's name + + if ( Ntokens < 2 ) return 0; + i = MSXproj_findObject(TERM, Tok[0]); + MSX.Term[i].id = MSXproj_findID(TERM, Tok[0]); + +// --- reconstruct the expression string from its tokens + + for (j=1; j 0 ) TermArray[i][k] = 1.0; + } + +// --- convert expression into a postfix stack of op codes + + expr = mathexpr_create(s, getVariableCode); + if ( expr == NULL ) return ERR_MATH_EXPR; + +// --- assign the expression to a Term object + + MSX.Term[i].expr = expr; + return 0; +} + +//============================================================================= + +int parseExpression(int classType) +/* +** Purpose: +** parses an input line containing a math expression. +** +** Input: +** classType = either LINK or TANK +** +** Returns: +** an error code (0 if no error) +*/ +{ + int i, j, k; + char s[MAXLINE+1] = ""; + MathExpr *expr; + +// --- determine expression type + + if ( Ntokens < 3 ) return ERR_ITEMS; + k = MSXutils_findmatch(Tok[0], ExprTypeWords); + if ( k < 0 ) return ERR_KEYWORD; + +// --- determine species associated with expression + + i = MSXproj_findObject(SPECIES, Tok[1]); + if ( i < 1 ) return ERR_NAME; + +// --- check that species does not already have an expression + + if ( classType == LINK ) + { + if ( MSX.Species[i].pipeExprType != NO_EXPR ) return ERR_DUP_EXPR; + } + if ( classType == TANK ) + { + if ( MSX.Species[i].tankExprType != NO_EXPR ) return ERR_DUP_EXPR; + } + +// --- reconstruct the expression string from its tokens + + for (j=2; j= 2 ) k = 2; + m = MSXproj_findObject(SPECIES, Tok[k]); + if ( m <= 0 ) return ERR_NAME; + +// --- get quality value + + if ( i >= 2 && Ntokens < 4 ) return ERR_ITEMS; + k = 2; + if ( i >= 2 ) k = 3; + if ( !MSXutils_getDouble(Tok[k], &x) ) return ERR_NUMBER; + +// --- for global specification, set initial quality either for +// all nodes or links depending on type of species + + if ( i == 1) + { + MSX.C0[m] = x; + if ( MSX.Species[m].type == BULK ) + { + for (j=1; j<=MSX.Nobjects[NODE]; j++) MSX.Node[j].c0[m] = x; + } + for (j=1; j<=MSX.Nobjects[LINK]; j++) MSX.Link[j].c0[m] = x; + } + +// --- for a specific node, get its index & set its initial quality + + else if ( i == 2 ) + { + err = ENgetnodeindex(Tok[1], &j); + if ( err ) return ERR_NAME; + if ( MSX.Species[m].type == BULK ) MSX.Node[j].c0[m] = x; + } + +// --- for a specific link, get its index & set its initial quality + + else if ( i == 3 ) + { + err = ENgetlinkindex(Tok[1], &j); + if ( err ) return ERR_NAME; + MSX.Link[j].c0[m] = x; + } + return 0; +} + +//============================================================================= + +int parseParameter() +/* +** Purpose: +** parses an input line containing a parameter data. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int err, i, j; + double x; + +// --- get parameter name + + if ( Ntokens < 4 ) return 0; + i = MSXproj_findObject(PARAMETER, Tok[2]); + +// --- get parameter value + + if ( !MSXutils_getDouble(Tok[3], &x) ) return ERR_NUMBER; + +// --- for pipe parameter, get pipe index and update parameter's value + + if ( MSXutils_match(Tok[0], "PIPE") ) + { + err = ENgetlinkindex(Tok[1], &j); + if ( err ) return ERR_NAME; + MSX.Link[j].param[i] = x; + } + +// --- for tank parameter, get tank index and update parameter's value + + else if ( MSXutils_match(Tok[0], "TANK") ) + { + err = ENgetnodeindex(Tok[1], &j); + if ( err ) return ERR_NAME; + j = MSX.Node[j].tank; + if ( j > 0 ) MSX.Tank[j].param[i] = x; + } + else return ERR_KEYWORD; + return 0; +} + +//============================================================================= + +int parseSource() +/* +** Purpose: +** parses an input line containing a source input data. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int err, i, j, k, m; + double x; + Psource source; + +// --- get source type + + if ( Ntokens < 4 ) return ERR_ITEMS; + k = MSXutils_findmatch(Tok[0], SourceTypeWords); + if ( k < 0 ) return ERR_KEYWORD; + +// --- get node index + + err = ENgetnodeindex(Tok[1], &j); + if ( err ) return ERR_NAME; + +// --- get species index + + m = MSXproj_findObject(SPECIES, Tok[2]); + if ( m <= 0 ) return ERR_NAME; + +// --- check that species is a BULK species + + if ( MSX.Species[m].type != BULK ) return 0; + +// --- get base strength + + if ( !MSXutils_getDouble(Tok[3], &x) ) return ERR_NUMBER; + +// --- get time pattern if present + + i = 0; + if ( Ntokens >= 5 ) + { + i = MSXproj_findObject(PATTERN, Tok[4]); + if ( i <= 0 ) return ERR_NAME; + } + +// --- check if a source for this species already exists + + source = MSX.Node[j].sources; + while ( source ) + { + if ( source->species == m ) break; + source = source->next; + } + +// --- otherwise create a new source object + + if ( source == NULL ) + { + source = (struct Ssource *) malloc(sizeof(struct Ssource)); + if ( source == NULL ) return 101; + source->next = MSX.Node[j].sources; + MSX.Node[j].sources = source; + } + +// --- save source's properties + + source->type = (char)k; + source->species = m; + source->c0 = x; + source->pat = i; + return 0; +} + +//============================================================================= + +int parsePattern() +/* +** Purpose: +** parses an input line containing a time pattern data. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int i, k; + double x; + SnumList *listItem; + +// --- get time pattern index + + if ( Ntokens < 2 ) return ERR_ITEMS; + i = MSXproj_findObject(PATTERN, Tok[0]); + if ( i <= 0 ) return ERR_NAME; + MSX.Pattern[i].id = MSXproj_findID(PATTERN, Tok[0]); + +// --- begin reading pattern multipliers + + k = 1; + while ( k < Ntokens ) + { + if ( !MSXutils_getDouble(Tok[k], &x) ) return ERR_NUMBER; + listItem = (SnumList *) malloc(sizeof(SnumList)); + if ( listItem == NULL ) return 101; + listItem->value = x; + listItem->next = NULL; + if ( MSX.Pattern[i].first == NULL ) + { + MSX.Pattern[i].current = listItem; + MSX.Pattern[i].first = listItem; + } + else + { + MSX.Pattern[i].current->next = listItem; + MSX.Pattern[i].current = listItem; + } + MSX.Pattern[i].length++; + k++; + } + return 0; +} + +//============================================================================= + +int parseReport() +{ + int i, j, k, err; + +// --- get keyword + + if ( Ntokens < 2 ) return 0; + k = MSXutils_findmatch(Tok[0], ReportWords); + if ( k < 0 ) return ERR_KEYWORD; + switch(k) + { + + // --- keyword is NODE; parse ID names of reported nodes + + case 0: + if ( MSXutils_strcomp(Tok[1], ALL) ) + { + for (j=1; j<=MSX.Nobjects[NODE]; j++) MSX.Node[j].rpt = 1; + } + else if ( MSXutils_strcomp(Tok[1], NONE) ) + { + for (j=1; j<=MSX.Nobjects[NODE]; j++) MSX.Node[j].rpt = 0; + } + else for (i=1; i= 3 ) + { + if ( MSXutils_strcomp(Tok[2], YES) ) MSX.Species[j].rpt = 1; + else if ( MSXutils_strcomp(Tok[2], NO) ) MSX.Species[j].rpt = 0; + else return ERR_KEYWORD; + } + if ( Ntokens >= 4 ) + { + if ( !MSXutils_getInt(Tok[3], &MSX.Species[j].precision) ) + return ERR_NUMBER; + } + break; + + // --- keyword is FILE: get name of report file + + case 3: + strcpy(MSX.RptFile.name, Tok[1]); + break; + + // --- keyword is PAGESIZE; + + case 4: + if ( !MSXutils_getInt(Tok[1], &MSX.PageSize) ) return ERR_NUMBER; + break; + } + return 0; +} + +int parseDiffu() +/* +** Purpose: +** parses an input line containing molecular diffusivity data. +** +** Input: +** none +** +** Returns: +** an error code (0 if no error) +*/ +{ + int m; + double x; + + // --- get source type + if (Ntokens < 2) return ERR_ITEMS; + + // --- get species index + m = MSXproj_findObject(SPECIES, Tok[0]); + if (m <= 0) return ERR_NAME; + + // --- check that species is a BULK species + if (MSX.Species[m].type != BULK) return 0; + + // --- get base strength + if (!MSXutils_getDouble(Tok[1], &x)) return ERR_NUMBER; + if (x < 0) return ERR_NUMBER; + + if (Ntokens > 2 && MSXutils_match(Tok[2], "FIXED")) + { + x = x * MSX.Dispersion.DIFFUS; + MSX.Dispersion.ld[m] = x; + } + else + { + x = x * MSX.Dispersion.DIFFUS; + MSX.Dispersion.md[m] = x; + } + MSX.DispersionFlag = 1; + return 0; +} + +//============================================================================= + +int getVariableCode(char *id) +/* +** Purpose: +** finds the index assigned to a species, intermediate term, +** parameter, or constant that appears in a math expression. +** +** Input: +** id = ID name being sought +** +** Returns: +** index of the symbolic variable or term named id. +** +** Note: +** Variables are assigned consecutive code numbers starting from 1 +** and proceeding through each Species, Term, Parameter and Constant. +*/ +{ + int j = MSXproj_findObject(SPECIES, id); + if ( j >= 1 ) return j; + j = MSXproj_findObject(TERM, id); + if ( j >= 1 ) return MSX.Nobjects[SPECIES] + j; + j = MSXproj_findObject(PARAMETER, id); + if ( j >= 1 ) return MSX.Nobjects[SPECIES] + MSX.Nobjects[TERM] + j; + j = MSXproj_findObject(CONSTANT, id); + if ( j >= 1 ) return MSX.Nobjects[SPECIES] + MSX.Nobjects[TERM] + + MSX.Nobjects[PARAMETER] + j; + j = MSXutils_findmatch(id, HydVarWords); + if ( j >= 1 ) return MSX.Nobjects[SPECIES] + MSX.Nobjects[TERM] + + MSX.Nobjects[PARAMETER] + MSX.Nobjects[CONSTANT] + j; + return -1; +} + +//============================================================================= + +int getTokens(char *s) +/* +** Purpose: +** scans a string for tokens, saving pointers to them +** in shared variable Tok[]. +** +** Input: +** s = a character string +** +** Returns: +** number of tokens found in s +** +** Notes: +** Tokens can be separated by the characters listed in SEPSTR +** (spaces, tabs, newline, carriage return) which is defined in +** MSXGLOBALS.H. Text between quotes is treated as a single token. +*/ +{ + int len, m, n; + char *c; + + // --- begin with no tokens + + for (n = 0; n < MAXTOKS; n++) Tok[n] = NULL; + n = 0; + + // --- truncate s at start of comment + + c = strchr(s,';'); + if (c) *c = '\0'; + len = (int)strlen(s); + + // --- scan s for tokens until nothing left + + while (len > 0 && n < MAXTOKS) + { + m = (int)strcspn(s,SEPSTR); // find token length + if (m == 0) s++; // no token found + else + { + if (*s == '"') // token begins with quote + { + s++; // start token after quote + len--; // reduce length of s + m = (int)strcspn(s,"\"\n"); // find end quote or new line + } + s[m] = '\0'; // null-terminate the token + Tok[n] = s; // save pointer to token + n++; // update token count + s += m+1; // begin next token + } + len -= m+1; // update length of s + } + return(n); +} + +//============================================================================= + +void writeInpErrMsg(int errcode, char *sect, char *line, int lineCount) +{ + char msg[MAXMSG+1]; + if ( errcode >= INP_ERR_LAST || errcode <= INP_ERR_FIRST ) + { + sprintf(msg, "Error Code = %d", errcode); + } + else + { + sprintf(msg, "%s at line %d of %s] section:", + InpErrorTxt[errcode-INP_ERR_FIRST], lineCount, sect); + } + ENwriteline(""); + ENwriteline(msg); + ENwriteline(line); +} + +//============================================================================= + +int checkCyclicTerms() +/* +** Purpose: +** checks for cyclic references in Term expressions (e.g., T1 = T2 + T3 +** and T3 = T2/T1) +** +** Input: +** none +** +** Returns: +** 1 if cyclic reference found or 0 if none found. +*/ +{ + int i, j, n; + char msg[MAXMSG+1]; + + n = MSX.Nobjects[TERM]; + for (i=1; i +#include +#include +#include + +#include "msxtypes.h" + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +// Local variables +//----------------- +static long ResultsOffset; // Offset byte where results begin +static long NodeBytesPerPeriod; // Bytes per time period used by all nodes +static long LinkBytesPerPeriod; // Bytes per time period used by all links + +// Imported functions +//-------------------- +double MSXqual_getNodeQual(int j, int m); +double MSXqual_getLinkQual(int k, int m); + +// Exported functions +//-------------------- +int MSXout_open(void); +int MSXout_saveInitialResults(void); +int MSXout_saveResults(void); +int MSXout_saveFinalResults(void); +float MSXout_getNodeQual(int k, int j, int m); +float MSXout_getLinkQual(int k, int j, int m); + +// Local functions +//----------------- +static int saveStatResults(void); +static void getStatResults(int objType, int m, double* stats1, + double* stats2, REAL4* x); + + +//============================================================================= + +int MSXout_open() +/* +** Purpose: +** opens an MSX binary output file. +** +** Input: +** none. +** +** Returns: +** an error code (or 0 if no error). +*/ +{ +// --- close output file if already opened + + if (MSX.OutFile.file != NULL) fclose(MSX.OutFile.file); + +// --- try to open the file + + if ( (MSX.OutFile.file = fopen(MSX.OutFile.name, "w+b")) == NULL) + { + return ERR_OPEN_OUT_FILE; + } + +// --- open a scratch output file for statistics + + if ( MSX.Statflag == SERIES ) MSX.TmpOutFile.file = MSX.OutFile.file; + else if ( (MSX.TmpOutFile.file = fopen(MSX.TmpOutFile.name, "w+b")) == NULL) + { + return ERR_OPEN_OUT_FILE; + } + +// --- write initial results to file + + MSX.Nperiods = 0; + MSXout_saveInitialResults(); + return 0; +} + +//============================================================================= + +int MSXout_saveInitialResults() +/* +** Purpose: +** saves general information to beginning of MSX binary output file. +** +** Input: +** none. +** +** Returns: +** an error code (or 0 if no error). +*/ +{ + int m; + INT4 n; + INT4 magic = MAGICNUMBER; + INT4 version = VERSION; + FILE* f = MSX.OutFile.file; + + rewind(f); + fwrite(&magic, sizeof(INT4), 1, f); //Magic number + fwrite(&version, sizeof(INT4), 1, f); //Version number + n = (INT4)MSX.Nobjects[NODE]; + fwrite(&n, sizeof(INT4), 1, f); //Number of nodes + n = (INT4)MSX.Nobjects[LINK]; + fwrite(&n, sizeof(INT4), 1, f); //Number of links + n = (INT4)MSX.Nobjects[SPECIES]; + fwrite(&n, sizeof(INT4), 1, f); //Number of species + n = (INT4)MSX.Rstep; + fwrite(&n, sizeof(INT4), 1, f); //Reporting step size + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + { + n = (INT4)strlen(MSX.Species[m].id); + fwrite(&n, sizeof(INT4), 1, f); //Length of species ID + fwrite(MSX.Species[m].id, sizeof(char), n, f); //Species ID string + fwrite(&MSX.Species[m].units, sizeof(char), MAXUNITS, f); //Species mass units + } + ResultsOffset = ftell(f); + NodeBytesPerPeriod = MSX.Nobjects[NODE]*MSX.Nobjects[SPECIES]*sizeof(REAL4); + LinkBytesPerPeriod = MSX.Nobjects[LINK]*MSX.Nobjects[SPECIES]*sizeof(REAL4); + return 0; +} + + +//============================================================================= + +int MSXout_saveResults() +/* +** Purpose: +** saves computed species concentrations for each node and link at the +** current time period to the temporary MSX binary output file (which +** will be the same as the permanent MSX binary file if time series +** values were specified as the reported statistic, which is the +** default case). +** +** Input: +** none. +** +** Returns: +** an error code (or 0 if no error). +*/ +{ + int m, j; + REAL4 x; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + { + for (j=1; j<=MSX.Nobjects[NODE]; j++) + { + x = (REAL4)MSXqual_getNodeQual(j, m); + fwrite(&x, sizeof(REAL4), 1, MSX.TmpOutFile.file); + } + } + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + { + for (j=1; j<=MSX.Nobjects[LINK]; j++) + { + x = (REAL4)MSXqual_getLinkQual(j, m); + fwrite(&x, sizeof(REAL4), 1, MSX.TmpOutFile.file); + } + } + return 0; +} + +//============================================================================= + +int MSXout_saveFinalResults() +/* +** Purpose: +** saves any statistical results plus the following information to the end +** of the MSX binary output file: +** - byte offset into file where WQ results for each time period begins, +** - total number of time periods written to the file, +** - any error code generated by the analysis (0 if there were no errors), +** - the Magic Number to indicate that the file is complete. +** +** Input: +** none. +** +** Returns: +** an error code (or 0 if no error). +*/ +{ + INT4 n; + INT4 magic = MAGICNUMBER; + int err = 0; + +// --- save statistical results to the file + + if ( MSX.Statflag != SERIES ) err = saveStatResults(); + if ( err > 0 ) return err; + +// --- write closing records to the file + + n = (INT4)ResultsOffset; + fwrite(&n, sizeof(INT4), 1, MSX.OutFile.file); + n = (INT4)MSX.Nperiods; + fwrite(&n, sizeof(INT4), 1, MSX.OutFile.file); + n = (INT4)MSX.ErrCode; + fwrite(&n, sizeof(INT4), 1, MSX.OutFile.file); + fwrite(&magic, sizeof(INT4), 1, MSX.OutFile.file); + return 0; +} + +//============================================================================= + +float MSXout_getNodeQual(int k, int j, int m) +/* +** Purpose: +** retrieves a result for a specific node from the MSX binary output file. +** +** Input: +** k = time period index +** j = node index +** m = species index. +** +** Returns: +** the requested species concentration. +*/ +{ + REAL4 c; + long bp = ResultsOffset + k * (NodeBytesPerPeriod + LinkBytesPerPeriod); + bp += ((m-1)*MSX.Nobjects[NODE] + (j-1)) * sizeof(REAL4); + fseek(MSX.OutFile.file, bp, SEEK_SET); + fread(&c, sizeof(REAL4), 1, MSX.OutFile.file); + return (float)c; +} + +//============================================================================= + +float MSXout_getLinkQual(int k, int j, int m) +/* +** Purpose: +** retrieves a result for a specific link from the MSX binary output file. +** +** Input: +** k = time period index +** j = link index +** m = species index. +** +** Returns: +** the requested species concentration. +*/ +{ + REAL4 c; + long bp = ResultsOffset + ((k+1)*NodeBytesPerPeriod) + (k*LinkBytesPerPeriod); + bp += ((m-1)*MSX.Nobjects[LINK] + (j-1)) * sizeof(REAL4); + fseek(MSX.OutFile.file, bp, SEEK_SET); + fread(&c, sizeof(REAL4), 1, MSX.OutFile.file); + return (float)c; +} + +//============================================================================= + +int saveStatResults() +/* +** Purpose: +** saves time statistic results (average, min., max., or range) for each +** node and link to the permanent binary output file. +** +** Input: +** none. +** +** Returns: +** an error code (or 0 if no error). +*/ +{ + int m, err = 0; + REAL4* x = NULL; + double* stats1 = NULL; + double* stats2 = NULL; + +// --- create arrays used to store statistics results + + if ( MSX.Nperiods <= 0 ) return err; + m = MAX(MSX.Nobjects[NODE], MSX.Nobjects[LINK]); + x = (REAL4 *) calloc(m+1, sizeof(REAL4)); + stats1 = (double *) calloc(m+1, sizeof(double)); + stats2 = (double *) calloc(m+1, sizeof(double)); + +// --- get desired statistic for each node & link and save to binary file + + if ( x && stats1 && stats2 ) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++ ) + { + getStatResults(NODE, m, stats1, stats2, x); + fwrite(x+1, sizeof(REAL4), MSX.Nobjects[NODE], MSX.OutFile.file); + } + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + getStatResults(LINK, m, stats1, stats2, x); + fwrite(x+1, sizeof(REAL4), MSX.Nobjects[LINK], MSX.OutFile.file); + } + MSX.Nperiods = 1; + } + else err = ERR_MEMORY; + +// --- free allocated arrays + + FREE(x); + FREE(stats1); + FREE(stats2); + return err; +} + +//============================================================================= + +void getStatResults(int objType, int m, double * stats1, double * stats2, + REAL4 * x) +/* +** Purpose: +** reads all results for a given type of object from the temporary +** binary output file and computes the required statistic (average, +** min., max., or range) for each object. +** +** Input: +** objType = type of object (nodes or links) +** m = species index +** stats1, stats2 = work arrays used to hold intermediate values +** x = array used to store results read from file. +** +** Output: +** x = array that contains computed statistic for each object. +*/ +{ + int j, k; + int n = MSX.Nobjects[objType]; + long bp; + +// --- initialize work arrays + + for (j = 1; j <= n; j++) + { + stats1[j] = 0.0; + stats2[j] = 0.0; + } + +// --- for all time periods + + for (k = 0; k < MSX.Nperiods; k++) + { + + // --- position file at start of time period + + bp = k*(NodeBytesPerPeriod + LinkBytesPerPeriod); + if ( objType == NODE ) + { + bp += (m-1) * MSX.Nobjects[NODE] * sizeof(REAL4); + } + if ( objType == LINK) + { + bp += NodeBytesPerPeriod + + (m-1) * MSX.Nobjects[LINK] * sizeof(REAL4); + } + fseek(MSX.TmpOutFile.file, bp, SEEK_SET); + + // --- read concentrations and update stats for all objects + + fread(x+1, sizeof(REAL4), n, MSX.TmpOutFile.file); + if ( MSX.Statflag == AVGERAGE ) + { + for (j = 1; j <= n; j++) stats1[j] += x[j]; + } + else for (j = 1; j <= n; j++) + { + stats1[j] = MIN(stats1[j], x[j]); + stats2[j] = MAX(stats2[j], x[j]); + } + } + +// --- place final stat value for each object in x + + if ( MSX.Statflag == AVGERAGE ) + { + for ( j = 1; j <= n; j++) stats1[j] /= (double)MSX.Nperiods; + } + if ( MSX.Statflag == RANGE ) + { + for ( j = 1; j <= n; j++) + stats1[j] = fabs(stats2[j] - stats1[j]); + } + if ( MSX.Statflag == MAXIMUM) + { + for ( j = 1; j <= MSX.Nobjects[NODE]; j++) stats1[j] = stats2[j]; + } + for (j = 1; j <= n; j++) x[j] = (REAL4)stats1[j]; +} diff --git a/src/solver/msxproj.c b/src/solver/msxproj.c new file mode 100644 index 0000000..ae98e66 --- /dev/null +++ b/src/solver/msxproj.c @@ -0,0 +1,791 @@ +/****************************************************************************** +** MODULE: MSXPROJ.C +** PROJECT: EPANET-MSX +** DESCRIPTION: project data manager used by the EPANET Multi-Species +** Extension toolkit. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 08/30/2022 +******************************************************************************/ + +#include +#include +#include +#include + +#include "msxtypes.h" +#include "msxutils.h" +//#include "mempool.h" +#include "hash.h" +#include "smatrix.h" +#include "epanet2.h" +#include "dispersion.h" +// Exported variables +//-------------------- +MSXproject MSX; // MSX project data + +// Local variables +//----------------- +static alloc_handle_t *HashPool; // Memory pool for hash tables +static HTtable *Htable[MAX_OBJECTS]; // Hash tables for object ID names + +static char * Errmsg[] = + {"unknown error code.", + "Error 501 - insufficient memory available.", + "Error 502 - no EPANET data file supplied.", + "Error 503 - could not open MSX input file.", + "Error 504 - could not open hydraulic results file.", + "Error 505 - could not read hydraulic results file.", + "Error 506 - could not read MSX input file.", + "Error 507 - too few pipe reaction expressions.", + "Error 508 - too few tank reaction expressions.", + "Error 509 - could not open differential equation solver.", + "Error 510 - could not open algebraic equation solver.", + "Error 511 - could not open binary results file.", + "Error 512 - read/write error on binary results file.", + "Error 513 - could not integrate reaction rate expressions.", + "Error 514 - could not solve reaction equilibrium expressions.", + "Error 515 - reference made to an unknown type of object.", + "Error 516 - reference made to an illegal object index.", + "Error 517 - reference made to an undefined object ID.", + "Error 518 - invalid property values were specified.", + "Error 519 - an MSX project was not opened.", + "Error 520 - an MSX project is already opened.", + "Error 521 - could not open MSX report file.", //(LR-11/20/07) + + "Error 522 - could not compile chemistry functions.", + "Error 523 - could not load functions from compiled chemistry file.", + "Error 524 - illegal math operation."}; + +// Imported functions +//-------------------- +int MSXinp_countMsxObjects(void); +int MSXinp_countNetObjects(void); +int MSXinp_readNetData(void); +int MSXinp_readMsxData(void); + +// Exported functions +//-------------------- +int MSXproj_open(char *fname); +int MSXproj_addObject(int type, char *id, int n); +int MSXproj_findObject(int type, char *id); +char * MSXproj_findID(int type, char *id); +char * MSXproj_getErrmsg(int errcode); + +// Local functions +//----------------- +static void setDefaults(void); +static int convertUnits(void); +static int createObjects(void); +static void deleteObjects(void); +static int createHashTables(void); +static void deleteHashTables(void); + +static int openRptFile(void); //(LR-11/20/07) + +static int buildadjlists(); +static void freeadjlists(); + + +//============================================================================= + +int MSXproj_open(char *fname) +/* +** Purpose: +** opens an EPANET-MSX project. +** +** Input: +** fname = name of EPANET-MSX input file +** +** Returns: +** an error code (0 if no error) +*/ +{ +// --- initialize data to default values + + int errcode = 0; + MSX.ProjectOpened = FALSE; + MSX.QualityOpened = FALSE; + setDefaults(); + +// --- open the MSX input file + + strcpy(MSX.MsxFile.name, fname); + if ((MSX.MsxFile.file = fopen(fname,"rt")) == NULL) return ERR_OPEN_MSX_FILE; + +// --- create hash tables to look up object ID names + + CALL(errcode, createHashTables()); + +// --- allocate memory for the required number of objects + + CALL(errcode, MSXinp_countMsxObjects()); + CALL(errcode, MSXinp_countNetObjects()); + CALL(errcode, createObjects()); + + MSX.DispersionFlag = 0; //no dispersion by default, unless yes in msx file + +// --- read in the EPANET and MSX object data + + CALL(errcode, MSXinp_readNetData()); + CALL(errcode, MSXinp_readMsxData()); + + if (strcmp(MSX.RptFile.name, "")) + CALL(errcode, openRptFile()); + +// --- convert user's units to internal units + + CALL(errcode, convertUnits()); + + if (MSX.DispersionFlag != 0) + { + float relvis; + ENgetoption(13, &relvis); + MSX.Dispersion.viscosity = relvis * 1.1E-5; + + createsparse(); //symmetric matrix + } + + // Build nodal adjacency lists + if (errcode == 0 && MSX.Adjlist == NULL) + { + errcode = buildadjlists(); //parallel links are included + if (errcode) return errcode; + } + +// --- close input file + + if ( MSX.MsxFile.file ) fclose(MSX.MsxFile.file); + MSX.MsxFile.file = NULL; + if ( !errcode ) MSX.ProjectOpened = TRUE; + return errcode; +} + +//============================================================================= + +void MSXproj_close() +/* +** Purpose: +** closes the current EPANET-MSX project. +** +** Input: +** none +*/ +{ + // --- close all files + + if ( MSX.RptFile.file ) fclose(MSX.RptFile.file); //(LR-11/20/07, to fix bug 08) + if ( MSX.HydFile.file ) fclose(MSX.HydFile.file); + if ( MSX.TmpOutFile.file && MSX.TmpOutFile.file != MSX.OutFile.file ) + fclose(MSX.TmpOutFile.file); + if ( MSX.OutFile.file ) fclose(MSX.OutFile.file); + + // --- delete all temporary files + + if ( MSX.HydFile.mode == SCRATCH_FILE ) remove(MSX.HydFile.name); + if ( MSX.OutFile.mode == SCRATCH_FILE ) remove(MSX.OutFile.name); + remove(MSX.TmpOutFile.name); + + // --- free all allocated memory + + MSX.RptFile.file = NULL; //(LR-11/20/07, to fix bug 08) + MSX.HydFile.file = NULL; + MSX.OutFile.file = NULL; + MSX.TmpOutFile.file = NULL; + deleteObjects(); + deleteHashTables(); + MSX.ProjectOpened = FALSE; +} + +//============================================================================= + +int MSXproj_addObject(int type, char *id, int n) +/* +** Purpose: +** adds an object ID to the project's hash tables. +** +** Input: +** type = object type +** id = object ID string +** n = object index. +** +** Returns: +** 0 if object already added, 1 if not, -1 if hashing fails. +*/ +{ + int result; + int len; + char *newID; + +// --- do nothing if object already exists in a hash table + + if ( MSXproj_findObject(type, id) > 0 ) return 0; + +// --- use memory from the hash tables' common memory pool to store +// a copy of the object's ID string + + len = (int)strlen(id) + 1; + newID = (char *) Alloc(len*sizeof(char)); + strcpy(newID, id); + +// --- insert object's ID into the hash table for that type of object + + result = HTinsert(Htable[type], newID, n); + if ( result == 0 ) result = -1; + return result; +} + +//============================================================================= + +int MSXproj_findObject(int type, char *id) +/* +** Purpose: +** uses hash table to find index of an object with a given ID. +** +** Input: +** type = object type +** id = object ID. +** +** Returns: +** index of object with given ID, or -1 if ID not found. +*/ +{ + return HTfind(Htable[type], id); +} + +//============================================================================= + +char * MSXproj_findID(int type, char *id) +/* +** Purpose: +** uses hash table to find address of given string entry. +** +** Input: +** type = object type +** id = ID name being sought. +** +** Returns: +** pointer to location where object's ID string is stored. +*/ +{ + return HTfindKey(Htable[type], id); +} + +//============================================================================= + +char * MSXproj_getErrmsg(int errcode) +/* +** Purpose: +** gets the text of an error message. +** +** Input: +** errcode = error code. +** +** Returns: +** text of error message. +*/ +{ + if ( errcode <= ERR_FIRST || errcode >= ERR_MAX ) return Errmsg[0]; + else return Errmsg[errcode - ERR_FIRST]; +} + +//============================================================================= + +void setDefaults() +/* +** Purpose: +** assigns default values to project variables. +** +** Input: +** none. +*/ +{ + int i; + MSX.RptFile.file = NULL; //(LR-11/20/07) + MSX.HydFile.file = NULL; + MSX.HydFile.mode = USED_FILE; + MSX.OutFile.file = NULL; + MSX.OutFile.mode = SCRATCH_FILE; + MSX.TmpOutFile.file = NULL; + MSXutils_getTempName(MSX.OutFile.name); + MSXutils_getTempName(MSX.TmpOutFile.name); + strcpy(MSX.RptFile.name, ""); + strcpy(MSX.Title, ""); + MSX.Rptflag = 0; + for (i=0; inext; + FREE(p); + p=MSX.Node[i].sources; + } + } + } + if (MSX.Link) for (i=1; i<=MSX.Nobjects[LINK]; i++) + { + FREE(MSX.Link[i].c0); + FREE(MSX.Link[i].param); + FREE(MSX.Link[i].reacted); + } + if (MSX.Tank) for (i=1; i<=MSX.Nobjects[TANK]; i++) + { + FREE(MSX.Tank[i].param); + FREE(MSX.Tank[i].c); + FREE(MSX.Tank[i].reacted); + } + + freeadjlists(); + + // --- free memory used by time patterns + if (MSX.Pattern) for (i=1; i<=MSX.Nobjects[PATTERN]; i++) + { + listItem = MSX.Pattern[i].first; + while (listItem) + { + MSX.Pattern[i].first = listItem->next; + free(listItem); + listItem = MSX.Pattern[i].first; + } + } + FREE(MSX.Pattern); + +// --- free memory used for hydraulics results + + FREE(MSX.D); + FREE(MSX.H); + FREE(MSX.Q); + FREE(MSX.S); + FREE(MSX.C0); + +// --- delete all nodes, links, and tanks + + FREE(MSX.Node); + FREE(MSX.Link); + FREE(MSX.Tank); + +// --- free memory used by reaction rate & equilibrium expressions + + if (MSX.Species) for (i=1; i<=MSX.Nobjects[SPECIES]; i++) + { + // --- free the species tank expression only if it doesn't + // already point to the species pipe expression + if ( MSX.Species[i].tankExpr != MSX.Species[i].pipeExpr ) + { + mathexpr_delete(MSX.Species[i].tankExpr); + } + mathexpr_delete(MSX.Species[i].pipeExpr); + } + +// --- delete all species, parameters, and constants + + FREE(MSX.Species); + FREE(MSX.Param); + FREE(MSX.Const); + FREE(MSX.K); + +// --- free memory used by intermediate terms + + if (MSX.Term) for (i=1; i<=MSX.Nobjects[TERM]; i++) + mathexpr_delete(MSX.Term[i].expr); + FREE(MSX.Term); +} + +//============================================================================= + +int createHashTables() +/* +** Purpose: +** allocates memory for object ID hash tables. +** +** Input: +** none. +** +** Returns: +** an error code (0 if no error). +*/ +{ int j; + +// --- create a hash table for each type of object + + for (j = 0; j < MAX_OBJECTS ; j++) + { + Htable[j] = HTcreate(); + if ( Htable[j] == NULL ) return ERR_MEMORY; + } + +// --- initialize the memory pool used to store object ID's + + HashPool = AllocInit(); + if ( HashPool == NULL ) return ERR_MEMORY; + return 0; +} + +//============================================================================= + +void deleteHashTables() +/* +** Purpose: +** frees memory allocated for object ID hash tables. +** +** Input: +** none. +*/ +{ + int j; + +// --- free the hash tables + + for (j = 0; j < MAX_OBJECTS; j++) + { + if ( Htable[j] != NULL ) HTfree(Htable[j]); + } + +// --- free the object ID memory pool + + if ( HashPool ) + { + AllocSetPool(HashPool); + AllocFreePool(); + } +} + +// New function added (LR-11/20/07, to fix bug 08) +int openRptFile() +{ + if ( MSX.RptFile.file ) fclose(MSX.RptFile.file); + MSX.RptFile.file = fopen(MSX.RptFile.name, "wt"); + if ( MSX.RptFile.file == NULL ) return ERR_OPEN_RPT_FILE; + return 0; +} + +int buildadjlists() //from epanet for node sorting in WQ routing +/* +**-------------------------------------------------------------- +** Input: none +** Output: returns error code +** Purpose: builds linked list of links adjacent to each node +**-------------------------------------------------------------- +*/ +{ + int i, j, k; + int errcode = 0; + Padjlist alink; + + // Create an array of adjacency lists + freeadjlists(); + MSX.Adjlist = (Padjlist*)calloc(MSX.Nobjects[NODE]+1, sizeof(Padjlist)); + if (MSX.Adjlist == NULL) return 101; + for (i = 0; i <= MSX.Nobjects[NODE]; i++) + MSX.Adjlist[i] = NULL; + + // For each link, update adjacency lists of its end nodes + for (k = 1; k <= MSX.Nobjects[LINK]; k++) + { + i = MSX.Link[k].n1; + j = MSX.Link[k].n2; + + // Include link in start node i's list + alink = (struct Sadjlist*) malloc(sizeof(struct Sadjlist)); + if (alink == NULL) + { + errcode = 101; + break; + } + alink->node = j; + alink->link = k; + alink->next = MSX.Adjlist[i]; + MSX.Adjlist[i] = alink; + + // Include link in end node j's list + alink = (struct Sadjlist*) malloc(sizeof(struct Sadjlist)); + if (alink == NULL) + { + errcode = 101; + break; + } + alink->node = i; + alink->link = k; + alink->next = MSX.Adjlist[j]; + MSX.Adjlist[j] = alink; + } + if (errcode) freeadjlists(); + return errcode; +} + + +void freeadjlists() //from epanet for node sorting in WQ routing +/* +**-------------------------------------------------------------- +** Input: none +** Output: none +** Purpose: frees memory used for nodal adjacency lists +**-------------------------------------------------------------- +*/ +{ + int i; + Padjlist alink; + + if (MSX.Adjlist == NULL) return; + for (i = 0; i <= MSX.Nobjects[NODE]; i++) + { + for (alink = MSX.Adjlist[i]; alink != NULL; alink = MSX.Adjlist[i]) + { + MSX.Adjlist[i] = alink->next; + free(alink); + } + } + free(MSX.Adjlist); + MSX.Adjlist = NULL; +} + diff --git a/src/solver/msxqual.c b/src/solver/msxqual.c new file mode 100644 index 0000000..42684e9 --- /dev/null +++ b/src/solver/msxqual.c @@ -0,0 +1,2009 @@ +/****************************************************************************** +** MODULE: MSXQUAL.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Water quality routing routines. +** COPYRIGHT: Copyright (C) 2007 Feng Shang, Lewis Rossman, and James Uber. +** All Rights Reserved. See license information in LICENSE.TXT. +** AUTHORS: See AUTHORS +** VERSION: 2.0.00 +** LAST UPDATE: 08/30/2022 +******************************************************************************/ + +#include +#include +#include +#include + +#include "msxtypes.h" +//#include "mempool.h" +#include "msxutils.h" +#include "dispersion.h" + +// Macros to identify upstream & downstream nodes of a link +// under the current flow and to compute link volume +// +#define UP_NODE(x) ( (MSX.FlowDir[(x)]==POSITIVE) ? MSX.Link[(x)].n1 : MSX.Link[(x)].n2 ) +#define DOWN_NODE(x) ( (MSX.FlowDir[(x)]==POSITIVE) ? MSX.Link[(x)].n2 : MSX.Link[(x)].n1 ) +#define LINKVOL(k) ( 0.785398*MSX.Link[(k)].len*SQR(MSX.Link[(k)].diam) ) + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +// Local variables +//----------------- +//static Pseg FreeSeg; // pointer to unused pipe segment +//static Pseg *NewSeg; // new segment added to each pipe +//static char *FlowDir; // flow direction for each pipe +//static double *VolIn; // inflow flow volume to each node +//static double **MassIn; // mass inflow of each species to each node +//static double **X; // work matrix +//static char HasWallSpecies; // wall species indicator +//static char OutOfMemory; // out of memory indicator +//static alloc_handle_t *QualPool; // memory pool + +// Stagnant flow tolerance +const double Q_STAGNANT = 0.005 / GPMperCFS; // 0.005 gpm = 1.114e-5 cfs + +// Imported functions +//-------------------- +int MSXchem_open(void); +void MSXchem_close(void); +extern int MSXchem_react(double dt); +extern int MSXchem_equil(int zone, int k, double *c); + +extern void MSXtank_mix1(int i, double vin, double *massin, double vnet); +extern void MSXtank_mix2(int i, double vin, double *massin, double vnet); +extern void MSXtank_mix3(int i, double vin, double *massin, double vnet); +extern void MSXtank_mix4(int i, double vIn, double *massin, double vnet); + + + +int MSXout_open(void); +int MSXout_saveResults(void); +int MSXout_saveFinalResults(void); + +void MSXerr_clearMathError(void); +int MSXerr_mathError(void); +char* MSXerr_writeMathErrorMsg(void); + +// Exported functions +//-------------------- +int MSXqual_open(void); +int MSXqual_init(void); +int MSXqual_step(double *t, double *tleft); +int MSXqual_close(void); +double MSXqual_getNodeQual(int j, int m); +double MSXqual_getLinkQual(int k, int m); +int MSXqual_isSame(double c1[], double c2[]); +void MSXqual_removeSeg(Pseg seg); +Pseg MSXqual_getFreeSeg(double v, double c[]); +void MSXqual_addSeg(int k, Pseg seg); +void MSXqual_reversesegs(int k); + +// Local functions +//----------------- +static int getHydVars(void); +static int transport(int64_t tstep); +static void initSegs(void); +static int flowdirchanged(void); +static void advectSegs(double dt); +static void getNewSegWallQual(int k, double dt, Pseg seg); +static void shiftSegWallQual(int k, double dt); +static void sourceInput(int n, double vout, double dt); +static void addSource(int n, Psource source, double v, double dt); +static double getSourceQual(Psource source); +static void removeAllSegs(int k); + +static void topological_transport(double dt); +static void findnodequal(int n, double volin, double* massin, double volout, double tstep); +static void noflowqual(int n); +static void evalnodeinflow(int, double, double*, double*); +static void evalnodeoutflow(int k, double* upnodequal, double tstep); +static int sortNodes(); +static int selectnonstacknode(int numsorted, int* indegree); +static void findstoredmass(double* mass); + +static void evalHydVariables(int k); +//============================================================================= + +int MSXqual_open() +/* +** Purpose: +** opens the WQ routing system. +** +** Returns: +** an error code (0 if no errors). +*/ +{ + int errcode = 0; + int n; + + // --- set flags + + MSX.QualityOpened = FALSE; + MSX.Saveflag = 0; + MSX.OutOfMemory = FALSE; + MSX.HasWallSpecies = FALSE; + + // --- initialize array pointers to null + + MSX.C1 = NULL; + MSX.FirstSeg = NULL; + MSX.LastSeg = NULL; + MSX.NewSeg = NULL; + MSX.FlowDir = NULL; + MSX.MassIn = NULL; + + + // --- open the chemistry system + + errcode = MSXchem_open(); + if (errcode > 0) return errcode; + + // --- allocate a memory pool for pipe segments + + MSX.QualPool = AllocInit(); + if (MSX.QualPool == NULL) return ERR_MEMORY; + +// --- allocate memory used for species concentrations + + MSX.C1 = (double *) calloc(MSX.Nobjects[SPECIES]+1, sizeof(double)); + + MSX.MassBalance.initial = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); + MSX.MassBalance.inflow = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); + MSX.MassBalance.indisperse = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); + MSX.MassBalance.outflow = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); + MSX.MassBalance.reacted = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); + MSX.MassBalance.final = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); + MSX.MassBalance.ratio = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); + +// --- allocate memory used for pointers to the first, last, +// and new WQ segments in each link and tank + + n = MSX.Nobjects[LINK] + MSX.Nobjects[TANK] + 1; + MSX.FirstSeg = (Pseg *) calloc(n, sizeof(Pseg)); + MSX.LastSeg = (Pseg *) calloc(n, sizeof(Pseg)); + MSX.NewSeg = (Pseg *) calloc(n, sizeof(Pseg)); + +// --- allocate memory used for flow direction in each link + + MSX.FlowDir = (FlowDirection *) calloc(n, sizeof(FlowDirection)); + +// --- allocate memory used to accumulate mass and volume +// inflows to each node + + n = MSX.Nobjects[NODE] + 1; + MSX.MassIn = (double *) calloc(MSX.Nobjects[SPECIES]+1, sizeof(double)); + MSX.SourceIn = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); + +// --- allocate memory for topologically sorted nodes + + MSX.SortedNodes = (int*)calloc(n, sizeof(int)); + +// --- check for successful memory allocation + + CALL(errcode, MEMCHECK(MSX.C1)); + CALL(errcode, MEMCHECK(MSX.FirstSeg)); + CALL(errcode, MEMCHECK(MSX.LastSeg)); + CALL(errcode, MEMCHECK(MSX.NewSeg)); + CALL(errcode, MEMCHECK(MSX.FlowDir)); + CALL(errcode, MEMCHECK(MSX.MassIn)); + CALL(errcode, MEMCHECK(MSX.SourceIn)); + CALL(errcode, MEMCHECK(MSX.SortedNodes)); + CALL(errcode, MEMCHECK(MSX.MassBalance.initial)); + CALL(errcode, MEMCHECK(MSX.MassBalance.inflow)); + CALL(errcode, MEMCHECK(MSX.MassBalance.indisperse)); + CALL(errcode, MEMCHECK(MSX.MassBalance.outflow)); + CALL(errcode, MEMCHECK(MSX.MassBalance.reacted)); + CALL(errcode, MEMCHECK(MSX.MassBalance.final)); + CALL(errcode, MEMCHECK(MSX.MassBalance.ratio)); + +// --- check if wall species are present + + for (n=1; n<=MSX.Nobjects[SPECIES]; n++) + { + if ( MSX.Species[n].type == WALL ) MSX.HasWallSpecies = TRUE; + } + if ( !errcode ) MSX.QualityOpened = TRUE; + return(errcode); +} + +//============================================================================= + +int MSXqual_init() +/* +** Purpose: +** re-initializes the WQ routing system. +** +** Input: +** none. +** +** Returns: +** an error code (or 0 if no errors). +*/ +{ + int i, n, m; + int errcode = 0; + +// --- initialize node concentrations, tank volumes, & source mass flows + + for (i=1; i<=MSX.Nobjects[NODE]; i++) + { + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + MSX.Node[i].c[m] = MSX.Node[i].c0[m]; + } + for (i = 1; i <= MSX.Nobjects[LINK]; i++) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.Link[i].reacted[m] = 0.0; + } + + for (i=1; i<=MSX.Nobjects[TANK]; i++) + { + MSX.Tank[i].hstep = 0.0; + MSX.Tank[i].v = MSX.Tank[i].v0; + n = MSX.Tank[i].node; + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + MSX.Tank[i].c[m] = MSX.Node[n].c0[m]; + MSX.Tank[i].reacted[m] = 0.0; + } + } + + for (i=1; i<=MSX.Nobjects[PATTERN]; i++) + { + MSX.Pattern[i].interval = 0; + MSX.Pattern[i].current = MSX.Pattern[i].first; + } + +// --- copy expression constants to vector MSX.K[] + + for (i=1; i<=MSX.Nobjects[CONSTANT]; i++) + { + MSX.K[i] = MSX.Const[i].value; + } + +// --- check if a separate WQ report is required + + MSX.Rptflag = 0; + n = 0; + for (i=1; i<=MSX.Nobjects[NODE]; i++) n += MSX.Node[i].rpt; + for (i=1; i<=MSX.Nobjects[LINK]; i++) n += MSX.Link[i].rpt; + if ( n > 0 ) + { + n = 0; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) n += MSX.Species[m].rpt; + } + if ( n > 0 ) MSX.Rptflag = 1; + if ( MSX.Rptflag ) MSX.Saveflag = 1; + +// --- reset memory pool + + AllocSetPool(MSX.QualPool); + MSX.FreeSeg = NULL; + AllocReset(); + +// --- re-position hydraulics file + + fseek(MSX.HydFile.file, MSX.HydOffset, SEEK_SET); + +// --- set elapsed times to zero + + MSX.Htime = 0; //Hydraulic solution time + MSX.Qtime = 0; //Quality routing time + MSX.Rtime = MSX.Rstart * 1000; //Reporting time + MSX.Nperiods = 0; //Number fo reporting periods + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + MSX.MassBalance.initial[m] = 0.0; + MSX.MassBalance.final[m] = 0.0; + MSX.MassBalance.inflow[m] = 0.0; + MSX.MassBalance.indisperse[m] = 0.0; + MSX.MassBalance.outflow[m] = 0.0; + MSX.MassBalance.reacted[m] = 0.0; + MSX.MassBalance.ratio[m] = 0.0; + } + +// --- open binary output file if results are to be saved + + if ( MSX.Saveflag ) errcode = MSXout_open(); + return errcode; +} + +//============================================================================= + +int MSXqual_step(double *t, double *tleft) +/* +** Purpose: +** updates WQ conditions over a single WQ time step. +** +** Input: +** none. +** +** Output: +** *t = current simulation time (sec) +** *tleft = time left in simulation (sec) +** +** Returns: +** an error code: +** 0 = no error +** 501 = memory error +** 307 = can't read hydraulics file +** 513 = can't integrate reaction rates +*/ +{ + int k, errcode = 0, flowchanged; + int m; + double smassin, smassout, sreacted; + int64_t hstep, tstep, dt; + +// --- set the shared memory pool to the water quality pool +// and the overall time step to nominal WQ time step + + AllocSetPool(MSX.QualPool); + tstep = MSX.Qstep; + if (MSX.Qtime + tstep > MSX.Dur) tstep = MSX.Dur - MSX.Qtime; + +// --- repeat until the end of the time step + + do + { + // --- find the time until the next hydraulic event occurs + dt = tstep; + hstep = MSX.Htime - MSX.Qtime; + + // --- check if next hydraulic event occurs within the current time step + + if (hstep <= dt) + { + + // --- reduce current time step to end at next hydraulic event + dt = hstep; + + // --- route WQ over this time step + if ( dt > 0 ) CALL(errcode, transport(dt)); + MSX.Qtime += dt; + + // --- retrieve new hydraulic solution + if (MSX.Qtime == MSX.Htime) + { + CALL(errcode, getHydVars()); + + for (int kl = 1; kl <= MSX.Nobjects[LINK]; kl++) + { + // --- skip non-pipe links + + if (MSX.Link[kl].len == 0.0) continue; + + // --- evaluate hydraulic variables + + evalHydVariables(kl); + } + + if (MSX.Qtime < MSX.Dur) + { + // --- initialize pipe segments (at time 0) or else re-orient segments + // to accommodate any flow reversals + if (MSX.Qtime == 0) + { + flowchanged = 1; + initSegs(); + } + else + flowchanged = flowdirchanged(); + + if (flowchanged) + { + CALL(errcode, sortNodes()); + } + } + } + + // --- report results if its time to do so + if (MSX.Saveflag && MSX.Qtime == MSX.Rtime) + { + CALL(errcode, MSXout_saveResults()); + MSX.Rtime += MSX.Rstep * 1000; + MSX.Nperiods++; + } + } + + // --- otherwise just route WQ over the current time step + + else + { + CALL(errcode, transport(dt)); + MSX.Qtime += dt; + } + + // --- reduce overall time step by the size of the current time step + + tstep -= dt; + if (MSX.OutOfMemory) errcode = ERR_MEMORY; + } while (!errcode && tstep > 0); + +// --- update the current time into the simulation and the amount remaining + + *t = MSX.Qtime / 1000.; + *tleft = (MSX.Dur - MSX.Qtime) / 1000.; + +// --- if there's no time remaining, then save the final records to output file + + if ( *tleft <= 0 && MSX.Saveflag ) + { + findstoredmass(MSX.MassBalance.final); + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + sreacted = 0.0; + for (k = 1; k <= MSX.Nobjects[LINK]; k++) + sreacted += MSX.Link[k].reacted[m]; + for (k = 1; k <= MSX.Nobjects[TANK]; k++) + sreacted += MSX.Tank[k].reacted[m]; + + MSX.MassBalance.reacted[m] = sreacted; + smassin = MSX.MassBalance.initial[m] + MSX.MassBalance.inflow[m] + MSX.MassBalance.indisperse[m]; + smassout = MSX.MassBalance.outflow[m]+MSX.MassBalance.final[m]; + if (sreacted < 0) //loss + smassout -= sreacted; + else + smassin += sreacted; + + if (smassin == 0) + MSX.MassBalance.ratio[m] = 1.0; + else + MSX.MassBalance.ratio[m] = smassout / smassin; + } + CALL(errcode, MSXout_saveFinalResults()); + } + return errcode; +} + +//============================================================================= + +double MSXqual_getNodeQual(int j, int m) +/* +** Purpose: +** retrieves WQ for species m at node n. +** +** Input: +** j = node index +** m = species index. +** +** Returns: +** WQ value of node. +*/ +{ + int k; + +// --- return 0 for WALL species + + if ( MSX.Species[m].type == WALL ) return 0.0; + +// --- if node is a tank, return its internal concentration + + k = MSX.Node[j].tank; + if (k > 0 && MSX.Tank[k].a > 0.0) + { + return MSX.Tank[k].c[m]; + } + +// --- otherwise return node's concentration (which includes +// any contribution from external sources) + + return MSX.Node[j].c[m]; +} + +//============================================================================= + +double MSXqual_getLinkQual(int k, int m) +/* +** Purpose: +** computes average quality in link k. +** +** Input: +** k = link index +** m = species index. +** +** Returns: +** WQ value of link. +*/ +{ + double vsum = 0.0, + msum = 0.0; + Pseg seg; + + seg = MSX.FirstSeg[k]; + while (seg != NULL) + { + vsum += seg->v; + msum += (seg->c[m])*(seg->v); + seg = seg->prev; + } + if (vsum > 0.0) return(msum/vsum); + else + { + return (MSXqual_getNodeQual(MSX.Link[k].n1, m) + + MSXqual_getNodeQual(MSX.Link[k].n2, m)) / 2.0; + } +} + +//============================================================================= + +int MSXqual_close() +/* +** Purpose: +** closes the WQ routing system. +** +** Input: +** none. +** +** Returns: +** error code (0 if no error). +*/ +{ + int errcode = 0; + if (!MSX.ProjectOpened) return 0; + MSXchem_close(); + + FREE(MSX.C1); + FREE(MSX.FirstSeg); + FREE(MSX.LastSeg); + FREE(MSX.NewSeg); + FREE(MSX.FlowDir); + FREE(MSX.SortedNodes); + FREE(MSX.MassIn); + FREE(MSX.SourceIn); + if ( MSX.QualPool) + { + AllocSetPool(MSX.QualPool); + AllocFreePool(); + } + FREE(MSX.MassBalance.initial); + FREE(MSX.MassBalance.inflow); + FREE(MSX.MassBalance.indisperse); + FREE(MSX.MassBalance.outflow); + FREE(MSX.MassBalance.reacted); + FREE(MSX.MassBalance.final); + FREE(MSX.MassBalance.ratio); + + MSX.QualityOpened = FALSE; + return errcode; +} + +//============================================================================= + +int MSXqual_isSame(double c1[], double c2[]) +/* +** Purpose: +** checks if two sets of concentrations are the same +** +** Input: +** c1[] = first set of species concentrations +** c2[] = second set of species concentrations +** +** Returns: +** 1 if the concentrations are all within a specific tolerance of each +** other or 0 if they are not. +*/ +{ + int m; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + { + if (fabs(c1[m] - c2[m]) >= MSX.Species[m].aTol ) return 0; + } + return 1; +} + + +//============================================================================= + +int getHydVars() +/* +** Purpose: +** retrieves hydraulic solution and time step for next hydraulic event +** from a hydraulics file. +** +** Input: +** none. +** +** Returns: +** error code +** +** NOTE: +** A hydraulic solution consists of the current time +** (hydtime), nodal demands (D) and heads (H), link +** flows (Q), and link status values and settings (which are not used). +*/ +{ + int errcode = 0; + long hydtime, hydstep; + INT4 n; + +// --- read hydraulic time, demands, heads, and flows from the file + + if (fread(&n, sizeof(INT4), 1, MSX.HydFile.file) < 1) + return ERR_READ_HYD_FILE; + hydtime = (long)n; + n = MSX.Nobjects[NODE]; + if (fread(MSX.D+1, sizeof(REAL4), n, MSX.HydFile.file) < (unsigned)n) + return ERR_READ_HYD_FILE; + if (fread(MSX.H+1, sizeof(REAL4), n, MSX.HydFile.file) < (unsigned)n) + return ERR_READ_HYD_FILE; + n = MSX.Nobjects[LINK]; + if (fread(MSX.Q+1, sizeof(REAL4), n, MSX.HydFile.file) < (unsigned)n) + return ERR_READ_HYD_FILE; + if (fread(MSX.S + 1, sizeof(REAL4), n, MSX.HydFile.file) < (unsigned)n) //03/17/2022 + return ERR_READ_HYD_FILE; + + for (int pi = 1; pi <= n; pi++) //06/10/2021 Shang + if (fabs(MSX.Q[pi]) < Q_STAGNANT) + MSX.Q[pi] = 0.0; + +// --- skip over link settings + + fseek(MSX.HydFile.file, 1*n*sizeof(REAL4), SEEK_CUR); + +// --- read time step until next hydraulic event + + if (fread(&n, sizeof(INT4), 1, MSX.HydFile.file) < 1) + return ERR_READ_HYD_FILE; + hydstep = (long)n; + +// --- update elapsed time until next hydraulic event + + MSX.Htime = hydtime + hydstep; + MSX.Htime *= 1000; + +/* + if (MSX.Qtime < MSX.Dur) + { + if (MSX.Qtime == 0) + { + flowchanged = 1; + initSegs(); + } + else flowchanged = flowdirchanged(); + } + return flowchanged;*/ + + return errcode; +} + +//============================================================================= + +int transport(int64_t tstep) +/* +** Purpose: +** transports constituent mass through pipe network +** under a period of constant hydraulic conditions. +** +** Input: +** tstep = length of current time step (sec). +** +** Returns: +** an error code or 0 if no error. +*/ +{ + int64_t qtime, dt64; + double dt; + int errcode = 0; + +// --- repeat until time step is exhausted + + MSXerr_clearMathError(); // clear math error flag + qtime = 0; + while (!MSX.OutOfMemory && + !errcode && + qtime < tstep) + { // Qstep is nominal quality time step + dt64 = MIN(MSX.Qstep, tstep-qtime); // get actual time step + qtime += dt64; // update amount of input tstep taken + dt = dt64 / 1000.; // time step as fractional seconds + + errcode = MSXchem_react(dt); // react species in each pipe & tank + if ( errcode ) return errcode; + advectSegs(dt); // advect segments in each pipe + + topological_transport(dt); //replace accumulate, updateNodes, sourceInput and release + + if (MSXerr_mathError()) // check for any math error + { + MSXerr_writeMathErrorMsg(); + errcode = ERR_ILLEGAL_MATH; + } + } + return errcode; +} + +//============================================================================= + +void initSegs() +/* +** Purpose: +** initializes water quality in pipe segments. +** +** Input: +** none. +*/ +{ + int j, k, m; + double v; + +// --- examine each link + + for (k=1; k<=MSX.Nobjects[LINK]; k++) + { + // --- establish flow direction + + if (fabs(MSX.Q[k]) < Q_STAGNANT) + MSX.FlowDir[k] = ZERO_FLOW; + else if (MSX.Q[k] > 0.0) + MSX.FlowDir[k] = POSITIVE; + else + MSX.FlowDir[k] = NEGATIVE; + + // --- start with no segments + + MSX.LastSeg[k] = NULL; + MSX.FirstSeg[k] = NULL; + MSX.NewSeg[k] = NULL; + + // --- use quality of downstream node for BULK species + // if no initial link quality supplied + +// j = DOWN_NODE(k); + j = MSX.Link[k].n2; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + { + if ( MSX.Link[k].c0[m] != MISSING ) + MSX.C1[m] = MSX.Link[k].c0[m]; + else if ( MSX.Species[m].type == BULK ) + MSX.C1[m] = MSX.Node[j].c0[m]; + else MSX.C1[m] = 0.0; + } + + // --- fill link with a single segment of this quality + + MSXchem_equil(LINK, k, MSX.C1); + v = LINKVOL(k); + if (v > 0.0) + { + int ninitsegs = MIN(100, MSX.MaxSegments); + + for (int ns = 0; ns < ninitsegs; ns++) + MSXqual_addSeg(k, MSXqual_getFreeSeg(v / (1.0*ninitsegs), MSX.C1)); + } + } + +// --- initialize segments in tanks + + for (j=1; j<=MSX.Nobjects[TANK]; j++) + { + // --- skip reservoirs + + if ( MSX.Tank[j].a == 0.0 ) continue; + + // --- tank segment pointers are stored after those for links + + k = MSX.Tank[j].node; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + MSX.C1[m] = MSX.Node[k].c0[m]; + k = MSX.Nobjects[LINK] + j; + MSX.LastSeg[k] = NULL; + MSX.FirstSeg[k] = NULL; + + MSXchem_equil(NODE, j, MSX.C1); + + // --- add 2 segments for 2-compartment model + + if (MSX.Tank[j].mixModel == MIX2) + { + v = MAX(0, MSX.Tank[j].v - MSX.Tank[j].vMix); + MSXqual_addSeg(k, MSXqual_getFreeSeg(v, MSX.C1)); + v = MSX.Tank[j].v - v; + MSXqual_addSeg(k, MSXqual_getFreeSeg(v, MSX.C1)); + } + + // --- add one segment for all other models + + else + { + v = MSX.Tank[j].v; + MSXqual_addSeg(k, MSXqual_getFreeSeg(v, MSX.C1)); + } + } + + findstoredmass(MSX.MassBalance.initial); // initial mass +} + +//============================================================================= + +int flowdirchanged() +/* +** Purpose: +** re-orients pipe segments (if flow reverses). +** +** Input: +** none. +*/ +{ + int k, flowchanged=0; + FlowDirection newdir; + + +// --- examine each link + + for (k=1; k<=MSX.Nobjects[LINK]; k++) + { + // --- find new flow direction + + newdir = POSITIVE; + if (fabs(MSX.Q[k]) < Q_STAGNANT) + newdir = ZERO_FLOW; + else if (MSX.Q[k] < 0.0) newdir = NEGATIVE; + + // --- if direction changes, then reverse the order of segments + // (first to last) and save new direction + + if (newdir*MSX.FlowDir[k] < 0) + { + MSXqual_reversesegs(k); + } + if (newdir != MSX.FlowDir[k]) + { + flowchanged = 1; + } + MSX.FlowDir[k] = newdir; + } + return flowchanged; +} + + +//============================================================================= + +void advectSegs(double dt) +/* +** Purpose: +** advects WQ segments within each pipe. +** +** Input: +** dt = current WQ time step (sec). +*/ +{ + int k, m; + +// --- examine each link + + for (k=1; k<=MSX.Nobjects[LINK]; k++) + { + // --- zero out WQ in new segment to be added at entrance of link + + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) MSX.C1[m] = 0.0; + + // --- get a free segment to add to entrance of link + + MSX.NewSeg[k] = MSXqual_getFreeSeg(0.0, MSX.C1); + + // --- skip zero-length links (pumps & valves) & no-flow links + + if ( MSX.NewSeg[k] == NULL || + MSX.Link[(k)].len == 0.0 || MSX.Q[k] == 0.0 ) continue; + + // --- find conc. of wall species in new segment to be added + // and adjust conc. of wall species to reflect shifted + // positions of existing segments + + if ( MSX.HasWallSpecies ) + { + getNewSegWallQual(k, dt, MSX.NewSeg[k]); + shiftSegWallQual(k, dt); + } + } +} + +//============================================================================= + +void getNewSegWallQual(int k, double dt, Pseg newseg) +/* +** Purpose: +** computes wall species concentrations for a new WQ segment that +** enters a pipe from its upstream node. +** +** Input: +** k = link index +** dt = current WQ time step (sec) +** newseg = pointer to a new, unused WQ segment +** +** Output: +** newseg->c[] = wall species concentrations in the new WQ segment +*/ +{ + Pseg seg; + int m; + double v, vin, vsum, vadded, vleft; + +// --- get volume of inflow to link + + if ( newseg == NULL ) return; + v = LINKVOL(k); + vin = ABS(MSX.Q[k])*dt; + if (vin > v) vin = v; + +// --- start at last (most upstream) existing WQ segment + + seg = MSX.LastSeg[k]; + vsum = 0.0; + vleft = vin; + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if ( MSX.Species[m].type == WALL ) newseg->c[m] = 0.0; + } + +// --- repeat while some inflow volume still remains + + while ( vleft > 0.0 && seg != NULL ) + { + + // --- find volume added by this segment + + vadded = seg->v; + if ( vadded > vleft ) vadded = vleft; + + // --- update total volume added and inflow volume remaining + + vsum += vadded; + vleft -= vadded; + + // --- add wall species mass contributed by this segment to new segment + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if ( MSX.Species[m].type == WALL ) newseg->c[m] += vadded*seg->c[m]; + } + + // --- move to next downstream WQ segment + + seg = seg->next; + } + +// --- convert mass of wall species in new segment to concentration + + if ( vsum > 0.0 ) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if ( MSX.Species[m].type == WALL ) newseg->c[m] /= vsum; + } + } +} + +//============================================================================= + +void shiftSegWallQual(int k, double dt) +/* +** Purpose: +** recomputes wall species concentrations in segments that remain +** within a pipe after flow is advected over current time step. +** +** Input: +** k = link index +** dt = current WQ time step (sec) +*/ +{ + Pseg seg1, seg2; + int m; + double v, vin, vstart, vend, vcur, vsum; + +// --- find volume of water displaced in pipe + + v = LINKVOL(k); + vin = ABS((double)MSX.Q[k])*dt; + if (vin > v) vin = v; + +// --- set future start position (measured by pipe volume) of original last segment + + vstart = vin; + +// --- examine each segment, from upstream to downstream + + for( seg1 = MSX.LastSeg[k]; seg1 != NULL; seg1 = seg1->next ) + { + + // --- initialize a "mixture" WQ + // if vstart >= v the segment seg1 will be out of the pipe, + // so no need to track wall concentration of this segment + if (vstart >= v) break; //2020 moved up + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) MSX.C1[m] = 0.0; + + // --- find the future end position of this segment + + vend = vstart + seg1->v; // + if (vend > v) vend = v; + vcur = vstart; + vsum = 0; + + // --- find volume taken up by the segment after it moves down the pipe + + for (seg2 = MSX.LastSeg[k]; seg2 != NULL; seg2 = seg2->next) + { + if ( seg2->v == 0.0 ) continue; + vsum += seg2->v; + if ( vsum >= vstart && vsum <= vend ) //DS end of seg2 is between vstart and vend + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if ( MSX.Species[m].type == WALL ) + MSX.C1[m] += (vsum - vcur) * seg2->c[m]; + } + vcur = vsum; + } + if ( vsum >= vend ) break; //DS of seg2 is at DS of vend + } + + // --- update the wall species concentrations in the segment + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if ( MSX.Species[m].type != WALL ) continue; + if (seg2 != NULL) MSX.C1[m] += (vend - vcur) * seg2->c[m]; //only part of seg2 + seg1->c[m] = MSX.C1[m] / (vend - vstart); + if ( seg1->c[m] < 0.0 ) seg1->c[m] = 0.0; + } + + // --- re-start at the current end location + + vstart = vend; + // if ( vstart >= v ) break; //2020 moved up + } +} + + +//============================================================================= + +void sourceInput(int n, double volout, double dt) +/* +** Purpose: +** computes contribution (if any) of mass additions from WQ +** sources at each node. +** +** Input: +** n = nodeindex +** dt = current WQ time step (sec) +*/ +{ + int m; + double qout, qcutoff; + Psource source; + +// --- establish a flow cutoff which indicates no outflow from a node + + qcutoff = 10.0*TINY; + +// --- consider each node + + // --- skip node if no WQ source + + source = MSX.Node[n].sources; + if (source == NULL) return; + + + qout = volout / dt; + + // --- evaluate source input only if node outflow > cutoff flow + if (qout <= qcutoff) return; + + // --- add contribution of each source species + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.SourceIn[m] = 0.0; + while (source) + { + addSource(n, source, volout, dt); + source = source->next; + } + + // --- compute a new chemical equilibrium at the source node + MSXchem_equil(NODE, 0, MSX.Node[n].c); + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + MSX.MassBalance.inflow[m] += MSX.SourceIn[m] * LperFT3; + } +} + +//============================================================================= + +void addSource(int n, Psource source, double volout, double dt) +/* +** Purpose: +** updates concentration of particular species leaving a node +** that receives external source input. +** +** Input: +** n = index of source node +** source = pointer to WQ source data +** volout = volume of water leaving node during current time step +** dt = current WQ time step (sec) +*/ +{ + int m; + double massadded, s; + +// --- only analyze bulk species + + m = source->species; + massadded = 0.0; + if (source->c0 > 0.0 && MSX.Species[m].type == BULK) + { + + // --- mass added depends on type of source + + s = getSourceQual(source); + switch(source->type) + { + // Concen. Source: + // Mass added = source concen. * -(demand) + + case CONCEN: + + // Only add source mass if demand is negative + if (MSX.Node[n].tank <=0 && MSX.D[n] < 0.0) massadded = -s*MSX.D[n]*dt; + + // If node is a tank then set concen. to 0. + // (It will be re-set to true value later on) + + // if (MSX.Node[n].tank > 0) MSX.Node[n].c[m] = 0.0; + break; + + // Mass Inflow Booster Source: + + case MASS: + massadded = s*dt/LperFT3; + break; + + // Setpoint Booster Source: + // Mass added is difference between source + // & node concen. times outflow volume + + case SETPOINT: + if (s > MSX.Node[n].c[m]) + massadded = (s - MSX.Node[n].c[m])*volout; + break; + + // Flow-Paced Booster Source: + // Mass added = source concen. times outflow volume + + case FLOWPACED: + massadded = s*volout; + break; + } + + // --- adjust nodal concentration to reflect source addition + MSX.Node[n].c[m] += massadded / volout; + MSX.SourceIn[m] += massadded; + } +} + + +//============================================================================= + +double getSourceQual(Psource source) +/* +** Input: j = source index +** Output: returns source WQ value +** Purpose: determines source concentration in current time period +*/ +{ + int i; + long k; + double c, f = 1.0; + +// --- get source concentration (or mass flow) in original units + c = source->c0; + +// --- convert mass flow rate from min. to sec. + if (source->type == MASS) c /= 60.0; + +// --- apply time pattern if assigned + i = source->pat; + if (i == 0) return(c); + k = (int)((MSX.Qtime + MSX.Pstart*1000) / (MSX.Pstep*1000)) % MSX.Pattern[i].length; + if (k != MSX.Pattern[i].interval) + { + if ( k < MSX.Pattern[i].interval ) + { + MSX.Pattern[i].current = MSX.Pattern[i].first; + MSX.Pattern[i].interval = 0; + } + while (MSX.Pattern[i].current && MSX.Pattern[i].interval < k) + { + MSX.Pattern[i].current = MSX.Pattern[i].current->next; + MSX.Pattern[i].interval++; + } + } + if (MSX.Pattern[i].current) f = MSX.Pattern[i].current->value; + return c*f; +} + +//============================================================================= + +void removeAllSegs(int k) +/* +** Purpose: +** removes all segments in a pipe link. +** +** Input: +** k = link index. +*/ +{ + Pseg seg; + seg = MSX.FirstSeg[k]; + while (seg != NULL) + { + MSX.FirstSeg[k] = seg->prev; + MSXqual_removeSeg(seg); + seg = MSX.FirstSeg[k]; + } + MSX.LastSeg[k] = NULL; + if (k <= MSX.Nobjects[LINK]) + MSX.Link[k].nsegs = 0; +} + +void topological_transport(double dt) +{ + int j, n, k, m; + double volin, volout; + Padjlist alink; + + + // Analyze each node in topological order + for (j = 1; j <= MSX.Nobjects[NODE]; j++) + { + // ... index of node to be processed + n = MSX.SortedNodes[j]; + + // ... zero out mass & flow volumes for this node + volin = 0.0; + volout = 0.0; + memset(MSX.MassIn, 0, (MSX.Nobjects[SPECIES] + 1) * sizeof(double)); + memset(MSX.SourceIn, 0, (MSX.Nobjects[SPECIES] + 1) * sizeof(double)); + + // ... examine each link with flow into the node + for (alink = MSX.Adjlist[n]; alink != NULL; alink = alink->next) + { + // ... k is index of next link incident on node n + k = alink->link; + + // ... link has flow into node - add it to node's inflow + // (m is index of link's downstream node) + m = MSX.Link[k].n2; + if (MSX.FlowDir[k] < 0) m = MSX.Link[k].n1; + if (m == n) + { + evalnodeinflow(k, dt, &volin, MSX.MassIn); + } + + // ... link has flow out of node - add it to node's outflow + else volout += fabs(MSX.Q[k]); + } + + // ... if node is a junction, add on any external outflow (e.g., demands) + if (MSX.Node[n].tank == 0) + { + volout += fmax(0.0, MSX.D[n]); + } + + // ... convert from outflow rate to volume + volout *= dt; + + // ... find the concentration of flow leaving the node + findnodequal(n, volin, MSX.MassIn, volout, dt); + + // ... examine each link with flow out of the node + for (alink = MSX.Adjlist[n]; alink != NULL; alink = alink->next) + { + // ... link k incident on node n has upstream node m equal to n + k = alink->link; + m = MSX.Link[k].n1; + if (MSX.FlowDir[k] < 0) m = MSX.Link[k].n2; + if (m == n) + { + // ... send flow at new node concen. into link + evalnodeoutflow(k, MSX.Node[n].c, dt); + } + } + + } + /*Advection-Reaction Done, Dispersion Starts*/ + //1. Linear relationship for each pipe + //2. Compose the nodal equations + //3. Solve the matrix to update nodal concentration + //4. Update segment concentration + for (int m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Dispersion.md[m] > 0 || MSX.Dispersion.ld[m] > 0) + { + dispersion_pipe(m, dt); + solve_nodequal(m, dt); + segqual_update(m, dt); + } + } +} + + +void evalnodeoutflow(int k, double * upnodequal, double tstep) +/* +**-------------------------------------------------------------- +** Input: k = link index +** c = quality from upstream node +** tstep = time step +** Output: none +** Purpose: releases flow volume and mass from the upstream +** node of a link over a time step. +**-------------------------------------------------------------- +*/ +{ + + double v; + Pseg seg; + int m; + int useNewSeg = 0; + + // Find flow volume (v) released over time step + v = fabs(MSX.Q[k]) * tstep; + if (v == 0.0) return; + + // Release flow and mass into upstream end of the link + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type == BULK) + MSX.NewSeg[k]->c[m] = upnodequal[m]; + } + + // ... case where link has a last (most upstream) segment + seg = MSX.LastSeg[k]; + + if (seg) + { + if (!MSXqual_isSame(seg->c, upnodequal) && MSX.Link[k].nsegs < MSX.MaxSegments) + { + useNewSeg = 1; + } + else + useNewSeg = 0; + +// if (MSX.DispersionFlag == 1 && MSX.Link[k].nsegs >= MSX.MaxSegments) +// useNewSeg = 0; + + if (useNewSeg == 0) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type == BULK) + seg->c[m] = (seg->c[m]*seg->v+upnodequal[m]*v)/(seg->v+v); + } + seg->v += v; + MSXqual_removeSeg(MSX.NewSeg[k]); + } + + // --- otherwise add the new seg to the end of the link + + else + { + MSX.NewSeg[k]->v = v; + MSXqual_addSeg(k, MSX.NewSeg[k]); + } + } + + // ... link has no segments so add one + else + { + MSX.NewSeg[k]->v = v; + MSXqual_addSeg(k, MSX.NewSeg[k]); + } + +} + + +void evalnodeinflow(int k, double tstep, double* volin, double* massin) + /* + **-------------------------------------------------------------- + ** Input: k = link index + ** tstep = quality routing time step + ** Output: volin = flow volume entering a node + ** massin = constituent mass entering a node + ** Purpose: adds the contribution of a link's outflow volume + ** and constituent mass to the total inflow into its + ** downstream node over a time step. + **-------------------------------------------------------------- + */ +{ + + double q, v, vseg; + int sindex; + Pseg seg; + + // Get flow rate (q) and flow volume (v) through link + q = MSX.Q[k]; + v = fabs(q) * tstep; + + // Transport flow volume v from link's leading segments into downstream + // node, removing segments once their full volume is consumed + while (v > 0.0) + { + seg = MSX.FirstSeg[k]; + if (!seg) break; + + // ... volume transported from first segment is smaller of + // remaining flow volume & segment volume + vseg = seg->v; + vseg = MIN(vseg, v); + + // ... update total volume & mass entering downstream node + *volin += vseg; + for (sindex = 1; sindex <= MSX.Nobjects[SPECIES]; sindex++) + massin[sindex] += vseg * seg->c[sindex] * LperFT3; + + // ... reduce remaining flow volume by amount transported + v -= vseg; + + // ... if all of segment's volume was transferred + if (v >= 0.0 && vseg >= seg->v) + { + // ... replace this leading segment with the one behind it + MSX.FirstSeg[k] = seg->prev; + MSX.Link[k].nsegs--; + if (MSX.FirstSeg[k] == NULL) MSX.LastSeg[k] = NULL; + + // ... recycle the used up segment + seg->prev = MSX.FreeSeg; + MSX.FreeSeg = seg; + } + + // ... otherwise just reduce this segment's volume + else seg->v -= vseg; + } +} + + +void findnodequal(int n, double volin, double* massin, double volout, double tstep) + /* + **-------------------------------------------------------------- + ** Input: n = node index + ** volin = flow volume entering node + ** massin = mass entering node + ** volout = flow volume leaving node + ** tstep = length of current time step + ** Output: returns water quality in a node's outflow + ** Purpose: computes a node's new quality from its inflow + ** volume and mass, including any source contribution. + **-------------------------------------------------------------- + */ +{ + int m, j; + // Node is a junction - update its water quality + j = MSX.Node[n].tank; + if (j <= 0) + { + // ... dilute inflow with any external negative demand + volin -= fmin(0.0, MSX.D[n]) * tstep; + + // ... new concen. is mass inflow / volume inflow + if (volin > 0.0) + { + for(m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.Node[n].c[m] = massin[m] / volin / LperFT3; + } + + // ... if no inflow adjust quality for reaction in connecting pipes + else + noflowqual(n); + + MSXchem_equil(NODE, 0, MSX.Node[n].c); + + } + else + { + // --- use initial quality for reservoirs + + if (MSX.Tank[j].a == 0.0) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + MSX.Node[n].c[m] = MSX.Node[n].c0[m]; + } + MSXchem_equil(NODE, 0, MSX.Node[n].c); + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + + MSX.MassBalance.inflow[m] += MSX.Node[n].c[m] * volout * LperFT3; + MSX.MassBalance.outflow[m] += massin[m]; + } + } + + // --- otherwise update tank WQ based on mixing model + + else + { + if (volin > 0.0) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + MSX.C1[m] = massin[m] / volin / LperFT3; + } + } + else for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.C1[m] = 0.0; + switch (MSX.Tank[j].mixModel) + { + case MIX1: MSXtank_mix1(j, volin, massin, volin-volout); + break; + case MIX2: MSXtank_mix2(j, volin, massin, volin-volout); + break; + case FIFO: MSXtank_mix3(j, volin, massin, volin-volout); + break; + case LIFO: MSXtank_mix4(j, volin, massin, volin-volout); + break; + } + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + MSX.Node[n].c[m] = MSX.Tank[j].c[m]; + } + MSX.Tank[j].v += (double)MSX.D[n] * tstep; + } + } + + // Find quality contribued by any external chemical source + sourceInput(n, volout, tstep); + if (MSX.Node[n].tank == 0) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + if(MSX.Species[m].type == BULK) + MSX.MassBalance.outflow[m] += MAX(0.0, MSX.D[n]) * tstep * MSX.Node[n].c[m]*LperFT3; + } +} + + +int sortNodes() +/* +**-------------------------------------------------------------- +** Input: none +** Output: returns an error code +** Purpose: topologically sorts nodes from upstream to downstream. +** Note: links with negligible flow are ignored since they can +** create spurious cycles that cause the sort to fail. +**-------------------------------------------------------------- +*/ +{ + + int i, j, k, n; + int* indegree = NULL; + int* stack = NULL; + int stacksize = 0; + int numsorted = 0; + int errcode = 0; + FlowDirection dir; + Padjlist alink; + + // Allocate an array to count # links with inflow to each node + // and for a stack to hold nodes waiting to be processed + indegree = (int*)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); + stack = (int*)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); + if (indegree && stack) + { + // Count links with "non-negligible" inflow to each node + for (k = 1; k <= MSX.Nobjects[LINK]; k++) + { + dir = MSX.FlowDir[k]; + if (dir == POSITIVE) n = MSX.Link[k].n2; + else if (dir == NEGATIVE) n = MSX.Link[k].n1; + else continue; + indegree[n]++; + } + + // Place nodes with no inflow onto a stack + for (i = 1; i <= MSX.Nobjects[NODE]; i++) + { + if (indegree[i] == 0) + { + stacksize++; + stack[stacksize] = i; + } + } + + // Examine each node on the stack until none are left + while (numsorted < MSX.Nobjects[NODE]) + { + // ... if stack is empty then a cycle exists + if (stacksize == 0) + { + // ... add a non-sorted node connected to a sorted one to stack + j = selectnonstacknode(numsorted, indegree); + if (j == 0) break; // This shouldn't happen. + indegree[j] = 0; + stacksize++; + stack[stacksize] = j; + } + + // ... make the last node added to the stack the next + // in sorted order & remove it from the stack + i = stack[stacksize]; + stacksize--; + numsorted++; + MSX.SortedNodes[numsorted] = i; + + // ... for each outflow link from this node reduce the in-degree + // of its downstream node + for (alink = MSX.Adjlist[i]; alink != NULL; alink = alink->next) + { + // ... k is the index of the next link incident on node i + k = alink->link; + + // ... skip link if flow is negligible + if (MSX.FlowDir[k] == 0) continue; + + // ... link has flow out of node (downstream node n not equal to i) + n = MSX.Link[k].n2; + if (MSX.FlowDir[k] < 0) n = MSX.Link[k].n1; + + // ... reduce degree of node n + if (n != i && indegree[n] > 0) + { + indegree[n]--; + + // ... no more degree left so add node n to stack + if (indegree[n] == 0) + { + stacksize++; + stack[stacksize] = n; + } + } + } + } + } + else errcode = 101; + if (numsorted < MSX.Nobjects[NODE]) errcode = 120; + FREE(indegree); + FREE(stack); + return errcode; +} + +int selectnonstacknode(int numsorted, int* indegree) +/* +**-------------------------------------------------------------- +** Input: numsorted = number of nodes that have been sorted +** indegree = number of inflow links to each node +** Output: returns a node index +** Purpose: selects a next node for sorting when a cycle exists. +**-------------------------------------------------------------- +*/ +{ + + int i, m, n; + Padjlist alink; + + // Examine each sorted node in last in - first out order + for (i = numsorted; i > 0; i--) + { + // For each link connected to the sorted node + m = MSX.SortedNodes[i]; + for (alink = MSX.Adjlist[m]; alink != NULL; alink = alink->next) + { + // ... n is the node of link k opposite to node m + n = alink->node; + + // ... select node n if it still has inflow links + if (indegree[n] > 0) return n; + } + } + + // If no node was selected by the above process then return the + // first node that still has inflow links remaining + for (i = 1; i <= MSX.Nobjects[NODE]; i++) + { + if (indegree[i] > 0) return i; + } + + // If all else fails return 0 indicating that no node was selected + return 0; +} + +void noflowqual(int n) +/* +**-------------------------------------------------------------- +** Input: n = node index +** Output: quality for node n +** Purpose: sets the quality for a junction node that has no +** inflow to the average of the quality in its +** adjoining link segments. +** Note: this function is only used for reactive substances. +**-------------------------------------------------------------- +*/ +{ + + int k, m, inflow, kount = 0; + double c = 0.0; + FlowDirection dir; + Padjlist alink; + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.Node[n].c[m] = 0.0; + // Examine each link incident on the node + for (alink = MSX.Adjlist[n]; alink != NULL; alink = alink->next) + { + // ... index of an incident link + k = alink->link; + dir = MSX.FlowDir[k]; + + // Node n is link's downstream node - add quality + // of link's first segment to average + if (MSX.Link[k].n2 == n && dir >= 0) inflow = TRUE; + else if (MSX.Link[k].n1 == n && dir < 0) inflow = TRUE; + else inflow = FALSE; + if (inflow == TRUE && MSX.FirstSeg[k] != NULL) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.Node[n].c[m] += MSX.FirstSeg[k]->c[m]; + kount++; + } + + // Node n is link's upstream node - add quality + // of link's last segment to average + else if (inflow == FALSE && MSX.LastSeg[k] != NULL) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.Node[n].c[m] += MSX.LastSeg[k]->c[m]; + kount++; + } + } + if (kount > 0) + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.Node[n].c[m] = MSX.Node[n].c[m] / (double)kount; +} + +void findstoredmass(double * mass) +/* +**-------------------------------------------------------------- +** Input: none +** Output: returns total constituent mass stored in the network +** Purpose: finds the current mass stored in +** all pipes and tanks. +**-------------------------------------------------------------- +*/ +{ + + int i, k, m; + Pseg seg; + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + mass[m] = 0; + } + + // Mass residing in each pipe + for (k = 1; k <= MSX.Nobjects[LINK]; k++) + { + // Sum up the quality and volume in each segment of the link + seg = MSX.FirstSeg[k]; + while (seg != NULL) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type == BULK) + mass[m] += seg->c[m] * seg->v * LperFT3; //M/L * ft3 * L/Ft3 = M + else + mass[m] += seg->c[m] * seg->v * 4.0 / MSX.Link[k].diam * MSX.Ucf[AREA_UNITS]; //Mass per area unit * ft3 / ft * area unit per ft2; + } + seg = seg->prev; + } + } + + // Mass residing in each tank + for (i = 1; i <= MSX.Nobjects[TANK]; i++) + { + // ... skip reservoirs + if (MSX.Tank[i].a == 0.0) continue; + + // ... add up mass in each volume segment + else + { + k = MSX.Nobjects[LINK] + i; + seg = MSX.FirstSeg[k]; + while (seg != NULL) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type == BULK) + mass[m] += seg->c[m] * seg->v * LperFT3; + } + seg = seg->prev; + } + } + } +} + +void MSXqual_reversesegs(int k) +/* +**-------------------------------------------------------------- +** Input: k = link index +** Output: none +** Purpose: re-orients a link's segments when flow reverses. +**-------------------------------------------------------------- +*/ +{ + Pseg seg, cseg, pseg; + + seg = MSX.FirstSeg[k]; + MSX.FirstSeg[k] = MSX.LastSeg[k]; + MSX.LastSeg[k] = seg; + pseg = NULL; + while (seg != NULL) + { + cseg = seg->prev; + seg->prev = pseg; + seg->next = cseg; + pseg = seg; + seg = cseg; + } +} + + + +//============================================================================= + +void MSXqual_removeSeg(Pseg seg) +/* +** Purpose: +** places a WQ segment back into the memory pool of segments. +** +** Input: +** seg = pointer to a WQ segment. +*/ +{ + if ( seg == NULL ) return; + seg->prev = MSX.FreeSeg; + seg->next = NULL; + MSX.FreeSeg = seg; +} + +//============================================================================= + +Pseg MSXqual_getFreeSeg(double v, double c[]) +/* +** Purpose: +** retrieves an unused water quality volume segment from the memory pool. +** +** Input: +** v = segment volume (ft3) +** c[] = segment quality +** +** Returns: +** a pointer to an unused water quality segment. +*/ +{ + Pseg seg; + int m; + +// --- try using the last discarded segment if one is available + + if (MSX.FreeSeg != NULL) + { + seg = MSX.FreeSeg; + MSX.FreeSeg = seg->prev; + } + +// --- otherwise create a new segment from the memory pool + + else + { + seg = (struct Sseg *) Alloc(sizeof(struct Sseg)); + if (seg == NULL) + { + MSX.OutOfMemory = TRUE; + return NULL; + } + seg->c = (double *) Alloc((MSX.Nobjects[SPECIES]+1)*sizeof(double)); + seg->lastc = (double *)Alloc((MSX.Nobjects[SPECIES] + 1) * sizeof(double)); + if ( seg->c == NULL||seg->lastc == NULL) + { + MSX.OutOfMemory = TRUE; + return NULL; + } + } + +// --- assign volume, WQ, & integration time step to the new segment + + seg->v = v; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) seg->c[m] = c[m]; + seg->hstep = 0.0; + return seg; +} + +//============================================================================= + +void MSXqual_addSeg(int k, Pseg seg) +/* +** Purpose: +** adds a new segment to the upstream end of a link. +** +** Input: +** k = link index +** seg = pointer to a free WQ segment. +*/ + +{ + seg->prev = NULL; + seg->next = NULL; + if (MSX.FirstSeg[k] == NULL) MSX.FirstSeg[k] = seg; + if (MSX.LastSeg[k] != NULL) + { + MSX.LastSeg[k]->prev = seg; + seg->next = MSX.LastSeg[k]; + } + MSX.LastSeg[k] = seg; + if (k <= MSX.Nobjects[LINK]) + MSX.Link[k].nsegs++; +} + +void evalHydVariables(int k) +/* +** Purpose: +** retrieves current values of hydraulic variables for the +** current link being analyzed. +** +** Input: +** k = link index +** +** Output: +** updates values stored in vector HydVar[] +*/ +{ + double dh; // headloss in ft + double diam = MSX.Link[k].diam; // diameter in ft + double length = MSX.Link[k].len; // length in ft + double av; // area per unit volume + +// --- pipe diameter and length in user's units (ft or m) + MSX.Link[k].HydVar[DIAMETER] = diam * MSX.Ucf[LENGTH_UNITS]; + MSX.Link[k].HydVar[LENGTH] = length * MSX.Ucf[LENGTH_UNITS]; + + // --- flow rate in user's units + MSX.Link[k].HydVar[FLOW] = fabs(MSX.Q[k]) * MSX.Ucf[FLOW_UNITS]; + + // --- flow velocity in ft/sec + if (diam == 0.0) MSX.Link[k].HydVar[VELOCITY] = 0.0; + else MSX.Link[k].HydVar[VELOCITY] = fabs(MSX.Q[k]) * 4.0 / PI / SQR(diam); + + // --- Reynolds number + MSX.Link[k].HydVar[REYNOLDS] = MSX.Link[k].HydVar[VELOCITY] * diam / VISCOS; + + // --- flow velocity in user's units (ft/sec or m/sec) + MSX.Link[k].HydVar[VELOCITY] *= MSX.Ucf[LENGTH_UNITS]; + + // --- Darcy Weisbach friction factor + if (MSX.Link[k].len == 0.0) MSX.Link[k].HydVar[FRICTION] = 0.0; + else + { + dh = ABS(MSX.H[MSX.Link[k].n1] - MSX.H[MSX.Link[k].n2]); + MSX.Link[k].HydVar[FRICTION] = 39.725 * dh * pow(diam, 5.0) / + MSX.Link[k].len / SQR((double)MSX.Q[k]); + } + + // --- shear velocity in user's units (ft/sec or m/sec) + MSX.Link[k].HydVar[SHEAR] = MSX.Link[k].HydVar[VELOCITY] * sqrt(MSX.Link[k].HydVar[FRICTION] / 8.0); + + // --- pipe surface area / volume in area_units/L + MSX.Link[k].HydVar[AREAVOL] = 1.0; + if (diam > 0.0) + { + av = 4.0 / diam; // ft2/ft3 + av *= MSX.Ucf[AREA_UNITS]; // area_units/ft3 + av /= LperFT3; // area_units/L + MSX.Link[k].HydVar[AREAVOL] = av; + } + + MSX.Link[k].HydVar[ROUGHNESS] = MSX.Link[k].roughness; +} diff --git a/src/solver/msxrpt.c b/src/solver/msxrpt.c new file mode 100644 index 0000000..c71a3e1 --- /dev/null +++ b/src/solver/msxrpt.c @@ -0,0 +1,400 @@ +/****************************************************************************** +** MODULE: MSXRPT.C +** PROJECT: EPANET-MSX +** DESCRIPTION: report writing routines for the EPANET Multi-Species +** Extension toolkit. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +******************************************************************************/ + +#include +#include +#include +#include + +#include "msxtypes.h" +#include "epanet2.h" + +// Constants +//---------- +#define SERIES_TABLE 0 +#define STATS_TABLE 1 + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +// Local variables +//----------------- +static char *Logo[] = + {"******************************************************************", + "* E P A N E T - M S X *", + "* Multi-Species Water Quality *", + "* Analysis for Pipe Networks *", + "* Version 2.0.0 *", //2.0.00 + "******************************************************************"}; + +static char PageHdr[] = " Page %d "; +static char *StatsHdrs[] = + {"", "Average Values ", "Minimum Values ", + "Maximum Values ", "Range of Values "}; +static char Line[MAXLINE+1]; +static long LineNum; +static long PageNum; +static int *RptdSpecies; +static struct TableHdrStruct +{ + char Line1[MAXLINE+1]; + char Line2[MAXLINE+1]; + char Line3[MAXLINE+1]; + char Line4[MAXLINE+1]; + char Line5[MAXLINE+1]; +} TableHdr; +static char IDname[MAXLINE+1]; + +// Imported functions +//-------------------- +void MSXinp_getSpeciesUnits(int m, char *units); +float MSXout_getNodeQual(int k, int j, int m); +float MSXout_getLinkQual(int k, int j, int m); + +// Exported functions +//-------------------- +int MSXrpt_write(void); +void MSXrpt_writeLine(char *line); + +// Local functions +//----------------- +static void createSeriesTables(void); +static void createStatsTables(void); +static void createTableHdr(int objType, int tableType); +static void writeTableHdr(void); +static void writeNodeTable(int j, int tableType); +static void writeLinkTable(int j, int tableType); +static void getHrsMins(int k, int *hrs, int *mins); +static void newPage(void); +static void writeLine(char *line); + +static void writemassbalance(); + +//============================================================================= + +int MSXrpt_write() +{ + INT4 magic = 0; + int j; + int recordsize = sizeof(INT4); + +// --- check that results are available + + if ( MSX.Nperiods < 1 ) return 0; + if ( MSX.OutFile.file == NULL ) return ERR_OPEN_OUT_FILE; + fseek(MSX.OutFile.file, -recordsize, SEEK_END); + fread(&magic, sizeof(INT4), 1, MSX.OutFile.file); + if ( magic != MAGICNUMBER ) return ERR_IO_OUT_FILE; + +// --- write program logo & project title + + PageNum = 1; + LineNum = 1; + newPage(); + for (j=0; j<=5; j++) writeLine(Logo[j]); + writeLine(""); + writeLine(MSX.Title); + +// --- generate the appropriate type of table + + if ( MSX.Statflag == SERIES ) createSeriesTables(); + else createStatsTables(); + + writemassbalance(); + + writeLine(""); + return 0; +} + +//============================================================================= + +void MSXrpt_writeLine(char *line) +{ + writeLine(line); +} + +//============================================================================= + +void createSeriesTables() +{ + int j; + +// --- report on all requested nodes + + for (j=1; j<=MSX.Nobjects[NODE]; j++) + { + if ( !MSX.Node[j].rpt ) continue; + ENgetnodeid(j, IDname); + createTableHdr(NODE, SERIES_TABLE); + writeNodeTable(j, SERIES_TABLE); + } + +// --- report on all requested links + + for (j=1; j<=MSX.Nobjects[LINK]; j++) + { + if ( !MSX.Link[j].rpt ) continue; + ENgetlinkid(j, IDname); + createTableHdr(LINK, SERIES_TABLE); + writeLinkTable(j, SERIES_TABLE); + } +} + +//============================================================================= + +void createStatsTables() +{ + int j; + int count; + +// --- check if any nodes to be reported + + count = 0; + for (j = 1; j <= MSX.Nobjects[NODE]; j++) count += MSX.Node[j].rpt; + +// --- report on all requested nodes + + if ( count > 0 ) + { + createTableHdr(NODE, STATS_TABLE); + for (j = 1; j <= MSX.Nobjects[NODE]; j++) + { + if ( MSX.Node[j].rpt ) writeNodeTable(j, STATS_TABLE); + } + } + +// --- check if any links to be reported + + count = 0; + for (j = 1; j <= MSX.Nobjects[LINK]; j++) count += MSX.Link[j].rpt; + +// --- report on all requested links + + if ( count > 0 ) + { + createTableHdr(LINK, STATS_TABLE); + for (j = 1; j <= MSX.Nobjects[LINK]; j++) + { + if ( MSX.Link[j].rpt ) writeLinkTable(j, STATS_TABLE); + } + } +} + +//============================================================================= + +void createTableHdr(int objType, int tableType) +{ + int m; + char s1[MAXLINE+1]; + char s2[MAXLINE+1]; + + if ( tableType == SERIES_TABLE ) + { + if ( objType == NODE ) + sprintf(TableHdr.Line1, "<<< Node %s >>>", IDname); + else + sprintf(TableHdr.Line1, "<<< Link %s >>>", IDname); + strcpy(TableHdr.Line2, "Time "); + strcpy(TableHdr.Line3, "hr:min "); + strcpy(TableHdr.Line4, "-------"); + } + if ( tableType == STATS_TABLE ) + { + strcpy(TableHdr.Line1, ""); + sprintf(TableHdr.Line2, "%-16s", StatsHdrs[tableType]); + if ( objType == NODE ) strcpy(TableHdr.Line3, "for Node "); + else strcpy(TableHdr.Line3, "for Link "); + strcpy(TableHdr.Line4, "----------------"); + } + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + { + if ( !MSX.Species[m].rpt ) continue; + if ( objType == NODE && MSX.Species[m].type == WALL ) continue; + sprintf(s1, " %10s", MSX.Species[m].id); + strcat(TableHdr.Line2, s1); + strcat(TableHdr.Line4, " ----------"); + MSXinp_getSpeciesUnits(m, s1); + sprintf(s2, " %10s", s1); + strcat(TableHdr.Line3, s2); + } + if ( MSX.PageSize > 0 && MSX.PageSize - LineNum < 8 ) newPage(); + else writeTableHdr(); +} + +//============================================================================= + +void writeTableHdr() +{ + if ( MSX.PageSize > 0 && MSX.PageSize - LineNum < 6 ) newPage(); + writeLine(""); + writeLine(TableHdr.Line1); + writeLine(""); + writeLine(TableHdr.Line2); + writeLine(TableHdr.Line3); + writeLine(TableHdr.Line4); +} + +//============================================================================= + +void writeNodeTable(int j, int tableType) +{ + int k, m, hrs, mins; + char s[MAXLINE+1]; + float c; + + for (k=0; k 1 ) writeTableHdr(); + PageNum++; +} + +//============================================================================= + +void writeLine(char *line) +{ + if ( LineNum == MSX.PageSize ) newPage(); + if ( MSX.RptFile.file ) fprintf(MSX.RptFile.file, " %s\n", line); //(modified, FS-01/07/2008) + else ENwriteline(line); + LineNum++; +} + + +void writemassbalance() +/* +**------------------------------------------------------------- +** Input: none +** Output: none +** Purpose: writes water quality mass balance ratio +** (Outflow + Final Storage) / Inflow + Initial Storage) +** to report file. +**------------------------------------------------------------- +*/ +{ + + char s1[MAXMSG + 1]; + int kunits = 0; + + for (int m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].pipeExprType != RATE) + continue; + + snprintf(s1, MAXMSG, "\n"); + writeLine(s1); + snprintf(s1, MAXMSG, "Water Quality Mass Balance: %s (%s)", MSX.Species[m].id, MSX.Species[m].units); + writeLine(s1); + snprintf(s1, MAXMSG, "================================"); + writeLine(s1); + snprintf(s1, MAXMSG, "Initial Mass: %12.5e", MSX.MassBalance.initial[m]); + writeLine(s1); + snprintf(s1, MAXMSG, "Mass Inflow: %12.5e", MSX.MassBalance.inflow[m]+ MSX.MassBalance.indisperse[m]); + writeLine(s1); + // snprintf(s1, MAXMSG, "Mass Dispersed Inflow: %12.5e", MSX.MassBalance.indisperse[m]); + // writeLine(s1); + snprintf(s1, MAXMSG, "Mass Outflow: %12.5e", MSX.MassBalance.outflow[m]); + writeLine(s1); + snprintf(s1, MAXMSG, "Mass Reacted: %12.5e", MSX.MassBalance.reacted[m]); + writeLine(s1); + snprintf(s1, MAXMSG, "Final Mass: %12.5e", MSX.MassBalance.final[m]); + writeLine(s1); + snprintf(s1, MAXMSG, "Mass Ratio: %-.5f", MSX.MassBalance.ratio[m]); + writeLine(s1); + snprintf(s1, MAXMSG, "================================\n"); + writeLine(s1); + } +} + + + + + + + + diff --git a/src/solver/msxtank.c b/src/solver/msxtank.c new file mode 100644 index 0000000..2e9e0eb --- /dev/null +++ b/src/solver/msxtank.c @@ -0,0 +1,422 @@ +/****************************************************************************** +** MODULE: MSXTANK.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Storage tank mixing routines. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +******************************************************************************/ + +#include +#include + +#include "msxtypes.h" + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +// Imported functions +//-------------------- +extern void MSXqual_removeSeg(Pseg seg); +extern Pseg MSXqual_getFreeSeg(double v, double c[]); +extern void MSXqual_addSeg(int k, Pseg seg); +extern int MSXqual_isSame(double c1[], double c2[]); +extern int MSXchem_equil(int zone, int k, double *c); +extern void MSXqual_reversesegs(int k); + +// Exported functions +//-------------------- +void MSXtank_mix1(int i, double vin, double *massin, double vnet); +void MSXtank_mix2(int i, double vin, double *massin, double vnet); +void MSXtank_mix3(int i, double vin, double *massin, double vnet); +void MSXtank_mix4(int i, double vin, double *massin, double vnet); + + +//============================================================================= + +void MSXtank_mix1(int i, double vin, double *massin, double vnet) +/* +** Purpose: +** computes new WQ at end of time step in a completely mixed tank +** (after contents have been reacted). +** +** Input: +** i = tank index +** vin = volume of inflow to tank (ft3) +** massin = massinflow +** vnet = inflow - outflow +*/ +{ + int k, m, n; + double c; + double vnew; + Pseg seg; + +// --- blend inflow with contents + + n = MSX.Tank[i].node; + k = MSX.Nobjects[LINK] + i; + seg = MSX.FirstSeg[k]; + if (seg) + { + vnew = seg->v + vin; + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type != BULK) continue; + c = seg->c[m]; + if (vnew > 0.0) + c = (c*seg->v*LperFT3+massin[m])/(vnew*LperFT3); + + c = MAX(0.0, c); + seg->c[m] = c; + MSX.Tank[i].c[m] = c; + } + seg->v += vnet; + seg->v = MAX(0, seg->v); + } + +// --- update species equilibrium + + if ( vin > 0.0 ) MSXchem_equil(NODE, i, MSX.Tank[i].c); +} + +//============================================================================= + +void MSXtank_mix2(int i, double vin, double *massin, double vnet) +/* +** Purpose: 2-compartment tank model +** +** Input: i = tank index +** vIn = volume of inflow to tank (ft3) +** massin = massinflow +** vnet = inflow - outflow +*/ +{ + int k, m, n; + double vt, //transferred volume + vmz; //full mixing zone volume + Pseg mixzone, // Mixing zone segment + stagzone; // Stagnant zone segment + +// --- find inflows & outflows + + n = MSX.Tank[i].node; + +// --- get segments for each zone + + k = MSX.Nobjects[LINK] + i; + mixzone = MSX.LastSeg[k]; + stagzone = MSX.FirstSeg[k]; + if (mixzone == NULL || stagzone == NULL) return; + + + // Full mixing zone volume + vmz = MSX.Tank[i].vMix; + + vt = 0.0; + + +// --- case of net filling (vnet > 0) + + if (vnet > 0.0) + { + vt = MAX(0.0, (mixzone->v + vnet - vmz)); + if (vin > 0) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type != BULK) continue; + + // --- new quality in mixing zone + mixzone->c[m] = (mixzone->c[m] * mixzone->v * LperFT3 + massin[m]) / ((mixzone->v + vin)*LperFT3); + mixzone->c[m] = MAX(0.0, mixzone->c[m]); + } + } + if (vt > 0) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type != BULK) continue; + + // --- new quality in stagnant zone + + stagzone->c[m] = (stagzone->c[m] * stagzone->v + mixzone->c[m] * vt) / (stagzone->v + vt); + stagzone->c[m] = MAX(0.0, stagzone->c[m]); + } + + + + } + } + else if (vnet < 0) //tank is draining + { + if (stagzone->v > 0.0) vt = MIN(stagzone->v, (-vnet)); + if (vin + vt > 0.0) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + if (MSX.Species[m].type != BULK) continue; + + // --- new quality in mixing zone + mixzone->c[m] = (mixzone->c[m] * mixzone->v * LperFT3 + massin[m] + stagzone->c[m]*vt*LperFT3) / ((mixzone->v + vin + vt)*LperFT3); + mixzone->c[m] = MAX(0.0, mixzone->c[m]); + } + } + } + + // Update segment volumes + if (vt > 0.0) + { + mixzone->v = vmz; + if (vnet > 0.0) stagzone->v += vt; + else stagzone->v = MAX(0.0, ((stagzone->v) - vt)); + } + else + { + mixzone->v += vnet; + mixzone->v = MIN(mixzone->v, vmz); + mixzone->v = MAX(0.0, mixzone->v); + stagzone->v = 0.0; + } + + if (mixzone->v > 0.0) MSXchem_equil(NODE, i, mixzone->c); + if (stagzone->v > 0.0) MSXchem_equil(NODE, i, stagzone->c); + +// --- use quality of mixed compartment (mixzone) to represent quality +// of tank since this is where outflow begins to flow from + + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) MSX.Tank[i].c[m] = mixzone->c[m]; +} + +//============================================================================= + +void MSXtank_mix3(int i, double vin, double *massin, double vnet) +/* +** Purpose: computes concentrations in the segments that form a +** first-in-first-out (FIFO) tank model. +** +** Input: i = tank index +** vIn = volume of inflow to tank (ft3) +** massin = mass inflow +** vnet = inflow - outflow +*/ +{ + int k, m, n; + double vout, vseg, vsum; + Pseg seg; + +// --- find inflows & outflows + + k = MSX.Nobjects[LINK] + i; + n = MSX.Tank[i].node; + vout = vin - vnet; + + if (MSX.LastSeg[k] == NULL || MSX.FirstSeg[k] == NULL) return; + + if (vin > 0.0) + { + + // --- quality is the same, so just add flow volume to last seg + seg = MSX.LastSeg[k]; + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + { + MSX.C1[m] = massin[m] / (vin*LperFT3); + } + if (seg != NULL && MSXqual_isSame(seg->c, MSX.C1)) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + seg->c[m] = (seg->c[m] * seg->v + MSX.C1[m] * vin) / (seg->v + vin); + seg->v += vin; + } + // --- Otherwise add a new seg to tank + else + { + seg = MSXqual_getFreeSeg(vin, MSX.C1); + MSXqual_addSeg(k, seg); + } + } + + +// --- initialize outflow volume & concentration + + vsum = 0.0; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + MSX.C1[m] = 0.0; +// --- withdraw flow from first segment + + while (vout > 0.0) + { + // --- get volume of current first segment + seg = MSX.FirstSeg[k]; + if (seg == NULL) break; + vseg = seg->v; + vseg = MIN(vseg, vout); + if ( seg == MSX.LastSeg[k] ) vseg = vout; + + // --- update mass & volume removed + vsum += vseg; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + { + MSX.C1[m] += (seg->c[m]) * vseg * LperFT3; + } + + // --- decrease vOut by volume of first segment + vout -= vseg; + + // --- remove segment if all its volume is consumed + if (vout >= 0.0 && vseg >= seg->v) + { + if (seg->prev) + { + MSX.FirstSeg[k] = seg->prev; + // MSXqual_removeSeg(seg); + seg->prev = MSX.FreeSeg; + MSX.FreeSeg = seg; + + } + } + + // --- otherwise just adjust volume of first segment + else seg->v -= vseg; + } + +// --- use quality from first segment to represent overall +// quality of tank since this is where outflow flows from + + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + { + if (vsum > 0.0) MSX.Tank[i].c[m] = MSX.C1[m]/(vsum * LperFT3); + else if (MSX.FirstSeg[k] == NULL) MSX.Tank[i].c[m] = 0.0; + else MSX.Tank[i].c[m] = MSX.FirstSeg[k]->c[m]; + } +// --- add new last segment for new flow entering tank +} + +//============================================================================= + +void MSXtank_mix4(int i, double vin, double *massin, double vnet) +/* +**---------------------------------------------------------- +** Input: i = tank index +** vin = volume of inflow to tank (ft3) +** massin = mass inflow +** vnet = vin - vout +** Output: none +** Purpose: Last In-First Out (LIFO) tank model +**---------------------------------------------------------- +*/ +{ + int k, m, n; + double vsum, vseg; + Pseg seg; + +// --- find inflows & outflows + + k = MSX.Nobjects[LINK] + i; + n = MSX.Tank[i].node; + + if (MSX.LastSeg[k] == NULL || MSX.FirstSeg[k] == NULL) return; + +// --- keep track of total volume & mass removed from tank + + vsum = 0.0; + if (vin > 0) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.C1[m] = massin[m] / (vin*LperFT3); + } + else + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.C1[m] = 0; + } + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.Tank[i].c[m] = MSX.LastSeg[k]->c[m]; + + seg = MSX.LastSeg[k]; +// --- if tank filling, then create a new last segment + if ( vnet > 0.0 ) + { + + // --- inflow quality = last segment quality so just expand last segment + if (seg != NULL && MSXqual_isSame(seg->c, MSX.C1)) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + seg->c[m] = (seg->c[m] * seg->v + MSX.C1[m] * vnet) / (seg->v + vnet); + seg->v += vnet; + } + + // --- otherwise add a new last segment to tank + + else + { + seg = MSXqual_getFreeSeg(vnet, MSX.C1); + MSXqual_addSeg(k, seg); + } + + // --- quality of tank is that of inflow + + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.Tank[i].c[m] = MSX.LastSeg[k]->c[m]; + + } + +// --- if tank emptying then remove last segments until vNet consumed + + else if (vnet < 0.0) + { + for (m = 1; m <= MSX.Nobjects[SPECIES]; m++) + MSX.C1[m] = 0; + // --- keep removing volume from last segments until vNet is removed + vsum = 0; + vnet = -vnet; + MSXqual_reversesegs(k); + while (vnet > 0.0) + { + + // --- get volume of current last segment + seg = MSX.FirstSeg[k]; + if ( seg == NULL ) break; + vseg = seg->v; + vseg = MIN(vseg, vnet); + if ( seg == MSX.LastSeg[k] ) vseg = vnet; + + // --- update mass & volume removed + vsum += vseg; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + MSX.C1[m] += (seg->c[m])*vseg*LperFT3; + + // --- reduce vNet by volume of last segment + vnet -= vseg; + + // --- remove segment if all its volume is used up + if (vnet >= 0.0 && vseg >= seg->v) + { + if (seg->prev) + { + MSX.FirstSeg[k] = seg->prev; + MSXqual_removeSeg(seg); + + } + } + // --- otherwise just reduce volume of last segment + else + { + seg->v -= vseg; + } + } + MSXqual_reversesegs(k); + // --- tank quality is mixture of flow released and any inflow + + vsum = vsum + vin; + for (m=1; m<=MSX.Nobjects[SPECIES]; m++) + { + if (vsum > 0.0) + MSX.Tank[i].c[m] = (MSX.C1[m] + massin[m]) / (vsum*LperFT3); + } + } +} diff --git a/src/solver/msxtoolkit.c b/src/solver/msxtoolkit.c new file mode 100644 index 0000000..e8f7732 --- /dev/null +++ b/src/solver/msxtoolkit.c @@ -0,0 +1,1132 @@ +/******************************************************************************* +** MODULE: MSXTOOLKIT.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Contains the exportable set of functions that comprise the +** EPANET Multi-Species Extension toolkit. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +** +** These functions can be used in conjunction with the original EPANET +** toolkit functions to model water quality fate and transport of +** multiple interacting chemcial species within piping networks. See the +** MSXMAIN.C module for an example of how these functions were used to +** extend the original command line version of EPANET to include multiple +** chemical species. Consult the EPANET and EPANET-MSX Users Manuals for +** detailed descriptions of the input data file formats required by both +** the original EPANET and its multi-species extension. +*******************************************************************************/ + +#include +#include +#include +#include + +#include "msxtypes.h" +#include "msxutils.h" +#include "epanet2.h" +#include "epanetmsx.h" + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data + +// Imported functions +//-------------------- +int MSXproj_open(char *fname); +int MSXproj_close(void); +int MSXproj_addObject(int type, char *id, int n); +int MSXproj_findObject(int type, char *id); +char * MSXproj_findID(int type, char *id); +char * MSXproj_getErrmsg(int errcode); +int MSXqual_open(void); +int MSXqual_init(void); +int MSXqual_step(double *t, double *tleft); +int MSXqual_close(void); +double MSXqual_getNodeQual(int j, int m); +double MSXqual_getLinkQual(int k, int m); +int MSXrpt_write(void); +int MSXfile_save(FILE *f); + +//============================================================================= + +int MSXDLLEXPORT MSXopen(char *fname) +/* +** Purpose: +** opens the EPANET-MSX toolkit system. +** +** Input: +** fname = name of an MSX input file. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int err = 0; + if (MSX.ProjectOpened) return(ERR_MSX_OPENED); + CALL(err, MSXproj_open(fname)); + CALL(err, MSXqual_open()); + + if ( err ) + { + ENwriteline(MSXproj_getErrmsg(err)); + ENwriteline(""); + } + + return err; +} + +//============================================================================= + +int MSXDLLEXPORT MSXsolveH() +/* +** Purpose: +** solves for system hydraulics which are written to a temporary file. +** +** Input: +** none. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int err = 0; + +// --- check that an MSX project was opened + + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + +// --- close & remove any existing hydraulics file + + if ( MSX.HydFile.file ) + { + fclose(MSX.HydFile.file); + MSX.HydFile.file = NULL; + } + if ( MSX.HydFile.mode == SCRATCH_FILE ) remove(MSX.HydFile.name); + +// --- create a temporary hydraulics file + + MSXutils_getTempName(MSX.HydFile.name); + MSX.HydFile.mode = SCRATCH_FILE; //(LR-10/05/08) + +// --- use EPANET to solve for & save hydraulics results + + CALL(err, ENsolveH()); + CALL(err, ENsavehydfile(MSX.HydFile.name)); + CALL(err, MSXusehydfile(MSX.HydFile.name)); + return err; +} + +//============================================================================= + +int MSXDLLEXPORT MSXusehydfile(char *fname) +/* +** Purpose: +** registers a hydraulics solution file with the MSX system. +** +** Input: +** fname = name of binary hydraulics results file. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + INT4 magic; + INT4 version; + INT4 n; + +// --- check that an MSX project was opened + + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + +// --- close any existing hydraulics file + + if ( MSX.HydFile.file ) + { + fclose(MSX.HydFile.file); + if ( MSX.HydFile.mode == SCRATCH_FILE ) remove(MSX.HydFile.name); //(LR-10/05/08) + } + + +// --- open hydraulics file + + //MSX.HydFile.mode = USED_FILE; + MSX.HydFile.file = fopen(fname, "rb"); + if (!MSX.HydFile.file) return ERR_OPEN_HYD_FILE; + +// --- check that file is really a hydraulics file for current project + + fread(&magic, sizeof(INT4), 1, MSX.HydFile.file); + if ( magic != MAGICNUMBER ) return ERR_READ_HYD_FILE; + fread(&version, sizeof(INT4), 1, MSX.HydFile.file); + fread(&n, sizeof(INT4), 1, MSX.HydFile.file); + if ( n != MSX.Nobjects[NODE] ) return ERR_READ_HYD_FILE; + fread(&n, sizeof(INT4), 1, MSX.HydFile.file); + if ( n != MSX.Nobjects[LINK] ) return ERR_READ_HYD_FILE; + fseek(MSX.HydFile.file, 3*sizeof(INT4), SEEK_CUR); + +// --- read length of simulation period covered by file + + fread(&n, sizeof(INT4), 1, MSX.HydFile.file); + MSX.Dur = 1000 * n; + MSX.HydOffset = ftell(MSX.HydFile.file); + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXsolveQ() +/* +** Purpose: +** runs a MSX water quality analysis over the entire simulation period. +** +** Input: +** none. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + double t, tleft = 0; + int err = 0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + CALL(err, MSXinit(1)); + do CALL(err, MSXstep(&t, &tleft)); + while (tleft > 0 && err == 0); + return err; +} + +//============================================================================= + +int MSXDLLEXPORT MSXinit(int saveFlag) +/* +** Purpose: +** initializes a MSX water quality analysis. +** +** Input: +** saveFlag = 1 if results saved to binary file, 0 if not. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int err= 0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + MSX.Saveflag = saveFlag; + err = MSXqual_init(); + return err; +} + +//============================================================================= + +int MSXDLLEXPORT MSXstep(double *t, double *tleft) +/* +** Purpose: +** advances the WQ simulation over a single time step. +** +** Input: +** none +** +** Output: +** *t = current simulation time at the end of the step (sec) +** *tleft = time left in the simulation (sec) +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + return MSXqual_step(t, tleft); +} + +//============================================================================= + +int MSXDLLEXPORT MSXsaveoutfile(char *fname) +/* +** Purpose: +** saves all results of the WQ simulation to a binary file. +** +** Input: +** fname = name of the binary results file. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + FILE *f; + int c; + + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( !MSX.OutFile.file ) return ERR_OPEN_OUT_FILE; + if ( (f = fopen(fname,"w+b") ) == NULL) return ERR_OPEN_OUT_FILE; + fseek(MSX.OutFile.file, 0, SEEK_SET); + while ( (c = fgetc(MSX.OutFile.file)) != EOF) fputc(c, f); + fclose(f); + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXreport() +/* +** Purpose: +** writes requested WQ simulation results to a text file. +** +** Input: +** none +** +** Returns: +** an error code (or 0 for no error). +** +** Notes: +** Results are written to the EPANET report file unless a specific +** water quality report file is named in the [REPORT] section of +** the MSX input file. +*/ +{ + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( MSX.Rptflag ) return MSXrpt_write(); + else return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXclose() +/* +** Purpose: +** closes the EPANET-MSX toolkit system. +** +** Input: +** none +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + MSXqual_close(); + MSXproj_close(); + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetindex(int type, char *id, int *index) +/* +** Purpose: +** retrieves the index of a named MSX object. +** +** Input: +** type = object type code +** id = name of water quality species. +** +** Output: +** index = index (base 1) in the list of all objects of the given type. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int i; + *index = 0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + switch(type) + { + case MSX_SPECIES: i = MSXproj_findObject(SPECIES, id); break; + case MSX_CONSTANT: i = MSXproj_findObject(CONSTANT, id); break; + case MSX_PARAMETER: i = MSXproj_findObject(PARAMETER, id); break; + case MSX_PATTERN: i = MSXproj_findObject(PATTERN, id); break; + default: return ERR_INVALID_OBJECT_TYPE; + } + if ( i < 1 ) return ERR_UNDEFINED_OBJECT_ID; + *index = i; + return 0; +} +//============================================================================= + +int MSXDLLEXPORT MSXgetIDlen(int type, int index, int *len) +/* +** Purpose: +** retrieves the number of characters in the ID name of an MSX object. +** +** Input: +** type = object type code +** index = index (base 1) of the object in list of all objects of the +** given type. +** +** Output: +** len = number of characters in the object's ID name. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int i; + *len = 0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + switch(type) + { + case MSX_SPECIES: i = SPECIES; break; + case MSX_CONSTANT: i = CONSTANT; break; + case MSX_PARAMETER: i = PARAMETER; break; + case MSX_PATTERN: i = PATTERN; break; + default: return ERR_INVALID_OBJECT_TYPE; + } + if ( index < 1 || index > MSX.Nobjects[i] ) return ERR_INVALID_OBJECT_INDEX; + switch(i) + { + case SPECIES: *len = (int) strlen(MSX.Species[index].id); break; + case CONSTANT: *len = (int) strlen(MSX.Const[index].id); break; + case PARAMETER: *len = (int) strlen(MSX.Param[index].id); break; + case PATTERN: *len = (int) strlen(MSX.Pattern[index].id); break; + } + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetID(int type, int index, char *id, int len) +/* +** Purpose: +** retrieves the name of an object given its index. +** +** Input: +** type = object type code +** index = index (base 1) of the object in list of all objects of the +** given type +** len = maximum number of characters that id can hold. +** +** Output: +** id = name of the object. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int i; + strcpy(id, ""); + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + switch(type) + { + case MSX_SPECIES: i = SPECIES; break; + case MSX_CONSTANT: i = CONSTANT; break; + case MSX_PARAMETER: i = PARAMETER; break; + case MSX_PATTERN: i = PATTERN; break; + default: return ERR_INVALID_OBJECT_TYPE; + } + if ( index < 1 || index > MSX.Nobjects[i] ) return ERR_INVALID_OBJECT_INDEX; + switch(i) + { + case SPECIES: strncpy(id, MSX.Species[index].id, len); break; + case CONSTANT: strncpy(id, MSX.Const[index].id, len); break; + case PARAMETER: strncpy(id, MSX.Param[index].id, len); break; + case PATTERN: strncpy(id, MSX.Pattern[index].id, len); break; + } + id[len] = '\0'; //(L. Rossman - 11/01/10) + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetcount(int type, int *count) +/* +** Purpose: +** retrieves the number of objects of a specific type. +** +** Input: +** type = object type code +** +** Output: +** count = number of objects of the given type. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + *count = 0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + switch(type) + { + case MSX_SPECIES: *count = MSX.Nobjects[SPECIES]; break; + case MSX_CONSTANT: *count = MSX.Nobjects[CONSTANT]; break; + case MSX_PARAMETER: *count = MSX.Nobjects[PARAMETER]; break; + case MSX_PATTERN: *count = MSX.Nobjects[PATTERN]; break; + default: return ERR_INVALID_OBJECT_TYPE; + } + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetspecies(int index, int *type, char *units, + double *aTol, double * rTol) +/* +** Purpose: +** retrieves the attributes of a chemical species. +** +** Input: +** index = index (base 1) of the species in the list of all species. +** +** Output: +** type = MSX_BULK (0) for a bulk flow species or MSX_WALL (1) for a +** surface species; +** units = character string containing the mass units defined for the species - +** must be sized in the calling program to accept up to 15 bytes +** plus a null termination character +** aTol = absolute concentration tolerance (concentration units); +** rTol = relative concentration tolerance (unitless) +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + *type = 0; + strcpy(units, ""); + *aTol = 0.0; + *rTol = 0.0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( index < 1 || index > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; + *type = MSX.Species[index].type; + strncpy(units, MSX.Species[index].units, MAXUNITS); + *aTol = MSX.Species[index].aTol; + *rTol = MSX.Species[index].rTol; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetconstant(int index, double *value) +/* +** Purpose: +** retrieves the value of a particular reaction constant. +** +** Input: +** index = index (base 1) of the constant in the list of all constants. +** +** Output: +** value = value assigned to the constant. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + *value = 0.0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( index < 1 || index > MSX.Nobjects[CONSTANT] ) return ERR_INVALID_OBJECT_INDEX; + *value = MSX.Const[index].value; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetparameter(int type, int index, int param, double *value) +/* +** Purpose: +** retrieves the value of a particular reaction parameter for a given pipe +** or tank within the pipe network. +** +** Input: +** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; +** index = index (base 1) assigned to the node or link; +** param = index (base 1) assigned to the reaction parameter. +** +** Output: +** value = value assigned to the parameter. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int j; + *value = 0.0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( param < 1 || param > MSX.Nobjects[PARAMETER] ) return ERR_INVALID_OBJECT_INDEX; + if ( type == MSX_NODE ) + { + if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; + j = MSX.Node[index].tank; + if ( j > 0 ) *value = MSX.Tank[j].param[param]; + } + else if ( type == MSX_LINK ) + { + if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; + *value = MSX.Link[index].param[param]; + } + else return ERR_INVALID_OBJECT_TYPE; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetsource(int node, int species, int *type, double *level, + int *pat) +/* +** Purpose: +** retrieves information on any external source of a particular chemical +** species assigned to a specific node of the pipe network. +** +** Input: +** node = index number (base 1) assigned to the node of interest; +** species = index number (base 1) of the species of interest; +** +** Output: +** type = one of the following of external source type codes: +** MSX_NOSOURCE = -1 for no source, +** MSX_CONCEN = 0 for a concentration source, +** MSX_MASS = 1 for a mass booster source, +** MSX_SETPOINT = 2 for a setpoint source, +** MSX_FLOWPACED = 3 for a flow paced source; +** level = the baseline concentration (or mass flow rate) of the species +** in the source; +** pat = the index of the time pattern assigned to the species at the source +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + Psource source; + *type = MSX_NOSOURCE; + *level = 0.0; + *pat = 0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( node < 1 || node > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; + if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; + source = MSX.Node[node].sources; + while ( source ) + { + if ( source->species == species ) + { + *type = source->type; + *level = source->c0; + *pat = source->pat; + break; + } + source = source->next; + } + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetpatternlen(int pat, int *len) +/* +** Purpose: +** retrieves the number of time periods within a source time pattern. +** +** Input: +** pat = the index number (base 1) of the time pattern; +** +** Output: +** len = the number of time periods that appear in the pattern. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + *len = 0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( pat < 1 || pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; + *len = MSX.Pattern[pat].length; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetpatternvalue(int pat, int period, double *value) +/* +** Purpose: +** retrieves the multiplier at a specific time period for a given +** source time pattern. +** +** Input: +** pat = the index number (base 1) of the time pattern; +** period = the index of the time period (starting from 1) whose +** multiplier is being sought; +** +** Output: +** value = the value of the pattern's multiplier in the desired period. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int n = 1; + *value = 0.0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( pat < 1 || pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; + if ( period <= MSX.Pattern[pat].length ) + { + MSX.Pattern[pat].current = MSX.Pattern[pat].first; + while ( MSX.Pattern[pat].current ) + { + if ( n == period ) + { + *value = MSX.Pattern[pat].current->value; + return 0; + } + MSX.Pattern[pat].current = MSX.Pattern[pat].current->next; + n++; + } + } + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetinitqual(int type, int index, int species, double *value) +/* +** Purpose: +** retrieves the initial concentration of a particular chemical species +** assigned to a specific node or link of the pipe network. +** +** Input: +** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; +** index = index (base 1) of the node or link of interest; +** species = index (base 1) of the species of interest. +** +** Output: +** value = initial concentration of the species at the node or link. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + *value = 0.0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; + if ( type == MSX_NODE ) + { + if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; + *value = MSX.Node[index].c0[species]; + } + else if ( type == MSX_LINK ) + { + if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; + *value = MSX.Link[index].c0[species]; + } + else return ERR_INVALID_OBJECT_TYPE; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgetqual(int type, int index, int species, double *value) +/* +** Purpose: +** retrieves the current concentration of a species at a particular node +** or link of the pipe network. +** +** Input: +** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; +** index = index (base 1) of the node or link of interest;. +** species = index (base 1) of the species of interest. +** +** Output: +** value = species concentration at the node or link. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + *value = 0.0; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; + if ( type == MSX_NODE ) + { + if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; + *value = MSXqual_getNodeQual(index, species); + } + else if ( type == MSX_LINK ) + { + if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; + *value = MSXqual_getLinkQual(index, species); + } + else return ERR_INVALID_OBJECT_TYPE; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXgeterror(int code, char *msg, int len) +/* +** Purpose: +** retrieves text of an error message. +** +** Input: +** code = error code number +** len = maximum length of string errmsg. +** +** Output: +** msg = text of error message. +** +** Returns: +** an error code which is always 0. +*/ +{ + strncpy(msg, MSXproj_getErrmsg(code), len); + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXsetconstant(int index, double value) +/* +** Purpose: +** assigns a new value to a specific reaction constant. +** +** Input: +** index = index (base 1) of the constant in the list of all constants; +** value = the new value to be assigned to the constant. +** +** Output: +** none. +** +** Returns: +** an error code or 0 for no error. +*/ +{ + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( index < 1 || index > MSX.Nobjects[CONSTANT] ) return ERR_INVALID_OBJECT_INDEX; + MSX.Const[index].value = value; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXsetparameter(int type, int index, int param, double value) +/* +** Purpose: +** assigns a value to a particular reaction parameter for a given pipe +** or tank within the pipe network. +** +** Input: +** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; +** index = index (base 1) assigned to the node or link; +** param = index (base 1) assigned to the reaction parameter; +** value = value to be assigned to the parameter. +** +** Output: +** none. +** +** Returns: +** an error code or 0 for no error. +*/ +{ + int j; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( param < 1 || param > MSX.Nobjects[PARAMETER] ) return ERR_INVALID_OBJECT_INDEX; + if ( type == MSX_NODE ) + { + if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; + j = MSX.Node[index].tank; + if ( j > 0 ) MSX.Tank[j].param[param] = value; + } + else if ( type == MSX_LINK ) + { + if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; + MSX.Link[index].param[param] = value; + } + else return ERR_INVALID_OBJECT_TYPE; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXsetinitqual(int type, int index, int species, double value) +/* +** Purpose: +** assigns an initial concentration of a particular chemical species +** to a specific node or link of the pipe network. +** +** Input: +** type = MSX_NODE (0) for a node or MSX_LINK (1) for a link; +** index = index (base 1) of the node or link of interest; +** species = index (base 1) of the species of interest. +** value = initial concentration of the species at the node or link. +** +** Output: +** none. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; + if ( type == MSX_NODE ) + { + if ( index < 1 || index > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; + if ( MSX.Species[species].type == BULK ) + MSX.Node[index].c0[species] = value; + } + else if ( type == MSX_LINK ) + { + if ( index < 1 || index > MSX.Nobjects[LINK] ) return ERR_INVALID_OBJECT_INDEX; + MSX.Link[index].c0[species] = value; + } + else return ERR_INVALID_OBJECT_TYPE; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXsetsource(int node, int species, int type, double level, + int pat) +/* +** Purpose: +** sets the attributes of an external source of a particular chemical +** species to a specific node of the pipe network. +** +** Input: +** node = index number (base 1) assigned to the node of interest; +** species = index number (base 1) of the species of interest; +** type = one of the following of external source type codes: +** MSX_NOSOURCE = -1 for no source, +** MSX_CONCEN = 0 for a concentration source, +** MSX_MASS = 1 for a mass booster source, +** MSX_SETPOINT = 2 for a setpoint source, +** MSX_FLOWPACED = 3 for a flow paced source; +** level = the baseline concentration (or mass flow rate) of the species +** in the source; +** pat = the index of the time pattern assigned to the species at the source +** +** Output: +** none. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + Psource source; + +// --- check for valid source parameters + + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( node < 1 || node > MSX.Nobjects[NODE] ) return ERR_INVALID_OBJECT_INDEX; + if ( species < 1 || species > MSX.Nobjects[SPECIES] ) return ERR_INVALID_OBJECT_INDEX; + if ( pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; + if ( pat < 0 ) pat = 0; + if ( type < MSX_NOSOURCE || + type > MSX_FLOWPACED ) return ERR_INVALID_OBJECT_PARAMS; + if ( MSX.Species[species].type != BULK ) return ERR_INVALID_OBJECT_PARAMS; + if ( level < 0.0 ) return ERR_INVALID_OBJECT_PARAMS; + +// --- check if a source for this species already exists at the node + + source = MSX.Node[node].sources; + while ( source ) + { + if ( source->species == species ) break; + source = source->next; + } + +// --- if no current source exists then create a new one + + if ( source == NULL ) + { + source = (struct Ssource *) malloc(sizeof(struct Ssource)); + if ( source == NULL ) return ERR_MEMORY; + source->next = MSX.Node[node].sources; + MSX.Node[node].sources = source; + } + +// --- assign parameters to the source + + source->type = (char)type; + source->species = species; + source->c0 = level; + source->pat = pat; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXsetpatternvalue(int pat, int period, double value) +/* +** Purpose: +** assigns a new value to the multiplier for a specific time period in +** a given time pattern. +** +** Input: +** pat = the index number (base 1) of the time pattern; +** period = the time period (starting from 1) whose multiplier is +** being replaced; +** value = the new value of the pattern's multiplier in the desired period. +** +** Output: +** none. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int n = 1; + +// --- check that pattern & period exists + + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( pat < 1 || pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; + if ( period <= 0 || period > MSX.Pattern[pat].length ) + return ERR_INVALID_OBJECT_PARAMS; + +// --- find desired time period in the pattern + + MSX.Pattern[pat].current = MSX.Pattern[pat].first; + while ( MSX.Pattern[pat].current ) + { + if ( n == period ) + { + MSX.Pattern[pat].current->value = value; + return 0; + } + MSX.Pattern[pat].current = MSX.Pattern[pat].current->next; + n++; + } + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXaddpattern(char *id) +/* +** Purpose: +** adds a new MSX time pattern to the project. +** +** Input: +** id = C-style character string with the ID name of the new pattern. +** +** Output: +** none. +** +** Returns: +** an error code (or 0 for no error). +** +** Notes: +** the new pattern is appended to the end of the existing patterns. +*/ +{ + int i, n; + Spattern *tmpPat; + +// --- check if a pattern with same id already exists + + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( MSXproj_findObject(PATTERN, id) >= 1 ) return ERR_INVALID_OBJECT_PARAMS; + +// --- allocate memory for a new array of patterns + + n = MSX.Nobjects[PATTERN] + 1; + tmpPat = (Spattern *) calloc((size_t)n+1, sizeof(Spattern)); + if ( tmpPat == NULL ) return ERR_MEMORY; + +// --- copy contents of old pattern array to new one + + for (i=1; i<=MSX.Nobjects[PATTERN]; i++) + { + tmpPat[i].id = MSX.Pattern[i].id; + tmpPat[i].length = MSX.Pattern[i].length; + tmpPat[i].first = MSX.Pattern[i].first; + tmpPat[i].current = MSX.Pattern[i].current; + } + +// --- add info for the new pattern + + if ( MSXproj_addObject(PATTERN, id, n) < 0 ) + { + free(tmpPat); + return ERR_MEMORY; + } + tmpPat[n].id = MSXproj_findID(PATTERN, id); + tmpPat[n].length = 0; + tmpPat[n].first = NULL; + tmpPat[n].current = NULL; + +// --- replace old pattern array with new one + + FREE(MSX.Pattern); + MSX.Pattern = tmpPat; + MSX.Nobjects[PATTERN]++; + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXsetpattern(int pat, double mult[], int len) +/* +** Purpose: +** Assigns a new set of multipliers to a given time pattern. +** +** Input: +** pat = the index number (base 1) of the time pattern; +** mult[] = an array of multiplier values (base 0) to replace those +** previously used by the pattern; +** len = the number of entries in the multiplier array mult. +** +** Output: +** none. +** +** Returns: +** an error code (or 0 for no error). +*/ +{ + int i; + SnumList *listItem; + +// --- check that pattern exists + + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ( pat < 1 || pat > MSX.Nobjects[PATTERN] ) return ERR_INVALID_OBJECT_INDEX; + if ( len < 0) len = 0; + +// --- delete current multipliers + + listItem = MSX.Pattern[pat].first; + while (listItem) + { + MSX.Pattern[pat].first = listItem->next; + free(listItem); + listItem = MSX.Pattern[pat].first; + } + MSX.Pattern[pat].first = NULL; + +// --- create a new set of multipliers + + MSX.Pattern[pat].length = 0; + for ( i = 0; i < len; i++ ) + { + listItem = (SnumList *) malloc(sizeof(SnumList)); + if ( listItem == NULL ) return ERR_MEMORY; + listItem->value = mult[i]; + listItem->next = NULL; + if ( MSX.Pattern[pat].first == NULL ) + { + MSX.Pattern[pat].current = listItem; + MSX.Pattern[pat].first = listItem; + } + else + { + MSX.Pattern[pat].current->next = listItem; + MSX.Pattern[pat].current = listItem; + } + MSX.Pattern[pat].length++; + } + + MSX.Pattern[pat].interval = 0; //Feng Shang 04/17/2008 + MSX.Pattern[pat].current = MSX.Pattern[pat].first; //Feng Shang 04/17/2008 + return 0; +} + +//============================================================================= + +int MSXDLLEXPORT MSXsavemsxfile(char *fname) +{ + int errcode; + FILE *f; + if ( !MSX.ProjectOpened ) return ERR_MSX_NOT_OPENED; + if ((f = fopen(fname,"wt")) == NULL) return ERR_OPEN_OUT_FILE; + errcode = MSXfile_save(f); + fclose(f); + return errcode; +} diff --git a/src/solver/msxtypes.h b/src/solver/msxtypes.h new file mode 100644 index 0000000..67f1803 --- /dev/null +++ b/src/solver/msxtypes.h @@ -0,0 +1,547 @@ +/************************************************************************ +** MODULE: TYPES.H +** PROJECT: EPANET-MSX +** DESCRIPTION: Global constants and data types used by the EPANET +** Multi-Species Extension toolkit. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 08/30/2022 +***********************************************************************/ + +#include "mathexpr.h" +#include "mempool.h" +#include + +//----------------------------------------------------------------------------- +// Definition of 4-byte integers & reals +//----------------------------------------------------------------------------- +typedef int INT4; +typedef float REAL4; + +//----------------------------------------------------------------------------- +// Macros for memory allocation +//----------------------------------------------------------------------------- +#define MEMCHECK(x) (((x) == NULL) ? ERR_MEMORY : 0 ) +#define FREE(x) { if (x) { free(x); x = NULL; } } + +//----------------------------------------------------------------------------- +// Conversion macros to be used in place of functions +//----------------------------------------------------------------------------- +#define INT(x) ((int)(x)) // integer portion of x +#define FRAC(x) ((x)-(int)(x)) // fractional part of x +#define ABS(x) (((x)<0) ? -(x) : (x)) // absolute value of x +#define MIN(x,y) (((x)<=(y)) ? (x) : (y)) // minimum of x and y +#define MAX(x,y) (((x)>=(y)) ? (x) : (y)) // maximum of x and y +#define ROUND(x) (((x)>=0) ? (int)((x)+.5) : (int)((x)-.5)) + // round-off of x +#define MOD(x,y) ((x)%(y)) // x modulus y +#define SQR(x) ((x)*(x)) // x-squared +#define SGN(x) (((x)<0) ? (-1) : (1)) // sign of x +#define UCHAR(x) (((x) >= 'a' && (x) <= 'z') ? ((x)&~32) : (x)) + // uppercase char of x +//----------------------------------------------------------------------------- +// Macro to evaluate function f with error checking +// (Fatal errors are numbered higher than 100) +//----------------------------------------------------------------------------- +#define CALL(err, f) (err = ( (err>100) ? (err) : (f) )) + + +//----------------------------------------------------------------------------- +// Defined Constants +//----------------------------------------------------------------------------- +#define MAGICNUMBER 516114521 +#define VERSION 200000 +#define MAXMSG 1024 // Max. # characters in message text +#define MAXLINE 1024 // Max. # characters in input line +#define TRUE 1 +#define FALSE 0 +#define BIG 1.E10 +#define TINY 1.E-6 +#define MISSING -1.E10 +#define PI 3.141592654 +#define VISCOS 1.1E-5 // Kinematic viscosity of water + // @ 20 deg C (sq ft/sec) + +//----------------------------------------------------------------------------- +// Various conversion factors +//----------------------------------------------------------------------------- +#define M2perFT2 0.09290304 +#define CM2perFT2 929.0304 +#define DAYperSEC 1.1574E-5 +#define HOURperSEC 2.7778E-4 +#define MINUTEperSEC 0.016667 +#define GPMperCFS 448.831 +#define AFDperCFS 1.9837 +#define MGDperCFS 0.64632 +#define IMGDperCFS 0.5382 +#define LPSperCFS 28.317 +#define LPMperCFS 1699.0 +#define CMHperCFS 101.94 +#define CMDperCFS 2446.6 +#define MLDperCFS 2.4466 +#define M3perFT3 0.028317 +#define LperFT3 28.317 +#define MperFT 0.3048 +#define PSIperFT 0.4333 +#define KPAperPSI 6.895 +#define KWperHP 0.7457 +#define SECperDAY 86400 + + +//----------------------------------------------------------------------------- +// Enumerated Types +//----------------------------------------------------------------------------- + enum ObjectTypes // Object types + {NODE, + LINK, + TANK, + SPECIES, + TERM, + PARAMETER, + CONSTANT, + PATTERN, + MAX_OBJECTS}; + + enum SourceType // Type of source quality input + {CONCEN, // inflow concentration + MASS, // mass inflow booster + SETPOINT, // setpoint booster + FLOWPACED}; // flow paced booster + + enum UnitSystemType // Unit system: + {US, // US + SI}; // SI (metric) + + enum FlowUnitsType // Flow units: + {CFS, // cubic feet per second + GPM, // gallons per minute + MGD, // million gallons per day + IMGD, // imperial million gal. per day + AFD, // acre-feet per day + LPS, // liters per second + LPM, // liters per minute + MLD, // megaliters per day + CMH, // cubic meters per hour + CMD}; // cubic meters per day + + enum MixType // Tank mixing regimes + {MIX1, // 1-compartment model + MIX2, // 2-compartment model + FIFO, // First in, first out model + LIFO}; // Last in, first out model + + enum SpeciesType // Types of water quality species + {BULK, // bulk flow species + WALL}; // pipe wall attached species + + enum ExpressionType // Types of math expressions + {NO_EXPR, // no expression + RATE, // reaction rate + FORMULA, // simple formula + EQUIL}; // equilibrium expression + + enum SolverType // ODE solver options + {EUL, // Euler + RK5, // 5th order Runge-Kutta + ROS2}; // 2nd order Rosenbrock + + enum CouplingType // Degree of coupling for solving DAE's + {NO_COUPLING, // no coupling between alg. & diff. eqns. + FULL_COUPLING}; // full coupling between alg. &diff. eqns. + + enum MassUnitsType // Concentration mass units + {MG, // milligram + UG, // microgram + MOLE, // mole + MMOLE}; // millimole + + enum AreaUnitsType // Pipe surface area units + {FT2, // square feet + M2, // square meters + CM2}; // square centimeters + + enum RateUnitsType // Reaction rate time units + {SECONDS, // seconds + MINUTES, // minutes + HOURS, // hours + DAYS}; // days + + enum UnitsType // Measurement unit types + {LENGTH_UNITS, // length + DIAM_UNITS, // pipe diameter + AREA_UNITS, // surface area + VOL_UNITS, // volume + FLOW_UNITS, // flow + CONC_UNITS, // concentration volume + RATE_UNITS, // reaction rate time units + MAX_UNIT_TYPES}; + + enum HydVarType // Hydraulic variables + {DIAMETER = 1, // link diameter + FLOW, // link flow rate + VELOCITY, // link flow velocity + REYNOLDS, // Reynolds number + SHEAR, // link shear velocity + FRICTION, // friction factor + AREAVOL, // area/volume + ROUGHNESS, // roughness /*Feng Shang 01/29/2008*/ + LENGTH, // pipe length /*Feng Shang 01/27/2023 + MAX_HYD_VARS}; + + enum TstatType // Time series statistics + {SERIES, // full time series + AVGERAGE, // time-averages + MINIMUM, // minimum values + MAXIMUM, // maximum values + RANGE}; // max - min values + + enum OptionType // Analysis options + {AREA_UNITS_OPTION, + RATE_UNITS_OPTION, + SOLVER_OPTION, + COUPLING_OPTION, + TIMESTEP_OPTION, + RTOL_OPTION, + ATOL_OPTION, + COMPILER_OPTION, + MAXSEGMENT_OPTION, + PECLETNUMER_OPTION}; + + enum CompilerType // C compiler type + {NO_COMPILER, + VC, // MS Visual C compiler + GC}; // Gnu C compiler + + enum FileModeType // File modes + {SCRATCH_FILE, + SAVED_FILE, + USED_FILE}; + + enum SectionType // Input data file sections + {s_TITLE, + s_SPECIES, + s_COEFF, + s_TERM, + s_PIPE, + s_TANK, + s_SOURCE, + s_QUALITY, + s_PARAMETER, + s_PATTERN, + s_OPTION, + s_REPORT, + s_Diffu, + }; + + enum ErrorCodeType // Error codes (501-525) + {ERR_FIRST = 500, + ERR_MEMORY, // 501 + ERR_NO_EPANET_FILE, // 502 + ERR_OPEN_MSX_FILE, // 503 + ERR_OPEN_HYD_FILE, // 504 + ERR_READ_HYD_FILE, // 505 + ERR_MSX_INPUT, // 506 + ERR_NUM_PIPE_EXPR, // 507 + ERR_NUM_TANK_EXPR, // 508 + ERR_INTEGRATOR_OPEN, // 509 + ERR_NEWTON_OPEN, // 510 + ERR_OPEN_OUT_FILE, // 511 + ERR_IO_OUT_FILE, // 512 + ERR_INTEGRATOR, // 513 + ERR_NEWTON, // 514 + ERR_INVALID_OBJECT_TYPE, // 515 + ERR_INVALID_OBJECT_INDEX, // 516 + ERR_UNDEFINED_OBJECT_ID, // 517 + ERR_INVALID_OBJECT_PARAMS, // 518 + ERR_MSX_NOT_OPENED, // 519 + ERR_MSX_OPENED, // 520 + ERR_OPEN_RPT_FILE, // 521 + ERR_COMPILE_FAILED, // 522 + ERR_COMPILED_LOAD, // 523 + ERR_ILLEGAL_MATH, // 524 + ERR_MAX}; + + +//----------------------------------------------------------------------------- +// Data Structures +//----------------------------------------------------------------------------- +struct NumList // List of numerical values +{ + double value; + struct NumList *next; +}; +typedef struct NumList SnumList; + + +typedef struct // TIME PATTERN OBJECT +{ + char *id; // pattern ID + long length; // number of pattern factors + long interval; // current time interval + SnumList *first; // first mutiplier + SnumList *current; // current multiplier +} Spattern; + + +struct Ssource // WATER QUALITY SOURCE OBJECT +{ + char type; // sourceType + int species; // species index + double c0; // base concentration + int pat; // time pattern index + double massRate; // actual mass flow rate + struct Ssource *next; // next bulk species source +}; +typedef struct Ssource *Psource; + + +typedef struct // NODE OBJECT +{ + Psource sources; // ptr. to WQ source list + double *c; // current species concentrations + double *c0; // initial species concentrations + int tank; // tank index + char rpt; // reporting flag +} Snode; + + +typedef struct // LINK OBJECT +{ + int nsegs; // number of active segments + int n1; // start node index + int n2; // end node index + double diam; // diameter + double len; // length + char rpt; // reporting flag + double *c0; // initial species concentrations + double *reacted; + double *param; // kinetic parameter values + double roughness; // roughness + double areasquare; + double HydVar[MAX_HYD_VARS]; // hydraulic variables +} Slink; + + +typedef struct // TANK OBJECT +{ + int node; // node index of tank + double hstep; // integration time step + double a; // tank area + double v0; // initial volume + double v; // tank volume + int mixModel; // type of mixing model + double vMix; // mixing compartment size + double *param; // kinetic parameter values + double *c; // current species concentrations + double *reacted; +} Stank; + + +struct Sseg // PIPE SEGMENT OBJECT +{ + double hstep; // integration time step + double v; // segment volume + double *c; // species concentrations + double * lastc; // species concentrations of previous step + struct Sseg *prev; // ptr. to previous segment + struct Sseg *next; // ptr. to next segment + double hresponse, // for dispersion response of initial, + uresponse, // upstream and downstream condition + dresponse; +}; +typedef struct Sseg *Pseg; + + +#define MAXUNITS 16 +typedef struct // CHEMICAL SPECIES OBJECT +{ + char *id; // name + char units[MAXUNITS]; // mass units code + double aTol; // absolute tolerance + double rTol; // relative tolerance + int type; // BULK or WALL + int pipeExprType; // type of pipe chemistry + int tankExprType; // type of tank chemistry + int precision; // reporting precision + char rpt; // reporting flag + MathExpr *pipeExpr; // pipe chemistry expression + MathExpr *tankExpr; // tank chemistry expression +} Sspecies; + + +typedef struct // INTERMEDIATE TERM OBJECT +{ + char *id; // name + MathExpr *expr; // math expression for term +} Sterm; + + +typedef struct // REACTION RATE PARAMETER OBJECT +{ + char *id; // name + double value; // value +} Sparam; + + +typedef struct // MATH EXPRESSION CONSTANT OBJECT +{ + char *id; // name + double value; // value +} Sconst; + + +#define MAXFNAME 259 // Max. # characters in file name +typedef struct // FILE OBJECT +{ + char name[MAXFNAME]; // file name + char mode; // see FileModeType enumeration below + FILE* file; // FILE structure pointer +} TFile; + + + +struct Sadjlist // Node Adjacency List Item +{ + int node; // index of connecting node + int link; // index of connecting link + struct Sadjlist* next; // next item in list +}; + +typedef struct Sadjlist* Padjlist; // Pointer to adjacency list + +typedef enum { + NEGATIVE = -1, // flow in reverse of pre-assigned direction + ZERO_FLOW = 0, // zero flow + POSITIVE = 1 // flow in pre-assigned direction +} FlowDirection; + +typedef struct // Mass Balance Components +{ + double * initial; // initial mass in system + double * inflow; // mass inflow to system + double * indisperse; // mass dispersed into the system + double * outflow; // mass outflow from system + double * reacted; // mass reacted in system + double * final; // final mass in system + double * ratio; // ratio of mass added to mass lost +} SmassBalance; + + +typedef struct +{ + + double viscosity; + double DIFFUS; // Diffusivity of chlorine 1.3E-8 @ 20 deg C (sq ft/sec) + double PecletLimit; // The Pectlet number below which the dispersion in a pipe is considered + + int* Order; // Node-to-row of re-ordered matrix + int* Row; // Row-to-node of re-ordered matrix + int* Ndx; // Index of link's coeff. in Aij + int* XLNZ; // Start position of each column in NZSUB + int* NZSUB; // Row index of each coeff.in each column + int* LNZ; // Position of each coeff. in Aij array + int* Degree; // Number of links adjacent to each node + int Ncoeffs; // Number of non-zero matrix coeffs + + int* link; // Array used by linear eqn. solver + int* first; // Array used by linear eqn. solver + double* temp; // Array used by linear eqn. solver + double* Aii; // Diagonal matrix coeffs. + double* Aij; // Non-zero, off-diagonal matrix coeffs. + double* F; // Right hand side vector + + Padjlist* Adjlist; // Node adjacency lists + + + double* md; // molecular diffusion + double* ld; // fixed longitudinal dispersion coefficient + double* pipeDispersionCoeff; //effective longitudinal dispersion coefficient +} Sdispersion; + + +typedef struct // MSX PROJECT VARIABLES +{ + TFile HydFile, // EPANET hydraulics file + MsxFile, // MSX input file + OutFile, // MSX binary output file + TmpOutFile, // Scratch MSX binary output file + RptFile; // MSX report file + + char Title[MAXLINE+1], // Project title + Msg[MAXLINE+1]; // Message string + + int Nobjects[MAX_OBJECTS], // Numbers of each type of object + Unitsflag, // Unit system flag + Flowflag, // Flow units flag + Saveflag, // Save results flag + Rptflag, // Report results flag + Coupling, // Degree of coupling for solving DAE's + Compiler, // chemistry function compiler code + AreaUnits, // Surface area units + RateUnits, // Reaction rate time units + Solver, // Choice of ODE solver + PageSize, // Lines per page in report + Nperiods, // Number of reporting periods + ErrCode, // Error code + ProjectOpened, // Project opened flag + QualityOpened; // Water quality system opened flag + int MaxSegments; // Maximum number of segments in a link + long HydOffset, // Hydraulics file byte offset + Pstep, // Time pattern time step (sec) + Pstart, // Starting pattern time (sec) + Rstep, // Reporting time step (sec) + Rstart, // Time when reporting starts + Statflag; // Reporting statistic flag + + int64_t Qstep, // Quality time step (millisec) + Qtime, // Current quality time (millisec) + Htime, // Current hydraulic time (millisec) + Rtime, // Next reporting time (millisec) + Dur; // Duration of simulation (millisec) + + REAL4 *D, // Node demands + *H, // Node heads + *Q, // Link flows + *S; // Link status + + double Ucf[MAX_UNIT_TYPES], // Unit conversion factors + DefRtol, // Default relative error tolerance + DefAtol, // Default absolute error tolerance + *K, // Vector of expression constants + *C0, // Species initial quality vector + *C1; // Species concentration vector + + Pseg *FirstSeg, // First WQ segment in each pipe/tank + *LastSeg; // Last WQ segment in each pipe/tank + + Sspecies *Species; // WQ species data + Sparam *Param; // Expression parameters + Sconst *Const; // Expression constants + Sterm *Term; // Intermediate terms + Snode *Node; // Node data + Slink *Link; // Link data + Stank *Tank; // Tank data + Spattern *Pattern; // Pattern data + + char HasWallSpecies; // wall species indicator + char OutOfMemory; // out of memory indicator + Padjlist* Adjlist; // Node adjacency lists + Pseg* NewSeg; // new segment added to each pipe + Pseg FreeSeg; // pointer to unused segment + FlowDirection *FlowDir; // flow direction for each pipe + SmassBalance MassBalance; + alloc_handle_t* QualPool; // memory pool + + int DispersionFlag; // 1 if dispersion modeling + + double* MassIn; // mass inflow of each species to each node + double* SourceIn; // external mass inflow of each species from WQ source; + int* SortedNodes; + + Sdispersion Dispersion; + +} MSXproject; + + diff --git a/src/solver/msxutils.c b/src/solver/msxutils.c new file mode 100644 index 0000000..76bd208 --- /dev/null +++ b/src/solver/msxutils.c @@ -0,0 +1,525 @@ +/******************************************************************************* +** MODULE: MSXUTILS.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Utility functions used by the EPANET Multi-Species Extension +** toolkit. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 2/8/11 +*******************************************************************************/ + +#include +#include +#include +#include +#include +#include + +#include "msxutils.h" +// --- define WINDOWS + +#undef WINDOWS +#ifdef _WIN32 + #define WINDOWS +#endif +#ifdef __WIN32__ + #define WINDOWS +#endif + +#define UCHAR(x) (((x) >= 'a' && (x) <= 'z') ? ((x)&~32) : (x)) +#define TINY1 1.0e-20 + +//============================================================================= + +char * MSXutils_getTempName(char *s) +/* +** Purpose: +** gets the name of a temporary file with path name and periods stripped +** +** Input: +** s = character string (must be of size L_tmpnam) +** +** Returns: +** a pointer to the file name. +*/ +{ +#ifdef WINDOWS + char *ptr; + char fname[L_tmpnam]; + unsigned int i; + + // --- use tmpnam() function to create a temporary file name + tmpnam(fname); + + // --- replace any '.' characters (they cause problems for some compilers) + for (i=0; i 0) return(0); + return(1); +} + +//============================================================================= + +int MSXutils_getDouble(char *s, double *y) +/* +** Purpose: +** converts a string to a double precision floating point number. +** +** Input: +** s = a character string. +** +** Output: +** y = converted value of s. +** +** Returns: +** 1 if conversion successful, 0 if not. +*/ +{ + char *endptr; + *y = strtod(s, &endptr); + if (*endptr > 0) return(0); + return(1); +} + +//============================================================================= + +double ** createMatrix(int nrows, int ncols) +/* +** Purpose: +** allocates memory for a 2-dimensional array of doubles. +** +** Input: +** nrows = number of rows (0-based) +** ncols = number of columns (0-based). +** +** Returns: +** a pointer to the matrix (a = matrix(nr, nc)). +*/ +{ + int i,j; + double **a; + +// --- allocate pointers to rows + + a = (double **) malloc(nrows * sizeof(double *)); + if ( !a ) return NULL; + +// --- allocate rows and set pointers to them + + a[0] = (double *) malloc (nrows * ncols * sizeof(double)); + if ( !a[0] ) return NULL; + for ( i = 1; i < nrows; i++ ) a[i] = a[i-1] + ncols; + + for ( i = 0; i < nrows; i++) + { + for ( j = 0; j < ncols; j++) a[i][j] = 0.0; + } + +// --- return pointer to array of pointers to rows + + return a; +} + +//============================================================================= + +void freeMatrix(double **a) +/* +** Purpose: +** frees the memory allocated for a matrix of doubles. +** +** Input: +** a = pointer to a matrix of doubles. +*/ +{ + if ( a != NULL ) + { + if ( a[0] != NULL ) free( a[0] ); + free( a ); + } +} + +//============================================================================= + +int factorize(double **a, int n, double *w, int *indx) +/* +** Purpose: +** performs an LU decomposition of a matrix. +** +** Input: +** a[1..n][1..n] = a square matrix of doubles +** n = matrix size (1-based) +** w[1..n] = work array of doubles. +** +** Output: +** a[][] = matrix that contains elements of L and U matrices +** indx[1..n] = vector that records the row permutation +** effected by the partial pivoting. +** +** Returns: +** 1 if successful, 0 if matrix is singular. +** +** Note: +** The arrays and matrices used in this function are 1-based, so +** they must have been sized to n+1 when first created. +*/ +{ + int i, imax, j, k; + double big, dum, sum, temp; + + for (i = 1; i <= n; i++) + { + /*Loop over rows to get the implicit scaling information.*/ + big = 0.0; + for (j = 1;j <= n;j++) + if ((temp = fabs(a[i][j])) > big) big = temp; + if (big == 0.0) + return 0; /* Warning for singular matrix*/ + /*No nonzero largest element.*/ + w[i] = 1.0/big; /*Save the scaling.*/ + } + for (j = 1;j <= n;j++) /**for each column*/ + { + /*This is the loop over columns of Crout’s method.*/ + for (i = 1; i < j; i++) + { + /*Up from the diagonal*/ + sum = a[i][j]; + for (k = 1;k < i;k++) sum -= a[i][k]*a[k][j]; + a[i][j] = sum; + } + big = 0.0; /*Initialize for the search for largest pivot element.*/ + imax = j; + for (i = j; i <= n; i++) + { + sum = a[i][j]; + for (k = 1; k < j; k++) sum -= a[i][k]*a[k][j]; + a[i][j] = sum; + if ( (dum = w[i]*fabs(sum)) >= big) + { + big = dum; + imax = i; + } + } + if (j != imax) + { + /*Do we need to interchange rows?*/ + for (k = 1; k <= n; k++) + { + /*Yes,do so...*/ + dum = a[imax][k]; + a[imax][k] = a[j][k]; + a[j][k] = dum; + } + w[imax] = w[j]; /* interchange the scale factor.*/ + } + indx[j] = imax; + if (a[j][j] == 0.0) a[j][j] = TINY1; + if (j != n) /* divide by the pivot element.*/ + { + dum = 1.0/(a[j][j]); + for (i = j+1;i <= n;i++) a[i][j] *= dum; + } + } + return 1; +} + +//============================================================================= + +void solve(double **a, int n, int *indx, double b[]) +/* +** Purpose: +** solves linear equations AX = B after LU decomposition of A. +** +** Input: +** a[1..n][1..n] = LU decomposed square matrix A returned by factorize +** n = matrix size +** indx[1..n] = permutation vector returned by factorize +** b[1..n] = right-hand side vector B. +** +** Output: +** b[1..n] = solution vector X. +** +** Note: +** The arrays and matrices used in this function are 1-based, so +** they must have been sized to n+1 when first created. +*/ +{ + int i, ii=0, ip, j; + double sum; + + /*forward substitution */ + for (i=1; i<=n; i++) + { + ip=indx[i]; + sum=b[ip]; + b[ip]=b[i]; + if (ii) + for (j=ii; j<=i-1; j++) + sum -= a[i][j]*b[j]; + else if (sum) ii=i; + b[i]=sum; + } + + /* back substitution */ + for (i=n; i>=1; i--) + { + sum=b[i]; + for (j=i+1; j<=n; j++) + sum -= a[i][j]*b[j]; + b[i]=sum/a[i][i]; + } +} + +//============================================================================= + +void jacobian(double *x, int n, double *f, double *w, double **a, + void (*func)(double, double*, int, double*)) +/* +** Purpose: +** computes Jacobian matrix of F(t,X) at given X +** +** Input: +** x[1..n] = vector of function variables +** n = number of variables +** f[1..n] = a work vector +** w[1..n] = a work vector +** func = user supplied routine that computes the function +** values at x. +** +** Output: +** f[1..n] = function values at x +** a[1..n][1..n] = coeffs. of the Jacobian matrix. +** +** Notes: +** 1. Arguments for func() are: +** t = independent variable (not used) +** x[1..n] = vector of dependent variables +** n = number of functions +** f[1..n] = function values at x. +** +** 2. The arrays and matrices used in this function are 1-based, so +** they must have been sized to n+1 when first created. +*/ +{ + + int i, j; + double temp, eps = 1.0e-7, eps2; + + for (j=1; j<=n; j++) + { + temp = x[j]; + x[j] = temp + eps; + func(0.0, x, n, f); + if ( temp == 0.0 ) + { + x[j] = temp; + eps2 = eps; + } + else + { + x[j] = temp - eps; + eps2 = 2.0*eps; + } + func(0.0, x, n, w); + for (i=1; i<=n; i++) a[i][j] = (f[i] - w[i]) / eps2; + x[j] = temp; + } + + +/* --- An alternative method that uses forward differencing + int i,j; + double temp, h; + double eps = sqrt(DBL_EPSILON); + + func(0.0, x, n, f); + for (j=1; j<=n; j++) + { + temp = x[j]; + h = eps*fabs(temp); + if (h == 0.0) h = eps; + x[j] = temp + h; + func(0.0, x, n, w); + for (i=1; i<=n; i++) a[i][j] = (w[i] - f[i]) / h; + x[j] = temp; + } +*/ + +} diff --git a/src/solver/msxutils.h b/src/solver/msxutils.h new file mode 100644 index 0000000..e1b984b --- /dev/null +++ b/src/solver/msxutils.h @@ -0,0 +1,51 @@ +/******************************************************************************* +** MODULE: MSXUTILS.H +** PROJECT: EPANET-MSX +** DESCRIPTION: Header file for the utility functions used by the EPANET +** Multi-Species Extension toolkit. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 2/8/11 +*******************************************************************************/ + +// Gets the name of a temporary file +char * MSXutils_getTempName(char *s); + +// Case insentive comparison of two strings +int MSXutils_strcomp(char *s1, char *s2); + +// Matches a string against an array of keywords +int MSXutils_findmatch(char *s, char *keyword[]); + +// Case insensitive search of a string for a substring +int MSXutils_match(char *str, char *substr); + +// Converts a 24-hr clocktime to number of seconds +int MSXutils_strToSeconds(char *s, long *t); + +// Converts a string to an integer +int MSXutils_getInt(char *s, int *y); + +// Converts a string to a float +int MSXutils_getFloat(char *s, float *y); + +// Converts a string to a double +int MSXutils_getDouble(char *s, double *y); + +// Creates a two dimensional array +double ** createMatrix(int nrows, int ncols); + +// Deletes a two dimensional array +void freeMatrix(double **a); + +// Applies L-D factorization to a square matrix +int factorize(double **a, int n, double *w, int *indx); + +// Solves a factorized, linear system of equations +void solve(double **a, int n, int *indx, double b[]); + +// Computes the Jacobian matrix of a set of functions +void jacobian(double *x, int n, double *f, double *w, double **a, + void (*func)(double, double*, int, double*)); diff --git a/src/solver/newton.c b/src/solver/newton.c new file mode 100644 index 0000000..43eea49 --- /dev/null +++ b/src/solver/newton.c @@ -0,0 +1,158 @@ +/****************************************************************************** +** MODULE: NEWTON.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Newton-Raphson algorithm used to solve a set of nonlinear +** algebraic equations. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +******************************************************************************/ + +#include +#include +#include +#include +#include "msxutils.h" +#include "newton.h" + +// Local declarations +//------------------- +MSXNewton MSXNewtonSolver; + +#pragma omp threadprivate(MSXNewtonSolver) + +//============================================================================= + +int newton_open(int n) +/* +** Purpose: +** opens the algebraic solver to handle a system of n equations. +** +** Input: +** n = number of equations +** +** Returns: +** 1 if successful, 0 if not. +** +** Note: +** All arrays are 1-based so an extra memory location +** must be allocated for the unused 0-th position. +*/ +{ + int errorcode = 1; + +#pragma omp parallel +{ + MSXNewtonSolver.Nmax = 0; + MSXNewtonSolver.Indx = NULL; + MSXNewtonSolver.F = NULL; + MSXNewtonSolver.W = NULL; + MSXNewtonSolver.Indx = (int*)calloc(n + 1, sizeof(int)); + MSXNewtonSolver.F = (double*)calloc(n + 1, sizeof(double)); + MSXNewtonSolver.W = (double*)calloc(n + 1, sizeof(double)); + MSXNewtonSolver.J = createMatrix(n + 1, n + 1); +#pragma omp critical + { + if (!MSXNewtonSolver.Indx || !MSXNewtonSolver.F || !MSXNewtonSolver.W || !MSXNewtonSolver.J) + errorcode = 0; + } + MSXNewtonSolver.Nmax = n; +} + + return errorcode; +} + +//============================================================================= + +void newton_close() +/* +** Purpose: +** closes the algebraic solver. +** +** Input: +** none +*/ +{ + +#pragma omp parallel +{ + if (MSXNewtonSolver.Indx) { free(MSXNewtonSolver.Indx); MSXNewtonSolver.Indx = NULL; } + if (MSXNewtonSolver.F) { free(MSXNewtonSolver.F); MSXNewtonSolver.F = NULL; } + if (MSXNewtonSolver.W) { free(MSXNewtonSolver.W); MSXNewtonSolver.W = NULL; } + freeMatrix(MSXNewtonSolver.J); + MSXNewtonSolver.J = NULL; +} + +} + +//============================================================================= + +int newton_solve(double x[], int n, int maxit, int numsig, + void (*func)(double, double*, int, double*)) +/* +** Purpose: +** uses newton-raphson iterations to solve n nonlinear eqns. +** +** Input: +** x[] = solution vector +** n = number of equations +** maxit = max. number of iterations allowed +** numsig = number of significant digits in error +** func = pointer to the function that returns the function values at x. +** +** Returns: +** number of iterations if successful, -1 if Jacobian is singular, +** -2 if it didn't converge, or -3 if n exceeds allowable size. +** +** Note: +** the arguments to the function func are: +** t = a time value (not used here) +** x = vector of unknowns being solved for +** n = number of unknowns +** f = vector of function values evaluated at x. +*/ +{ + int i, k; + double errx, errmax, cscal, relconvg = pow(10.0, -numsig); + + // --- check that system was sized adequetely + + if ( n > MSXNewtonSolver.Nmax ) return -3; + + // --- use up to maxit iterations to find a solution + + for (k=1; k<=maxit; k++) + { + // --- evaluate the Jacobian matrix + + jacobian(x, n, MSXNewtonSolver.F, MSXNewtonSolver.W, MSXNewtonSolver.J, func); + + // --- factorize the Jacobian + + if ( !factorize(MSXNewtonSolver.J, n, MSXNewtonSolver.W, MSXNewtonSolver.Indx) ) return -1; + + // --- solve for the updates to x (returned in F) + + for (i=1; i<=n; i++) MSXNewtonSolver.F[i] = -MSXNewtonSolver.F[i]; + solve(MSXNewtonSolver.J, n, MSXNewtonSolver.Indx, MSXNewtonSolver.F); + + // --- update solution x & check for convergence + + errmax = 0.0; + for (i=1; i<=n; i++) + { + cscal = x[i]; + if (cscal < relconvg) cscal = relconvg; + x[i] += MSXNewtonSolver.F[i]; + errx = fabs(MSXNewtonSolver.F[i]/cscal); + if (errx > errmax) errmax = errx; + } + if (errmax <= relconvg) return k; + } + + // --- return error code if no convergence + + return -2; +} diff --git a/src/solver/newton.h b/src/solver/newton.h new file mode 100644 index 0000000..8902f60 --- /dev/null +++ b/src/solver/newton.h @@ -0,0 +1,29 @@ +/****************************************************************************** +** MODULE: NEWTON.H +** PROJECT: EPANET-MSX +** DESCRIPTION: header file for the equation solver contained in newton.c. +** AUTHORS: see AUTHORS +** Copyright: see AUTHORS +** License: see LICENSE +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +******************************************************************************/ + +typedef struct +{ + int Nmax; // max. number of equations + int* Indx; // permutation vector of row indexes + double* F; // function & adjustment vector + double* W; // work vector + double** J; // Jacobian matrix +}MSXNewton; + +// Opens the equation solver system +int newton_open(int n); + +// Closes the equation solver system +void newton_close(void); + +// Applies the solver to a specific system of equations +int newton_solve(double x[], int n, int maxit, int numsig, + void (*func)(double, double*, int, double*)); diff --git a/src/solver/rk5.c b/src/solver/rk5.c new file mode 100644 index 0000000..dc81574 --- /dev/null +++ b/src/solver/rk5.c @@ -0,0 +1,287 @@ +/************************************************************************ +** MODULE: RK5.C +** PROJECT: EPANET-MSX +** DESCRIPTION: Numerical solution of a system of first order +** ordinary differential equations dY/dt = F(t,Y). +** AUTHOR: L. Rossman, US EPA - NRMRL +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +** +** This is an explicit Runge-Kutta method of order (4)5 +** due to Dormand & Prince (with optional stepsize control). +** The code was adapted from the DOPRI5 code of E. Hairer +** and G. Wanner as described in: +** E. HAIRER, S.P. NORSETT AND G. WANNER, SOLVING ORDINARY +** DIFFERENTIAL EQUATIONS I. NONSTIFF PROBLEMS. 2ND EDITION. +** SPRINGER SERIES IN COMPUTATIONAL MATHEMATICS, +** SPRINGER-VERLAG (1993) +***********************************************************************/ + +#include +#include +#include "rk5.h" + +#define fmin(x,y) (((x)<=(y)) ? (x) : (y)) /* minimum of x and y */ +#define fmax(x,y) (((x)>=(y)) ? (x) : (y)) /* maximum of x and y */ + +// Local variables +//----------------- +MSXRungeKutta MSXRungeKuttaSolver; + +#pragma omp threadprivate(MSXRungeKuttaSolver) +//============================================================================= + +int rk5_open(int n, int itmax, int adjust) +/* +** Purpose: +** Opens the RK5 solver to solve system of n equations +** +** Input: +** n = number of equtions +** itmax = maximum iterations allowed +** adjust = 1 if time step adjustment used, 0 if not +** +** Returns: +** 1 if successful and 0 if not. +*/ +{ + int n1 = n+1; + int errorcode = 1; + MSXRungeKuttaSolver.Report = NULL; + +#pragma omp parallel +{ + MSXRungeKuttaSolver.Nmax = 0; + MSXRungeKuttaSolver.Itmax = itmax; + MSXRungeKuttaSolver.Adjust = adjust; + MSXRungeKuttaSolver.Ynew = (double*)calloc(n1, sizeof(double)); + MSXRungeKuttaSolver.Ak = (double*)calloc(6 * n1, sizeof(double)); +#pragma omp critical + { + if (!MSXRungeKuttaSolver.Ynew || !MSXRungeKuttaSolver.Ak) errorcode = 0; + } + + MSXRungeKuttaSolver.Nmax = n; + MSXRungeKuttaSolver.K1 = (MSXRungeKuttaSolver.Ak); + MSXRungeKuttaSolver.K2 = ((MSXRungeKuttaSolver.Ak)+(n1)); + MSXRungeKuttaSolver.K3 = ((MSXRungeKuttaSolver.Ak)+(2 * n1)); + MSXRungeKuttaSolver.K4 = ((MSXRungeKuttaSolver.Ak)+(3 * n1)); + MSXRungeKuttaSolver.K5 = ((MSXRungeKuttaSolver.Ak)+(4 * n1)); + MSXRungeKuttaSolver.K6 = ((MSXRungeKuttaSolver.Ak)+(5 * n1)); +} + + return errorcode; +} + +//============================================================================= + +void rk5_close() +/* +** Purpose: +** Closes the RK5 solver. +*/ +{ + +#pragma omp parallel +{ + if (MSXRungeKuttaSolver.Ynew) free(MSXRungeKuttaSolver.Ynew); + MSXRungeKuttaSolver.Ynew = NULL; + if (MSXRungeKuttaSolver.Ak) free(MSXRungeKuttaSolver.Ak); + MSXRungeKuttaSolver.Ak = NULL; + MSXRungeKuttaSolver.Nmax = 0; + MSXRungeKuttaSolver.Report = NULL; +} + +} + +//============================================================================= + +int rk5_integrate(double y[], int n, double t, double tnext, + double* htry, double atol[], double rtol[], + void (*func)(double, double*, int, double*)) +/* +** Purpose: +** Integrates system of equations dY/dt = F(t,Y) over a +** given interval. +** +** Input: +** y[] = values of dependent variables at start of interval +** n = number of dependent variables +** t = value of independent variable at start of interval +** tnext = value of independent variable at end of interval +** htry = initial step size +** atol[] = absolute error tolerance on each dependent variable +** rtol[] = relative error tolerance on each dependent variable +** func = pointer to function that evaluates dY/dt at given +** values of t and Y. +** +** Output: +** y[] = values of dependent variables at end of interval +** htry = last step size used +** +** Returns: +** number of function evaluations if successful, -1 if not +** successful within Itmax iterations or -2 if step size +** shrinks to 0. +*/ +{ + double c2=0.20, c3=0.30, c4=0.80, c5=8.0/9.0; + double a21=0.20, a31=3.0/40.0, a32=9.0/40.0, + a41=44.0/45.0, a42=-56.0/15.0, a43=32.0/9.0, + a51=19372.0/6561.0, a52=-25360.0/2187.0, a53=64448.0/6561.0, + a54=-212.0/729.0, a61=9017.0/3168.0, a62=-355.0/33.0, + a63=46732.0/5247.0, a64=49.0/176.0, a65=-5103.0/18656.0, + a71=35.0/384.0, a73=500.0/1113.0, a74=125.0/192.0, + a75=-2187.0/6784.0, a76=11.0/84.0; + double e1=71.0/57600.0, e3=-71.0/16695.0, e4=71.0/1920.0, + e5=-17253.0/339200.0, e6=22.0/525.0, e7=-1.0/40.0; + + double tnew, h, hmax, hnew, ytol, err, sk, fac, fac11 = 1.0; + int i; + +// --- parameters for step size control + + double UROUND = 2.3e-16; + double SAFE = 0.90; + double fac1 = 0.2; + double fac2 = 10.0; + double beta = 0.04; + double facold = 1.e-4; + double expo1 = 0.2 - beta*0.75; + double facc1 = 1.0/fac1; + double facc2 = 1.0/fac2; + +// --- various counters + + int nstep = 1; + int nfcn = 0; + int naccpt = 0; + int nrejct = 0; + int reject = 0; + int adjust = MSXRungeKuttaSolver.Adjust; + +// --- initial function evaluation + + func(t, y, n, MSXRungeKuttaSolver.K1); + nfcn++; + +// --- initial step size + h = *htry; + hmax = tnext - t; + if (h == 0.0) + { + adjust = 1; + h = tnext - t; + for (i=1; i<=n; i++) + { + ytol = atol[i] + rtol[i]*fabs(y[i]); + if (MSXRungeKuttaSolver.K1[i] != 0.0) + h = fmin(h, (ytol/fabs(MSXRungeKuttaSolver.K1[i]))); + } + } + h = fmax(1.e-8, h); + +// --- while not at end of time interval + + while (t < tnext) + { + // --- check for zero step size + if (0.10*fabs(h) <= fabs(t)*UROUND) return -2; + + // --- adjust step size if interval exceeded + if ((t + 1.01*h - tnext) > 0.0) h = tnext - t; + + tnew = t + c2*h; + for (i=1; i<=n; i++) + MSXRungeKuttaSolver.Ynew[i] = y[i] + h*a21* MSXRungeKuttaSolver.K1[i]; + func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K2); + + tnew = t + c3*h; + for (i=1; i<=n; i++) + MSXRungeKuttaSolver.Ynew[i] = y[i] + h*(a31* MSXRungeKuttaSolver.K1[i] + a32* MSXRungeKuttaSolver.K2[i]); + func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K3); + + tnew = t + c4*h; + for (i=1; i<=n; i++) + MSXRungeKuttaSolver.Ynew[i]=y[i] + h*(a41* MSXRungeKuttaSolver.K1[i] + a42* MSXRungeKuttaSolver.K2[i] + a43* MSXRungeKuttaSolver.K3[i]); + func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K4); + + tnew = t + c5*h; + for (i=1; i<=n; i++) + MSXRungeKuttaSolver.Ynew[i] = y[i] + h*(a51* MSXRungeKuttaSolver.K1[i] + a52* MSXRungeKuttaSolver.K2[i] + a53* MSXRungeKuttaSolver.K3[i]+a54* MSXRungeKuttaSolver.K4[i]); + func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K5); + + tnew = t + h; + for (i=1; i<=n; i++) + MSXRungeKuttaSolver.Ynew[i] = y[i] + h*(a61* MSXRungeKuttaSolver.K1[i] + a62* MSXRungeKuttaSolver.K2[i] + + a63* MSXRungeKuttaSolver.K3[i] + a64* MSXRungeKuttaSolver.K4[i] + a65* MSXRungeKuttaSolver.K5[i]); + func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K6); + + for (i=1; i<=n; i++) + MSXRungeKuttaSolver.Ynew[i] = y[i] + h*(a71* MSXRungeKuttaSolver.K1[i] + a73* MSXRungeKuttaSolver.K3[i] + + a74* MSXRungeKuttaSolver.K4[i] + a75* MSXRungeKuttaSolver.K5[i] + a76* MSXRungeKuttaSolver.K6[i]); + func(tnew, MSXRungeKuttaSolver.Ynew, n, MSXRungeKuttaSolver.K2); + nfcn += 6; + + // --- step size adjustment + + err = 0.0; + hnew = h; + if (adjust) + { + for (i=1; i<=n; i++) + MSXRungeKuttaSolver.K4[i] = (e1* MSXRungeKuttaSolver.K1[i] + e3* MSXRungeKuttaSolver.K3[i] + e4* MSXRungeKuttaSolver.K4[i] + e5* MSXRungeKuttaSolver.K5[i] + + e6* MSXRungeKuttaSolver.K6[i] + e7* MSXRungeKuttaSolver.K2[i])*h; + + for (i=1; i<=n; i++) + { + sk = atol[i] + rtol[i]*fmax(fabs(y[i]), fabs(MSXRungeKuttaSolver.Ynew[i])); + sk = MSXRungeKuttaSolver.K4[i]/sk; + err = err + (sk*sk); + } + err = sqrt(err/n); + + // --- computation of hnew + fac11 = pow(err, expo1); + fac = fac11/pow(facold, beta); // LUND-stabilization + fac = fmax(facc2, fmin(facc1, (fac/SAFE))); // must have FAC1 <= HNEW/H <= FAC2 + hnew = h/fac; + } + + // --- step is accepted + + if( err <= 1.0 ) + { + facold = fmax(err, 1.0e-4); + naccpt++; + for (i=1; i<=n; i++) + { + MSXRungeKuttaSolver.K1[i] = MSXRungeKuttaSolver.K2[i]; + y[i] = MSXRungeKuttaSolver.Ynew[i]; + } + t = t + h; + if ( adjust && t <= tnext ) *htry = h; + if (fabs(hnew) > hmax) hnew = hmax; + if (reject) hnew = fmin(fabs(hnew), fabs(h)); + reject = 0; + if (MSXRungeKuttaSolver.Report) MSXRungeKuttaSolver.Report(t, y, n); + } + + // --- step is rejected + + else + { + if ( adjust ) hnew = h/fmin(facc1, (fac11/SAFE)); + reject = 1; + if (naccpt >= 1) nrejct++; + } + + // --- take another step + + h = hnew; + if ( adjust ) *htry = h; + nstep++; + if (nstep >= MSXRungeKuttaSolver.Itmax) return -1; + } + return nfcn; +} diff --git a/src/solver/rk5.h b/src/solver/rk5.h new file mode 100644 index 0000000..f20f9f8 --- /dev/null +++ b/src/solver/rk5.h @@ -0,0 +1,34 @@ +/************************************************************************ +** MODULE: RK5.H +** PROJECT: EPANET-MSX +** DESCRIPTION: Header file for the ODE solver contained in RK5.C. +** AUTHOR: L. Rossman, US EPA - NRMRL +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +***********************************************************************/ + +typedef struct +{ + int Nmax; // max. number of equations + int Itmax; // max. number of integration steps + int Adjust; // use adjustable step size + double* Ak; // work arrays + double* K1; + double* K2; + double* K3; + double* K4; + double* K5; + double* K6; + double* Ynew; // updated solution + void (*Report) (double, double*, int); +}MSXRungeKutta; +// Opens the ODE solver system +int rk5_open(int n, int itmax, int adjust); + +// Closes the ODE solver system +void rk5_close(void); + +// Applies the solver to integrate a specific system of ODEs +int rk5_integrate(double y[], int n, double t, double tnext, + double* htry, double atol[], double rtol[], + void (*func)(double, double*, int, double*)); diff --git a/src/solver/ros2.c b/src/solver/ros2.c new file mode 100644 index 0000000..9647032 --- /dev/null +++ b/src/solver/ros2.c @@ -0,0 +1,293 @@ +/******************************************************************************* +** MODULE: ROS2.C +** PROJECT: EPANET-MSX +** DESCRIPTION: a second order Rosenbrock 2(1) method for solving stiff sets of +** ordinary differential equations. +** AUTHOR: L. Rossman, US EPA - NRMRL +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +** +** This code is based on material presented in: +** Verwer, J.G., Spee, E.J., Blom, J.G. and Hundsdorfer, W.H., +** "A second order Rosenbrock method applied to photochemical dispersion +** problems", SIAM J. Sci. Comput., 20:1456-1480, July 1999. +*******************************************************************************/ + +#include +#include +#include "msxutils.h" +#include "ros2.h" + +#define fmin(x,y) (((x)<=(y)) ? (x) : (y)) /* minimum of x and y */ +#define fmax(x,y) (((x)>=(y)) ? (x) : (y)) /* maximum of x and y */ + +// Local variables +//----------------- +MSXRosenbrock MSXRosenbrockSolver; + +#pragma omp threadprivate(MSXRosenbrockSolver) + +//============================================================================= + +int ros2_open(int n, int adjust) +/* +** Purpose: +** Opens the ROS2 integrator. +** +** Input: +** n = number of equations to be solved +** adjust = 1 if step size adjustment used, 0 if not +** +** Returns: +** 1 if successful, 0 if not. +*/ +{ + int errorcode = 1; + int n1 = n + 1; + +#pragma omp parallel +{ + MSXRosenbrockSolver.Nmax = n; + MSXRosenbrockSolver.Adjust = adjust; + MSXRosenbrockSolver.K1 = NULL; + MSXRosenbrockSolver.K2 = NULL; + MSXRosenbrockSolver.Jindx = NULL; + MSXRosenbrockSolver.Ynew = NULL; + MSXRosenbrockSolver.A = NULL; + MSXRosenbrockSolver.K1 = (double*)calloc(n1, sizeof(double)); + MSXRosenbrockSolver.K2 = (double*)calloc(n1, sizeof(double)); + MSXRosenbrockSolver.Jindx = (int*)calloc(n1, sizeof(int)); + MSXRosenbrockSolver.Ynew = (double*)calloc(n1, sizeof(double)); + MSXRosenbrockSolver.A = createMatrix(n1, n1); +#pragma omp critical + { + if (!MSXRosenbrockSolver.Jindx || !MSXRosenbrockSolver.Ynew || + !MSXRosenbrockSolver.K1 || !MSXRosenbrockSolver.K2) errorcode = 0; + if (!MSXRosenbrockSolver.A) errorcode = 0; + } +} + + return errorcode; +} + +//============================================================================= + +void ros2_close() +/* +** Purpose: +** closes the ROS2 integrator. +** +** Input: +** none. +*/ +{ + +#pragma omp parallel +{ + + if (MSXRosenbrockSolver.Jindx) { free(MSXRosenbrockSolver.Jindx); MSXRosenbrockSolver.Jindx = NULL; } + if (MSXRosenbrockSolver.Ynew) { free(MSXRosenbrockSolver.Ynew); MSXRosenbrockSolver.Ynew = NULL; } + if (MSXRosenbrockSolver.K1) { free(MSXRosenbrockSolver.K1); MSXRosenbrockSolver.K1 = NULL; } + if (MSXRosenbrockSolver.K2) { free(MSXRosenbrockSolver.K2); MSXRosenbrockSolver.K2 = NULL; } + freeMatrix(MSXRosenbrockSolver.A); + MSXRosenbrockSolver.A = NULL; +} + +} + +//============================================================================= + +int ros2_integrate(double y[], int n, double t, double tnext, + double* htry, double atol[], double rtol[], + void (*func)(double, double*, int, double*)) +/* +** Purpose: +** integrates a system of ODEs over a specified time interval. +** +** Input: +** y[1..n] = vector of dependent variable values at the start +** of the integration interval +** n = number of dependent variables +** t = time value at the start of the interval +** tnext = time value at the end of the interval +** htry = initial step size to be taken +** atol[1..n] = vector of absolute tolerances on the variables y +** rtol[1..n] = vector of relative tolerances on the variables y +** func = name of the function that computes dy/dt for each y +** +** Output: +** htry = size of the last full time step taken. +** +** Returns: +** the number of times that func() was called, -1 if +** the Jacobian is singular, or -2 if the step size +** shrinks to 0. +** +** Notes: +** 1. The arguments to the function func() are: +** t = current time +** y[1..n] = vector of dependent variable values +** n = number of dependent variables +** dfdy[1..n] = vector of derivative values computed. +** +** 2. The arrays used in this function are 1-based, so +** they must have been sized to n+1 when first created. +*/ +{ + double UROUND = 2.3e-16; + double g, ghinv, ghinv1, dghinv, ytol; + double h, hold, hmin, hmax, tplus; + double ej, err, factor, facmax; + int nfcn, njac, naccept, nreject, j; + int isReject; + int adjust = MSXRosenbrockSolver.Adjust; + +// --- Initialize counters, etc. + + g = 1.0 + 1.0 / sqrt(2.0); + ghinv1 = 0.0; + tplus = t; + isReject = 0; + naccept = 0; + nreject = 0; + nfcn = 0; + njac = 0; + +// --- Initial step size + + hmax = tnext - t; + hmin = 1.e-8; + h = *htry; + if ( h == 0.0 ) + { + func(t, y, n, MSXRosenbrockSolver.K1); + nfcn += 1; + adjust = 1; + h = tnext - t; + for (j=1; j<=n; j++) + { + ytol = atol[j] + rtol[j]*fabs(y[j]); + if (MSXRosenbrockSolver.K1[j] != 0.0) h = fmin(h, (ytol/fabs(MSXRosenbrockSolver.K1[j]))); + } + } + h = fmax(hmin, h); + h = fmin(hmax, h); + +// --- Start the time loop + + while ( t < tnext ) + { + // --- check for zero step size + + if (0.10*fabs(h) <= fabs(t)*UROUND) return -2; + + // --- adjust step size if interval exceeded + + tplus = t + h; + if ( tplus > tnext ) + { + h = tnext - t; + tplus = tnext; + } + + // --- Re-compute the Jacobian if step size accepted + + if ( isReject == 0 ) + { + jacobian(y, n, MSXRosenbrockSolver.K1, MSXRosenbrockSolver.K2, MSXRosenbrockSolver.A, func); + njac++; + nfcn += 2*n; + ghinv1 = 0.0; + } + + // --- Update the Jacobian to reflect new step size + + ghinv = -1.0 / (g*h); + dghinv = ghinv - ghinv1; + for (j=1; j<=n; j++) + { + MSXRosenbrockSolver.A[j][j] += dghinv; + } + ghinv1 = ghinv; + if ( !factorize(MSXRosenbrockSolver.A, n, MSXRosenbrockSolver.K1, MSXRosenbrockSolver.Jindx) ) return -1; + + // --- Stage 1 solution + + func(t, y, n, MSXRosenbrockSolver.K1); + nfcn += 1; + for (j=1; j<=n; j++) MSXRosenbrockSolver.K1[j] *= ghinv; + solve(MSXRosenbrockSolver.A, n, MSXRosenbrockSolver.Jindx, MSXRosenbrockSolver.K1); + + // --- Stage 2 solution + + for (j=1; j<=n; j++) + { + MSXRosenbrockSolver.Ynew[j] = y[j] + h* MSXRosenbrockSolver.K1[j]; + } + func(t, MSXRosenbrockSolver.Ynew, n, MSXRosenbrockSolver.K2); + nfcn += 1; + for (j=1; j<=n; j++) + { + MSXRosenbrockSolver.K2[j] = (MSXRosenbrockSolver.K2[j] - 2.0* MSXRosenbrockSolver.K1[j])*ghinv; + } + solve(MSXRosenbrockSolver.A, n, MSXRosenbrockSolver.Jindx, MSXRosenbrockSolver.K2); + + // --- Overall solution + + for (j=1; j<=n; j++) + { + MSXRosenbrockSolver.Ynew[j] = y[j] + 1.5*h* MSXRosenbrockSolver.K1[j] + 0.5*h* MSXRosenbrockSolver.K2[j]; + } + + // --- Error estimation + + hold = h; + err = 0.0; + if ( adjust ) + { + for (j=1; j<=n; j++) + { + ytol = atol[j] + rtol[j]*fabs(MSXRosenbrockSolver.Ynew[j]); + ej = fabs(MSXRosenbrockSolver.Ynew[j] - y[j] - h* MSXRosenbrockSolver.K1[j])/ytol; + err = err + ej*ej; + } + err = sqrt(err/n); + err = fmax(UROUND, err); + + // --- Choose the step size + + factor = 0.9 / sqrt(err); + if (isReject) facmax = 1.0; + else facmax = 10.0; + factor = fmin(factor, facmax); + factor = fmax(factor, 1.0e-1); + h = factor*h; + h = fmin(hmax, h); + } + + // --- Reject/accept the step + + if ( err > 1.0 ) + { + isReject = 1; + nreject++; + h = 0.5*h; + } + else + { + isReject = 0; + for (j=1; j<=n; j++) + { + y[j] = MSXRosenbrockSolver.Ynew[j]; + if ( y[j] <= UROUND ) y[j] = 0.0; + } + if ( adjust ) *htry = h; + t = tplus; + naccept++; + } + +// --- End of the time loop + + } + return nfcn; +} diff --git a/src/solver/ros2.h b/src/solver/ros2.h new file mode 100644 index 0000000..bc36871 --- /dev/null +++ b/src/solver/ros2.h @@ -0,0 +1,30 @@ +/************************************************************************ +** MODULE: ROS2.H +** PROJECT: EPANET-MSX +** DESCRIPTION: Header file for the stiff ODE solver ROS2.C. +** AUTHOR: L. Rossman, US EPA - NRMRL +** VERSION: 2.0.00 +** LAST UPDATE: 04/14/2021 +***********************************************************************/ + +typedef struct { + + double** A; // Jacobian matrix + double* K1; // Intermediate solutions + double* K2; + double* Ynew; // Updated function values + int* Jindx; // Jacobian column indexes + int Nmax; // Max. number of equations + int Adjust; // use adjustable step size +}MSXRosenbrock; + +// Opens the ODE solver system +int ros2_open(int n, int adjust); + +// Closes the ODE solver system +void ros2_close(void); + +// Applies the solver to integrate a specific system of ODEs +int ros2_integrate(double y[], int n, double t, double tnext, + double* htry, double atol[], double rtol[], + void (*func)(double, double*, int, double*)); diff --git a/src/solver/smatrix.c b/src/solver/smatrix.c new file mode 100644 index 0000000..c0f110c --- /dev/null +++ b/src/solver/smatrix.c @@ -0,0 +1,815 @@ +/* +******************************************************************* +Modified from: + +SMATRIX.C -- Sparse matrix routines for EPANET program, VERSION: 2.0.0. + + +DATE: 5/8/00 +AUTHOR: L. Rossman + US EPA - NRMRL + +This module contains the sparse matrix routines used to solve +a network's hydraulic equations. The entry points into this +module are: + createsparse() -- called from openhyd() in HYDRAUL.C + freesparse() -- called from closehyd() in HYDRAUL.C + linsolve() -- called from netsolve() in HYDRAUL.C + +Createsparse() does the following: + 1. for each node, builds an adjacency list that identifies + all links connected to the node (see buildlists()) + 2. re-orders the network's nodes to minimize the number + of non-zero entries in the hydraulic solution matrix + (see reorder()) + 3. converts the adjacency lists into a compact scheme + for storing the non-zero coeffs. in the lower diagonal + portion of the solution matrix (see storesparse()) +Freesparse() frees the memory used for the sparse matrix. +Linsolve() solves the linearized system of hydraulic equations. + +******************************************************************** +*/ + +#include +#include +#include +#include +#include "hash.h" +#include "msxtypes.h" +#include "smatrix.h" +#include "dispersion.h" +#define EXTERN extern + + + +// External variables +//-------------------- +extern MSXproject MSX; // MSX project data +#define ERRCODE(x) (errcode = ((errcode>100) ? (errcode) : (x))) + + + + +int createsparse() +/* +**-------------------------------------------------------------- +** Input: none +** Output: returns error code +** Purpose: creates sparse representation of coeff. matrix +**-------------------------------------------------------------- +*/ +{ + int errcode = 0; + int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; + + /* Allocate data structures */ + ERRCODE(allocsparse()); + if (errcode) return(errcode); + + /* Build node-link adjacency lists with parallel links removed. */ + + ERRCODE(buildlists(TRUE)); //TRUE localadjlists in 2.2 + if (!errcode) + { + xparalinks(); /* Remove parallel links */ + countdegree(); /* Find degree of each junction */ + } /* (= # of adjacent links) */ + + /* Re-order nodes to minimize number of non-zero coeffs. */ + /* in factorized solution matrix. At same time, adjacency */ + /* list is updated with links representing non-zero coeffs. */ + MSX.Dispersion.Ncoeffs = MSX.Nobjects[LINK]; + ERRCODE(reordernodes()); + + /* Allocate memory for sparse storage of positions of non-zero */ + /* coeffs. and store these positions in vector NZSUB. */ + ERRCODE(storesparse(njuncs)); + + /* Free memory used for adjacency lists and sort */ + /* row indexes in NZSUB to optimize linsolve(). */ + if (!errcode) freelists(); + ERRCODE(ordersparse(njuncs)); + + MSX.Dispersion.Aij = (double*)calloc(MSX.Dispersion.Ncoeffs + 1, sizeof(double)); + MSX.Dispersion.Aii = (double*)calloc(MSX.Nobjects[NODE]+1, sizeof(double)); + MSX.Dispersion.F = (double*)calloc(MSX.Nobjects[NODE]+1, sizeof(double)); + MSX.Dispersion.temp = (double*)calloc(MSX.Nobjects[NODE] + 1, sizeof(double)); + MSX.Dispersion.link = (int*)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); + MSX.Dispersion.first = (int*)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); + ERRCODE(MEMCHECK(MSX.Dispersion.Aij)); + ERRCODE(MEMCHECK(MSX.Dispersion.Aii)); + ERRCODE(MEMCHECK(MSX.Dispersion.F)); + ERRCODE(MEMCHECK(MSX.Dispersion.temp)); + ERRCODE(MEMCHECK(MSX.Dispersion.link)); + ERRCODE(MEMCHECK(MSX.Dispersion.first)); + + // MSX.Dispersion.md = (double*)calloc(MSX.Nobjects[SPECIES] + 1, sizeof(double)); + + MSX.Dispersion.pipeDispersionCoeff = (double*)calloc(MSX.Nobjects[LINK] + 1, sizeof(double)); + + + + ERRCODE(MEMCHECK(MSX.Dispersion.ld)); + ERRCODE(MEMCHECK(MSX.Dispersion.md)); + + + dispersion_open(); + + /* Re-build adjacency lists without removing parallel */ + /* links for use in future connectivity checking. */ + ERRCODE(buildlists(FALSE)); //FALSE buildadjlists in 2.2 + + /* Free allocated memory */ + free(MSX.Dispersion.Degree); + return(errcode); +} /* End of createsparse */ + + +int allocsparse() +/* +**-------------------------------------------------------------- +** Input: none +** Output: returns error code +** Purpose: allocates memory for indexing the solution matrix +**-------------------------------------------------------------- +*/ +{ + int errcode = 0; + int nnodes = MSX.Nobjects[NODE]; + int nlinks = MSX.Nobjects[LINK]; + MSX.Dispersion.Aii = NULL; + MSX.Dispersion.Aij = NULL; + MSX.Dispersion.F = NULL; + MSX.Dispersion.temp = NULL; + MSX.Dispersion.link = NULL; + MSX.Dispersion.first = NULL; + + MSX.Dispersion.Adjlist = (Padjlist *) calloc(nnodes+1, sizeof(Padjlist)); + MSX.Dispersion.Order = (int *) calloc(nnodes+1, sizeof(int)); + MSX.Dispersion.Row = (int *) calloc(nnodes+1, sizeof(int)); + MSX.Dispersion.Ndx = (int *) calloc(nlinks+1, sizeof(int)); + ERRCODE(MEMCHECK(MSX.Dispersion.Adjlist)); + ERRCODE(MEMCHECK(MSX.Dispersion.Order)); + ERRCODE(MEMCHECK(MSX.Dispersion.Row)); + ERRCODE(MEMCHECK(MSX.Dispersion.Ndx)); + return(errcode); +} + + +void freesparse() +/* +**---------------------------------------------------------------- +** Input: None +** Output: None +** Purpose: Frees memory used for sparse matrix storage +**---------------------------------------------------------------- +*/ +{ + freelists(); + FREE(MSX.Dispersion.Adjlist); + FREE(MSX.Dispersion.Order); + FREE(MSX.Dispersion.Row); + FREE(MSX.Dispersion.Ndx); + FREE(MSX.Dispersion.XLNZ); + FREE(MSX.Dispersion.NZSUB); + FREE(MSX.Dispersion.LNZ); + FREE(MSX.Dispersion.Aii); + FREE(MSX.Dispersion.Aij); + FREE(MSX.Dispersion.F); + FREE(MSX.Dispersion.link); + FREE(MSX.Dispersion.first); + FREE(MSX.Dispersion.temp); + + FREE(MSX.Dispersion.md); + + FREE(MSX.Dispersion.pipeDispersionCoeff); + dispersion_close(); + + + + +} /* End of freesparse */ + + +int buildlists(int paraflag) +/* +**-------------------------------------------------------------- +** Input: paraflag = TRUE if list marks parallel links +** Output: returns error code +** Purpose: builds linked list of links adjacent to each node +**-------------------------------------------------------------- +*/ +{ + int i,j,k; + int pmark = 0; + int errcode = 0; + int nlinks = MSX.Nobjects[LINK]; + Padjlist alink; + + freelists(); + MSX.Dispersion.Adjlist = (Padjlist*)calloc(MSX.Nobjects[NODE] + 1, sizeof(Padjlist)); + if (MSX.Dispersion.Adjlist == NULL) return 101; + for (i = 0; i <= MSX.Nobjects[NODE]; i++) + MSX.Dispersion.Adjlist[i] = NULL; + + /* For each link, update adjacency lists of its end nodes */ + for (k=1; k<=nlinks; k++) + { + i = MSX.Link[k].n1; + j = MSX.Link[k].n2; + if (paraflag) pmark = paralink(i,j,k); /* Parallel link check */ + + /* Include link in start node i's list */ + alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist)); + if (alink == NULL) return(101); + if (!pmark) alink->node = j; + else alink->node = 0; /* Parallel link marker */ + alink->link = k; + alink->next = MSX.Dispersion.Adjlist[i]; + MSX.Dispersion.Adjlist[i] = alink; + + /* Include link in end node j's list */ + alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist)); + if (alink == NULL) return(101); + if (!pmark) alink->node = i; + else alink->node = 0; /* Parallel link marker */ + alink->link = k; + alink->next = MSX.Dispersion.Adjlist[j]; + MSX.Dispersion.Adjlist[j] = alink; + } + if (errcode)freelists(); + return(errcode); +} /* End of buildlists */ + + +int paralink(int i, int j, int k) +/* +**-------------------------------------------------------------- +** Input: i = index of start node of link +** j = index of end node of link +** k = link index +** Output: returns 1 if link k parallels another link, else 0 +** Purpose: checks for parallel links between nodes i and j +** +**-------------------------------------------------------------- +*/ +{ + Padjlist alink; + for (alink = MSX.Dispersion.Adjlist[i]; alink != NULL; alink = alink->next) + { + if (alink->node == j) /* Link || to k (same end nodes) */ + { + MSX.Dispersion.Ndx[k] = alink->link; /* Assign Ndx entry to this link */ + return(1); + } + } + MSX.Dispersion.Ndx[k] = k; /* Ndx entry if link not parallel */ + return(0); +} /* End of paralink */ + + +void xparalinks() +/* +**-------------------------------------------------------------- +** Input: none +** Output: none +** Purpose: removes parallel links from nodal adjacency lists +**-------------------------------------------------------------- +*/ +{ + int i; + Padjlist alink, /* Current item in adjacency list */ + blink; /* Previous item in adjacency list */ + int nnodes = MSX.Nobjects[NODE]; + + /* Scan adjacency list of each node */ + for (i=1; i<=nnodes; i++) + { + alink = MSX.Dispersion.Adjlist[i]; /* First item in list */ + blink = NULL; + while (alink != NULL) + { + if (alink->node == 0) /* Parallel link marker found */ + { + if (blink == NULL) /* This holds at start of list */ + { + MSX.Dispersion.Adjlist[i] = alink->next; + free(alink); /* Remove item from list */ + alink = MSX.Dispersion.Adjlist[i]; + } + else /* This holds for interior of list */ + { + blink->next = alink->next; + free(alink); /* Remove item from list */ + alink = blink->next; + } + } + else + { + blink = alink; /* Move to next item in list */ + alink = alink->next; + } + } + } +} /* End of xparalinks */ + + +void freelists() +/* +**-------------------------------------------------------------- +** Input: none +** Output: none +** Purpose: frees memory used for nodal adjacency lists +**-------------------------------------------------------------- +*/ +{ + int i; + Padjlist alink; + int nnodes = MSX.Nobjects[NODE]; + + if (MSX.Dispersion.Adjlist == NULL) + return; + for (i=0; i<=nnodes; i++) + { + for (alink = MSX.Dispersion.Adjlist[i]; alink != NULL; alink = MSX.Dispersion.Adjlist[i]) + { + MSX.Dispersion.Adjlist[i] = alink->next; + free(alink); + } + } + free(MSX.Dispersion.Adjlist); + MSX.Dispersion.Adjlist = NULL; +} /* End of freelists */ + + +void countdegree() +/* +**---------------------------------------------------------------- +** Input: none +** Output: none +** Purpose: counts number of nodes directly connected to each node +**---------------------------------------------------------------- +*/ +{ + int i; + Padjlist alink; + + int nnodes = MSX.Nobjects[NODE]; + int njuncs = MSX.Nobjects[NODE]-MSX.Nobjects[TANK]; + int errcode; + + errcode = 0; + + MSX.Dispersion.Degree = (int *)calloc(MSX.Nobjects[NODE] + 1, sizeof(int)); + ERRCODE(MEMCHECK(MSX.Dispersion.Degree)); + memset(MSX.Dispersion.Degree,0,(nnodes+1)*sizeof(int)); + + /* NOTE: For purposes of node re-ordering, Tanks (nodes with */ + /* indexes above Njuncs) have zero degree of adjacency. */ + + for (i=1; i<=njuncs; i++) + for (alink = MSX.Dispersion.Adjlist[i]; alink != NULL; alink = alink->next) + if (alink->node > 0) MSX.Dispersion.Degree[i]++; +} + + +int reordernodes() +/* +**-------------------------------------------------------------- +** Input: none +** Output: returns 1 if successful, 0 if not +** Purpose: re-orders nodes to minimize # of non-zeros that +** will appear in factorized solution matrix +**-------------------------------------------------------------- +*/ +{ + int k, knode, m, n; + int nnodes = MSX.Nobjects[NODE]; + int njuncs = MSX.Nobjects[NODE] - MSX.Nobjects[TANK]; + for (k=1; k<=nnodes; k++) + { + MSX.Dispersion.Row[k] = k; + MSX.Dispersion.Order[k] = k; + } + n = njuncs; + for (k=1; k<=n; k++) /* Examine each junction */ + { + m = mindegree(k,n); /* Node with lowest degree */ + knode = MSX.Dispersion.Order[m]; /* Node's index */ + if (!growlist(knode)) return(101); /* Augment adjacency list */ + MSX.Dispersion.Order[m] = MSX.Dispersion.Order[k]; /* Switch order of nodes */ + MSX.Dispersion.Order[k] = knode; + MSX.Dispersion.Degree[knode] = 0; /* In-activate node */ + } + for (k=1; k<=n; k++) /* Assign nodes to rows of */ + MSX.Dispersion.Row[MSX.Dispersion.Order[k]] = k; /* coeff. matrix */ + return(0); +} /* End of reordernodes */ + + +int mindegree(int k, int n) +/* +**-------------------------------------------------------------- +** Input: k = first node in list of active nodes +** n = total number of junction nodes +** Output: returns node index with fewest direct connections +** Purpose: finds active node with fewest direct connections +**-------------------------------------------------------------- +*/ +{ + int i, m; + int min = n, + imin = n; + + for (i=k; i<=n; i++) + { + m = MSX.Dispersion.Degree[MSX.Dispersion.Order[i]]; + if (m < min) + { + min = m; + imin = i; + } + } + return(imin); +} /* End of mindegree */ + + +int growlist(int knode) +/* +**-------------------------------------------------------------- +** Input: knode = node index +** Output: returns 1 if successful, 0 if not +** Purpose: creates new entries in knode's adjacency list for +** all unlinked pairs of active nodes that are +** adjacent to knode +**-------------------------------------------------------------- +*/ +{ + int node; + Padjlist alink; + + /* Iterate through all nodes connected to knode */ + for (alink = MSX.Dispersion.Adjlist[knode]; alink != NULL; alink = alink -> next) + { + node = alink->node; /* End node of connecting link */ + if (MSX.Dispersion.Degree[node] > 0) /* End node is active */ + { + MSX.Dispersion.Degree[node]--; /* Reduce degree of adjacency */ + if (!newlink(alink)) /* Add to adjacency list */ + return(0); + } + } + return(1); +} /* End of growlist */ + + +int newlink(Padjlist alink) +/* +**-------------------------------------------------------------- +** Input: alink = element of node's adjacency list +** Output: returns 1 if successful, 0 if not +** Purpose: links end of current adjacent link to end nodes of +** all links that follow it on adjacency list +**-------------------------------------------------------------- +*/ +{ + int inode, jnode; + Padjlist blink; + + /* Scan all entries in adjacency list that follow anode. */ + inode = alink->node; /* End node of connection to anode */ + for (blink = alink->next; blink != NULL; blink = blink->next) + { + jnode = blink->node; /* End node of next connection */ + + /* If jnode still active, and inode not connected to jnode, */ + /* then add a new connection between inode and jnode. */ + if (MSX.Dispersion.Degree[jnode] > 0) /* jnode still active */ + { + if (!linked(inode,jnode)) /* inode not linked to jnode */ + { + + /* Since new connection represents a non-zero coeff. */ + /* in the solution matrix, update the coeff. count. */ + MSX.Dispersion.Ncoeffs++; + + /* Update adjacency lists for inode & jnode to */ + /* reflect the new connection. */ + if (!addlink(inode,jnode,MSX.Dispersion.Ncoeffs)) return(0); + if (!addlink(jnode,inode,MSX.Dispersion.Ncoeffs)) return(0); + MSX.Dispersion.Degree[inode]++; + MSX.Dispersion.Degree[jnode]++; + } + } + } + return(1); +} /* End of newlink */ + + +int linked(int i, int j) +/* +**-------------------------------------------------------------- +** Input: i = node index +** j = node index +** Output: returns 1 if nodes i and j are linked, 0 if not +** Purpose: checks if nodes i and j are already linked. +**-------------------------------------------------------------- +*/ +{ + Padjlist alink; + for (alink = MSX.Dispersion.Adjlist[i]; alink != NULL; alink = alink->next) + if (alink->node == j) return(1); + return(0); +} /* End of linked */ + + +int addlink(int i, int j, int n) +/* +**-------------------------------------------------------------- +** Input: i = node index +** j = node index +** n = link index +** Output: returns 1 if successful, 0 if not +** Purpose: augments node i's adjacency list with node j +**-------------------------------------------------------------- +*/ +{ + Padjlist alink; + alink = (struct Sadjlist *) malloc(sizeof(struct Sadjlist)); + if (alink == NULL) return(0); + alink->node = j; + alink->link = n; + alink->next = MSX.Dispersion.Adjlist[i]; + MSX.Dispersion.Adjlist[i] = alink; + return(1); +} /* End of addlink */ + + +int storesparse(int n) +/* +**-------------------------------------------------------------- +** Input: n = number of rows in solution matrix +** Output: returns error code +** Purpose: stores row indexes of non-zeros of each column of +** lower triangular portion of factorized matrix +**-------------------------------------------------------------- +*/ +{ + Padjlist alink; + int i, ii, j, k, l, m; + int errcode = 0; + + /* Allocate sparse matrix storage */ + MSX.Dispersion.XLNZ = (int *) calloc(n+2, sizeof(int)); + MSX.Dispersion.NZSUB = (int *) calloc(MSX.Dispersion.Ncoeffs+2, sizeof(int)); + MSX.Dispersion.LNZ = (int *) calloc(MSX.Dispersion.Ncoeffs+2, sizeof(int)); + ERRCODE(MEMCHECK(MSX.Dispersion.XLNZ)); + ERRCODE(MEMCHECK(MSX.Dispersion.NZSUB)); + ERRCODE(MEMCHECK(MSX.Dispersion.LNZ)); + if (errcode) return(errcode); + + /* Generate row index pointers for each column of matrix */ + k = 0; + MSX.Dispersion.XLNZ[1] = 1; + for (i=1; i<=n; i++) /* column */ + { + m = 0; + ii = MSX.Dispersion.Order[i]; + for (alink = MSX.Dispersion.Adjlist[ii]; alink != NULL; alink = alink->next) + { + j = MSX.Dispersion.Row[alink->node]; /* row */ + l = alink->link; + if (j > i && j <= n) + { + m++; + k++; + MSX.Dispersion.NZSUB[k] = j; + MSX.Dispersion.LNZ[k] = l; + } + } + MSX.Dispersion.XLNZ[i+1] = MSX.Dispersion.XLNZ[i] + m; + } + return(errcode); +} /* End of storesparse */ + + +int ordersparse(int n) +/* +**-------------------------------------------------------------- +** Input: n = number of rows in solution matrix +** Output: returns eror code +** Purpose: puts row indexes in ascending order in NZSUB +**-------------------------------------------------------------- +*/ +{ + int i, k; + int *xlnzt, *nzsubt, *lnzt, *nzt; + int errcode = 0; + + xlnzt = (int *) calloc(n+2, sizeof(int)); + nzsubt = (int *) calloc(MSX.Dispersion.Ncoeffs+2, sizeof(int)); + lnzt = (int *) calloc(MSX.Dispersion.Ncoeffs+2, sizeof(int)); + nzt = (int *) calloc(n+2, sizeof(int)); + ERRCODE(MEMCHECK(xlnzt)); + ERRCODE(MEMCHECK(nzsubt)); + ERRCODE(MEMCHECK(lnzt)); + ERRCODE(MEMCHECK(nzt)); + if (!errcode) + { + + /* Count # non-zeros in each row */ + for (i=1; i<=n; i++) nzt[i] = 0; + for (i=1; i<=n; i++) + { + for (k=MSX.Dispersion.XLNZ[i]; k= istrt) + { + + /* Before modification, update vectors 'first' */ + /* and 'link' for future modification steps. */ + MSX.Dispersion.first[k] = istrt; + isub = MSX.Dispersion.NZSUB[istrt]; + MSX.Dispersion.link[k] = MSX.Dispersion.link[isub]; + MSX.Dispersion.link[isub] = k; + + /* The actual mod is saved in vector 'temp'. */ + for (i=istrt; i<=istop; i++) + { + isub = MSX.Dispersion.NZSUB[i]; + MSX.Dispersion.temp[isub] += Aij[MSX.Dispersion.LNZ[i]]*ljk; + } + } + k = newk; + } + + /* Apply the modifications accumulated */ + /* in 'temp' to column L(*,j). */ + diagj = Aii[j] - diagj; + if (diagj <= 0.0) /* Check for ill-conditioning */ + { + errcode = j; + return errcode; + } + diagj = sqrt(diagj); + Aii[j] = diagj; + istrt = MSX.Dispersion.XLNZ[j]; + istop = MSX.Dispersion.XLNZ[j+1] - 1; + if (istop >= istrt) + { + MSX.Dispersion.first[j] = istrt; + isub = MSX.Dispersion.NZSUB[istrt]; + MSX.Dispersion.link[j] = MSX.Dispersion.link[isub]; + MSX.Dispersion.link[isub] = j; + for (i=istrt; i<=istop; i++) + { + isub = MSX.Dispersion.NZSUB[i]; + bj = (Aij[MSX.Dispersion.LNZ[i]] - MSX.Dispersion.temp[isub])/diagj; + Aij[MSX.Dispersion.LNZ[i]] = bj; + MSX.Dispersion.temp[isub] = 0.0; + } + } + } /* next j */ + + /* Foward substitution */ + for (j=1; j<=n; j++) + { + bj = B[j]/Aii[j]; + B[j] = bj; + istrt = MSX.Dispersion.XLNZ[j]; + istop = MSX.Dispersion.XLNZ[j+1] - 1; + if (istop >= istrt) + { + for (i=istrt; i<=istop; i++) + { + isub = MSX.Dispersion.NZSUB[i]; + B[isub] -= Aij[MSX.Dispersion.LNZ[i]]*bj; + } + } + } + + /* Backward substitution */ + for (j=n; j>=1; j--) + { + bj = B[j]; + istrt = MSX.Dispersion.XLNZ[j]; + istop = MSX.Dispersion.XLNZ[j+1] - 1; + if (istop >= istrt) + { + for (i=istrt; i<=istop; i++) + { + isub = MSX.Dispersion.NZSUB[i]; + bj -= Aij[MSX.Dispersion.LNZ[i]]*B[isub]; + } + } + B[j] = bj/Aii[j]; + } + + return(errcode); +} /* End of linsolve */ + + +/************************ END OF SMATRIX.C ************************/ + diff --git a/src/solver/smatrix.h b/src/solver/smatrix.h new file mode 100644 index 0000000..18b1b95 --- /dev/null +++ b/src/solver/smatrix.h @@ -0,0 +1,21 @@ +/* ----------- SMATRIX.C ---------------*/ +int createsparse(void); /* Creates sparse matrix */ +int allocsparse(void); /* Allocates matrix memory */ +void freesparse(void); /* Frees matrix memory */ +int buildlists(int); /* Builds adjacency lists */ +int paralink(int, int, int); /* Checks for parallel links */ +void xparalinks(void); /* Removes parallel links */ +void freelists(void); /* Frees adjacency lists */ +void countdegree(void); /* Counts links at each node */ +int reordernodes(void); /* Finds a node re-ordering */ +int mindegree(int, int); /* Finds min. degree node */ +int growlist(int); /* Augments adjacency list */ +int newlink(Padjlist); /* Adds fill-ins for a node */ +int linked(int, int); /* Checks if 2 nodes linked */ +int addlink(int, int, int); /* Creates new fill-in */ +int storesparse(int); /* Stores sparse matrix */ +int ordersparse(int); /* Orders matrix storage */ +void transpose(int, int*, int*, /* Transposes sparse matrix */ + int*, int*, int*, int*, int*); +int linsolve(int, double*, double*, /* Solution of linear eqns. */ + double*); /* via Cholesky factorization */ \ No newline at end of file From 992108aa3ed6b5866901c6a6287cb594bf986723 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 15:27:27 -0500 Subject: [PATCH 06/32] Triplet WIP --- src/run/CMakeLists.txt | 54 --------------------------------------- src/solver/CMakeLists.txt | 24 ++--------------- 2 files changed, 2 insertions(+), 76 deletions(-) diff --git a/src/run/CMakeLists.txt b/src/run/CMakeLists.txt index 765b78a..f79e1ea 100644 --- a/src/run/CMakeLists.txt +++ b/src/run/CMakeLists.txt @@ -1,49 +1,3 @@ -# # EPANETMSX COMMAND LINE EXECUTABLE -# cmake_minimum_required (VERSION 2.8.8) -# # Sets for output directory for executables and libraries. -# set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) -# set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -# set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) -# set(RELEASEVAR, "Release") -# set(DEBUGVAR, "Debug") - -# # Sets the position independent code property for all targets. -# set(CMAKE_POSITION_INDEPENDENT_CODE ON) - -# # Link to multi-threaded static runtime library -# IF (MSVC) -# add_definitions(-D_CRT_SECURE_NO_DEPRECATE -MT) -# ENDIF (MSVC) - - -# # Set up file groups for exe target -# set(MSX_CLI_SOURCES msxmain.c) -# include_directories(include) - -# source_group("CLI" FILES ${MSX_CLI_SOURCES}) - -# # Creates the EPANET-MSX command line executable -# add_executable(runepanetmsx ${MSX_CLI_SOURCES}) - -# target_compile_definitions(runepanetmsx PUBLIC FOO=1) - -# IF(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)") -# find_library(EPANET_LIB epanet2 NAMES epanet2 PATHS ${PROJECT_SOURCE_DIR}/include/x86 NO_DEFAULT_PATH) -# target_link_libraries(runepanetmsx LINK_PUBLIC epanetmsx ${EPANET_LIB}) -# add_custom_command( -# TARGET runepanetmsx -# COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/x86/epanet2.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/epanet2.dll -# COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/runvc.bat ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/runvc.bat) -# else(TRUE) -# find_library(EPANET_LIB epanet2 NAMES epanet2 PATHS ${PROJECT_SOURCE_DIR}/include/x64 NO_DEFAULT_PATH) -# target_link_libraries(runepanetmsx LINK_PUBLIC epanetmsx ${EPANET_LIB}) -# add_custom_command( -# TARGET runepanetmsx -# COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/x64/epanet2.dll ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/epanet2.dll -# COMMAND ${CMAKE_COMMAND} -E copy ${PROJECT_SOURCE_DIR}/include/runvc.bat ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$/runvc.bat) -# endif(MSVC AND "${CMAKE_VS_PLATFORM_NAME}" MATCHES "(Win32)") - - # CMakeLists.txt - CMake configuration file for EPANET MSX runner # # Created: Nov 13, 2023 @@ -91,11 +45,3 @@ set_target_properties(runepanetmsx install(TARGETS runepanetmsx DESTINATION "${TOOL_DIST}" ) - - -# # copy runswmm to build tree for testing -# add_custom_command(TARGET runepanet POST_BUILD -# COMMAND ${CMAKE_COMMAND} -E copy -# $ -# ${CMAKE_BINARY_DIR}/bin/$/$ -# ) \ No newline at end of file diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 893851e..6082287 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -10,7 +10,7 @@ find_package(OpenMP) -set(EPANET_PUBLIC_HEADERS +set(EPANETMSX_PUBLIC_HEADERS ${PROJECT_SOURCE_DIR}/include/epanetmsx.h ) @@ -68,7 +68,7 @@ if(UNIX) PRIVATE m ) -endif() +endif(UNIX) target_include_directories(epanetmsx PUBLIC @@ -77,26 +77,6 @@ target_include_directories(epanetmsx $ ) -# include(GenerateExportHeader) -# generate_export_header(epanet2 -# STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC -# ) - -# if(APPLE) -# set(LIB_ROOT "@loader_path") -# else() -# set(LIB_ROOT "$ORIGIN") -# endif() - -# set_target_properties(epanet2 -# PROPERTIES -# MACOSX_RPATH TRUE -# SKIP_BUILD_RPATH FALSE -# BUILD_WITH_INSTALL_RPATH FALSE -# INSTALL_RPATH "${LIB_ROOT};${PACKAGE_RPATH};" -# INSTALL_RPATH_USE_LINK_PATH TRUE -# ) - install(TARGETS epanetmsx EXPORT epanetmsxTargets RUNTIME DESTINATION "${TOOL_DIST}" From 642e5f2fa2bc34d4443409aba09426d22fb2ce66 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 20:13:13 -0500 Subject: [PATCH 07/32] Configuring triplet build --- .gitmodules | 2 +- src/solver/CMakeLists.txt | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.gitmodules b/.gitmodules index 050f6a5..c248d5b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "EPANET2.2"] path = EPANET2.2 url = https://github.com/USEPA/EPANET2.2.git - branch = master + branch = triplet_build diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 6082287..c4e5082 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -63,18 +63,23 @@ target_link_options(epanetmsx ">" ) -if(UNIX) - target_link_libraries(epanetmsx - PRIVATE - m - ) -endif(UNIX) + +target_link_libraries(epanetmsx + PUBLIC + $<$>>:m> + $<$:OpenMP::OpenMP_C> + $<$:omp> +) + target_include_directories(epanetmsx PUBLIC $ $ $ + + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/.. ) From 8fa80e606c575bc34fe80af729f12a37146e6062 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 20:23:23 -0500 Subject: [PATCH 08/32] Remove unnecessary malloc.h include --- src/solver/hash.c | 1 - src/solver/mempool.c | 1 - src/solver/msxchem.c | 1 - src/solver/msxinp.c | 1 - src/solver/msxout.c | 1 - src/solver/msxproj.c | 1 - src/solver/msxqual.c | 1 - src/solver/msxtoolkit.c | 1 - src/solver/msxutils.c | 3 +-- src/solver/smatrix.c | 1 - 10 files changed, 1 insertion(+), 11 deletions(-) diff --git a/src/solver/hash.c b/src/solver/hash.c index dce691e..9bcaeaa 100644 --- a/src/solver/hash.c +++ b/src/solver/hash.c @@ -14,7 +14,6 @@ // HTfree() - frees a hash table //----------------------------------------------------------------------------- -#include #include #include "hash.h" diff --git a/src/solver/mempool.c b/src/solver/mempool.c index f2cc2ee..55723dd 100644 --- a/src/solver/mempool.c +++ b/src/solver/mempool.c @@ -16,7 +16,6 @@ */ #include -#include #include "mempool.h" /* diff --git a/src/solver/msxchem.c b/src/solver/msxchem.c index 11cc3fb..4594382 100644 --- a/src/solver/msxchem.c +++ b/src/solver/msxchem.c @@ -11,7 +11,6 @@ #include #include -#include #include #include "msxtypes.h" diff --git a/src/solver/msxinp.c b/src/solver/msxinp.c index 01d6a1f..cebf547 100644 --- a/src/solver/msxinp.c +++ b/src/solver/msxinp.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include "msxtypes.h" diff --git a/src/solver/msxout.c b/src/solver/msxout.c index 2a3500c..f9000bf 100644 --- a/src/solver/msxout.c +++ b/src/solver/msxout.c @@ -12,7 +12,6 @@ #include #include -#include #include #include "msxtypes.h" diff --git a/src/solver/msxproj.c b/src/solver/msxproj.c index ae98e66..ff3036a 100644 --- a/src/solver/msxproj.c +++ b/src/solver/msxproj.c @@ -12,7 +12,6 @@ #include #include -#include #include #include "msxtypes.h" diff --git a/src/solver/msxqual.c b/src/solver/msxqual.c index 42684e9..e1e85d0 100644 --- a/src/solver/msxqual.c +++ b/src/solver/msxqual.c @@ -11,7 +11,6 @@ #include #include -#include #include #include "msxtypes.h" diff --git a/src/solver/msxtoolkit.c b/src/solver/msxtoolkit.c index e8f7732..f51068d 100644 --- a/src/solver/msxtoolkit.c +++ b/src/solver/msxtoolkit.c @@ -21,7 +21,6 @@ #include #include -#include #include #include "msxtypes.h" diff --git a/src/solver/msxutils.c b/src/solver/msxutils.c index 76bd208..b6caf6b 100644 --- a/src/solver/msxutils.c +++ b/src/solver/msxutils.c @@ -13,7 +13,6 @@ #include #include #include -#include #include #include @@ -357,7 +356,7 @@ int factorize(double **a, int n, double *w, int *indx) } for (j = 1;j <= n;j++) /**for each column*/ { - /*This is the loop over columns of Crout’s method.*/ + /*This is the loop over columns of Crout�s method.*/ for (i = 1; i < j; i++) { /*Up from the diagonal*/ diff --git a/src/solver/smatrix.c b/src/solver/smatrix.c index c0f110c..91b592b 100644 --- a/src/solver/smatrix.c +++ b/src/solver/smatrix.c @@ -33,7 +33,6 @@ Linsolve() solves the linearized system of hydraulic equations. #include #include -#include #include #include "hash.h" #include "msxtypes.h" From a8c4390bf62705736651af1e378b7f19a6f8bb6a Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 20:36:48 -0500 Subject: [PATCH 09/32] Import stlib to address semantic issue --- .github/workflows/build-and-test.yml | 2 +- src/solver/smatrix.c | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index dfe830d..dbd9b5c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -3,7 +3,7 @@ name: Build and Test MSX on: push: - branches: [ master, triplet_build ] + branches: [ master ] pull_request: branches: [ master ] diff --git a/src/solver/smatrix.c b/src/solver/smatrix.c index 91b592b..1b85212 100644 --- a/src/solver/smatrix.c +++ b/src/solver/smatrix.c @@ -33,6 +33,11 @@ Linsolve() solves the linearized system of hydraulic equations. #include #include + +#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) +#include +#endif + #include #include "hash.h" #include "msxtypes.h" From 2fee1ed97b171549d56c671fbc4f63775ad07765 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 20:40:39 -0500 Subject: [PATCH 10/32] Import stlib.h to address semantic issue --- src/solver/CMakeLists.txt | 1 + src/solver/msxtoolkit.c | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index c4e5082..2174058 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -76,6 +76,7 @@ target_include_directories(epanetmsx PUBLIC $ $ + ${PROJECT_SOURCE_DIR}/include $ PRIVATE diff --git a/src/solver/msxtoolkit.c b/src/solver/msxtoolkit.c index f51068d..02bc7a2 100644 --- a/src/solver/msxtoolkit.c +++ b/src/solver/msxtoolkit.c @@ -23,6 +23,10 @@ #include #include +#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) +#include +#endif + #include "msxtypes.h" #include "msxutils.h" #include "epanet2.h" From f29eb1d175f677f64c1b7450f959423c632f9887 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 20:58:41 -0500 Subject: [PATCH 11/32] Fixed macos build issues --- src/solver/hash.c | 4 ++++ src/solver/msxchem.c | 4 ++++ src/solver/msxout.c | 4 ++++ src/solver/msxproj.c | 4 ++++ src/solver/msxqual.c | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/src/solver/hash.c b/src/solver/hash.c index 9bcaeaa..65922bc 100644 --- a/src/solver/hash.c +++ b/src/solver/hash.c @@ -17,6 +17,10 @@ #include #include "hash.h" +#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) +#include +#endif + /* Use Fletcher's checksum to compute 2-byte hash of string */ unsigned int hash(char *str) { diff --git a/src/solver/msxchem.c b/src/solver/msxchem.c index 4594382..70595f3 100644 --- a/src/solver/msxchem.c +++ b/src/solver/msxchem.c @@ -13,6 +13,10 @@ #include #include +#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) +#include +#endif + #include "msxtypes.h" #include "rk5.h" #include "ros2.h" diff --git a/src/solver/msxout.c b/src/solver/msxout.c index f9000bf..2bf7441 100644 --- a/src/solver/msxout.c +++ b/src/solver/msxout.c @@ -14,6 +14,10 @@ #include #include +#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) +#include +#endif + #include "msxtypes.h" // External variables diff --git a/src/solver/msxproj.c b/src/solver/msxproj.c index ff3036a..dd59e52 100644 --- a/src/solver/msxproj.c +++ b/src/solver/msxproj.c @@ -14,6 +14,10 @@ #include #include +#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) +#include +#endif + #include "msxtypes.h" #include "msxutils.h" //#include "mempool.h" diff --git a/src/solver/msxqual.c b/src/solver/msxqual.c index e1e85d0..d5fc099 100644 --- a/src/solver/msxqual.c +++ b/src/solver/msxqual.c @@ -13,6 +13,10 @@ #include #include +#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) +#include +#endif + #include "msxtypes.h" //#include "mempool.h" #include "msxutils.h" From cceeaaacc4be14a1ec89a667d167c01c79d9934d Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 21:01:31 -0500 Subject: [PATCH 12/32] Fixed include paths --- src/run/CMakeLists.txt | 6 +++++- src/solver/CMakeLists.txt | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/run/CMakeLists.txt b/src/run/CMakeLists.txt index f79e1ea..2d49c59 100644 --- a/src/run/CMakeLists.txt +++ b/src/run/CMakeLists.txt @@ -23,7 +23,11 @@ add_executable(runepanetmsx target_include_directories(runepanetmsx PUBLIC - ${PROJECT_SOURCE_DIR}/include + $ + $ + + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/.. ) target_link_libraries(runepanetmsx diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index 2174058..c4e5082 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -76,7 +76,6 @@ target_include_directories(epanetmsx PUBLIC $ $ - ${PROJECT_SOURCE_DIR}/include $ PRIVATE From 81976845288e9277154e19778a7ef2ea416a2e98 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 21:06:47 -0500 Subject: [PATCH 13/32] Install openmp on macos --- .github/workflows/build-and-test.yml | 5 ++ shell/apple/libomp.rb | 74 ++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 shell/apple/libomp.rb diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index dbd9b5c..3c787f5 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -34,6 +34,11 @@ jobs: with: submodules: true + - name: Install OpenMP Binaries for MacOS + if: ${{ matrix.os == 'macos-latest' }} + run: | + brew reinstall --build-from-source --formula ../../shell/apple/libomp.rb + - name: Build # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type diff --git a/shell/apple/libomp.rb b/shell/apple/libomp.rb new file mode 100644 index 0000000..b32dbf9 --- /dev/null +++ b/shell/apple/libomp.rb @@ -0,0 +1,74 @@ +class Libomp < Formula + desc "LLVM's OpenMP runtime library" + homepage "https://openmp.llvm.org/" + url "https://github.com/llvm/llvm-project/releases/download/llvmorg-14.0.0/openmp-14.0.0.src.tar.xz" + sha256 "28a1cbdd3dfdd331e4ed2dda2b4477fc418e455c883bd0d1d6acc331118e4688" + license "MIT" + + livecheck do + url "https://llvm.org/" + regex(/LLVM (\d+\.\d+\.\d+)/i) + end + + bottle do + sha256 cellar: :any, arm64_monterey: "cf1058b26e1a778e523d51562c99b4145aea1b1cb89f1c60b3315677a86c7a08" + sha256 cellar: :any, arm64_big_sur: "bbf77a1a151f00a18e340ab1f655fb87fe787a85834518f1dc44bf0c52ae7d4c" + sha256 cellar: :any, monterey: "e66d2009d6d205c19499dcb453dfac4376ab6bdba805987be00ddbbab65a0818" + sha256 cellar: :any, big_sur: "ed9dc636a5fc8c2a0cfb1643f7932d742ae4805c3f193a9e56cab7d7cf7342e7" + sha256 cellar: :any, catalina: "c72ce9beecde09052e7eac3550b0286ed9bfb2d14f1dd5954705ab5fb25f231b" + sha256 cellar: :any_skip_relocation, x86_64_linux: "9fe14d5f4c8b472de1fad74278da6ba38da7322775b8a88ac61de0c373c4ad10" + end + + depends_on "cmake" => :build + depends_on :xcode => :build # Sometimes CLT cannot build arm64 + uses_from_macos "llvm" => :build + + on_linux do + keg_only "provided by LLVM, which is not keg-only on Linux" + end + + def install + # Disable LIBOMP_INSTALL_ALIASES, otherwise the library is installed as + # libgomp alias which can conflict with GCC's libgomp. + + args = ["-DLIBOMP_INSTALL_ALIASES=OFF"] + args << "-DOPENMP_ENABLE_LIBOMPTARGET=OFF" if OS.linux? + + # Build universal binary + ENV.permit_arch_flags + ENV.runtime_cpu_detection + args << "-DCMAKE_OSX_ARCHITECTURES=arm64;x86_64" + + system "cmake", "-S", "openmp-#{version}.src", "-B", "build/shared", *std_cmake_args, *args + system "cmake", "--build", "build/shared" + system "cmake", "--install", "build/shared" + + system "cmake", "-S", "openmp-#{version}.src", "-B", "build/static", + "-DLIBOMP_ENABLE_SHARED=OFF", + *std_cmake_args, *args + system "cmake", "--build", "build/static" + system "cmake", "--install", "build/static" + end + + test do + (testpath/"test.cpp").write <<~EOS + #include + #include + int main (int argc, char** argv) { + std::array arr = {0,0}; + #pragma omp parallel num_threads(2) + { + size_t tid = omp_get_thread_num(); + arr.at(tid) = tid + 1; + } + if(arr.at(0) == 1 && arr.at(1) == 2) + return 0; + else + return 1; + } + EOS + system ENV.cxx, "-Werror", "-Xpreprocessor", "-fopenmp", "test.cpp", "-std=c++11", + "-L#{lib}", "-lomp", "-o", "test" + system "./test" + end + end \ No newline at end of file From 58f3b3c8aa0a684b7e03147dd96ade16d66ce91d Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 21:08:02 -0500 Subject: [PATCH 14/32] Fixed include paths --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 3c787f5..ef24543 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -37,7 +37,7 @@ jobs: - name: Install OpenMP Binaries for MacOS if: ${{ matrix.os == 'macos-latest' }} run: | - brew reinstall --build-from-source --formula ../../shell/apple/libomp.rb + brew reinstall --build-from-source --formula ../shell/apple/libomp.rb - name: Build # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. From 97ff631ce3d5b1ca210de1cba3536deaddbac55a Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 21:10:04 -0500 Subject: [PATCH 15/32] Install openmp on macos --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ef24543..f10410c 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -37,7 +37,7 @@ jobs: - name: Install OpenMP Binaries for MacOS if: ${{ matrix.os == 'macos-latest' }} run: | - brew reinstall --build-from-source --formula ../shell/apple/libomp.rb + brew reinstall --build-from-source --formula ../../../shell/apple/libomp.rb - name: Build # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. From 7659aac1cdbb48037ed66509e362dfd408bc8576 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 21:11:44 -0500 Subject: [PATCH 16/32] Fixed macos build issues --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f10410c..ecccecd 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -37,7 +37,7 @@ jobs: - name: Install OpenMP Binaries for MacOS if: ${{ matrix.os == 'macos-latest' }} run: | - brew reinstall --build-from-source --formula ../../../shell/apple/libomp.rb + brew reinstall --build-from-source --formula shell/apple/libomp.rb - name: Build # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. From 4e1ea2e4117d5df5e9972935deeabacccd2aa436 Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 21:15:09 -0500 Subject: [PATCH 17/32] Fixed macos build issues --- .github/workflows/build-and-test.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index ecccecd..4618c2e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -37,7 +37,9 @@ jobs: - name: Install OpenMP Binaries for MacOS if: ${{ matrix.os == 'macos-latest' }} run: | - brew reinstall --build-from-source --formula shell/apple/libomp.rb + echo $PWD + brew update + brew reinstall --build-from-source --formula ./shell/apple/libomp.rb - name: Build # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. From febaaf9bb9e7629e2e5caaa04341902dfaddf9bc Mon Sep 17 00:00:00 2001 From: Caleb Date: Mon, 13 Nov 2023 22:03:41 -0500 Subject: [PATCH 18/32] Use stlib across all platforms --- .github/workflows/build-and-test.yml | 1 - src/solver/hash.c | 6 ++---- src/solver/mathexpr.c | 1 + src/solver/mempool.c | 1 + src/solver/msxchem.c | 3 --- src/solver/msxcompiler.c | 1 + src/solver/msxdispersion.c | 1 + src/solver/msxproj.c | 3 --- src/solver/msxqual.c | 3 --- src/solver/msxtoolkit.c | 3 --- src/solver/smatrix.c | 5 +---- 11 files changed, 7 insertions(+), 21 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 4618c2e..836d662 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -37,7 +37,6 @@ jobs: - name: Install OpenMP Binaries for MacOS if: ${{ matrix.os == 'macos-latest' }} run: | - echo $PWD brew update brew reinstall --build-from-source --formula ./shell/apple/libomp.rb diff --git a/src/solver/hash.c b/src/solver/hash.c index 65922bc..f75fc17 100644 --- a/src/solver/hash.c +++ b/src/solver/hash.c @@ -15,11 +15,9 @@ //----------------------------------------------------------------------------- #include -#include "hash.h" - -#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) #include -#endif + +#include "hash.h" /* Use Fletcher's checksum to compute 2-byte hash of string */ unsigned int hash(char *str) diff --git a/src/solver/mathexpr.c b/src/solver/mathexpr.c index f09baa3..c0a9b0b 100644 --- a/src/solver/mathexpr.c +++ b/src/solver/mathexpr.c @@ -49,6 +49,7 @@ #include #include #include + #include "mathexpr.h" #define MAX_STACK_SIZE 1024 diff --git a/src/solver/mempool.c b/src/solver/mempool.c index 55723dd..3feb8c4 100644 --- a/src/solver/mempool.c +++ b/src/solver/mempool.c @@ -16,6 +16,7 @@ */ #include + #include "mempool.h" /* diff --git a/src/solver/msxchem.c b/src/solver/msxchem.c index 70595f3..3fca3e3 100644 --- a/src/solver/msxchem.c +++ b/src/solver/msxchem.c @@ -12,10 +12,7 @@ #include #include #include - -#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) #include -#endif #include "msxtypes.h" #include "rk5.h" diff --git a/src/solver/msxcompiler.c b/src/solver/msxcompiler.c index c98de10..2d73d10 100644 --- a/src/solver/msxcompiler.c +++ b/src/solver/msxcompiler.c @@ -12,6 +12,7 @@ #include #include #include + #include "msxtypes.h" #include "msxfuncs.h" #include "msxutils.h" diff --git a/src/solver/msxdispersion.c b/src/solver/msxdispersion.c index 2282539..3584bbc 100644 --- a/src/solver/msxdispersion.c +++ b/src/solver/msxdispersion.c @@ -9,6 +9,7 @@ #include #include #include + #include "msxtypes.h" #include "dispersion.h" #include "smatrix.h" diff --git a/src/solver/msxproj.c b/src/solver/msxproj.c index dd59e52..072e113 100644 --- a/src/solver/msxproj.c +++ b/src/solver/msxproj.c @@ -13,10 +13,7 @@ #include #include #include - -#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) #include -#endif #include "msxtypes.h" #include "msxutils.h" diff --git a/src/solver/msxqual.c b/src/solver/msxqual.c index d5fc099..aea02e3 100644 --- a/src/solver/msxqual.c +++ b/src/solver/msxqual.c @@ -12,10 +12,7 @@ #include #include #include - -#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) #include -#endif #include "msxtypes.h" //#include "mempool.h" diff --git a/src/solver/msxtoolkit.c b/src/solver/msxtoolkit.c index 02bc7a2..5e34f58 100644 --- a/src/solver/msxtoolkit.c +++ b/src/solver/msxtoolkit.c @@ -22,10 +22,7 @@ #include #include #include - -#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) #include -#endif #include "msxtypes.h" #include "msxutils.h" diff --git a/src/solver/smatrix.c b/src/solver/smatrix.c index 1b85212..65b482f 100644 --- a/src/solver/smatrix.c +++ b/src/solver/smatrix.c @@ -33,12 +33,9 @@ Linsolve() solves the linearized system of hydraulic equations. #include #include - -#if defined(macintosh) || defined(Macintosh) || defined(__APPLE__) && defined(__MACH__) #include -#endif - #include + #include "hash.h" #include "msxtypes.h" #include "smatrix.h" From 4800dfeb0228723ad69c84fc5c50afbceb98be6b Mon Sep 17 00:00:00 2001 From: Caleb Date: Tue, 14 Nov 2023 09:15:52 -0500 Subject: [PATCH 19/32] Work in progress fixing ubuntu build --- .github/workflows/build-and-test.yml | 5 +++-- CMakeLists.txt | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 836d662..2e59fdc 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -34,14 +34,15 @@ jobs: with: submodules: true - - name: Install OpenMP Binaries for MacOS + - name: Build OpenMP Binaries for MacOS via Homebrew if: ${{ matrix.os == 'macos-latest' }} run: | brew update brew reinstall --build-from-source --formula ./shell/apple/libomp.rb - name: Build - # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only + # required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | cmake -B .\build ${{ matrix.cmake_generator }} . diff --git a/CMakeLists.txt b/CMakeLists.txt index 019995f..200a729 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ # Created: Nov 13, 2023 # Modified: Nov 13, 2023 # -# Author: Michael E. Tryby +# Author: Caleb Buahin # US EPA ORD/CESER # From 2f40a391c2044d7280d79383823a5ce72670f663 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 09:17:17 -0500 Subject: [PATCH 20/32] Auto generate export macro --- EPANET2.2 | 2 +- src/solver/CMakeLists.txt | 17 +++++++++++++++-- {Include => src/solver/include}/epanet2.bas | 0 {Include => src/solver/include}/epanet2.pas | 0 {Include => src/solver/include}/epanetmsx.bas | 0 {Include => src/solver/include}/epanetmsx.def | 0 {Include => src/solver/include}/epanetmsx.h | 0 {Include => src/solver/include}/epanetmsx.pas | 0 8 files changed, 16 insertions(+), 3 deletions(-) rename {Include => src/solver/include}/epanet2.bas (100%) rename {Include => src/solver/include}/epanet2.pas (100%) rename {Include => src/solver/include}/epanetmsx.bas (100%) rename {Include => src/solver/include}/epanetmsx.def (100%) rename {Include => src/solver/include}/epanetmsx.h (100%) rename {Include => src/solver/include}/epanetmsx.pas (100%) diff --git a/EPANET2.2 b/EPANET2.2 index 2b3c2e9..35040bb 160000 --- a/EPANET2.2 +++ b/EPANET2.2 @@ -1 +1 @@ -Subproject commit 2b3c2e9dc002ec2feacdf6b4455ed17826966cc8 +Subproject commit 35040bb921791f22e7e531d8e1cd519ae217273b diff --git a/src/solver/CMakeLists.txt b/src/solver/CMakeLists.txt index c4e5082..92113b3 100644 --- a/src/solver/CMakeLists.txt +++ b/src/solver/CMakeLists.txt @@ -11,7 +11,7 @@ find_package(OpenMP) set(EPANETMSX_PUBLIC_HEADERS - ${PROJECT_SOURCE_DIR}/include/epanetmsx.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/epanetmsx.h ) file(GLOB @@ -63,6 +63,19 @@ target_link_options(epanetmsx ">" ) +include(GenerateExportHeader) +generate_export_header(epanetmsx + BASE_NAME epanetmsx + EXPORT_MACRO_NAME MSXDLLEXPORT + EXPORT_FILE_NAME epanetmsx_export.h + STATIC_DEFINE SHARED_EXPORTS_BUILT_AS_STATIC +) + +file(COPY ${CMAKE_CURRENT_BINARY_DIR}/epanetmsx_export.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include +) + + target_link_libraries(epanetmsx PUBLIC @@ -75,7 +88,7 @@ target_link_libraries(epanetmsx target_include_directories(epanetmsx PUBLIC $ - $ + $ $ PRIVATE diff --git a/Include/epanet2.bas b/src/solver/include/epanet2.bas similarity index 100% rename from Include/epanet2.bas rename to src/solver/include/epanet2.bas diff --git a/Include/epanet2.pas b/src/solver/include/epanet2.pas similarity index 100% rename from Include/epanet2.pas rename to src/solver/include/epanet2.pas diff --git a/Include/epanetmsx.bas b/src/solver/include/epanetmsx.bas similarity index 100% rename from Include/epanetmsx.bas rename to src/solver/include/epanetmsx.bas diff --git a/Include/epanetmsx.def b/src/solver/include/epanetmsx.def similarity index 100% rename from Include/epanetmsx.def rename to src/solver/include/epanetmsx.def diff --git a/Include/epanetmsx.h b/src/solver/include/epanetmsx.h similarity index 100% rename from Include/epanetmsx.h rename to src/solver/include/epanetmsx.h diff --git a/Include/epanetmsx.pas b/src/solver/include/epanetmsx.pas similarity index 100% rename from Include/epanetmsx.pas rename to src/solver/include/epanetmsx.pas From d4b756e6702726ea5ad1879b40a7a279e7db0640 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 09:28:12 -0500 Subject: [PATCH 21/32] Added include guards --- src/run/msxmain.c | 1 + src/solver/dispersion.h | 7 ++++++- src/solver/hash.h | 4 ++++ src/solver/mathexpr.h | 5 +++++ src/solver/mempool.h | 5 +++++ src/solver/msxdict.h | 6 ++++++ src/solver/msxtypes.h | 6 +++++- src/solver/msxutils.h | 5 +++++ src/solver/newton.h | 5 +++++ src/solver/rk5.h | 5 +++++ src/solver/ros2.h | 5 +++++ src/solver/smatrix.h | 8 +++++++- 12 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/run/msxmain.c b/src/run/msxmain.c index 138f3e3..8ec628f 100644 --- a/src/run/msxmain.c +++ b/src/run/msxmain.c @@ -30,6 +30,7 @@ #include "epanet2.h" // EPANET toolkit header file #include "epanetmsx.h" // EPANET-MSX toolkit header file #include + int main(int argc, char* argv[]) /* ** Purpose: diff --git a/src/solver/dispersion.h b/src/solver/dispersion.h index ceae365..89fea46 100644 --- a/src/solver/dispersion.h +++ b/src/solver/dispersion.h @@ -1,3 +1,6 @@ +#ifndef DISPERSION_H +#define DISPERSION_H + #define MAXSEGMENTS 5000 typedef enum { @@ -19,4 +22,6 @@ int dispersion_close(); void dispersion_pipe(int m, double tstep); //effective dispersion coefficient and upstream/downstream node impact calculation void solve_nodequal(int m, double tstep); //solve nodal concentration void segqual_update(int m, double tstep); //update pipe segment concentration -void tridiag(int n, double *a, double *b, double *c, double *r, double *y); \ No newline at end of file +void tridiag(int n, double *a, double *b, double *c, double *r, double *y); + +#endif \ No newline at end of file diff --git a/src/solver/hash.h b/src/solver/hash.h index a6b0433..7cf2f70 100644 --- a/src/solver/hash.h +++ b/src/solver/hash.h @@ -4,6 +4,9 @@ ** */ +#ifndef HASH_H +#define HASH_H + #define HTMAXSIZE 1999 #define NOTFOUND 0 @@ -22,3 +25,4 @@ int HTfind(HTtable *, char *); char *HTfindKey(HTtable *, char *); void HTfree(HTtable *); +#endif \ No newline at end of file diff --git a/src/solver/mathexpr.h b/src/solver/mathexpr.h index 71e0fb3..e8f29e1 100644 --- a/src/solver/mathexpr.h +++ b/src/solver/mathexpr.h @@ -9,6 +9,9 @@ ** LAST UPDATE: 2/8/11 ******************************************************************************/ +#ifndef MATHEXPR_H +#define MATHEXPR_H + // Node in a tokenized math expression list struct ExprNode { @@ -32,3 +35,5 @@ void mathexpr_delete(MathExpr* expr); // Returns reconstructed string version of a tokenized expression char * mathexpr_getStr(MathExpr* expr, char* exprStr, char * (*getVariableStr) (int, char *)); + +#endif \ No newline at end of file diff --git a/src/solver/mempool.h b/src/solver/mempool.h index bed1787..b68675f 100644 --- a/src/solver/mempool.h +++ b/src/solver/mempool.h @@ -7,6 +7,9 @@ ** alloc pool - only the alloc routines know its structure. */ +#ifndef MEMPOOL_H +#define MEMPOOL_H + typedef struct { long dummy; @@ -17,3 +20,5 @@ char *Alloc(long); alloc_handle_t *AllocSetPool(alloc_handle_t *); void AllocReset(void); void AllocFreePool(void); + +#endif \ No newline at end of file diff --git a/src/solver/msxdict.h b/src/solver/msxdict.h index b68e97a..8956ea0 100644 --- a/src/solver/msxdict.h +++ b/src/solver/msxdict.h @@ -10,6 +10,10 @@ ** LAST UPDATE: 09/29/08 ***********************************************************************/ +#ifndef MSXDICT_H +#define MSXDICT_H + + // NOTE: the entries in MsxsectWords must match the entries in the enumeration // variable SectionType defined in msxtypes.h. static char *MsxSectWords[] = {"[TITLE", "[SPECIE", "[COEFF", "[TERM", @@ -34,3 +38,5 @@ static char YES[] = "YES"; static char NO[] = "NO"; static char ALL[] = "ALL"; static char NONE[] = "NONE"; + +#endif \ No newline at end of file diff --git a/src/solver/msxtypes.h b/src/solver/msxtypes.h index 67f1803..363f78e 100644 --- a/src/solver/msxtypes.h +++ b/src/solver/msxtypes.h @@ -10,6 +10,10 @@ ** LAST UPDATE: 08/30/2022 ***********************************************************************/ +#ifndef MSXTYPES_H +#define MSXTYPES_H + + #include "mathexpr.h" #include "mempool.h" #include @@ -544,4 +548,4 @@ typedef struct // MSX PROJECT VARIABLES } MSXproject; - +#endif diff --git a/src/solver/msxutils.h b/src/solver/msxutils.h index e1b984b..84fde29 100644 --- a/src/solver/msxutils.h +++ b/src/solver/msxutils.h @@ -10,6 +10,9 @@ ** LAST UPDATE: 2/8/11 *******************************************************************************/ +#ifndef MSXUTILS_H +#define MSXUTILS_H + // Gets the name of a temporary file char * MSXutils_getTempName(char *s); @@ -49,3 +52,5 @@ void solve(double **a, int n, int *indx, double b[]); // Computes the Jacobian matrix of a set of functions void jacobian(double *x, int n, double *f, double *w, double **a, void (*func)(double, double*, int, double*)); + +#endif \ No newline at end of file diff --git a/src/solver/newton.h b/src/solver/newton.h index 8902f60..7ce8fe4 100644 --- a/src/solver/newton.h +++ b/src/solver/newton.h @@ -9,6 +9,9 @@ ** LAST UPDATE: 04/14/2021 ******************************************************************************/ +#ifndef NEWTON_H +#define NEWTON_H + typedef struct { int Nmax; // max. number of equations @@ -27,3 +30,5 @@ void newton_close(void); // Applies the solver to a specific system of equations int newton_solve(double x[], int n, int maxit, int numsig, void (*func)(double, double*, int, double*)); + +#endif \ No newline at end of file diff --git a/src/solver/rk5.h b/src/solver/rk5.h index f20f9f8..dd4954b 100644 --- a/src/solver/rk5.h +++ b/src/solver/rk5.h @@ -7,6 +7,9 @@ ** LAST UPDATE: 04/14/2021 ***********************************************************************/ +#ifndef RK5_H +#define RK5_H + typedef struct { int Nmax; // max. number of equations @@ -32,3 +35,5 @@ void rk5_close(void); int rk5_integrate(double y[], int n, double t, double tnext, double* htry, double atol[], double rtol[], void (*func)(double, double*, int, double*)); + +#endif \ No newline at end of file diff --git a/src/solver/ros2.h b/src/solver/ros2.h index bc36871..c191046 100644 --- a/src/solver/ros2.h +++ b/src/solver/ros2.h @@ -7,6 +7,9 @@ ** LAST UPDATE: 04/14/2021 ***********************************************************************/ +#ifndef ROS2_H +#define ROS2_H + typedef struct { double** A; // Jacobian matrix @@ -28,3 +31,5 @@ void ros2_close(void); int ros2_integrate(double y[], int n, double t, double tnext, double* htry, double atol[], double rtol[], void (*func)(double, double*, int, double*)); + +#endif \ No newline at end of file diff --git a/src/solver/smatrix.h b/src/solver/smatrix.h index 18b1b95..7736e9b 100644 --- a/src/solver/smatrix.h +++ b/src/solver/smatrix.h @@ -1,3 +1,7 @@ + +#ifndef SMATRIX_H +#define SMATRIX_H + /* ----------- SMATRIX.C ---------------*/ int createsparse(void); /* Creates sparse matrix */ int allocsparse(void); /* Allocates matrix memory */ @@ -18,4 +22,6 @@ int ordersparse(int); /* Orders matrix storage */ void transpose(int, int*, int*, /* Transposes sparse matrix */ int*, int*, int*, int*, int*); int linsolve(int, double*, double*, /* Solution of linear eqns. */ - double*); /* via Cholesky factorization */ \ No newline at end of file + double*); /* via Cholesky factorization */ + +#endif \ No newline at end of file From 5cb09e40e4ccfff0e3a48e4eef69a08c4dafedd9 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 14:37:01 -0500 Subject: [PATCH 22/32] Addressing multiple definition error on linux --- src/solver/msxcompiler.c | 1 - src/solver/msxdispersion.c | 1 + src/solver/msxfuncs.c | 18 ++++++++++++++---- src/solver/msxfuncs.h | 12 ++++++------ src/solver/msxtypes.h | 2 +- 5 files changed, 22 insertions(+), 12 deletions(-) diff --git a/src/solver/msxcompiler.c b/src/solver/msxcompiler.c index 2d73d10..dbef11e 100644 --- a/src/solver/msxcompiler.c +++ b/src/solver/msxcompiler.c @@ -14,7 +14,6 @@ #include #include "msxtypes.h" -#include "msxfuncs.h" #include "msxutils.h" // --- define WINDOWS diff --git a/src/solver/msxdispersion.c b/src/solver/msxdispersion.c index 3584bbc..b0e1cc8 100644 --- a/src/solver/msxdispersion.c +++ b/src/solver/msxdispersion.c @@ -13,6 +13,7 @@ #include "msxtypes.h" #include "dispersion.h" #include "smatrix.h" + #define ERRCODE(x) (errcode = ((errcode>100) ? (errcode) : (x))) // External variables //-------------------- diff --git a/src/solver/msxfuncs.c b/src/solver/msxfuncs.c index 7af0311..42d358a 100644 --- a/src/solver/msxfuncs.c +++ b/src/solver/msxfuncs.c @@ -34,6 +34,16 @@ HMODULE hDLL; #include "msxfuncs.h" + +MSXGETRATES MSXgetPipeRates = NULL; +MSXGETRATES MSXgetTankRates = NULL; +MSXGETEQUIL MSXgetPipeEquil = NULL; +MSXGETEQUIL MSXgetTankEquil = NULL; +MSXGETFORMULAS MSXgetPipeFormulas = NULL; +MSXGETFORMULAS MSXgetTankFormulas = NULL; + + + //============================================================================= int MSXfuncs_load(char * libName) @@ -53,7 +63,7 @@ int MSXfuncs_load(char * libName) hDLL = LoadLibraryA(libName); if (hDLL == NULL) return 1; - MSXgetPipeRates = (MSXGETRATES) GetProcAddress(hDLL, "MSXgetPipeRates"); + MSXgetPipeRates = (MSXGETRATES) GetProcAddress(hDLL, "MSXgetPipeRates"); MSXgetTankRates = (MSXGETRATES) GetProcAddress(hDLL, "MSXgetTankRates"); MSXgetPipeEquil = (MSXGETEQUIL) GetProcAddress(hDLL, "MSXgetPipeEquil"); MSXgetTankEquil = (MSXGETEQUIL) GetProcAddress(hDLL, "MSXgetTankEquil"); @@ -72,9 +82,9 @@ int MSXfuncs_load(char * libName) MSXgetTankFormulas = (MSXGETFORMULAS) dlsym(hDLL, "MSXgetTankFormulas"); #endif - if (NULL == MSXgetPipeRates || NULL == MSXgetTankRates || - NULL == MSXgetPipeEquil || NULL == MSXgetTankEquil || - NULL == MSXgetPipeFormulas || NULL == MSXgetTankFormulas) + if (MSXgetPipeRates == NULL || MSXgetTankRates == NULL || + MSXgetPipeEquil == NULL || MSXgetTankEquil == NULL || + MSXgetPipeFormulas == NULL || MSXgetTankFormulas == NULL) { MSXfuncs_free(); hDLL = NULL; diff --git a/src/solver/msxfuncs.h b/src/solver/msxfuncs.h index 4cb7d19..bd14f87 100644 --- a/src/solver/msxfuncs.h +++ b/src/solver/msxfuncs.h @@ -18,12 +18,12 @@ typedef void (*MSXGETEQUIL)(double *, double *, double * , double *, double *); typedef void (*MSXGETFORMULAS)(double *, double *, double *, double *); // Declare each chemistry function -MSXGETRATES MSXgetPipeRates; -MSXGETRATES MSXgetTankRates; -MSXGETEQUIL MSXgetPipeEquil; -MSXGETEQUIL MSXgetTankEquil; -MSXGETFORMULAS MSXgetPipeFormulas; -MSXGETFORMULAS MSXgetTankFormulas; +extern MSXGETRATES MSXgetPipeRates; +extern MSXGETRATES MSXgetTankRates; +extern MSXGETEQUIL MSXgetPipeEquil; +extern MSXGETEQUIL MSXgetTankEquil; +extern MSXGETFORMULAS MSXgetPipeFormulas; +extern MSXGETFORMULAS MSXgetTankFormulas; // Functions that load and free the chemistry functions int MSXfuncs_load(char *); diff --git a/src/solver/msxtypes.h b/src/solver/msxtypes.h index 363f78e..836ad5d 100644 --- a/src/solver/msxtypes.h +++ b/src/solver/msxtypes.h @@ -13,10 +13,10 @@ #ifndef MSXTYPES_H #define MSXTYPES_H +#include #include "mathexpr.h" #include "mempool.h" -#include //----------------------------------------------------------------------------- // Definition of 4-byte integers & reals From b406e7871165edf342164d330a921bc9bef62d6c Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 14:54:52 -0500 Subject: [PATCH 23/32] Openmp install fix for macos --- .github/workflows/build-and-test.yml | 1 - .gitmodules | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2e59fdc..a5b0bbf 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -37,7 +37,6 @@ jobs: - name: Build OpenMP Binaries for MacOS via Homebrew if: ${{ matrix.os == 'macos-latest' }} run: | - brew update brew reinstall --build-from-source --formula ./shell/apple/libomp.rb - name: Build diff --git a/.gitmodules b/.gitmodules index c248d5b..050f6a5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "EPANET2.2"] path = EPANET2.2 url = https://github.com/USEPA/EPANET2.2.git - branch = triplet_build + branch = master From 51b5967d0e8887564d70776645bbfb1deb3f1267 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 15:27:34 -0500 Subject: [PATCH 24/32] Adding needed msxfuncs.h header --- src/solver/msxcompiler.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/solver/msxcompiler.c b/src/solver/msxcompiler.c index dbef11e..47fec40 100644 --- a/src/solver/msxcompiler.c +++ b/src/solver/msxcompiler.c @@ -15,6 +15,7 @@ #include "msxtypes.h" #include "msxutils.h" +#include "msxfuncs.h" // --- define WINDOWS From 6a52926434568c46c3d411bcbe661f921a843b33 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 16:35:40 -0500 Subject: [PATCH 25/32] Run example in actions --- .github/workflows/build-and-test.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a5b0bbf..a7b1931 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,15 +18,21 @@ jobs: - os: windows-latest cmake_generator: -G "Visual Studio 17 2022" -A "x64" continue-on-error: false + alias: win64 - os: ubuntu-latest cmake_generator: -G "Unix Makefiles" continue-on-error: false + alias: Linux - os: macos-latest cmake_generator: -G "Xcode" continue-on-error: false + alias: Darwin runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.continue-on-error }} environment: testing + env: + BuildVersion: 2.0.0 + steps: - name: Checkout Repository @@ -47,6 +53,13 @@ jobs: cmake -B .\build ${{ matrix.cmake_generator }} . cmake --build .\build --config Release --target package + - name: Run Example + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only + # required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + run: | + ./build/_CPack_Packages/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./examples/example.inp ./examples/example.msx ./examples/example.rpt ./examples/example.out + - name: Upload artifacts if: ${{ always() }} uses: actions/upload-artifact@v3 From c838e026b591875c58880f45353aaf38f6603722 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 16:40:44 -0500 Subject: [PATCH 26/32] Run example in actions --- .github/workflows/build-and-test.yml | 2 +- readme.md | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index a7b1931..23a27ee 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -58,7 +58,7 @@ jobs: # required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | - ./build/_CPack_Packages/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./examples/example.inp ./examples/example.msx ./examples/example.rpt ./examples/example.out + ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./examples/example.inp ./examples/example.msx ./examples/example.rpt ./examples/example.out - name: Upload artifacts if: ${{ always() }} diff --git a/readme.md b/readme.md index 88b8f44..29d98f8 100644 --- a/readme.md +++ b/readme.md @@ -13,10 +13,11 @@ CMake (https://cmake.org/) can be used to build EPANETMSX applications. The proj root directory and supports builds for Linux, Mac OS and Windows. To build the EPANETMSX library and its command line executable using CMake, first open a console window and navigate to the project's root directory. Then enter the following commands: -mkdir build\ -cd build\ -cmake ..\ -cmake --build . --config Release +``` +cmake -B build . +cmake --build build --config Release --target package + +``` Note: under Windows, the third command should be cmake .. -A Win32 for a 32-bit build or cmake .. -A x64 for a 64-bit build when Microsoft Visual Studio is the default compiler. 64-bit EPANETMSX application need to work with 64-bit EPANET2 engine. From 71d5c1b9d524e25beb3f4d29b9496332972fac9e Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 16:47:12 -0500 Subject: [PATCH 27/32] Run example in actions --- .github/workflows/build-and-test.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 23a27ee..f9562f3 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -18,14 +18,17 @@ jobs: - os: windows-latest cmake_generator: -G "Visual Studio 17 2022" -A "x64" continue-on-error: false + assign_permission: alias: win64 - os: ubuntu-latest cmake_generator: -G "Unix Makefiles" continue-on-error: false + assign_permission: chmod u+x ./build/_CPack_Packages/${{ matrix.alias }}/TGZ/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx alias: Linux - os: macos-latest cmake_generator: -G "Xcode" continue-on-error: false + assign_permission: chmod u+x ./build/_CPack_Packages/${{ matrix.alias }}/TGZ/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx alias: Darwin runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.continue-on-error }} @@ -58,6 +61,7 @@ jobs: # required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | + ${{ matrix.assign_permission }} ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./examples/example.inp ./examples/example.msx ./examples/example.rpt ./examples/example.out - name: Upload artifacts From 577d22a0e7f34f68891a22cb4ba63a6dfacd35f2 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 16:49:32 -0500 Subject: [PATCH 28/32] Run example in actions --- .github/workflows/build-and-test.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f9562f3..7467223 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -10,6 +10,9 @@ on: jobs: build: name: Build, Unit Testing, and Regression Testing + environment: testing + env: + BuildVersion: 2.0.0 strategy: fail-fast: false matrix: @@ -18,23 +21,20 @@ jobs: - os: windows-latest cmake_generator: -G "Visual Studio 17 2022" -A "x64" continue-on-error: false - assign_permission: alias: win64 + assign_permission: - os: ubuntu-latest cmake_generator: -G "Unix Makefiles" continue-on-error: false - assign_permission: chmod u+x ./build/_CPack_Packages/${{ matrix.alias }}/TGZ/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx alias: Linux + assign_permission: chmod u+x ./build/_CPack_Packages/${{ matrix.alias }}/TGZ/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx - os: macos-latest cmake_generator: -G "Xcode" continue-on-error: false - assign_permission: chmod u+x ./build/_CPack_Packages/${{ matrix.alias }}/TGZ/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx alias: Darwin + assign_permission: chmod u+x ./build/_CPack_Packages/${{ matrix.alias }}/TGZ/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.continue-on-error }} - environment: testing - env: - BuildVersion: 2.0.0 steps: From e8b48b1de440a3d239c3cfe10a6c660d5a713963 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 16:55:38 -0500 Subject: [PATCH 29/32] Run example in actions --- .github/workflows/build-and-test.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7467223..bddc45b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -22,17 +22,14 @@ jobs: cmake_generator: -G "Visual Studio 17 2022" -A "x64" continue-on-error: false alias: win64 - assign_permission: - os: ubuntu-latest cmake_generator: -G "Unix Makefiles" continue-on-error: false alias: Linux - assign_permission: chmod u+x ./build/_CPack_Packages/${{ matrix.alias }}/TGZ/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx - os: macos-latest cmake_generator: -G "Xcode" continue-on-error: false alias: Darwin - assign_permission: chmod u+x ./build/_CPack_Packages/${{ matrix.alias }}/TGZ/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx runs-on: ${{ matrix.os }} continue-on-error: ${{ matrix.continue-on-error }} @@ -56,13 +53,23 @@ jobs: cmake -B .\build ${{ matrix.cmake_generator }} . cmake --build .\build --config Release --target package - - name: Run Example + - name: Run Example on Windows # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only # required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + if: ${{ matrix.os == 'windows-latest' }} run: | - ${{ matrix.assign_permission }} ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./examples/example.inp ./examples/example.msx ./examples/example.rpt ./examples/example.out + + - name: Run Example on Linux and MacOS + # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only + # required if you are using a single-configuration generator such as make. + # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type + if: ${{ matrix.os != 'windows-latest' }} + run: | + chmod +x ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx + ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./examples/example.inp ./examples/example.msx ./examples/example.rpt ./examples/example.out + - name: Upload artifacts if: ${{ always() }} From ec24b852988903586fb7e71dcc9600a175a71f76 Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 16:58:02 -0500 Subject: [PATCH 30/32] Run example in actions --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index bddc45b..f670730 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -50,8 +50,8 @@ jobs: # required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: | - cmake -B .\build ${{ matrix.cmake_generator }} . - cmake --build .\build --config Release --target package + cmake -B build ${{ matrix.cmake_generator }} . + cmake --build build --config Release --target package - name: Run Example on Windows # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only From bf63aa1fe2f817e295795f0edd6c36cee8ac567c Mon Sep 17 00:00:00 2001 From: Caleb Date: Wed, 15 Nov 2023 17:01:21 -0500 Subject: [PATCH 31/32] Run example in actions --- .github/workflows/build-and-test.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f670730..9b30a0e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -59,7 +59,7 @@ jobs: # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type if: ${{ matrix.os == 'windows-latest' }} run: | - ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./examples/example.inp ./examples/example.msx ./examples/example.rpt ./examples/example.out + ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./Examples/example.inp ./Examples/example.msx ./Examples/example.rpt ./Examples/example.out - name: Run Example on Linux and MacOS # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only @@ -67,8 +67,9 @@ jobs: # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type if: ${{ matrix.os != 'windows-latest' }} run: | + chmod +x ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanet chmod +x ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx - ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./examples/example.inp ./examples/example.msx ./examples/example.rpt ./examples/example.out + ./build/_CPack_Packages/${{ matrix.alias }}/ZIP/EPANETMSX-${{ env.BuildVersion }}-${{ matrix.alias }}/bin/runepanetmsx ./Examples/example.inp ./Examples/example.msx ./Examples/example.rpt ./Examples/example.out - name: Upload artifacts From 8230e1f600fa7a3765408473e4a2ac8ec30137db Mon Sep 17 00:00:00 2001 From: Caleb Date: Thu, 16 Nov 2023 12:09:02 -0500 Subject: [PATCH 32/32] Fix conflicting names in smatrix between epanet and msx --- readme.md | 4 ---- src/solver/msxdispersion.c | 2 +- src/solver/msxproj.c | 2 +- src/solver/smatrix.c | 20 ++++++++++---------- src/solver/smatrix.h | 8 +++++--- 5 files changed, 17 insertions(+), 19 deletions(-) diff --git a/readme.md b/readme.md index 29d98f8..6337c99 100644 --- a/readme.md +++ b/readme.md @@ -16,12 +16,8 @@ using CMake, first open a console window and navigate to the project's root dire ``` cmake -B build . cmake --build build --config Release --target package - ``` -Note: under Windows, the third command should be cmake .. -A Win32 for a 32-bit build or cmake .. -A x64 for a 64-bit build -when Microsoft Visual Studio is the default compiler. 64-bit EPANETMSX application need to work with 64-bit EPANET2 engine. - # Documentation EPANET-MSX manual can be found here: [MSX manual](https://github.com/USEPA/EPANETMSX/blob/master/Doc/EPANETMSX.pdf) diff --git a/src/solver/msxdispersion.c b/src/solver/msxdispersion.c index b0e1cc8..e18c364 100644 --- a/src/solver/msxdispersion.c +++ b/src/solver/msxdispersion.c @@ -382,7 +382,7 @@ void solve_nodequal(int m, double tstep) } } - int errcode = linsolve(njuncs, MSX.Dispersion.Aii, MSX.Dispersion.Aij, MSX.Dispersion.F); + int errcode = msx_linsolve(njuncs, MSX.Dispersion.Aii, MSX.Dispersion.Aij, MSX.Dispersion.F); for (int i = 1; i <= njuncs; i++) { diff --git a/src/solver/msxproj.c b/src/solver/msxproj.c index 072e113..c9c45ac 100644 --- a/src/solver/msxproj.c +++ b/src/solver/msxproj.c @@ -145,7 +145,7 @@ int MSXproj_open(char *fname) ENgetoption(13, &relvis); MSX.Dispersion.viscosity = relvis * 1.1E-5; - createsparse(); //symmetric matrix + msx_createsparse(); //symmetric matrix } // Build nodal adjacency lists diff --git a/src/solver/smatrix.c b/src/solver/smatrix.c index 65b482f..0d25dd1 100644 --- a/src/solver/smatrix.c +++ b/src/solver/smatrix.c @@ -12,9 +12,9 @@ AUTHOR: L. Rossman This module contains the sparse matrix routines used to solve a network's hydraulic equations. The entry points into this module are: - createsparse() -- called from openhyd() in HYDRAUL.C - freesparse() -- called from closehyd() in HYDRAUL.C - linsolve() -- called from netsolve() in HYDRAUL.C + msx_createsparse() -- called from openhyd() in HYDRAUL.C + msx_freesparse() -- called from closehyd() in HYDRAUL.C + msx_linsolve() -- called from netsolve() in HYDRAUL.C Createsparse() does the following: 1. for each node, builds an adjacency list that identifies @@ -52,7 +52,7 @@ extern MSXproject MSX; // MSX project data -int createsparse() +int msx_createsparse() /* **-------------------------------------------------------------- ** Input: none @@ -88,7 +88,7 @@ int createsparse() ERRCODE(storesparse(njuncs)); /* Free memory used for adjacency lists and sort */ - /* row indexes in NZSUB to optimize linsolve(). */ + /* row indexes in NZSUB to optimize msx_linsolve(). */ if (!errcode) freelists(); ERRCODE(ordersparse(njuncs)); @@ -124,7 +124,7 @@ int createsparse() /* Free allocated memory */ free(MSX.Dispersion.Degree); return(errcode); -} /* End of createsparse */ +} /* End of msx_createsparse */ int allocsparse() @@ -158,7 +158,7 @@ int allocsparse() } -void freesparse() +void msx_freesparse() /* **---------------------------------------------------------------- ** Input: None @@ -190,7 +190,7 @@ void freesparse() -} /* End of freesparse */ +} /* End of msx_freesparse */ int buildlists(int paraflag) @@ -671,7 +671,7 @@ void transpose(int n, int *il, int *jl, int *xl, int *ilt, int *jlt, } /* End of transpose */ -int linsolve(int n, double *Aii, double *Aij, double *B) +int msx_linsolve(int n, double *Aii, double *Aij, double *B) /* **-------------------------------------------------------------- ** Input: n = number of equations @@ -809,7 +809,7 @@ int linsolve(int n, double *Aii, double *Aij, double *B) } return(errcode); -} /* End of linsolve */ +} /* End of msx_linsolve */ /************************ END OF SMATRIX.C ************************/ diff --git a/src/solver/smatrix.h b/src/solver/smatrix.h index 7736e9b..f46fc7c 100644 --- a/src/solver/smatrix.h +++ b/src/solver/smatrix.h @@ -2,10 +2,12 @@ #ifndef SMATRIX_H #define SMATRIX_H +#include "msxtypes.h" + /* ----------- SMATRIX.C ---------------*/ -int createsparse(void); /* Creates sparse matrix */ +int msx_createsparse(void); /* Creates sparse matrix */ int allocsparse(void); /* Allocates matrix memory */ -void freesparse(void); /* Frees matrix memory */ +void msx_freesparse(void); /* Frees matrix memory */ int buildlists(int); /* Builds adjacency lists */ int paralink(int, int, int); /* Checks for parallel links */ void xparalinks(void); /* Removes parallel links */ @@ -21,7 +23,7 @@ int storesparse(int); /* Stores sparse matrix */ int ordersparse(int); /* Orders matrix storage */ void transpose(int, int*, int*, /* Transposes sparse matrix */ int*, int*, int*, int*, int*); -int linsolve(int, double*, double*, /* Solution of linear eqns. */ +int msx_linsolve(int, double*, double*, /* Solution of linear eqns. */ double*); /* via Cholesky factorization */ #endif \ No newline at end of file