From b46b67ec47fabe65f55eef1c1c1b030792017eda Mon Sep 17 00:00:00 2001 From: xuxi Date: Tue, 30 Jun 2020 18:53:48 +0800 Subject: [PATCH 01/10] fix a typo in Curve::getYofX(double x) method --- src/Elements/curve.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Elements/curve.cpp b/src/Elements/curve.cpp index 59ddcca..9ad6fd1 100644 --- a/src/Elements/curve.cpp +++ b/src/Elements/curve.cpp @@ -71,7 +71,7 @@ double Curve::getYofX(double x) { double dx = xData[i] - xData[i-1]; if ( dx == 0.0 ) return yData[i-1]; - return yData[i-1] + (x - yData[i-1]) / dx * (yData[i] - yData[i-1]); + return yData[i-1] + (x - xData[i-1]) / dx * (yData[i] - yData[i-1]); } } return yData[xData.size()-1]; From a1dc45171b2ee906c79183f102baa1d58f46400f Mon Sep 17 00:00:00 2001 From: xuxi Date: Sat, 11 Jul 2020 00:28:31 +0800 Subject: [PATCH 02/10] fix a time parse issue (with units) in Utilities::getSeconds method --- src/Utilities/utilities.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Utilities/utilities.cpp b/src/Utilities/utilities.cpp index 7a53c96..0687d66 100644 --- a/src/Utilities/utilities.cpp +++ b/src/Utilities/utilities.cpp @@ -233,10 +233,10 @@ int Utilities::getSeconds(const string& strTime, const string& strUnits) // determine time units and convert time accordingly - if (match(strUnits, s_Day) == 0) return (int) (3600. * 24. * t); - if (match(strUnits, s_Hour) == 0) return (int) (3600. * t); - if (match(strUnits, s_Minute) == 0) return (int) (60. * t); - if (match(strUnits, s_Second) == 0) return (int) t; + if (match(strUnits, s_Day)) return (int) (3600. * 24. * t); + if (match(strUnits, s_Hour)) return (int) (3600. * t); + if (match(strUnits, s_Minute)) return (int) (60. * t); + if (match(strUnits, s_Second)) return (int) t; // if AM/PM supplied, time is in hours and adjust it accordingly From 8dcae2faabfcfc8085b506778f0c04bfd36db930 Mon Sep 17 00:00:00 2001 From: xuxi Date: Sat, 4 Sep 2021 13:31:50 +0800 Subject: [PATCH 03/10] fix: the time units of pipe/tank's reaction coefficients are not consistent with global reaction coefficients (Bulk/Wall) --- src/Input/linkparser.cpp | 6 +++--- src/Input/nodeparser.cpp | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/Input/linkparser.cpp b/src/Input/linkparser.cpp index 8e94104..4841578 100644 --- a/src/Input/linkparser.cpp +++ b/src/Input/linkparser.cpp @@ -201,10 +201,10 @@ void LinkParser::parseReaction(Link* link, int type, vector& tokenList) throw InputError(InputError::INVALID_NUMBER, tokens[1]); } - // ... save reaction coeff. converted to 1/sec + // ... save reaction coeff. - if (type == Link::BULK) pipe->bulkCoeff = x / SECperDAY; - else if (type == Link::WALL) pipe->wallCoeff = x / SECperDAY; + if (type == Link::BULK) pipe->bulkCoeff = x; + else if (type == Link::WALL) pipe->wallCoeff = x; } //----------------------------------------------------------------------------- diff --git a/src/Input/nodeparser.cpp b/src/Input/nodeparser.cpp index 5a40b2b..ba9abba 100644 --- a/src/Input/nodeparser.cpp +++ b/src/Input/nodeparser.cpp @@ -228,10 +228,6 @@ void NodeParser::parseTankReact(Node* node, vector& tokenList) { throw InputError(InputError::INVALID_NUMBER, tokens[1]); } - - // ... convert coefficient to 1/sec - - tank->bulkCoeff /= 86400; } //----------------------------------------------------------------------------- From daf9643b6292d28d6e041c32be8a111626708a51 Mon Sep 17 00:00:00 2001 From: xuxi Date: Sat, 4 Sep 2021 15:31:02 +0800 Subject: [PATCH 04/10] fix NodeParser:parseTankReact - the index of reaction coeff. number in the tokens should be 2, but not 1 --- src/Input/nodeparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Input/nodeparser.cpp b/src/Input/nodeparser.cpp index ba9abba..42f3283 100644 --- a/src/Input/nodeparser.cpp +++ b/src/Input/nodeparser.cpp @@ -224,7 +224,7 @@ void NodeParser::parseTankReact(Node* node, vector& tokenList) // ... read reaction coefficient in 1/days - if ( !Utilities::parseNumber(tokens[1], tank->bulkCoeff) ) + if ( !Utilities::parseNumber(tokens[2], tank->bulkCoeff) ) { throw InputError(InputError::INVALID_NUMBER, tokens[1]); } From 28b2f3a2da9cbd49c0fbb67a3d3485d6583327b6 Mon Sep 17 00:00:00 2001 From: xuxi Date: Sun, 5 Sep 2021 16:19:15 +0800 Subject: [PATCH 05/10] fix hydraulic radius conversion during finding the wall reaction rate --- src/Models/qualmodel.cpp | 6 +++++- src/Models/qualmodel.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Models/qualmodel.cpp b/src/Models/qualmodel.cpp index a9a3816..9dac4d9 100644 --- a/src/Models/qualmodel.cpp +++ b/src/Models/qualmodel.cpp @@ -60,6 +60,7 @@ ChemModel::ChemModel() : QualModel(CHEM) wallOrder = 1.0; // pipe wall reaction order pipeUcf = 1.0; // volume conversion factor for pipes tankUcf = 1.0; // volume conversion factor for tanks + radiusUcf = 1.0; // hydraulic radius conversion factor for pipes cLimit = 0.001; // min/max concentration limit (mass/ft3) } @@ -80,6 +81,8 @@ void ChemModel::init(Network* nw) pipeUcf = pow(LperFT3, (1.0 - pipeOrder)); tankUcf = pow(LperFT3, (1.0 - tankOrder)); + radiusUcf = nw->ucf(Units::LENGTH); + // save diffusuivity, viscosity & Schmidt number diffus = nw->option(Options::MOLEC_DIFFUSIVITY); viscos = nw->option(Options::KIN_VISCOSITY); @@ -236,7 +239,7 @@ double ChemModel::findWallRate(double kw, double d, double order, double c) if ( massTransCoeff == 0.0 ) { if (order == 0.0) c = 1.0; - return c * kw / rh; + return c * kw / rh / radiusUcf; } // ... otherwise rate is combination of wall & mass transfer coeff. @@ -257,6 +260,7 @@ double ChemModel::findWallRate(double kw, double d, double order, double c) else { double kf = massTransCoeff; + kw /= radiusUcf; return c * kw * kf / (kf + abs(kw)) / rh; } } diff --git a/src/Models/qualmodel.h b/src/Models/qualmodel.h index f1ad0fe..752c645 100644 --- a/src/Models/qualmodel.h +++ b/src/Models/qualmodel.h @@ -88,6 +88,7 @@ class ChemModel : public QualModel double massTransCoeff; // a pipe's mass transfer coeff. (ft/sec) double pipeUcf; // volume conversion factor for pipes double tankUcf; // volume conversion factor for tanks + double radiusUcf; // hydraulic radius conversion factor for pipes double cLimit; // min/max concentration limit (mass/ft3) bool setReactive(Network* nw); From 25b99e4aedd297bcc243c241e2f0e4c8f78acf47 Mon Sep 17 00:00:00 2001 From: xuxi Date: Sun, 5 Sep 2021 16:51:52 +0800 Subject: [PATCH 06/10] fix the token index when parse fail for reaction coefficient --- src/Input/nodeparser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Input/nodeparser.cpp b/src/Input/nodeparser.cpp index 42f3283..51158dc 100644 --- a/src/Input/nodeparser.cpp +++ b/src/Input/nodeparser.cpp @@ -226,7 +226,7 @@ void NodeParser::parseTankReact(Node* node, vector& tokenList) if ( !Utilities::parseNumber(tokens[2], tank->bulkCoeff) ) { - throw InputError(InputError::INVALID_NUMBER, tokens[1]); + throw InputError(InputError::INVALID_NUMBER, tokens[2]); } } From b97f6588c1ca729fe82d3377b6bb5d38189965c1 Mon Sep 17 00:00:00 2001 From: xuxi Date: Sun, 19 Sep 2021 14:50:18 +0800 Subject: [PATCH 07/10] add pipe wall coefficiency conversion factor in ChemModel instead of hydraulic radius conversion factor --- src/Models/qualmodel.cpp | 14 +++++++++----- src/Models/qualmodel.h | 2 +- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Models/qualmodel.cpp b/src/Models/qualmodel.cpp index 9dac4d9..f1309b9 100644 --- a/src/Models/qualmodel.cpp +++ b/src/Models/qualmodel.cpp @@ -60,7 +60,7 @@ ChemModel::ChemModel() : QualModel(CHEM) wallOrder = 1.0; // pipe wall reaction order pipeUcf = 1.0; // volume conversion factor for pipes tankUcf = 1.0; // volume conversion factor for tanks - radiusUcf = 1.0; // hydraulic radius conversion factor for pipes + wallUcf = 1.0; // wall reaction coefficient conversion factor for pipes cLimit = 0.001; // min/max concentration limit (mass/ft3) } @@ -81,7 +81,12 @@ void ChemModel::init(Network* nw) pipeUcf = pow(LperFT3, (1.0 - pipeOrder)); tankUcf = pow(LperFT3, (1.0 - tankOrder)); - radiusUcf = nw->ucf(Units::LENGTH); + // wall reaction coefficient conversion + double ucf = nw->ucf(Units::LENGTH); + if (wallOrder == 0) + wallUcf = ucf * ucf; + else + wallUcf = 1.0 / ucf; // save diffusuivity, viscosity & Schmidt number diffus = nw->option(Options::MOLEC_DIFFUSIVITY); @@ -166,7 +171,7 @@ double ChemModel::pipeReact(Pipe* pipe, double c, double tstep) double kb = pipe->bulkCoeff / SECperDAY; if ( kb != 0.0 ) dCdT = findBulkRate(kb, pipeOrder, c) * pipeUcf; - double kw = pipe->wallCoeff / SECperDAY; + double kw = pipe->wallCoeff / SECperDAY * wallUcf; if ( kw != 0.0 ) dCdT += findWallRate(kw, pipe->diameter, wallOrder, c); c = c + dCdT * tstep; @@ -239,7 +244,7 @@ double ChemModel::findWallRate(double kw, double d, double order, double c) if ( massTransCoeff == 0.0 ) { if (order == 0.0) c = 1.0; - return c * kw / rh / radiusUcf; + return c * kw / rh; } // ... otherwise rate is combination of wall & mass transfer coeff. @@ -260,7 +265,6 @@ double ChemModel::findWallRate(double kw, double d, double order, double c) else { double kf = massTransCoeff; - kw /= radiusUcf; return c * kw * kf / (kf + abs(kw)) / rh; } } diff --git a/src/Models/qualmodel.h b/src/Models/qualmodel.h index 752c645..9c8e512 100644 --- a/src/Models/qualmodel.h +++ b/src/Models/qualmodel.h @@ -88,7 +88,7 @@ class ChemModel : public QualModel double massTransCoeff; // a pipe's mass transfer coeff. (ft/sec) double pipeUcf; // volume conversion factor for pipes double tankUcf; // volume conversion factor for tanks - double radiusUcf; // hydraulic radius conversion factor for pipes + double wallUcf; // wall reaction coefficient conversion factor for pipes double cLimit; // min/max concentration limit (mass/ft3) bool setReactive(Network* nw); From 7dcf62b6bfdb61ca4446804a5676d40d3093281d Mon Sep 17 00:00:00 2001 From: xuxi Date: Sat, 21 May 2022 22:03:56 +0800 Subject: [PATCH 08/10] fix - OptionParser::parseQualOption doesn't consider the cases for "Quality Trace" mode: the trace node has not been specified; the specified trace node doesn't exist --- src/Input/optionparser.cpp | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/Input/optionparser.cpp b/src/Input/optionparser.cpp index 822be2a..bb66226 100644 --- a/src/Input/optionparser.cpp +++ b/src/Input/optionparser.cpp @@ -471,25 +471,25 @@ void OptionParser::parseQualOption(const string& s2, const string& s3, network->options.setOption(Options::QUAL_UNITS, Options::MGL); } - if ( !s3.empty() ) + if (network->option(Options::QUAL_TYPE) == Options::TRACE) { - if ( network->option(Options::QUAL_TYPE) == Options::TRACE ) - { - int nodeIndex = network->indexOf(Element::NODE, s3); - if (i < 0) throw InputError(InputError::UNDEFINED_OBJECT, s3); - network->options.setOption(Options::TRACE_NODE, nodeIndex); - network->options.setOption(Options::TRACE_NODE_NAME, s3); - } - if ( network->option(Options::QUAL_TYPE) == Options::CHEM ) - { - string s3U = Utilities::upperCase(s3); - if ( s3U.compare("MG/L") == 0 ) - network->options.setOption(Options::QUAL_UNITS, Options::MGL); - else if ( s3U.compare("UG/L") == 0 ) - network->options.setOption(Options::QUAL_UNITS, Options::UGL); - else throw InputError(InputError::INVALID_KEYWORD, s3); - } - } + if (s3.empty()) throw InputError(InputError::UNDEFINED_OBJECT, s3); + int nodeIndex = network->indexOf(Element::NODE, s3); + if (nodeIndex < 0) throw InputError(InputError::UNDEFINED_OBJECT, s3); + network->options.setOption(Options::TRACE_NODE, nodeIndex); + network->options.setOption(Options::TRACE_NODE_NAME, s3); + } + + if (network->option(Options::QUAL_TYPE) == Options::CHEM) + { + if (s3.empty()) throw InputError(InputError::INVALID_KEYWORD, s3); + string s3U = Utilities::upperCase(s3); + if (s3U.compare("MG/L") == 0) + network->options.setOption(Options::QUAL_UNITS, Options::MGL); + else if (s3U.compare("UG/L") == 0) + network->options.setOption(Options::QUAL_UNITS, Options::UGL); + else throw InputError(InputError::INVALID_KEYWORD, s3); + } } //----------------------------------------------------------------------------- From cc3bc0d6cbf926b2191e53498683e71da2c77cb0 Mon Sep 17 00:00:00 2001 From: xuxi Date: Tue, 31 May 2022 23:05:49 +0800 Subject: [PATCH 09/10] for the CHEM quality type, the use of a third token to contain the chemical units is optional. --- src/Input/optionparser.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Input/optionparser.cpp b/src/Input/optionparser.cpp index bb66226..e34d510 100644 --- a/src/Input/optionparser.cpp +++ b/src/Input/optionparser.cpp @@ -480,9 +480,8 @@ void OptionParser::parseQualOption(const string& s2, const string& s3, network->options.setOption(Options::TRACE_NODE_NAME, s3); } - if (network->option(Options::QUAL_TYPE) == Options::CHEM) + if (network->option(Options::QUAL_TYPE) == Options::CHEM && !s3.empty()) { - if (s3.empty()) throw InputError(InputError::INVALID_KEYWORD, s3); string s3U = Utilities::upperCase(s3); if (s3U.compare("MG/L") == 0) network->options.setOption(Options::QUAL_UNITS, Options::MGL); From 59f775af8ba6233ea686897c11896c141cdb9b2b Mon Sep 17 00:00:00 2001 From: xuxi Date: Mon, 12 Dec 2022 09:37:44 +0800 Subject: [PATCH 10/10] fix - the last volume segment should be initialized as the first volume segment during intializing a tank's mixing model --- src/Models/tankmixmodel.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Models/tankmixmodel.cpp b/src/Models/tankmixmodel.cpp index dfd28c1..f873dd6 100644 --- a/src/Models/tankmixmodel.cpp +++ b/src/Models/tankmixmodel.cpp @@ -46,10 +46,10 @@ void TankMixModel::init(Tank* tank, SegPool* segPool, double _cTol) vMixed = fracMixed * tank->maxVolume; // ... create a volume segment for the entire tank - lastSeg = nullptr; firstSeg = segPool->getSegment(tank->volume, cTank); if ( firstSeg == nullptr ) throw SystemError(SystemError::OUT_OF_MEMORY); + lastSeg = firstSeg; // ... create a second segment for the 2-compartment model if ( type == MIX2 )