From 66db3f41a467611d7fe13ac601cc6cdb2fab367b Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Wed, 6 Dec 2017 15:27:53 -0600 Subject: [PATCH 01/45] add surfaceArea to node parameters --- src/node.c | 2 +- src/objects.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node.c b/src/node.c index 2606c620e..9dbe735de 100644 --- a/src/node.c +++ b/src/node.c @@ -381,7 +381,7 @@ double node_getSurfArea(int j, double d) switch (Node[j].type) { case STORAGE: return storage_getSurfArea(j, d); - default: return 0.0; + default: return Node[j].surfaceArea; } } diff --git a/src/objects.h b/src/objects.h index 9ade1359d..9754bfaf4 100644 --- a/src/objects.h +++ b/src/objects.h @@ -499,6 +499,7 @@ typedef struct double fullDepth; // dist. from invert to surface (ft) double surDepth; // added depth under surcharge (ft) double pondedArea; // area filled by ponded water (ft2) + double surfaceArea; // area used to calculate node's volume (ft2) TExtInflow* extInflow; // pointer to external inflow data TDwfInflow* dwfInflow; // pointer to dry weather flow inflow data TRdiiInflow* rdiiInflow; // pointer to RDII inflow data From 26cb1d7a6adf78e4710d0b93ede3a01a77f26205 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Wed, 6 Dec 2017 15:30:38 -0600 Subject: [PATCH 02/45] add setter and getter for node surfaceArea --- src/toolkitAPI.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 631b75387..4a6b9d00f 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -371,6 +371,8 @@ int DLLEXPORT swmm_getNodeParam(int index, int Param, double *value) case 3: *value = Node[index].pondedArea * UCF(LENGTH) * UCF(LENGTH); break; // initDepth case 4: *value = Node[index].initDepth * UCF(LENGTH); break; + // surfaceArea + case 5: *value = Node[index].surfaceArea * UCF(LENGTH) * UCF(LENGTH); break; // Type not available default: return(ERR_API_OUTBOUNDS); } @@ -404,6 +406,8 @@ int DLLEXPORT swmm_setNodeParam(int index, int Param, double value) case 3: Node[index].pondedArea = value / ( UCF(LENGTH) * UCF(LENGTH) ); break; // initDepth case 4: Node[index].initDepth = value / UCF(LENGTH); break; + // surfaceArea + case 5: Node[index].surfaceArea = value / UCF(LENGTH) * UCF(LENGTH); break; // Type not available default: return(ERR_API_OUTBOUNDS); } @@ -1232,4 +1236,4 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage) Outfall[k].outfallStage = stage / UCF(LENGTH); } return(errcode); -} \ No newline at end of file +} From 6e90eaacd7467f31d70bdeceef0bf33f70565e6b Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Fri, 8 Dec 2017 10:33:31 -0600 Subject: [PATCH 03/45] set fullVolume at the same time than surfaceArea --- src/toolkitAPI.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 4a6b9d00f..341b3d6e0 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -407,7 +407,10 @@ int DLLEXPORT swmm_setNodeParam(int index, int Param, double value) // initDepth case 4: Node[index].initDepth = value / UCF(LENGTH); break; // surfaceArea - case 5: Node[index].surfaceArea = value / UCF(LENGTH) * UCF(LENGTH); break; + case 5: + Node[index].surfaceArea = value / UCF(LENGTH) * UCF(LENGTH); + Node[index].fullVolume = Node[index].surfaceArea * Node[index].fullDepth; + break; // Type not available default: return(ERR_API_OUTBOUNDS); } From 4d796157880a852bb08065c2ec61c895f5445842 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Fri, 8 Dec 2017 10:49:52 -0600 Subject: [PATCH 04/45] set fullVolume as a result of node_getVolume(). Change the calculation of the latter to use surfaceArea --- src/node.c | 2 +- src/toolkitAPI.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node.c b/src/node.c index 9dbe735de..74cb7bc0d 100644 --- a/src/node.c +++ b/src/node.c @@ -363,7 +363,7 @@ double node_getVolume(int j, double d) default: if ( Node[j].fullDepth > 0.0 ) - return Node[j].fullVolume * (d / Node[j].fullDepth); + return Node[j].surfaceArea * d; else return 0.0; } } diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 341b3d6e0..99693c920 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -409,7 +409,7 @@ int DLLEXPORT swmm_setNodeParam(int index, int Param, double value) // surfaceArea case 5: Node[index].surfaceArea = value / UCF(LENGTH) * UCF(LENGTH); - Node[index].fullVolume = Node[index].surfaceArea * Node[index].fullDepth; + Node[index].fullVolume = node_getVolume(index, Node[index].fullDepth); break; // Type not available default: return(ERR_API_OUTBOUNDS); From a6bb5b4c1be76eb7d8c987c2144aac05cab1c87a Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Fri, 8 Dec 2017 13:50:44 -0600 Subject: [PATCH 05/45] add node lid opening object. Add it as a property of Node --- src/objects.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/objects.h b/src/objects.h index 9754bfaf4..4f8b6f676 100644 --- a/src/objects.h +++ b/src/objects.h @@ -436,6 +436,22 @@ struct ExtInflow typedef struct ExtInflow TExtInflow; +//------------------------------ +// NODE LID OPENING OBJECT +//------------------------------ +struct LidOpening +{ + int type; // type of opening (grate, etc). From an enum + double area; // area of the opening (ft2) + double length; // length of the opening (~circumference, ft) + double coeffOrifice; // orifice coefficient + double coeffFreeWeir; // free weir coefficient + double coeffSubWeir; // submerged weir coefficient + struct LidOpening* next; // pointer to next opening data object +}; +typedef struct LidOpening TLidOpening; + + //------------------------------- // DRY WEATHER FLOW INFLOW OBJECT //------------------------------- @@ -504,6 +520,7 @@ typedef struct TDwfInflow* dwfInflow; // pointer to dry weather flow inflow data TRdiiInflow* rdiiInflow; // pointer to RDII inflow data TTreatment* treatment; // array of treatment data + TLidOpening* lidOpening; // pointer to node lid opening data //----------------------------- int degree; // number of outflow links char updated; // true if state has been updated From 58f32e8119e488c2a44c4dfde846c4a8c2b76165 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Fri, 8 Dec 2017 14:07:18 -0600 Subject: [PATCH 06/45] add coupling type parameter to TNode. add corresponding enum --- src/enums.h | 7 +++++++ src/objects.h | 1 + 2 files changed, 8 insertions(+) diff --git a/src/enums.h b/src/enums.h index 142ab8be9..362c54d8c 100644 --- a/src/enums.h +++ b/src/enums.h @@ -471,3 +471,10 @@ enum NoneAllType { NONE, ALL, SOME}; + +enum SurfaceCouplingType { + NO_COUPLING, + NO_COUPLING_FLOW, + ORIFICE_COUPLING, + FREE_WEIR_COUPLING, + SUBMERGED_WEIR_COUPLING}; diff --git a/src/objects.h b/src/objects.h index 4f8b6f676..67c04419f 100644 --- a/src/objects.h +++ b/src/objects.h @@ -522,6 +522,7 @@ typedef struct TTreatment* treatment; // array of treatment data TLidOpening* lidOpening; // pointer to node lid opening data //----------------------------- + int surfCouplingType;// type of surface coupling (enum SurfaceCouplingType) int degree; // number of outflow links char updated; // true if state has been updated double crownElev; // top of highest connecting conduit (ft) From 9d53c9180a17aa51300725587533f7bb9eafb1cd Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Fri, 8 Dec 2017 14:24:55 -0600 Subject: [PATCH 07/45] rename lid opening to cover opening to prevent confusion with Low Impact Development. move coupling type from node to cover opening --- src/objects.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/objects.h b/src/objects.h index 67c04419f..4156ffba0 100644 --- a/src/objects.h +++ b/src/objects.h @@ -437,19 +437,20 @@ typedef struct ExtInflow TExtInflow; //------------------------------ -// NODE LID OPENING OBJECT +// NODE COVER OPENING OBJECT //------------------------------ -struct LidOpening +struct CoverOpening { - int type; // type of opening (grate, etc). From an enum - double area; // area of the opening (ft2) - double length; // length of the opening (~circumference, ft) - double coeffOrifice; // orifice coefficient - double coeffFreeWeir; // free weir coefficient - double coeffSubWeir; // submerged weir coefficient - struct LidOpening* next; // pointer to next opening data object + int type; // type of opening (grate, etc). From an enum + int couplingType; // type of surface coupling (enum SurfaceCouplingType) + double area; // area of the opening (ft2) + double length; // length of the opening (~circumference, ft) + double coeffOrifice; // orifice coefficient + double coeffFreeWeir; // free weir coefficient + double coeffSubWeir; // submerged weir coefficient + struct CoverOpening* next; // pointer to next opening data object }; -typedef struct LidOpening TLidOpening; +typedef struct CoverOpening TCoverOpening; //------------------------------- @@ -520,9 +521,8 @@ typedef struct TDwfInflow* dwfInflow; // pointer to dry weather flow inflow data TRdiiInflow* rdiiInflow; // pointer to RDII inflow data TTreatment* treatment; // array of treatment data - TLidOpening* lidOpening; // pointer to node lid opening data + TCoverOpening* coverOpening; // pointer to node cover opening data //----------------------------- - int surfCouplingType;// type of surface coupling (enum SurfaceCouplingType) int degree; // number of outflow links char updated; // true if state has been updated double crownElev; // top of highest connecting conduit (ft) From fa9282f1ac1564a257637d6ed099c1b56ca95b52 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Fri, 8 Dec 2017 19:17:00 -0600 Subject: [PATCH 08/45] add functions for 2D models coupling --- src/node.c | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 176 insertions(+), 1 deletion(-) diff --git a/src/node.c b/src/node.c index 74cb7bc0d..560e4fd73 100644 --- a/src/node.c +++ b/src/node.c @@ -7,7 +7,7 @@ // 09/15/14 (Build 5.1.007) // 04/02/15 (Build 5.1.008) // 08/05/15 (Build 5.1.010) -// Author: L. Rossman +// Authors: L. Rossman, Laurent Courty // // Conveyance system node functions. // @@ -83,6 +83,14 @@ static int divider_readParams(int j, int k, char* tok[], int ntoks); static void divider_validate(int j); static double divider_getOutflow(int j, int link); +static double node_getCouplingFlow(int j, double d); +static int node_isCoupled(int j); +static void node_findCouplingTypes(int j, double crestElev, + double surfaceElev, double nodeHead); +static void opening_findCouplingType(TCoverOpening* opening, double nodeHead, + double crestElev, double surfaceElev); +static double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, + double crestElev, double surfaceElev); //============================================================================= @@ -591,6 +599,173 @@ double node_getLosses(int j, double tStep) else return 0.0; } +//============================================================================= +// C O U P L I N G M E T H O D S +//============================================================================= + +double node_getCouplingFlow(int j, double d) +// +// Input: j = node index +// d = water depth on the surface, above the node crest (ft) +// Output: total inflow from coupling (ft3/s) +// Purpose: compute the coupling inflow for every openings +// +{ + double crestElev, surfaceElev, nodeHead; + double totalCouplingInflow; + TCoverOpening* opening; + + // --- calculate elevations + crestElev = Node[j].invertElev + Node[j].fullDepth; + nodeHead = Node[j].invertElev + Node[j].newDepth; + surfaceElev = crestElev + d; + + // --- init + totalCouplingInflow = 0.0; + + opening = Node[j].coverOpening; + // --- iterate among the openings. Add each flow to total inflow. + while ( opening ) + { + totalCouplingInflow += opening_getCouplingInflow(opening, nodeHead, + crestElev, surfaceElev); + opening = opening->next; + } + return(totalCouplingInflow); +} + +//============================================================================= + +int node_isCoupled(int j) +// +// Input: j = node index +// Output: returns the coupling status of a node (yes/no) +// Purpose: if at least one opening is coupled, return yes. +// +{ + TCoverOpening* opening; + + opening = Node[j].coverOpening; + // --- if not any cover, the node is not coupled + if ( !opening ) return NO; + // --- iterate among the openings. If one is coupled, return YES + while ( opening ) + { + if ( opening->couplingType != NO_COUPLING ) return YES; + opening = opening->next; + } + return NO; +} + +//============================================================================= + +void node_findCouplingTypes(int j, double crestElev, double surfaceElev, double nodeHead) +// +// Input: j = node index +// nodeHead = water elevation in the node (ft) +// crestElev = elevation of the node crest (= ground) (ft) +// surfaceElev = water elevation on the surface (ft) +// Output: none +// Purpose: calculate all coupling types of a node +// +{ + TCoverOpening* opening; + + opening = Node[j].coverOpening; + // --- iterate among the openings and find coupling + while ( opening ) + { + opening_findCouplingType(opening, nodeHead, crestElev, surfaceElev); + opening = opening->next; + } +} + +//============================================================================= + +void opening_findCouplingType(TCoverOpening* opening, double nodeHead, + double crestElev, double surfaceElev) +// +// Input: opening = a node opening data structure +// nodeHead = water elevation in the node (ft) +// crestElev = elevation of the node crest (= ground) (ft) +// surfaceElev = water elevation on the surface (ft) +// Output: nothing +// Purpose: determine the coupling type of an opening +// according the the relative water elevations in node and surface +// +{ + int overflow, drainage; + int overflowOrifice, drainageOrifice, submergedWeir, freeWeir; + double surfaceDepth, weirRatio; + double overflowArea = opening->area; + double weirWidth = opening->length; + + surfaceDepth = surfaceElev - crestElev; + weirRatio = overflowArea / weirWidth; + + // --- boolean cases. See DOI 10.1016/j.jhydrol.2017.06.024 + overflow = nodeHead > surfaceElev; + drainage = nodeHead < surfaceElev; + overflowOrifice = overflow; + drainageOrifice = drainage && + ((nodeHead > crestElev) && (surfaceDepth > weirRatio)); + submergedWeir = drainage && + ((nodeHead > crestElev) && (surfaceDepth < weirRatio)); + freeWeir = drainage && (nodeHead < crestElev); + + // --- set the coupling type + if ( !overflow && !drainage ) opening->couplingType = NO_COUPLING_FLOW; + else if ( overflowOrifice || drainageOrifice ) + opening->couplingType = ORIFICE_COUPLING; + else if ( submergedWeir ) opening->couplingType = SUBMERGED_WEIR_COUPLING; + else if ( freeWeir ) opening->couplingType = FREE_WEIR_COUPLING; + else opening->couplingType = NO_COUPLING_FLOW; +} + +//============================================================================= + +double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, + double crestElev, double surfaceElev) +// +// Input: opening = a node opening data structure +// nodeHead = water elevation in the node (ft) +// crestElev = elevation of the node crest (= ground) (ft) +// surfaceElev = water elevation on the surface (ft) +// Output: the flow entering through the opening (ft3/s) +// Purpose: computes the coupling flow of the opening +// +{ + double orificeCoeff, freeWeirCoeff, subWeirCoeff, overflowArea, weirWidth; + double headUp, headDown, headDiff, depthUp; + double orif_v, sweir_v, couplingFlow; + + orificeCoeff = opening->coeffOrifice; + freeWeirCoeff = opening->coeffFreeWeir; + subWeirCoeff = opening->coeffSubWeir; + overflowArea = opening->area; + weirWidth = opening->length; + + headUp = fmax(surfaceElev, nodeHead); + headDown = fmin(surfaceElev, nodeHead); + headDiff = headUp - headDown; + depthUp = headUp - crestElev; + + switch(opening->couplingType) + { + case ORIFICE_COUPLING: + orif_v = sqrt(2 * GRAVITY * headDiff); + couplingFlow = orificeCoeff * overflowArea * orif_v; + case FREE_WEIR_COUPLING: + couplingFlow = ((2/3.) * freeWeirCoeff * weirWidth * + pow(depthUp, 3/2.) * sqrt(2 * GRAVITY)); + case SUBMERGED_WEIR_COUPLING: + sweir_v = sqrt(2. * GRAVITY * depthUp); + couplingFlow = subWeirCoeff * weirWidth * depthUp * sweir_v; + default: couplingFlow = 0.0; + } + return(copysign(couplingFlow, surfaceElev-nodeHead)); +} + //============================================================================= // J U N C T I O N M E T H O D S //============================================================================= From 41f933974bebc3e7f6e007a1dd504cc6f91395f6 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sat, 9 Dec 2017 19:25:40 -0600 Subject: [PATCH 09/45] update AUTHORS --- AUTHORS | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index de9b3312c..4b9e15d0e 100644 --- a/AUTHORS +++ b/AUTHORS @@ -6,7 +6,9 @@ Adam Erispaha Sam Hatchett Gonzalo Peña-Castellanos Katherine Ratliff - +Lew Rossman +Laurent Courty + EmNet LLC From 4bf50d84d9b1e143b66227306590d417eb9c9dca Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sat, 9 Dec 2017 19:28:05 -0600 Subject: [PATCH 10/45] add copyright notice --- src/node.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/node.c b/src/node.c index 560e4fd73..4bf161adc 100644 --- a/src/node.c +++ b/src/node.c @@ -9,6 +9,9 @@ // 08/05/15 (Build 5.1.010) // Authors: L. Rossman, Laurent Courty // +// Contributions by Laurent Courty are copyrighted (c) +// and distributed under the MIT license (see LICENSE.txt) +// // Conveyance system node functions. // // Build 5.1.007: From 34a4a93d0896567fa159f3b024b00d598a1683b9 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 00:05:45 -0600 Subject: [PATCH 11/45] rename surfaceHead for consistency --- src/node.c | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/node.c b/src/node.c index 4bf161adc..2d902568e 100644 --- a/src/node.c +++ b/src/node.c @@ -89,11 +89,11 @@ static double divider_getOutflow(int j, int link); static double node_getCouplingFlow(int j, double d); static int node_isCoupled(int j); static void node_findCouplingTypes(int j, double crestElev, - double surfaceElev, double nodeHead); + double surfaceHead, double nodeHead); static void opening_findCouplingType(TCoverOpening* opening, double nodeHead, - double crestElev, double surfaceElev); + double crestElev, double surfaceHead); static double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, - double crestElev, double surfaceElev); + double crestElev, double surfaceHead); //============================================================================= @@ -614,14 +614,14 @@ double node_getCouplingFlow(int j, double d) // Purpose: compute the coupling inflow for every openings // { - double crestElev, surfaceElev, nodeHead; + double crestElev, surfaceHead, nodeHead; double totalCouplingInflow; TCoverOpening* opening; // --- calculate elevations crestElev = Node[j].invertElev + Node[j].fullDepth; nodeHead = Node[j].invertElev + Node[j].newDepth; - surfaceElev = crestElev + d; + surfaceHead = crestElev + d; // --- init totalCouplingInflow = 0.0; @@ -631,7 +631,7 @@ double node_getCouplingFlow(int j, double d) while ( opening ) { totalCouplingInflow += opening_getCouplingInflow(opening, nodeHead, - crestElev, surfaceElev); + crestElev, surfaceHead); opening = opening->next; } return(totalCouplingInflow); @@ -662,12 +662,12 @@ int node_isCoupled(int j) //============================================================================= -void node_findCouplingTypes(int j, double crestElev, double surfaceElev, double nodeHead) +void node_findCouplingTypes(int j, double crestElev, double surfaceHead, double nodeHead) // // Input: j = node index // nodeHead = water elevation in the node (ft) // crestElev = elevation of the node crest (= ground) (ft) -// surfaceElev = water elevation on the surface (ft) +// surfaceHead = water elevation on the surface (ft) // Output: none // Purpose: calculate all coupling types of a node // @@ -678,7 +678,7 @@ void node_findCouplingTypes(int j, double crestElev, double surfaceElev, double // --- iterate among the openings and find coupling while ( opening ) { - opening_findCouplingType(opening, nodeHead, crestElev, surfaceElev); + opening_findCouplingType(opening, nodeHead, crestElev, surfaceHead); opening = opening->next; } } @@ -686,12 +686,12 @@ void node_findCouplingTypes(int j, double crestElev, double surfaceElev, double //============================================================================= void opening_findCouplingType(TCoverOpening* opening, double nodeHead, - double crestElev, double surfaceElev) + double crestElev, double surfaceHead) // // Input: opening = a node opening data structure // nodeHead = water elevation in the node (ft) // crestElev = elevation of the node crest (= ground) (ft) -// surfaceElev = water elevation on the surface (ft) +// surfaceHead = water elevation on the surface (ft) // Output: nothing // Purpose: determine the coupling type of an opening // according the the relative water elevations in node and surface @@ -703,12 +703,12 @@ void opening_findCouplingType(TCoverOpening* opening, double nodeHead, double overflowArea = opening->area; double weirWidth = opening->length; - surfaceDepth = surfaceElev - crestElev; + surfaceDepth = surfaceHead - crestElev; weirRatio = overflowArea / weirWidth; // --- boolean cases. See DOI 10.1016/j.jhydrol.2017.06.024 - overflow = nodeHead > surfaceElev; - drainage = nodeHead < surfaceElev; + overflow = nodeHead > surfaceHead; + drainage = nodeHead < surfaceHead; overflowOrifice = overflow; drainageOrifice = drainage && ((nodeHead > crestElev) && (surfaceDepth > weirRatio)); @@ -728,12 +728,12 @@ void opening_findCouplingType(TCoverOpening* opening, double nodeHead, //============================================================================= double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, - double crestElev, double surfaceElev) + double crestElev, double surfaceHead) // // Input: opening = a node opening data structure // nodeHead = water elevation in the node (ft) // crestElev = elevation of the node crest (= ground) (ft) -// surfaceElev = water elevation on the surface (ft) +// surfaceHead = water elevation on the surface (ft) // Output: the flow entering through the opening (ft3/s) // Purpose: computes the coupling flow of the opening // @@ -748,8 +748,8 @@ double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, overflowArea = opening->area; weirWidth = opening->length; - headUp = fmax(surfaceElev, nodeHead); - headDown = fmin(surfaceElev, nodeHead); + headUp = fmax(surfaceHead, nodeHead); + headDown = fmin(surfaceHead, nodeHead); headDiff = headUp - headDown; depthUp = headUp - crestElev; @@ -766,7 +766,7 @@ double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, couplingFlow = subWeirCoeff * weirWidth * depthUp * sweir_v; default: couplingFlow = 0.0; } - return(copysign(couplingFlow, surfaceElev-nodeHead)); + return(copysign(couplingFlow, surfaceHead-nodeHead)); } //============================================================================= From 2cec36f1ca7d8622d9a209ea76d72f51231bd579 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 10:03:21 -0600 Subject: [PATCH 12/45] add oldInflow and newInflow values to opening object. Adjust functions accordingly --- src/node.c | 91 +++++++++++++++++++++++++++++++++------------------ src/objects.h | 2 ++ 2 files changed, 61 insertions(+), 32 deletions(-) diff --git a/src/node.c b/src/node.c index 2d902568e..e2418785b 100644 --- a/src/node.c +++ b/src/node.c @@ -86,14 +86,17 @@ static int divider_readParams(int j, int k, char* tok[], int ntoks); static void divider_validate(int j); static double divider_getOutflow(int j, int link); -static double node_getCouplingFlow(int j, double d); +// --- coupling functions (L. Courty) +static double node_getCouplingFlow(int j, double overlandDepth, + double overlandSurfArea); +static void node_setOldCouplingState(int j); static int node_isCoupled(int j); static void node_findCouplingTypes(int j, double crestElev, - double surfaceHead, double nodeHead); + double overlandHead, double nodeHead); static void opening_findCouplingType(TCoverOpening* opening, double nodeHead, - double crestElev, double surfaceHead); -static double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, - double crestElev, double surfaceHead); + double crestElev, double overlandHead); +static void opening_findCouplingInflow(TCoverOpening* opening, double nodeHead, + double crestElev, double overlandHead); //============================================================================= @@ -300,6 +303,8 @@ void node_setOldHydState(int j) { Node[j].oldDepth = Node[j].newDepth; Node[j].oldVolume = Node[j].newVolume; + // --- do it for overland model coupling + node_setOldCouplingState(j); } //============================================================================= @@ -606,32 +611,33 @@ double node_getLosses(int j, double tStep) // C O U P L I N G M E T H O D S //============================================================================= -double node_getCouplingFlow(int j, double d) +double node_getCouplingFlow(int j, double overlandDepth, double overlandSurfArea) // // Input: j = node index -// d = water depth on the surface, above the node crest (ft) +// overlandDepth = water depth in the overland model (ft) +// overlandSurfArea = surface in the overland model that is coupled to this node (ft2) // Output: total inflow from coupling (ft3/s) // Purpose: compute the coupling inflow for every openings // { - double crestElev, surfaceHead, nodeHead; + double crestElev, overlandHead, nodeHead; double totalCouplingInflow; TCoverOpening* opening; // --- calculate elevations crestElev = Node[j].invertElev + Node[j].fullDepth; nodeHead = Node[j].invertElev + Node[j].newDepth; - surfaceHead = crestElev + d; + overlandHead = crestElev + overlandDepth; // --- init totalCouplingInflow = 0.0; opening = Node[j].coverOpening; - // --- iterate among the openings. Add each flow to total inflow. + // --- iterate among the openings. Add each flow to total inflow. while ( opening ) { - totalCouplingInflow += opening_getCouplingInflow(opening, nodeHead, - crestElev, surfaceHead); + opening_findCouplingInflow(opening, nodeHead, crestElev, overlandHead); + totalCouplingInflow += opening->newInflow; opening = opening->next; } return(totalCouplingInflow); @@ -639,6 +645,26 @@ double node_getCouplingFlow(int j, double d) //============================================================================= +void node_setOldCouplingState(int j) +// +// Input: j = node index +// Output: none +// Purpose: replaces a node's old hydraulic coupling state values with new ones. +// +{ + TCoverOpening* opening; + + opening = Node[j].coverOpening; + // --- iterate among the openings. + while ( opening ) + { + opening->oldInflow = opening->newInflow; + opening = opening->next; + } +} + +//============================================================================= + int node_isCoupled(int j) // // Input: j = node index @@ -662,12 +688,12 @@ int node_isCoupled(int j) //============================================================================= -void node_findCouplingTypes(int j, double crestElev, double surfaceHead, double nodeHead) +void node_findCouplingTypes(int j, double crestElev, double overlandHead, double nodeHead) // // Input: j = node index // nodeHead = water elevation in the node (ft) // crestElev = elevation of the node crest (= ground) (ft) -// surfaceHead = water elevation on the surface (ft) +// overlandHead = water elevation in the overland model (ft) // Output: none // Purpose: calculate all coupling types of a node // @@ -678,7 +704,7 @@ void node_findCouplingTypes(int j, double crestElev, double surfaceHead, double // --- iterate among the openings and find coupling while ( opening ) { - opening_findCouplingType(opening, nodeHead, crestElev, surfaceHead); + opening_findCouplingType(opening, nodeHead, crestElev, overlandHead); opening = opening->next; } } @@ -686,12 +712,12 @@ void node_findCouplingTypes(int j, double crestElev, double surfaceHead, double //============================================================================= void opening_findCouplingType(TCoverOpening* opening, double nodeHead, - double crestElev, double surfaceHead) + double crestElev, double overlandHead) // // Input: opening = a node opening data structure // nodeHead = water elevation in the node (ft) // crestElev = elevation of the node crest (= ground) (ft) -// surfaceHead = water elevation on the surface (ft) +// overlandHead = water elevation in the overland model (ft) // Output: nothing // Purpose: determine the coupling type of an opening // according the the relative water elevations in node and surface @@ -703,12 +729,12 @@ void opening_findCouplingType(TCoverOpening* opening, double nodeHead, double overflowArea = opening->area; double weirWidth = opening->length; - surfaceDepth = surfaceHead - crestElev; + surfaceDepth = overlandHead - crestElev; weirRatio = overflowArea / weirWidth; // --- boolean cases. See DOI 10.1016/j.jhydrol.2017.06.024 - overflow = nodeHead > surfaceHead; - drainage = nodeHead < surfaceHead; + overflow = nodeHead > overlandHead; + drainage = nodeHead < overlandHead; overflowOrifice = overflow; drainageOrifice = drainage && ((nodeHead > crestElev) && (surfaceDepth > weirRatio)); @@ -727,20 +753,20 @@ void opening_findCouplingType(TCoverOpening* opening, double nodeHead, //============================================================================= -double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, - double crestElev, double surfaceHead) +void opening_findCouplingInflow(TCoverOpening* opening, double nodeHead, + double crestElev, double overlandHead) // // Input: opening = a node opening data structure // nodeHead = water elevation in the node (ft) // crestElev = elevation of the node crest (= ground) (ft) -// surfaceHead = water elevation on the surface (ft) +// overlandHead = water elevation in the overland model (ft) // Output: the flow entering through the opening (ft3/s) // Purpose: computes the coupling flow of the opening // { double orificeCoeff, freeWeirCoeff, subWeirCoeff, overflowArea, weirWidth; double headUp, headDown, headDiff, depthUp; - double orif_v, sweir_v, couplingFlow; + double orif_v, sweir_v, u_couplingFlow; orificeCoeff = opening->coeffOrifice; freeWeirCoeff = opening->coeffFreeWeir; @@ -748,8 +774,8 @@ double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, overflowArea = opening->area; weirWidth = opening->length; - headUp = fmax(surfaceHead, nodeHead); - headDown = fmin(surfaceHead, nodeHead); + headUp = fmax(overlandHead, nodeHead); + headDown = fmin(overlandHead, nodeHead); headDiff = headUp - headDown; depthUp = headUp - crestElev; @@ -757,16 +783,17 @@ double opening_getCouplingInflow(TCoverOpening* opening, double nodeHead, { case ORIFICE_COUPLING: orif_v = sqrt(2 * GRAVITY * headDiff); - couplingFlow = orificeCoeff * overflowArea * orif_v; + u_couplingFlow = orificeCoeff * overflowArea * orif_v; case FREE_WEIR_COUPLING: - couplingFlow = ((2/3.) * freeWeirCoeff * weirWidth * - pow(depthUp, 3/2.) * sqrt(2 * GRAVITY)); + u_couplingFlow = (2/3.) * freeWeirCoeff * weirWidth * + pow(depthUp, 3/2.) * sqrt(2 * GRAVITY); case SUBMERGED_WEIR_COUPLING: sweir_v = sqrt(2. * GRAVITY * depthUp); - couplingFlow = subWeirCoeff * weirWidth * depthUp * sweir_v; - default: couplingFlow = 0.0; + u_couplingFlow = subWeirCoeff * weirWidth * depthUp * sweir_v; + default: u_couplingFlow = 0.0; } - return(copysign(couplingFlow, surfaceHead-nodeHead)); + // --- Flow into the node is positive + opening->newInflow = copysign(u_couplingFlow, overlandHead - nodeHead); } //============================================================================= diff --git a/src/objects.h b/src/objects.h index 4156ffba0..b479e2a2b 100644 --- a/src/objects.h +++ b/src/objects.h @@ -448,6 +448,8 @@ struct CoverOpening double coeffOrifice; // orifice coefficient double coeffFreeWeir; // free weir coefficient double coeffSubWeir; // submerged weir coefficient + double oldInflow; // inflow during last time-step + double newInflow; // current inflow struct CoverOpening* next; // pointer to next opening data object }; typedef struct CoverOpening TCoverOpening; From 6bc4e85219d9eda5285734c1a9aa5b697b13e257 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 11:03:39 -0600 Subject: [PATCH 13/45] add stability helpers --- src/node.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 4 deletions(-) diff --git a/src/node.c b/src/node.c index e2418785b..126918c24 100644 --- a/src/node.c +++ b/src/node.c @@ -87,10 +87,11 @@ static void divider_validate(int j); static double divider_getOutflow(int j, int link); // --- coupling functions (L. Courty) -static double node_getCouplingFlow(int j, double overlandDepth, - double overlandSurfArea); +static double node_getCouplingFlow(int j, double tStep, + double overlandDepth, double overlandSurfArea); static void node_setOldCouplingState(int j); static int node_isCoupled(int j); +static void node_adjustCouplingInflows(int j, double inflowAdjustingFactor); static void node_findCouplingTypes(int j, double crestElev, double overlandHead, double nodeHead); static void opening_findCouplingType(TCoverOpening* opening, double nodeHead, @@ -611,17 +612,21 @@ double node_getLosses(int j, double tStep) // C O U P L I N G M E T H O D S //============================================================================= -double node_getCouplingFlow(int j, double overlandDepth, double overlandSurfArea) +double node_getCouplingFlow(int j, double tStep, + double overlandDepth, double overlandSurfArea) // // Input: j = node index +// tStep = time step of the drainage model (s) // overlandDepth = water depth in the overland model (ft) // overlandSurfArea = surface in the overland model that is coupled to this node (ft2) // Output: total inflow from coupling (ft3/s) -// Purpose: compute the coupling inflow for every openings +// Purpose: compute the coupling inflow for each node's opening // { double crestElev, overlandHead, nodeHead; double totalCouplingInflow; + double rawMaxInflow, maxInflow, inflowAdjustingFactor; + int inflow2outflow, outflow2inflow; TCoverOpening* opening; // --- calculate elevations @@ -637,9 +642,31 @@ double node_getCouplingFlow(int j, double overlandDepth, double overlandSurfArea while ( opening ) { opening_findCouplingInflow(opening, nodeHead, crestElev, overlandHead); + // --- prevent oscillations + inflow2outflow = (opening->oldInflow > 0.0) && (opening->newInflow < 0.0); + outflow2inflow = (opening->oldInflow < 0.0) && (opening->newInflow > 0.0); + if (inflow2outflow || outflow2inflow) + { + opening->couplingType = NO_COUPLING_FLOW; + opening->newInflow = 0.0; + } totalCouplingInflow += opening->newInflow; opening = opening->next; } + // --- inflow cannot drain the overland model + if (TotalCouplingInflow > 0.0) + { + rawMaxInflow = (overlandDepth * overlandSurfArea) / tStep; + maxInflow = fmin(rawMaxInflow, totalCouplingInflow); + inflowAdjustingFactor = maxInflow / totalCouplingInflow; + node_adjustCouplingInflows(j, inflowAdjustingFactor); + // --- get adjusted inflows + while ( opening ) + { + totalCouplingInflow += opening->newInflow; + opening = opening->next; + } + } return(totalCouplingInflow); } @@ -688,6 +715,27 @@ int node_isCoupled(int j) //============================================================================= +void node_adjustCouplingInflows(int j, double inflowAdjustingFactor) +// +// Input: j = node index +// inflowAdjustingFactor = an inflow adjusting coefficient +// Output: none +// Purpose: adjust the inflow according to an adjusting factor +// +{ + TCoverOpening* opening; + + opening = Node[j].coverOpening; + // --- iterate among the openings + while ( opening ) + { + opening->newInflow = opening->newInflow * inflowAdjustingFactor; + opening = opening->next; + } +} + +//============================================================================= + void node_findCouplingTypes(int j, double crestElev, double overlandHead, double nodeHead) // // Input: j = node index From f42ff9173719433b91865d58cf7580bab5b7afad Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 14:08:30 -0600 Subject: [PATCH 14/45] set an overlandFlow parameter of the node; change functions accordingly. first draft of the node_executeCoupling() function --- src/node.c | 38 ++++++++++++++++++++++++++++++-------- src/objects.h | 1 + 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/node.c b/src/node.c index 126918c24..a0f770106 100644 --- a/src/node.c +++ b/src/node.c @@ -87,8 +87,8 @@ static void divider_validate(int j); static double divider_getOutflow(int j, int link); // --- coupling functions (L. Courty) -static double node_getCouplingFlow(int j, double tStep, - double overlandDepth, double overlandSurfArea); +static void node_findCouplingFlow(int j, double tStep, + double overlandDepth, double overlandSurfArea); static void node_setOldCouplingState(int j); static int node_isCoupled(int j); static void node_adjustCouplingInflows(int j, double inflowAdjustingFactor); @@ -612,14 +612,33 @@ double node_getLosses(int j, double tStep) // C O U P L I N G M E T H O D S //============================================================================= -double node_getCouplingFlow(int j, double tStep, - double overlandDepth, double overlandSurfArea) +void node_executeCoupling(double tStep) +// +// Input: j = node index +// tStep = time step of the drainage model (s) +// Output: none +// Purpose: +// +{ + int j; + double overlandDepth, overlandSurfArea; + + for ( j = 0; j < Nobjects[NODE]; j++ ) + { + node_findCouplingFlow(j, tStep, overlandDepth, overlandSurfArea); + } +} + +//============================================================================= + +void node_findCouplingFlow(int j, double tStep, + double overlandDepth, double overlandSurfArea) // // Input: j = node index // tStep = time step of the drainage model (s) // overlandDepth = water depth in the overland model (ft) // overlandSurfArea = surface in the overland model that is coupled to this node (ft2) -// Output: total inflow from coupling (ft3/s) +// Output: none // Purpose: compute the coupling inflow for each node's opening // { @@ -637,8 +656,11 @@ double node_getCouplingFlow(int j, double tStep, // --- init totalCouplingInflow = 0.0; - opening = Node[j].coverOpening; + // --- find coupling types + node_findCouplingTypes(j, crestElev, overlandHead, nodeHead); + // --- iterate among the openings. Add each flow to total inflow. + opening = Node[j].coverOpening; while ( opening ) { opening_findCouplingInflow(opening, nodeHead, crestElev, overlandHead); @@ -654,7 +676,7 @@ double node_getCouplingFlow(int j, double tStep, opening = opening->next; } // --- inflow cannot drain the overland model - if (TotalCouplingInflow > 0.0) + if (totalCouplingInflow > 0.0) { rawMaxInflow = (overlandDepth * overlandSurfArea) / tStep; maxInflow = fmin(rawMaxInflow, totalCouplingInflow); @@ -667,7 +689,7 @@ double node_getCouplingFlow(int j, double tStep, opening = opening->next; } } - return(totalCouplingInflow); + Node[j].overlandFlow = totalCouplingInflow; } //============================================================================= diff --git a/src/objects.h b/src/objects.h index b479e2a2b..676507dc7 100644 --- a/src/objects.h +++ b/src/objects.h @@ -539,6 +539,7 @@ typedef struct double newDepth; // current water depth (ft) double oldLatFlow; // previous lateral inflow (cfs) double newLatFlow; // current lateral inflow (cfs) + double overlandFlow; // flow from the overland model(cfs) double* oldQual; // previous quality state double* newQual; // current quality state double oldFlowInflow; // previous flow inflow From 9abb1f86a356a8a21a241eadcb47aeea48e8e97d Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 14:13:08 -0600 Subject: [PATCH 15/45] refactor node_isCoupled() --- src/node.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/node.c b/src/node.c index a0f770106..fe00a43eb 100644 --- a/src/node.c +++ b/src/node.c @@ -721,18 +721,21 @@ int node_isCoupled(int j) // Purpose: if at least one opening is coupled, return yes. // { + int isCoupled = FALSE; TCoverOpening* opening; - opening = Node[j].coverOpening; - // --- if not any cover, the node is not coupled - if ( !opening ) return NO; // --- iterate among the openings. If one is coupled, return YES + opening = Node[j].coverOpening; while ( opening ) { - if ( opening->couplingType != NO_COUPLING ) return YES; + if ( opening->couplingType != NO_COUPLING ) + { + isCoupled = TRUE; + break; + } opening = opening->next; } - return NO; + return isCoupled; } //============================================================================= From 8ced7266beeb82196c9cdb75e846007fa8112e75 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 14:26:09 -0600 Subject: [PATCH 16/45] add overlandInflow to other inflows during routing --- src/node.c | 3 ++- src/objects.h | 2 +- src/routing.c | 6 +++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/node.c b/src/node.c index fe00a43eb..f4cc9bcbe 100644 --- a/src/node.c +++ b/src/node.c @@ -262,6 +262,7 @@ void node_initState(int j) Node[j].oldLatFlow = 0.0; Node[j].newLatFlow = 0.0; Node[j].losses = 0.0; //(5.1.007) + Node[j].overlandInflow = 0.0; //coupling //// Following code section added to release 5.1.007. //// //(5.1.007) @@ -689,7 +690,7 @@ void node_findCouplingFlow(int j, double tStep, opening = opening->next; } } - Node[j].overlandFlow = totalCouplingInflow; + Node[j].overlandInflow = totalCouplingInflow; } //============================================================================= diff --git a/src/objects.h b/src/objects.h index 676507dc7..c6fb59028 100644 --- a/src/objects.h +++ b/src/objects.h @@ -539,7 +539,7 @@ typedef struct double newDepth; // current water depth (ft) double oldLatFlow; // previous lateral inflow (cfs) double newLatFlow; // current lateral inflow (cfs) - double overlandFlow; // flow from the overland model(cfs) + double overlandInflow; // flow from the overland model(cfs) double* oldQual; // previous quality state double* newQual; // current quality state double oldFlowInflow; // previous flow inflow diff --git a/src/routing.c b/src/routing.c index 038daf624..4c694da1a 100644 --- a/src/routing.c +++ b/src/routing.c @@ -346,7 +346,7 @@ void addExternalInflows(DateTime currentDate) for (j = 0; j < Nobjects[NODE]; j++) { inflow = Node[j].extInflow; - if ( !inflow ) continue; + if ( !inflow && Node[j].overlandInflow == 0.0 ) continue; //coupling // --- get flow inflow q = 0.0; @@ -359,6 +359,10 @@ void addExternalInflows(DateTime currentDate) } else inflow = inflow->next; } + // --- add overland inflow to inflow q //coupling + q += Node[j].overlandInflow; + Node[j].overlandInflow = 0.0; + if ( fabs(q) < FLOW_TOL ) q = 0.0; // --- add flow inflow to node's lateral inflow From f7c7f4f021422cedbaac17d9460dc9f23b2754c6 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 15:48:59 -0600 Subject: [PATCH 17/45] create a struct for overland data. Advance on node_executeCoupling() --- src/node.c | 25 +++++++++++++++++-------- src/objects.h | 11 +++++++++++ 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/node.c b/src/node.c index f4cc9bcbe..0138e7075 100644 --- a/src/node.c +++ b/src/node.c @@ -613,12 +613,13 @@ double node_getLosses(int j, double tStep) // C O U P L I N G M E T H O D S //============================================================================= -void node_executeCoupling(double tStep) +void node_executeCoupling(double tStep, TOverlandData* OverlandData) // -// Input: j = node index -// tStep = time step of the drainage model (s) +// Input: tStep = time step of the drainage model (s) +// OverlandData = an array of TOverlandData +// /!\ OverlandData should be same length and order than Node // Output: none -// Purpose: +// Purpose: find coupling flow for each node. // { int j; @@ -626,7 +627,13 @@ void node_executeCoupling(double tStep) for ( j = 0; j < Nobjects[NODE]; j++ ) { + if ( !node_isCoupled(j) ) continue; + // --- find coupling flow + overlandDepth = OverlandData[j].depth; + overlandSurfArea = OverlandData[j].surfArea; node_findCouplingFlow(j, tStep, overlandDepth, overlandSurfArea); + // --- apply coupling flow to output array + OverlandData[j].couplingFlow = Node[j].overlandInflow; } } @@ -673,6 +680,7 @@ void node_findCouplingFlow(int j, double tStep, opening->couplingType = NO_COUPLING_FLOW; opening->newInflow = 0.0; } + // --- add inflow to total inflow totalCouplingInflow += opening->newInflow; opening = opening->next; } @@ -684,7 +692,8 @@ void node_findCouplingFlow(int j, double tStep, inflowAdjustingFactor = maxInflow / totalCouplingInflow; node_adjustCouplingInflows(j, inflowAdjustingFactor); // --- get adjusted inflows - while ( opening ) + opening = Node[j].coverOpening; + while ( opening ) { totalCouplingInflow += opening->newInflow; opening = opening->next; @@ -704,8 +713,8 @@ void node_setOldCouplingState(int j) { TCoverOpening* opening; - opening = Node[j].coverOpening; // --- iterate among the openings. + opening = Node[j].coverOpening; while ( opening ) { opening->oldInflow = opening->newInflow; @@ -751,8 +760,8 @@ void node_adjustCouplingInflows(int j, double inflowAdjustingFactor) { TCoverOpening* opening; - opening = Node[j].coverOpening; // --- iterate among the openings + opening = Node[j].coverOpening; while ( opening ) { opening->newInflow = opening->newInflow * inflowAdjustingFactor; @@ -774,8 +783,8 @@ void node_findCouplingTypes(int j, double crestElev, double overlandHead, double { TCoverOpening* opening; - opening = Node[j].coverOpening; // --- iterate among the openings and find coupling + opening = Node[j].coverOpening; while ( opening ) { opening_findCouplingType(opening, nodeHead, crestElev, overlandHead); diff --git a/src/objects.h b/src/objects.h index c6fb59028..9117f6292 100644 --- a/src/objects.h +++ b/src/objects.h @@ -1107,3 +1107,14 @@ typedef struct char Enabled; // TRUE if appears in report table int Precision; // number of decimal places when reported } TRptField; + + +//-------------------- +// OVERLAND MODEL DATA +//-------------------- +typedef struct +{ + double surfArea; // coupling area (ft2) + double depth; // water depth (ft) + double couplingFlow; // flow (ft3/s) +} TOverlandData; From 80705243ecedc392bcf72d0baa0c35833070704e Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 16:32:52 -0600 Subject: [PATCH 18/45] create global OverlandData array; update related func accordingly. Create new func for deleting node openings. Declare coupling global funcs --- src/funcs.h | 4 ++++ src/globals.h | 1 + src/node.c | 24 +++++++++++++++++++++--- src/project.c | 5 +++++ 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/funcs.h b/src/funcs.h index 2985979a9..be1650827 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -393,6 +393,10 @@ double node_getMaxOutflow(int node, double q, double tStep); double node_getSystemOutflow(int node, int *isFlooded); void node_getResults(int node, double wt, float x[]); +// --- coupling functions +void coupling_execute(double tStep); +void node_deleteOpenings(int node); + //----------------------------------------------------------------------------- // Conveyance System Inflow Methods //----------------------------------------------------------------------------- diff --git a/src/globals.h b/src/globals.h index 1e7fdbeff..1539b820e 100644 --- a/src/globals.h +++ b/src/globals.h @@ -142,6 +142,7 @@ EXTERN TSubcatch* Subcatch; // Array of subcatchments EXTERN TAquifer* Aquifer; // Array of groundwater aquifers EXTERN TUnitHyd* UnitHyd; // Array of unit hydrographs EXTERN TNode* Node; // Array of nodes +EXTERN TOverlandData* OverlandData; // Array of overland model data EXTERN TOutfall* Outfall; // Array of outfall nodes EXTERN TDivider* Divider; // Array of divider nodes EXTERN TStorage* Storage; // Array of storage nodes diff --git a/src/node.c b/src/node.c index 0138e7075..38ed92b37 100644 --- a/src/node.c +++ b/src/node.c @@ -613,11 +613,9 @@ double node_getLosses(int j, double tStep) // C O U P L I N G M E T H O D S //============================================================================= -void node_executeCoupling(double tStep, TOverlandData* OverlandData) +void coupling_execute(double tStep) // // Input: tStep = time step of the drainage model (s) -// OverlandData = an array of TOverlandData -// /!\ OverlandData should be same length and order than Node // Output: none // Purpose: find coupling flow for each node. // @@ -794,6 +792,26 @@ void node_findCouplingTypes(int j, double crestElev, double overlandHead, double //============================================================================= +void node_deleteOpenings(int j) +// +// Input: j = node index +// Output: none +// Purpose: deletes all opening data for a node. +// +{ + TCoverOpening* opening1; + TCoverOpening* opening2; + opening1 = Node[j].coverOpening; + while ( opening1 ) + { + opening2 = opening1->next; + free(opening1); + opening1 = opening2; + } +} + +//============================================================================= + void opening_findCouplingType(TCoverOpening* opening, double nodeHead, double crestElev, double overlandHead) // diff --git a/src/project.c b/src/project.c index 847e5f54f..cec1bcd48 100644 --- a/src/project.c +++ b/src/project.c @@ -731,6 +731,7 @@ void initPointers() Gage = NULL; Subcatch = NULL; Node = NULL; + OverlandData = NULL; Outfall = NULL; Divider = NULL; Storage = NULL; @@ -963,6 +964,7 @@ void createObjects() Gage = (TGage *) calloc(Nobjects[GAGE], sizeof(TGage)); Subcatch = (TSubcatch *) calloc(Nobjects[SUBCATCH], sizeof(TSubcatch)); Node = (TNode *) calloc(Nobjects[NODE], sizeof(TNode)); + OverlandData = (TOverlandData *) calloc(Nobjects[NODE], sizeof(TOverlandData)); Outfall = (TOutfall *) calloc(Nnodes[OUTFALL], sizeof(TOutfall)); Divider = (TDivider *) calloc(Nnodes[DIVIDER], sizeof(TDivider)); Storage = (TStorage *) calloc(Nnodes[STORAGE], sizeof(TStorage)); @@ -1021,6 +1023,7 @@ void createObjects() Node[j].dwfInflow = NULL; Node[j].rdiiInflow = NULL; Node[j].treatment = NULL; + Node[j].coverOpening = NULL; } for (j = 0; j < Nobjects[LINK]; j++) { @@ -1200,6 +1203,7 @@ void deleteObjects() inflow_deleteDwfInflows(j); rdii_deleteRdiiInflow(j); treatmnt_delete(j); + node_deleteOpenings(j); } // --- delete table entries for curves and time series @@ -1221,6 +1225,7 @@ void deleteObjects() FREE(Gage); FREE(Subcatch); FREE(Node); + FREE(OverlandData); FREE(Outfall); FREE(Divider); FREE(Storage); From 3ccc6fe3d573110d499fde4aafe079e1ba5d7601 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 16:35:21 -0600 Subject: [PATCH 19/45] call coupling_execute() from flowrout_execute() --- src/flowrout.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/flowrout.c b/src/flowrout.c index f1a3b1b10..8efbbb2e7 100644 --- a/src/flowrout.c +++ b/src/flowrout.c @@ -160,7 +160,9 @@ int flowrout_execute(int links[], int routingModel, double tStep) // --- execute dynamic wave routing if called for if ( routingModel == DW ) { - return dynwave_execute(tStep); + steps = dynwave_execute(tStep); + coupling_execute(tStep); //coupling + return steps; } // --- otherwise examine each link, moving from upstream to downstream From 888d766212dc54ff618eda4428460da7f37623cb Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 16:48:18 -0600 Subject: [PATCH 20/45] move coupling functions in their own file --- src/coupling.c | 322 +++++++++++++++++++++++++++++++++++++++++++++++++ src/funcs.h | 1 + src/node.c | 306 +--------------------------------------------- 3 files changed, 324 insertions(+), 305 deletions(-) create mode 100644 src/coupling.c diff --git a/src/coupling.c b/src/coupling.c new file mode 100644 index 000000000..89827a4cb --- /dev/null +++ b/src/coupling.c @@ -0,0 +1,322 @@ +//----------------------------------------------------------------------------- +// coupling.c +// +// Project: EPA SWMM5 +// Version: 5.1 +// Date: 03/20/14 (Build 5.1.001) +// 09/15/14 (Build 5.1.007) +// 04/02/15 (Build 5.1.008) +// 08/05/15 (Build 5.1.010) +// Authors: Laurent Courty +// +// Copyrighted (c) distributed under the MIT license (see LICENSE.txt) +// +// Overland model flow coupling functions. +// +//----------------------------------------------------------------------------- +#define _CRT_SECURE_NO_DEPRECATE + +#include +#include +#include +#include "headers.h" + +//----------------------------------------------------------------------------- +// Local functions +//----------------------------------------------------------------------------- +static void node_findCouplingFlow(int j, double tStep, + double overlandDepth, double overlandSurfArea); +static int node_isCoupled(int j); +static void node_adjustCouplingInflows(int j, double inflowAdjustingFactor); +static void node_findCouplingTypes(int j, double crestElev, + double overlandHead, double nodeHead); +static void opening_findCouplingType(TCoverOpening* opening, double nodeHead, + double crestElev, double overlandHead); +static void opening_findCouplingInflow(TCoverOpening* opening, double nodeHead, + double crestElev, double overlandHead); + +//============================================================================= + +void coupling_execute(double tStep) +// +// Input: tStep = time step of the drainage model (s) +// Output: none +// Purpose: find coupling flow for each node. +// +{ + int j; + double overlandDepth, overlandSurfArea; + + for ( j = 0; j < Nobjects[NODE]; j++ ) + { + if ( !node_isCoupled(j) ) continue; + // --- find coupling flow + overlandDepth = OverlandData[j].depth; + overlandSurfArea = OverlandData[j].surfArea; + node_findCouplingFlow(j, tStep, overlandDepth, overlandSurfArea); + // --- apply coupling flow to output array + OverlandData[j].couplingFlow = Node[j].overlandInflow; + } +} + +//============================================================================= + +void node_findCouplingFlow(int j, double tStep, + double overlandDepth, double overlandSurfArea) +// +// Input: j = node index +// tStep = time step of the drainage model (s) +// overlandDepth = water depth in the overland model (ft) +// overlandSurfArea = surface in the overland model that is coupled to this node (ft2) +// Output: none +// Purpose: compute the coupling inflow for each node's opening +// +{ + double crestElev, overlandHead, nodeHead; + double totalCouplingInflow; + double rawMaxInflow, maxInflow, inflowAdjustingFactor; + int inflow2outflow, outflow2inflow; + TCoverOpening* opening; + + // --- calculate elevations + crestElev = Node[j].invertElev + Node[j].fullDepth; + nodeHead = Node[j].invertElev + Node[j].newDepth; + overlandHead = crestElev + overlandDepth; + + // --- init + totalCouplingInflow = 0.0; + + // --- find coupling types + node_findCouplingTypes(j, crestElev, overlandHead, nodeHead); + + // --- iterate among the openings. Add each flow to total inflow. + opening = Node[j].coverOpening; + while ( opening ) + { + opening_findCouplingInflow(opening, nodeHead, crestElev, overlandHead); + // --- prevent oscillations + inflow2outflow = (opening->oldInflow > 0.0) && (opening->newInflow < 0.0); + outflow2inflow = (opening->oldInflow < 0.0) && (opening->newInflow > 0.0); + if (inflow2outflow || outflow2inflow) + { + opening->couplingType = NO_COUPLING_FLOW; + opening->newInflow = 0.0; + } + // --- add inflow to total inflow + totalCouplingInflow += opening->newInflow; + opening = opening->next; + } + // --- inflow cannot drain the overland model + if (totalCouplingInflow > 0.0) + { + rawMaxInflow = (overlandDepth * overlandSurfArea) / tStep; + maxInflow = fmin(rawMaxInflow, totalCouplingInflow); + inflowAdjustingFactor = maxInflow / totalCouplingInflow; + node_adjustCouplingInflows(j, inflowAdjustingFactor); + // --- get adjusted inflows + opening = Node[j].coverOpening; + while ( opening ) + { + totalCouplingInflow += opening->newInflow; + opening = opening->next; + } + } + Node[j].overlandInflow = totalCouplingInflow; +} + +//============================================================================= + +void node_setOldCouplingState(int j) +// +// Input: j = node index +// Output: none +// Purpose: replaces a node's old hydraulic coupling state values with new ones. +// +{ + TCoverOpening* opening; + + // --- iterate among the openings. + opening = Node[j].coverOpening; + while ( opening ) + { + opening->oldInflow = opening->newInflow; + opening = opening->next; + } +} + +//============================================================================= + +int node_isCoupled(int j) +// +// Input: j = node index +// Output: returns the coupling status of a node (yes/no) +// Purpose: if at least one opening is coupled, return yes. +// +{ + int isCoupled = FALSE; + TCoverOpening* opening; + + // --- iterate among the openings. If one is coupled, return YES + opening = Node[j].coverOpening; + while ( opening ) + { + if ( opening->couplingType != NO_COUPLING ) + { + isCoupled = TRUE; + break; + } + opening = opening->next; + } + return isCoupled; +} + +//============================================================================= + +void node_adjustCouplingInflows(int j, double inflowAdjustingFactor) +// +// Input: j = node index +// inflowAdjustingFactor = an inflow adjusting coefficient +// Output: none +// Purpose: adjust the inflow according to an adjusting factor +// +{ + TCoverOpening* opening; + + // --- iterate among the openings + opening = Node[j].coverOpening; + while ( opening ) + { + opening->newInflow = opening->newInflow * inflowAdjustingFactor; + opening = opening->next; + } +} + +//============================================================================= + +void node_findCouplingTypes(int j, double crestElev, double overlandHead, double nodeHead) +// +// Input: j = node index +// nodeHead = water elevation in the node (ft) +// crestElev = elevation of the node crest (= ground) (ft) +// overlandHead = water elevation in the overland model (ft) +// Output: none +// Purpose: calculate all coupling types of a node +// +{ + TCoverOpening* opening; + + // --- iterate among the openings and find coupling + opening = Node[j].coverOpening; + while ( opening ) + { + opening_findCouplingType(opening, nodeHead, crestElev, overlandHead); + opening = opening->next; + } +} + +//============================================================================= + +void node_deleteOpenings(int j) +// +// Input: j = node index +// Output: none +// Purpose: deletes all opening data for a node. +// +{ + TCoverOpening* opening1; + TCoverOpening* opening2; + opening1 = Node[j].coverOpening; + while ( opening1 ) + { + opening2 = opening1->next; + free(opening1); + opening1 = opening2; + } +} + +//============================================================================= + +void opening_findCouplingType(TCoverOpening* opening, double nodeHead, + double crestElev, double overlandHead) +// +// Input: opening = a node opening data structure +// nodeHead = water elevation in the node (ft) +// crestElev = elevation of the node crest (= ground) (ft) +// overlandHead = water elevation in the overland model (ft) +// Output: nothing +// Purpose: determine the coupling type of an opening +// according the the relative water elevations in node and surface +// +{ + int overflow, drainage; + int overflowOrifice, drainageOrifice, submergedWeir, freeWeir; + double surfaceDepth, weirRatio; + double overflowArea = opening->area; + double weirWidth = opening->length; + + surfaceDepth = overlandHead - crestElev; + weirRatio = overflowArea / weirWidth; + + // --- boolean cases. See DOI 10.1016/j.jhydrol.2017.06.024 + overflow = nodeHead > overlandHead; + drainage = nodeHead < overlandHead; + overflowOrifice = overflow; + drainageOrifice = drainage && + ((nodeHead > crestElev) && (surfaceDepth > weirRatio)); + submergedWeir = drainage && + ((nodeHead > crestElev) && (surfaceDepth < weirRatio)); + freeWeir = drainage && (nodeHead < crestElev); + + // --- set the coupling type + if ( !overflow && !drainage ) opening->couplingType = NO_COUPLING_FLOW; + else if ( overflowOrifice || drainageOrifice ) + opening->couplingType = ORIFICE_COUPLING; + else if ( submergedWeir ) opening->couplingType = SUBMERGED_WEIR_COUPLING; + else if ( freeWeir ) opening->couplingType = FREE_WEIR_COUPLING; + else opening->couplingType = NO_COUPLING_FLOW; +} + +//============================================================================= + +void opening_findCouplingInflow(TCoverOpening* opening, double nodeHead, + double crestElev, double overlandHead) +// +// Input: opening = a node opening data structure +// nodeHead = water elevation in the node (ft) +// crestElev = elevation of the node crest (= ground) (ft) +// overlandHead = water elevation in the overland model (ft) +// Output: the flow entering through the opening (ft3/s) +// Purpose: computes the coupling flow of the opening +// +{ + double orificeCoeff, freeWeirCoeff, subWeirCoeff, overflowArea, weirWidth; + double headUp, headDown, headDiff, depthUp; + double orif_v, sweir_v, u_couplingFlow; + + orificeCoeff = opening->coeffOrifice; + freeWeirCoeff = opening->coeffFreeWeir; + subWeirCoeff = opening->coeffSubWeir; + overflowArea = opening->area; + weirWidth = opening->length; + + headUp = fmax(overlandHead, nodeHead); + headDown = fmin(overlandHead, nodeHead); + headDiff = headUp - headDown; + depthUp = headUp - crestElev; + + switch(opening->couplingType) + { + case ORIFICE_COUPLING: + orif_v = sqrt(2 * GRAVITY * headDiff); + u_couplingFlow = orificeCoeff * overflowArea * orif_v; + case FREE_WEIR_COUPLING: + u_couplingFlow = (2/3.) * freeWeirCoeff * weirWidth * + pow(depthUp, 3/2.) * sqrt(2 * GRAVITY); + case SUBMERGED_WEIR_COUPLING: + sweir_v = sqrt(2. * GRAVITY * depthUp); + u_couplingFlow = subWeirCoeff * weirWidth * depthUp * sweir_v; + default: u_couplingFlow = 0.0; + } + // --- Flow into the node is positive + opening->newInflow = copysign(u_couplingFlow, overlandHead - nodeHead); +} diff --git a/src/funcs.h b/src/funcs.h index be1650827..817765703 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -396,6 +396,7 @@ void node_getResults(int node, double wt, float x[]); // --- coupling functions void coupling_execute(double tStep); void node_deleteOpenings(int node); +void node_setOldCouplingState(int j); //----------------------------------------------------------------------------- // Conveyance System Inflow Methods diff --git a/src/node.c b/src/node.c index 38ed92b37..709fade1c 100644 --- a/src/node.c +++ b/src/node.c @@ -7,10 +7,7 @@ // 09/15/14 (Build 5.1.007) // 04/02/15 (Build 5.1.008) // 08/05/15 (Build 5.1.010) -// Authors: L. Rossman, Laurent Courty -// -// Contributions by Laurent Courty are copyrighted (c) -// and distributed under the MIT license (see LICENSE.txt) +// Authors: L. Rossman // // Conveyance system node functions. // @@ -86,19 +83,6 @@ static int divider_readParams(int j, int k, char* tok[], int ntoks); static void divider_validate(int j); static double divider_getOutflow(int j, int link); -// --- coupling functions (L. Courty) -static void node_findCouplingFlow(int j, double tStep, - double overlandDepth, double overlandSurfArea); -static void node_setOldCouplingState(int j); -static int node_isCoupled(int j); -static void node_adjustCouplingInflows(int j, double inflowAdjustingFactor); -static void node_findCouplingTypes(int j, double crestElev, - double overlandHead, double nodeHead); -static void opening_findCouplingType(TCoverOpening* opening, double nodeHead, - double crestElev, double overlandHead); -static void opening_findCouplingInflow(TCoverOpening* opening, double nodeHead, - double crestElev, double overlandHead); - //============================================================================= int node_readParams(int j, int type, int k, char* tok[], int ntoks) @@ -609,294 +593,6 @@ double node_getLosses(int j, double tStep) else return 0.0; } -//============================================================================= -// C O U P L I N G M E T H O D S -//============================================================================= - -void coupling_execute(double tStep) -// -// Input: tStep = time step of the drainage model (s) -// Output: none -// Purpose: find coupling flow for each node. -// -{ - int j; - double overlandDepth, overlandSurfArea; - - for ( j = 0; j < Nobjects[NODE]; j++ ) - { - if ( !node_isCoupled(j) ) continue; - // --- find coupling flow - overlandDepth = OverlandData[j].depth; - overlandSurfArea = OverlandData[j].surfArea; - node_findCouplingFlow(j, tStep, overlandDepth, overlandSurfArea); - // --- apply coupling flow to output array - OverlandData[j].couplingFlow = Node[j].overlandInflow; - } -} - -//============================================================================= - -void node_findCouplingFlow(int j, double tStep, - double overlandDepth, double overlandSurfArea) -// -// Input: j = node index -// tStep = time step of the drainage model (s) -// overlandDepth = water depth in the overland model (ft) -// overlandSurfArea = surface in the overland model that is coupled to this node (ft2) -// Output: none -// Purpose: compute the coupling inflow for each node's opening -// -{ - double crestElev, overlandHead, nodeHead; - double totalCouplingInflow; - double rawMaxInflow, maxInflow, inflowAdjustingFactor; - int inflow2outflow, outflow2inflow; - TCoverOpening* opening; - - // --- calculate elevations - crestElev = Node[j].invertElev + Node[j].fullDepth; - nodeHead = Node[j].invertElev + Node[j].newDepth; - overlandHead = crestElev + overlandDepth; - - // --- init - totalCouplingInflow = 0.0; - - // --- find coupling types - node_findCouplingTypes(j, crestElev, overlandHead, nodeHead); - - // --- iterate among the openings. Add each flow to total inflow. - opening = Node[j].coverOpening; - while ( opening ) - { - opening_findCouplingInflow(opening, nodeHead, crestElev, overlandHead); - // --- prevent oscillations - inflow2outflow = (opening->oldInflow > 0.0) && (opening->newInflow < 0.0); - outflow2inflow = (opening->oldInflow < 0.0) && (opening->newInflow > 0.0); - if (inflow2outflow || outflow2inflow) - { - opening->couplingType = NO_COUPLING_FLOW; - opening->newInflow = 0.0; - } - // --- add inflow to total inflow - totalCouplingInflow += opening->newInflow; - opening = opening->next; - } - // --- inflow cannot drain the overland model - if (totalCouplingInflow > 0.0) - { - rawMaxInflow = (overlandDepth * overlandSurfArea) / tStep; - maxInflow = fmin(rawMaxInflow, totalCouplingInflow); - inflowAdjustingFactor = maxInflow / totalCouplingInflow; - node_adjustCouplingInflows(j, inflowAdjustingFactor); - // --- get adjusted inflows - opening = Node[j].coverOpening; - while ( opening ) - { - totalCouplingInflow += opening->newInflow; - opening = opening->next; - } - } - Node[j].overlandInflow = totalCouplingInflow; -} - -//============================================================================= - -void node_setOldCouplingState(int j) -// -// Input: j = node index -// Output: none -// Purpose: replaces a node's old hydraulic coupling state values with new ones. -// -{ - TCoverOpening* opening; - - // --- iterate among the openings. - opening = Node[j].coverOpening; - while ( opening ) - { - opening->oldInflow = opening->newInflow; - opening = opening->next; - } -} - -//============================================================================= - -int node_isCoupled(int j) -// -// Input: j = node index -// Output: returns the coupling status of a node (yes/no) -// Purpose: if at least one opening is coupled, return yes. -// -{ - int isCoupled = FALSE; - TCoverOpening* opening; - - // --- iterate among the openings. If one is coupled, return YES - opening = Node[j].coverOpening; - while ( opening ) - { - if ( opening->couplingType != NO_COUPLING ) - { - isCoupled = TRUE; - break; - } - opening = opening->next; - } - return isCoupled; -} - -//============================================================================= - -void node_adjustCouplingInflows(int j, double inflowAdjustingFactor) -// -// Input: j = node index -// inflowAdjustingFactor = an inflow adjusting coefficient -// Output: none -// Purpose: adjust the inflow according to an adjusting factor -// -{ - TCoverOpening* opening; - - // --- iterate among the openings - opening = Node[j].coverOpening; - while ( opening ) - { - opening->newInflow = opening->newInflow * inflowAdjustingFactor; - opening = opening->next; - } -} - -//============================================================================= - -void node_findCouplingTypes(int j, double crestElev, double overlandHead, double nodeHead) -// -// Input: j = node index -// nodeHead = water elevation in the node (ft) -// crestElev = elevation of the node crest (= ground) (ft) -// overlandHead = water elevation in the overland model (ft) -// Output: none -// Purpose: calculate all coupling types of a node -// -{ - TCoverOpening* opening; - - // --- iterate among the openings and find coupling - opening = Node[j].coverOpening; - while ( opening ) - { - opening_findCouplingType(opening, nodeHead, crestElev, overlandHead); - opening = opening->next; - } -} - -//============================================================================= - -void node_deleteOpenings(int j) -// -// Input: j = node index -// Output: none -// Purpose: deletes all opening data for a node. -// -{ - TCoverOpening* opening1; - TCoverOpening* opening2; - opening1 = Node[j].coverOpening; - while ( opening1 ) - { - opening2 = opening1->next; - free(opening1); - opening1 = opening2; - } -} - -//============================================================================= - -void opening_findCouplingType(TCoverOpening* opening, double nodeHead, - double crestElev, double overlandHead) -// -// Input: opening = a node opening data structure -// nodeHead = water elevation in the node (ft) -// crestElev = elevation of the node crest (= ground) (ft) -// overlandHead = water elevation in the overland model (ft) -// Output: nothing -// Purpose: determine the coupling type of an opening -// according the the relative water elevations in node and surface -// -{ - int overflow, drainage; - int overflowOrifice, drainageOrifice, submergedWeir, freeWeir; - double surfaceDepth, weirRatio; - double overflowArea = opening->area; - double weirWidth = opening->length; - - surfaceDepth = overlandHead - crestElev; - weirRatio = overflowArea / weirWidth; - - // --- boolean cases. See DOI 10.1016/j.jhydrol.2017.06.024 - overflow = nodeHead > overlandHead; - drainage = nodeHead < overlandHead; - overflowOrifice = overflow; - drainageOrifice = drainage && - ((nodeHead > crestElev) && (surfaceDepth > weirRatio)); - submergedWeir = drainage && - ((nodeHead > crestElev) && (surfaceDepth < weirRatio)); - freeWeir = drainage && (nodeHead < crestElev); - - // --- set the coupling type - if ( !overflow && !drainage ) opening->couplingType = NO_COUPLING_FLOW; - else if ( overflowOrifice || drainageOrifice ) - opening->couplingType = ORIFICE_COUPLING; - else if ( submergedWeir ) opening->couplingType = SUBMERGED_WEIR_COUPLING; - else if ( freeWeir ) opening->couplingType = FREE_WEIR_COUPLING; - else opening->couplingType = NO_COUPLING_FLOW; -} - -//============================================================================= - -void opening_findCouplingInflow(TCoverOpening* opening, double nodeHead, - double crestElev, double overlandHead) -// -// Input: opening = a node opening data structure -// nodeHead = water elevation in the node (ft) -// crestElev = elevation of the node crest (= ground) (ft) -// overlandHead = water elevation in the overland model (ft) -// Output: the flow entering through the opening (ft3/s) -// Purpose: computes the coupling flow of the opening -// -{ - double orificeCoeff, freeWeirCoeff, subWeirCoeff, overflowArea, weirWidth; - double headUp, headDown, headDiff, depthUp; - double orif_v, sweir_v, u_couplingFlow; - - orificeCoeff = opening->coeffOrifice; - freeWeirCoeff = opening->coeffFreeWeir; - subWeirCoeff = opening->coeffSubWeir; - overflowArea = opening->area; - weirWidth = opening->length; - - headUp = fmax(overlandHead, nodeHead); - headDown = fmin(overlandHead, nodeHead); - headDiff = headUp - headDown; - depthUp = headUp - crestElev; - - switch(opening->couplingType) - { - case ORIFICE_COUPLING: - orif_v = sqrt(2 * GRAVITY * headDiff); - u_couplingFlow = orificeCoeff * overflowArea * orif_v; - case FREE_WEIR_COUPLING: - u_couplingFlow = (2/3.) * freeWeirCoeff * weirWidth * - pow(depthUp, 3/2.) * sqrt(2 * GRAVITY); - case SUBMERGED_WEIR_COUPLING: - sweir_v = sqrt(2. * GRAVITY * depthUp); - u_couplingFlow = subWeirCoeff * weirWidth * depthUp * sweir_v; - default: u_couplingFlow = 0.0; - } - // --- Flow into the node is positive - opening->newInflow = copysign(u_couplingFlow, overlandHead - nodeHead); -} - //============================================================================= // J U N C T I O N M E T H O D S //============================================================================= From 6093accc67500263462b0fed5cbf47bd7f906c55 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 17:05:54 -0600 Subject: [PATCH 21/45] rename coupling functions --- src/coupling.c | 74 ++++++++++++++++---------------------------------- src/funcs.h | 4 +-- src/node.c | 3 +- src/project.c | 2 +- 4 files changed, 28 insertions(+), 55 deletions(-) diff --git a/src/coupling.c b/src/coupling.c index 89827a4cb..1292aa865 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -7,7 +7,7 @@ // 09/15/14 (Build 5.1.007) // 04/02/15 (Build 5.1.008) // 08/05/15 (Build 5.1.010) -// Authors: Laurent Courty +// Authors: Laurent Courty // // Copyrighted (c) distributed under the MIT license (see LICENSE.txt) // @@ -24,16 +24,14 @@ //----------------------------------------------------------------------------- // Local functions //----------------------------------------------------------------------------- -static void node_findCouplingFlow(int j, double tStep, +static void coupling_findNodeInflow(int j, double tStep, double overlandDepth, double overlandSurfArea); -static int node_isCoupled(int j); -static void node_adjustCouplingInflows(int j, double inflowAdjustingFactor); -static void node_findCouplingTypes(int j, double crestElev, - double overlandHead, double nodeHead); -static void opening_findCouplingType(TCoverOpening* opening, double nodeHead, - double crestElev, double overlandHead); -static void opening_findCouplingInflow(TCoverOpening* opening, double nodeHead, - double crestElev, double overlandHead); +static int coupling_isNodeCoupled(int j); +static void coupling_adjustInflows(int j, double inflowAdjustingFactor); +static void opening_findCouplingType(TCoverOpening* opening, double crestElev, + double nodeHead, double overlandHead); +static void opening_findCouplingInflow(TCoverOpening* opening, double crestElev, + double nodeHead, double overlandHead); //============================================================================= @@ -49,11 +47,11 @@ void coupling_execute(double tStep) for ( j = 0; j < Nobjects[NODE]; j++ ) { - if ( !node_isCoupled(j) ) continue; + if ( !coupling_isNodeCoupled(j) ) continue; // --- find coupling flow overlandDepth = OverlandData[j].depth; overlandSurfArea = OverlandData[j].surfArea; - node_findCouplingFlow(j, tStep, overlandDepth, overlandSurfArea); + coupling_findNodeInflow(j, tStep, overlandDepth, overlandSurfArea); // --- apply coupling flow to output array OverlandData[j].couplingFlow = Node[j].overlandInflow; } @@ -61,7 +59,7 @@ void coupling_execute(double tStep) //============================================================================= -void node_findCouplingFlow(int j, double tStep, +void coupling_findNodeInflow(int j, double tStep, double overlandDepth, double overlandSurfArea) // // Input: j = node index @@ -86,14 +84,13 @@ void node_findCouplingFlow(int j, double tStep, // --- init totalCouplingInflow = 0.0; - // --- find coupling types - node_findCouplingTypes(j, crestElev, overlandHead, nodeHead); - - // --- iterate among the openings. Add each flow to total inflow. + // --- iterate among the openings opening = Node[j].coverOpening; while ( opening ) { - opening_findCouplingInflow(opening, nodeHead, crestElev, overlandHead); + // --- compute types and inflows + opening_findCouplingType(opening, crestElev, nodeHead, overlandHead); + opening_findCouplingInflow(opening, crestElev, nodeHead, overlandHead); // --- prevent oscillations inflow2outflow = (opening->oldInflow > 0.0) && (opening->newInflow < 0.0); outflow2inflow = (opening->oldInflow < 0.0) && (opening->newInflow > 0.0); @@ -112,7 +109,7 @@ void node_findCouplingFlow(int j, double tStep, rawMaxInflow = (overlandDepth * overlandSurfArea) / tStep; maxInflow = fmin(rawMaxInflow, totalCouplingInflow); inflowAdjustingFactor = maxInflow / totalCouplingInflow; - node_adjustCouplingInflows(j, inflowAdjustingFactor); + coupling_adjustInflows(j, inflowAdjustingFactor); // --- get adjusted inflows opening = Node[j].coverOpening; while ( opening ) @@ -126,7 +123,7 @@ void node_findCouplingFlow(int j, double tStep, //============================================================================= -void node_setOldCouplingState(int j) +void coupling_setOldState(int j) // // Input: j = node index // Output: none @@ -146,7 +143,7 @@ void node_setOldCouplingState(int j) //============================================================================= -int node_isCoupled(int j) +int coupling_isNodeCoupled(int j) // // Input: j = node index // Output: returns the coupling status of a node (yes/no) @@ -172,7 +169,7 @@ int node_isCoupled(int j) //============================================================================= -void node_adjustCouplingInflows(int j, double inflowAdjustingFactor) +void coupling_adjustInflows(int j, double inflowAdjustingFactor) // // Input: j = node index // inflowAdjustingFactor = an inflow adjusting coefficient @@ -193,30 +190,7 @@ void node_adjustCouplingInflows(int j, double inflowAdjustingFactor) //============================================================================= -void node_findCouplingTypes(int j, double crestElev, double overlandHead, double nodeHead) -// -// Input: j = node index -// nodeHead = water elevation in the node (ft) -// crestElev = elevation of the node crest (= ground) (ft) -// overlandHead = water elevation in the overland model (ft) -// Output: none -// Purpose: calculate all coupling types of a node -// -{ - TCoverOpening* opening; - - // --- iterate among the openings and find coupling - opening = Node[j].coverOpening; - while ( opening ) - { - opening_findCouplingType(opening, nodeHead, crestElev, overlandHead); - opening = opening->next; - } -} - -//============================================================================= - -void node_deleteOpenings(int j) +void coupling_deleteOpenings(int j) // // Input: j = node index // Output: none @@ -236,8 +210,8 @@ void node_deleteOpenings(int j) //============================================================================= -void opening_findCouplingType(TCoverOpening* opening, double nodeHead, - double crestElev, double overlandHead) +void opening_findCouplingType(TCoverOpening* opening, double crestElev, + double nodeHead, double overlandHead) // // Input: opening = a node opening data structure // nodeHead = water elevation in the node (ft) @@ -278,8 +252,8 @@ void opening_findCouplingType(TCoverOpening* opening, double nodeHead, //============================================================================= -void opening_findCouplingInflow(TCoverOpening* opening, double nodeHead, - double crestElev, double overlandHead) +void opening_findCouplingInflow(TCoverOpening* opening, double crestElev, + double nodeHead, double overlandHead) // // Input: opening = a node opening data structure // nodeHead = water elevation in the node (ft) diff --git a/src/funcs.h b/src/funcs.h index 817765703..f832d1ec3 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -395,8 +395,8 @@ void node_getResults(int node, double wt, float x[]); // --- coupling functions void coupling_execute(double tStep); -void node_deleteOpenings(int node); -void node_setOldCouplingState(int j); +void coupling_deleteOpenings(int node); +void coupling_setOldState(int j); //----------------------------------------------------------------------------- // Conveyance System Inflow Methods diff --git a/src/node.c b/src/node.c index 709fade1c..43206bf97 100644 --- a/src/node.c +++ b/src/node.c @@ -289,8 +289,7 @@ void node_setOldHydState(int j) { Node[j].oldDepth = Node[j].newDepth; Node[j].oldVolume = Node[j].newVolume; - // --- do it for overland model coupling - node_setOldCouplingState(j); + coupling_setOldState(j); //coupling } //============================================================================= diff --git a/src/project.c b/src/project.c index cec1bcd48..6f77cbaf5 100644 --- a/src/project.c +++ b/src/project.c @@ -1203,7 +1203,7 @@ void deleteObjects() inflow_deleteDwfInflows(j); rdii_deleteRdiiInflow(j); treatmnt_delete(j); - node_deleteOpenings(j); + coupling_deleteOpenings(j); //(coupling) } // --- delete table entries for curves and time series From 499db853807fddd35c25a5486e71d4eb1e7b67f7 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 17:13:12 -0600 Subject: [PATCH 22/45] add init of overland data --- src/coupling.c | 14 ++++++++++++++ src/funcs.h | 1 + src/project.c | 1 + 3 files changed, 16 insertions(+) diff --git a/src/coupling.c b/src/coupling.c index 1292aa865..b1a515d00 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -35,6 +35,20 @@ static void opening_findCouplingInflow(TCoverOpening* opening, double crestEle //============================================================================= +void coupling_initOverlandData(int j) +// +// Input: j = node index +// Output: none +// Purpose: initializes a OverlandData's value variables at start of simulation. +// +{ + OverlandData[j].surfArea = 0.0; + OverlandData[j].depth = 0.0; + OverlandData[j].couplingFlow = 0.0; +} + +//============================================================================= + void coupling_execute(double tStep) // // Input: tStep = time step of the drainage model (s) diff --git a/src/funcs.h b/src/funcs.h index f832d1ec3..50ca89d2f 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -394,6 +394,7 @@ double node_getSystemOutflow(int node, int *isFlooded); void node_getResults(int node, double wt, float x[]); // --- coupling functions +void coupling_initOverlandData(int node); void coupling_execute(double tStep); void coupling_deleteOpenings(int node); void coupling_setOldState(int j); diff --git a/src/project.c b/src/project.c index 6f77cbaf5..76e433030 100644 --- a/src/project.c +++ b/src/project.c @@ -296,6 +296,7 @@ int project_init(void) for (j=0; j Date: Sun, 10 Dec 2017 17:54:07 -0600 Subject: [PATCH 23/45] add func to set an opening --- src/coupling.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/funcs.h | 2 ++ src/objects.h | 1 + 3 files changed, 57 insertions(+) diff --git a/src/coupling.c b/src/coupling.c index b1a515d00..109dedd2c 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -224,6 +224,60 @@ void coupling_deleteOpenings(int j) //============================================================================= +void coupling_setOpening(int j, int idx, int oType, double A, double l, + double Co, double Cfw, double Csw) +// Purpose: Assigns property values to the node opening object +// Inputs: j = Node index +// idx = opening's index +// otype = type of opening (grate, etc). From an enum +// A = area of the opening (ft2) +// l = length of the opening (~circumference, ft) +// Co = orifice coefficient +// Cfw = free weir coefficient +// Csw = submerged weir coefficient +// Return: error code +{ + int errcode = 0; + TCoverOpening* opening; // opening object + + // --- check if an opening object with this index already exists + opening = Node[j].coverOpening; + while ( opening ) + { + if ( opening->ID == idx ) break; + opening = opening->next; + } + + // --- if it doesn't exist, then create it + if ( opening == NULL ) + { + opening = (TCoverOpening *) malloc(sizeof(TCoverOpening)); + if ( opening == NULL ) + { + return error_setInpError(ERR_MEMORY, ""); + } + opening->next = Node[j].coverOpening; + Node[j].coverOpening = opening; + } + + // Assign values to the opening object + opening->ID = idx; + opening->type = oType; + opening->area = A; + opening->length = l; + opening->coeffOrifice = Co; + opening->coeffFreeWeir = Cfw; + opening->coeffSubWeir = Csw; + // --- default values + opening->couplingType = NO_COUPLING_FLOW; + opening->oldInflow = 0.0; + opening->newInflow = 0.0; + + return(errcode); +} + +//============================================================================= + void opening_findCouplingType(TCoverOpening* opening, double crestElev, double nodeHead, double overlandHead) // diff --git a/src/funcs.h b/src/funcs.h index 50ca89d2f..6d8c48c16 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -395,6 +395,8 @@ void node_getResults(int node, double wt, float x[]); // --- coupling functions void coupling_initOverlandData(int node); +void coupling_setOpening(int j, int idx, int oType, double A, double l, + double Co, double Cfw, double Csw); void coupling_execute(double tStep); void coupling_deleteOpenings(int node); void coupling_setOldState(int j); diff --git a/src/objects.h b/src/objects.h index 9117f6292..a6ebbd398 100644 --- a/src/objects.h +++ b/src/objects.h @@ -441,6 +441,7 @@ typedef struct ExtInflow TExtInflow; //------------------------------ struct CoverOpening { + int ID; // opening index number int type; // type of opening (grate, etc). From an enum int couplingType; // type of surface coupling (enum SurfaceCouplingType) double area; // area of the opening (ft2) From 5005bd254cc4300c989615d855ce083524bfea46 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 18:05:02 -0600 Subject: [PATCH 24/45] add a func to delete a single opening --- src/coupling.c | 59 +++++++++++++++++++++++++++++++++----------------- src/funcs.h | 1 + 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/src/coupling.c b/src/coupling.c index 109dedd2c..c86e7714f 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -204,26 +204,6 @@ void coupling_adjustInflows(int j, double inflowAdjustingFactor) //============================================================================= -void coupling_deleteOpenings(int j) -// -// Input: j = node index -// Output: none -// Purpose: deletes all opening data for a node. -// -{ - TCoverOpening* opening1; - TCoverOpening* opening2; - opening1 = Node[j].coverOpening; - while ( opening1 ) - { - opening2 = opening1->next; - free(opening1); - opening1 = opening2; - } -} - -//============================================================================= - void coupling_setOpening(int j, int idx, int oType, double A, double l, double Co, double Cfw, double Csw) // Purpose: Assigns property values to the node opening object @@ -275,6 +255,45 @@ void coupling_setOpening(int j, int idx, int oType, double A, double l, return(errcode); } +//============================================================================= + +void coupling_deleteOpening(int j, int idx) +// +// Input: j = node index +// idx = opening index +// Output: none +// Purpose: deletes an opening from a node. +// +{ + TCoverOpening* opening; + + opening = Node[j].coverOpening; + while ( opening ) + { + if ( opening->ID == idx ) free(opening); + opening = opening->next; + } +} + +//============================================================================= + +void coupling_deleteOpenings(int j) +// +// Input: j = node index +// Output: none +// Purpose: deletes all opening data for a node. +// +{ + TCoverOpening* opening1; + TCoverOpening* opening2; + opening1 = Node[j].coverOpening; + while ( opening1 ) + { + opening2 = opening1->next; + free(opening1); + opening1 = opening2; + } +} //============================================================================= diff --git a/src/funcs.h b/src/funcs.h index 6d8c48c16..f9f1e8a53 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -397,6 +397,7 @@ void node_getResults(int node, double wt, float x[]); void coupling_initOverlandData(int node); void coupling_setOpening(int j, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); +void coupling_deleteOpening(int j, int idx); void coupling_execute(double tStep); void coupling_deleteOpenings(int node); void coupling_setOldState(int j); From 517263a6b65a2106a01110535ace6c520bd80f2a Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 18:06:53 -0600 Subject: [PATCH 25/45] return file header to previous state --- src/node.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/node.c b/src/node.c index 43206bf97..89b3da81e 100644 --- a/src/node.c +++ b/src/node.c @@ -7,7 +7,7 @@ // 09/15/14 (Build 5.1.007) // 04/02/15 (Build 5.1.008) // 08/05/15 (Build 5.1.010) -// Authors: L. Rossman +// Author: L. Rossman // // Conveyance system node functions. // @@ -83,6 +83,7 @@ static int divider_readParams(int j, int k, char* tok[], int ntoks); static void divider_validate(int j); static double divider_getOutflow(int j, int link); + //============================================================================= int node_readParams(int j, int type, int k, char* tok[], int ntoks) From dea174f1ad7b4cabe5bcf45ae828150f5f86abbe Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 19:12:23 -0600 Subject: [PATCH 26/45] fix return type of coupling_setOpening() --- src/coupling.c | 4 ++-- src/funcs.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coupling.c b/src/coupling.c index c86e7714f..7c9a74c52 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -204,8 +204,8 @@ void coupling_adjustInflows(int j, double inflowAdjustingFactor) //============================================================================= -void coupling_setOpening(int j, int idx, int oType, double A, double l, - double Co, double Cfw, double Csw) +int coupling_setOpening(int j, int idx, int oType, double A, double l, + double Co, double Cfw, double Csw) // Purpose: Assigns property values to the node opening object // Inputs: j = Node index // idx = opening's index diff --git a/src/funcs.h b/src/funcs.h index f9f1e8a53..9057d45a9 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -395,7 +395,7 @@ void node_getResults(int node, double wt, float x[]); // --- coupling functions void coupling_initOverlandData(int node); -void coupling_setOpening(int j, int idx, int oType, double A, double l, +int coupling_setOpening(int j, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); void coupling_deleteOpening(int j, int idx); void coupling_execute(double tStep); From a18a25e18b2a21dee6631486485baa96cad252cd Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 19:13:37 -0600 Subject: [PATCH 27/45] add the possibility to retrieve overlandinflow. add function to set a node opening --- src/toolkitAPI.c | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 99693c920..cdffb05c6 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -4,7 +4,8 @@ // Project: EPA SWMM5 // Version: 5.1 // Date: 08/30/2016 -// Author: B. McDonnell (EmNet LLC) +// Authors: B. McDonnell (EmNet LLC) +// Laurent Courty // // Exportable Functions for Project Definition API. // @@ -693,6 +694,8 @@ int DLLEXPORT swmm_getNodeResult(int index, int type, double *result) case 6: *result = (Node[index].newDepth + Node[index].invertElev) * UCF(LENGTH); break; // Current Lateral Inflow case 7: *result = Node[index].newLatFlow * UCF(FLOW); break; + // Inflow from/to the overland model + case 8: *result = Node[index].overlandInflow * UCF(FLOW); break; // Type not available default: return(ERR_API_OUTBOUNDS); } @@ -1240,3 +1243,36 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage) } return(errcode); } + +//====================================================================== +// COUPLING FUNCTIONS +//====================================================================== + +int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, + double l, double Co, double Cfw, double Csw) +// +// Input: nodeID = Index of desired ID +// idx = opening's index +// otype = type of opening (grate, etc). Not used yet +// A = area of the opening (ft2) +// l = length of the opening (~circumference, ft) +// Co = orifice coefficient +// Cfw = free weir coefficient +// Csw = submerged weir coefficient + +// Return: API Error +// Purpose: Sets Node opening parameters. +{ + int errcode; + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if Simulation is Running + if(swmm_IsStartedFlag() == TRUE) return(ERR_API_SIM_NRUNNING); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + errcode = coupling_setOpening(nodeID, idx, oType, + A / UCF(LENGTH) * UCF(LENGTH), l / UCF(LENGTH), + Co, Cfw, Csw); + return(errcode); +} From d7086f53a838493885283be22cfa6bcd7ba1e057 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 19:46:23 -0600 Subject: [PATCH 28/45] add API func to set overlan params and retrieve coupling flow --- src/enums.h | 4 +++ src/toolkitAPI.c | 72 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/enums.h b/src/enums.h index 362c54d8c..c0ebd229a 100644 --- a/src/enums.h +++ b/src/enums.h @@ -478,3 +478,7 @@ enum SurfaceCouplingType { ORIFICE_COUPLING, FREE_WEIR_COUPLING, SUBMERGED_WEIR_COUPLING}; + +enum OverlandDataType { + OVERLAND_AREA, + OVERLAND_DEPTH}; diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index cdffb05c6..99b3d80a3 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1251,14 +1251,14 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage) int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, double l, double Co, double Cfw, double Csw) // -// Input: nodeID = Index of desired ID -// idx = opening's index -// otype = type of opening (grate, etc). Not used yet -// A = area of the opening (ft2) -// l = length of the opening (~circumference, ft) -// Co = orifice coefficient -// Cfw = free weir coefficient -// Csw = submerged weir coefficient +// Input: nodeID = Index of desired node +// idx = opening's index +// otype = type of opening (grate, etc). Not used yet +// A = area of the opening (ft2) +// l = length of the opening (~circumference, ft) +// Co = orifice coefficient +// Cfw = free weir coefficient +// Csw = submerged weir coefficient // Return: API Error // Purpose: Sets Node opening parameters. @@ -1272,7 +1272,61 @@ int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); errcode = coupling_setOpening(nodeID, idx, oType, - A / UCF(LENGTH) * UCF(LENGTH), l / UCF(LENGTH), + A / ( UCF(LENGTH) * UCF(LENGTH) ), + l / UCF(LENGTH), Co, Cfw, Csw); return(errcode); } + +int DLLEXPORT swmm_setOverlandParam(int nodeID, int Param, double value) +// +// Input: nodeID = Index of desired node +// Param = Parameter desired (From enum OverlandDataType) +// value = value to be input +// Return: API Error +// Purpose: Sets Node opening parameters. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if Simulation is Running + if(swmm_IsStartedFlag() == TRUE) return(ERR_API_SIM_NRUNNING); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + switch(Param) + { + // surfArea + case OVERLAND_AREA: + { + OverlandData[nodeID].surfArea = value / ( UCF(LENGTH) * UCF(LENGTH) ); + break; + } + // fullDepth + case OVERLAND_DEPTH: + { + Node[nodeID].fullDepth = value / UCF(LENGTH); + break; + } + // Type not available + default: return(ERR_API_OUTBOUNDS); + } + return(0); +} + +int DLLEXPORT swmm_getCouplingFlow(int nodeID, double *value) +// +// Input: nodeID = Index of desired node +// Output value = coupling flow +// Return: API Error +// Purpose: get overland coupling flow. >0 if entering the drainage. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if Simulation is Running + if(swmm_IsStartedFlag() == TRUE) return(ERR_API_SIM_NRUNNING); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + *value = OverlandData[nodeID].couplingFlow * UCF(FLOW); + return(0); +} From f99de88beebfa722dff2c3b0f258ae941985cc32 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 21:33:52 -0600 Subject: [PATCH 29/45] add API function to get overland model parameters --- src/toolkitAPI.c | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 99b3d80a3..0d1ea9a01 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1288,8 +1288,6 @@ int DLLEXPORT swmm_setOverlandParam(int nodeID, int Param, double value) { // Check if Open if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); - // Check if Simulation is Running - if(swmm_IsStartedFlag() == TRUE) return(ERR_API_SIM_NRUNNING); // Check if object index is within bounds if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); @@ -1313,6 +1311,39 @@ int DLLEXPORT swmm_setOverlandParam(int nodeID, int Param, double value) return(0); } +int DLLEXPORT swmm_getOverlandParam(int nodeID, int Param, double *value) +// +// Input: nodeID = Index of desired node +// Param = Parameter desired (From enum OverlandDataType) +// Output value = value +// Return: API Error +// Purpose: Sets Node opening parameters. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + switch(Param) + { + // surfArea + case OVERLAND_AREA: + { + *value = OverlandData[nodeID].surfArea * ( UCF(LENGTH) * UCF(LENGTH) ); + break; + } + // fullDepth + case OVERLAND_DEPTH: + { + *value = Node[nodeID].fullDepth * UCF(LENGTH); + break; + } + // Type not available + default: return(ERR_API_OUTBOUNDS); + } + return(0); +} + int DLLEXPORT swmm_getCouplingFlow(int nodeID, double *value) // // Input: nodeID = Index of desired node From 4bd169ae0238bf0e4d462642deb1796fc458a994 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 22:01:36 -0600 Subject: [PATCH 30/45] fix wrong array in setter and getter of verland params --- src/toolkitAPI.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 0d1ea9a01..c47766f48 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1302,7 +1302,7 @@ int DLLEXPORT swmm_setOverlandParam(int nodeID, int Param, double value) // fullDepth case OVERLAND_DEPTH: { - Node[nodeID].fullDepth = value / UCF(LENGTH); + OverlandData[nodeID].depth = value / UCF(LENGTH); break; } // Type not available @@ -1335,7 +1335,7 @@ int DLLEXPORT swmm_getOverlandParam(int nodeID, int Param, double *value) // fullDepth case OVERLAND_DEPTH: { - *value = Node[nodeID].fullDepth * UCF(LENGTH); + *value = OverlandData[nodeID].depth * UCF(LENGTH); break; } // Type not available From d2c4cdf0bbe56dec4e5d0dd876ab28b5553403e4 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Sun, 10 Dec 2017 22:09:15 -0600 Subject: [PATCH 31/45] refactor getOverlandParam --- src/toolkitAPI.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index c47766f48..6814e2e2e 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1329,7 +1329,7 @@ int DLLEXPORT swmm_getOverlandParam(int nodeID, int Param, double *value) // surfArea case OVERLAND_AREA: { - *value = OverlandData[nodeID].surfArea * ( UCF(LENGTH) * UCF(LENGTH) ); + *value = OverlandData[nodeID].surfArea * UCF(LENGTH) * UCF(LENGTH); break; } // fullDepth From a30f6ecb9b641cdcfeec279cc38420bff9e13eed Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 10:32:18 -0600 Subject: [PATCH 32/45] integrate overland values inside of Node struct. Remove OverlandData struct. --- src/coupling.c | 34 +++-------------- src/enums.h | 4 -- src/funcs.h | 1 - src/globals.h | 1 - src/node.c | 2 +- src/objects.h | 18 +++------ src/project.c | 4 -- src/routing.c | 6 +-- src/toolkitAPI.c | 96 ++++-------------------------------------------- 9 files changed, 23 insertions(+), 143 deletions(-) diff --git a/src/coupling.c b/src/coupling.c index 7c9a74c52..466e27868 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -24,8 +24,7 @@ //----------------------------------------------------------------------------- // Local functions //----------------------------------------------------------------------------- -static void coupling_findNodeInflow(int j, double tStep, - double overlandDepth, double overlandSurfArea); +static void coupling_findNodeInflow(int j, double tStep); static int coupling_isNodeCoupled(int j); static void coupling_adjustInflows(int j, double inflowAdjustingFactor); static void opening_findCouplingType(TCoverOpening* opening, double crestElev, @@ -35,20 +34,6 @@ static void opening_findCouplingInflow(TCoverOpening* opening, double crestEle //============================================================================= -void coupling_initOverlandData(int j) -// -// Input: j = node index -// Output: none -// Purpose: initializes a OverlandData's value variables at start of simulation. -// -{ - OverlandData[j].surfArea = 0.0; - OverlandData[j].depth = 0.0; - OverlandData[j].couplingFlow = 0.0; -} - -//============================================================================= - void coupling_execute(double tStep) // // Input: tStep = time step of the drainage model (s) @@ -57,24 +42,17 @@ void coupling_execute(double tStep) // { int j; - double overlandDepth, overlandSurfArea; for ( j = 0; j < Nobjects[NODE]; j++ ) { if ( !coupling_isNodeCoupled(j) ) continue; - // --- find coupling flow - overlandDepth = OverlandData[j].depth; - overlandSurfArea = OverlandData[j].surfArea; - coupling_findNodeInflow(j, tStep, overlandDepth, overlandSurfArea); - // --- apply coupling flow to output array - OverlandData[j].couplingFlow = Node[j].overlandInflow; + coupling_findNodeInflow(j, tStep); } } //============================================================================= -void coupling_findNodeInflow(int j, double tStep, - double overlandDepth, double overlandSurfArea) +void coupling_findNodeInflow(int j, double tStep) // // Input: j = node index // tStep = time step of the drainage model (s) @@ -93,7 +71,7 @@ void coupling_findNodeInflow(int j, double tStep, // --- calculate elevations crestElev = Node[j].invertElev + Node[j].fullDepth; nodeHead = Node[j].invertElev + Node[j].newDepth; - overlandHead = crestElev + overlandDepth; + overlandHead = crestElev + Node[j].overlandDepth; // --- init totalCouplingInflow = 0.0; @@ -120,7 +98,7 @@ void coupling_findNodeInflow(int j, double tStep, // --- inflow cannot drain the overland model if (totalCouplingInflow > 0.0) { - rawMaxInflow = (overlandDepth * overlandSurfArea) / tStep; + rawMaxInflow = (Node[j].overlandDepth * Node[j].couplingArea) / tStep; maxInflow = fmin(rawMaxInflow, totalCouplingInflow); inflowAdjustingFactor = maxInflow / totalCouplingInflow; coupling_adjustInflows(j, inflowAdjustingFactor); @@ -132,7 +110,7 @@ void coupling_findNodeInflow(int j, double tStep, opening = opening->next; } } - Node[j].overlandInflow = totalCouplingInflow; + Node[j].couplingInflow = totalCouplingInflow; } //============================================================================= diff --git a/src/enums.h b/src/enums.h index c0ebd229a..362c54d8c 100644 --- a/src/enums.h +++ b/src/enums.h @@ -478,7 +478,3 @@ enum SurfaceCouplingType { ORIFICE_COUPLING, FREE_WEIR_COUPLING, SUBMERGED_WEIR_COUPLING}; - -enum OverlandDataType { - OVERLAND_AREA, - OVERLAND_DEPTH}; diff --git a/src/funcs.h b/src/funcs.h index 9057d45a9..057142be8 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -394,7 +394,6 @@ double node_getSystemOutflow(int node, int *isFlooded); void node_getResults(int node, double wt, float x[]); // --- coupling functions -void coupling_initOverlandData(int node); int coupling_setOpening(int j, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); void coupling_deleteOpening(int j, int idx); diff --git a/src/globals.h b/src/globals.h index 1539b820e..1e7fdbeff 100644 --- a/src/globals.h +++ b/src/globals.h @@ -142,7 +142,6 @@ EXTERN TSubcatch* Subcatch; // Array of subcatchments EXTERN TAquifer* Aquifer; // Array of groundwater aquifers EXTERN TUnitHyd* UnitHyd; // Array of unit hydrographs EXTERN TNode* Node; // Array of nodes -EXTERN TOverlandData* OverlandData; // Array of overland model data EXTERN TOutfall* Outfall; // Array of outfall nodes EXTERN TDivider* Divider; // Array of divider nodes EXTERN TStorage* Storage; // Array of storage nodes diff --git a/src/node.c b/src/node.c index 89b3da81e..564649d68 100644 --- a/src/node.c +++ b/src/node.c @@ -247,7 +247,7 @@ void node_initState(int j) Node[j].oldLatFlow = 0.0; Node[j].newLatFlow = 0.0; Node[j].losses = 0.0; //(5.1.007) - Node[j].overlandInflow = 0.0; //coupling + Node[j].couplingInflow = 0.0; //coupling //// Following code section added to release 5.1.007. //// //(5.1.007) diff --git a/src/objects.h b/src/objects.h index a6ebbd398..6d2b9b602 100644 --- a/src/objects.h +++ b/src/objects.h @@ -524,7 +524,11 @@ typedef struct TDwfInflow* dwfInflow; // pointer to dry weather flow inflow data TRdiiInflow* rdiiInflow; // pointer to RDII inflow data TTreatment* treatment; // array of treatment data - TCoverOpening* coverOpening; // pointer to node cover opening data + //----------------------------- + TCoverOpening* coverOpening; // pointer to node opening data + double couplingArea; // coupling area in the overland model (ft2) + double overlandDepth; // water depth in the overland model (ft) + double couplingInflow; // flow from the overland model (cfs) //----------------------------- int degree; // number of outflow links char updated; // true if state has been updated @@ -540,7 +544,6 @@ typedef struct double newDepth; // current water depth (ft) double oldLatFlow; // previous lateral inflow (cfs) double newLatFlow; // current lateral inflow (cfs) - double overlandInflow; // flow from the overland model(cfs) double* oldQual; // previous quality state double* newQual; // current quality state double oldFlowInflow; // previous flow inflow @@ -1108,14 +1111,3 @@ typedef struct char Enabled; // TRUE if appears in report table int Precision; // number of decimal places when reported } TRptField; - - -//-------------------- -// OVERLAND MODEL DATA -//-------------------- -typedef struct -{ - double surfArea; // coupling area (ft2) - double depth; // water depth (ft) - double couplingFlow; // flow (ft3/s) -} TOverlandData; diff --git a/src/project.c b/src/project.c index 76e433030..4637b6780 100644 --- a/src/project.c +++ b/src/project.c @@ -296,7 +296,6 @@ int project_init(void) for (j=0; jnext; } // --- add overland inflow to inflow q //coupling - q += Node[j].overlandInflow; - Node[j].overlandInflow = 0.0; + q += Node[j].couplingInflow; + Node[j].couplingInflow = 0.0; if ( fabs(q) < FLOW_TOL ) q = 0.0; diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 6814e2e2e..d3e9daed7 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -391,8 +391,8 @@ int DLLEXPORT swmm_setNodeParam(int index, int Param, double value) // Check if Open if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); // Check if Simulation is Running - if(swmm_IsStartedFlag() == TRUE) return(ERR_API_SIM_NRUNNING); - // Check if object index is within bounds + //~ if(swmm_IsStartedFlag() == TRUE) return(ERR_API_SIM_NRUNNING); + // Check if object index is within bounds if (index < 0 || index >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); switch(Param) @@ -402,7 +402,7 @@ int DLLEXPORT swmm_setNodeParam(int index, int Param, double value) // fullDepth case 1: Node[index].fullDepth = value / UCF(LENGTH); break; // surDepth - case 2: Node[index].surDepth = value / UCF(LENGTH); break; + case 2: Node[index].surDepth = value / UCF(LENGTH); break; // pondedArea case 3: Node[index].pondedArea = value / ( UCF(LENGTH) * UCF(LENGTH) ); break; // initDepth @@ -412,6 +412,10 @@ int DLLEXPORT swmm_setNodeParam(int index, int Param, double value) Node[index].surfaceArea = value / UCF(LENGTH) * UCF(LENGTH); Node[index].fullVolume = node_getVolume(index, Node[index].fullDepth); break; + // couplingArea + case 6: Node[index].couplingArea = value / ( UCF(LENGTH) * UCF(LENGTH) ); break; + // overlandDepth + case 7: Node[index].overlandDepth = value / UCF(LENGTH); break; // Type not available default: return(ERR_API_OUTBOUNDS); } @@ -695,7 +699,7 @@ int DLLEXPORT swmm_getNodeResult(int index, int type, double *result) // Current Lateral Inflow case 7: *result = Node[index].newLatFlow * UCF(FLOW); break; // Inflow from/to the overland model - case 8: *result = Node[index].overlandInflow * UCF(FLOW); break; + case 8: *result = Node[index].couplingInflow * UCF(FLOW); break; // Type not available default: return(ERR_API_OUTBOUNDS); } @@ -1277,87 +1281,3 @@ int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, Co, Cfw, Csw); return(errcode); } - -int DLLEXPORT swmm_setOverlandParam(int nodeID, int Param, double value) -// -// Input: nodeID = Index of desired node -// Param = Parameter desired (From enum OverlandDataType) -// value = value to be input -// Return: API Error -// Purpose: Sets Node opening parameters. -{ - // Check if Open - if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); - // Check if object index is within bounds - if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); - - switch(Param) - { - // surfArea - case OVERLAND_AREA: - { - OverlandData[nodeID].surfArea = value / ( UCF(LENGTH) * UCF(LENGTH) ); - break; - } - // fullDepth - case OVERLAND_DEPTH: - { - OverlandData[nodeID].depth = value / UCF(LENGTH); - break; - } - // Type not available - default: return(ERR_API_OUTBOUNDS); - } - return(0); -} - -int DLLEXPORT swmm_getOverlandParam(int nodeID, int Param, double *value) -// -// Input: nodeID = Index of desired node -// Param = Parameter desired (From enum OverlandDataType) -// Output value = value -// Return: API Error -// Purpose: Sets Node opening parameters. -{ - // Check if Open - if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); - // Check if object index is within bounds - if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); - - switch(Param) - { - // surfArea - case OVERLAND_AREA: - { - *value = OverlandData[nodeID].surfArea * UCF(LENGTH) * UCF(LENGTH); - break; - } - // fullDepth - case OVERLAND_DEPTH: - { - *value = OverlandData[nodeID].depth * UCF(LENGTH); - break; - } - // Type not available - default: return(ERR_API_OUTBOUNDS); - } - return(0); -} - -int DLLEXPORT swmm_getCouplingFlow(int nodeID, double *value) -// -// Input: nodeID = Index of desired node -// Output value = coupling flow -// Return: API Error -// Purpose: get overland coupling flow. >0 if entering the drainage. -{ - // Check if Open - if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); - // Check if Simulation is Running - if(swmm_IsStartedFlag() == TRUE) return(ERR_API_SIM_NRUNNING); - // Check if object index is within bounds - if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); - - *value = OverlandData[nodeID].couplingFlow * UCF(FLOW); - return(0); -} From 63dd9613a048032bcc0b40630d480db582b2c8ad Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 10:46:55 -0600 Subject: [PATCH 33/45] add getter for overland area and depth --- src/toolkitAPI.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index d3e9daed7..92b71ee4e 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -374,6 +374,10 @@ int DLLEXPORT swmm_getNodeParam(int index, int Param, double *value) case 4: *value = Node[index].initDepth * UCF(LENGTH); break; // surfaceArea case 5: *value = Node[index].surfaceArea * UCF(LENGTH) * UCF(LENGTH); break; + // couplingArea + case 6: *value = Node[index].couplingArea * UCF(LENGTH) * UCF(LENGTH); break; + // overlandDepth + case 7: *value = Node[index].overlandDepth * UCF(LENGTH); break; // Type not available default: return(ERR_API_OUTBOUNDS); } From 18fe4a5865c74767253ee000e94d995493610818 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 11:25:54 -0600 Subject: [PATCH 34/45] export coupling API functions. Add API function to get noide coupling status --- include/toolkitAPI.h | 8 ++++++++ src/coupling.c | 1 - src/funcs.h | 5 ++++- src/toolkitAPI.c | 14 ++++++++++++++ 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/toolkitAPI.h b/include/toolkitAPI.h index b6fb82a7f..289363f4a 100644 --- a/include/toolkitAPI.h +++ b/include/toolkitAPI.h @@ -90,6 +90,14 @@ int DLLEXPORT swmm_setLinkSetting(int index, double setting); int DLLEXPORT swmm_setNodeInflow(int index, double flowrate); int DLLEXPORT swmm_setOutfallStage(int index, double stage); +//------------------------------- +// Coupling API +//------------------------------- + +int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, + double l, double Co, double Cfw, double Csw); +int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled); + #ifdef __cplusplus } // matches the linkage specification from above */ #endif diff --git a/src/coupling.c b/src/coupling.c index 466e27868..3a0ddd2b7 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -25,7 +25,6 @@ // Local functions //----------------------------------------------------------------------------- static void coupling_findNodeInflow(int j, double tStep); -static int coupling_isNodeCoupled(int j); static void coupling_adjustInflows(int j, double inflowAdjustingFactor); static void opening_findCouplingType(TCoverOpening* opening, double crestElev, double nodeHead, double overlandHead); diff --git a/src/funcs.h b/src/funcs.h index 057142be8..9e8eaf87a 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -393,10 +393,13 @@ double node_getMaxOutflow(int node, double q, double tStep); double node_getSystemOutflow(int node, int *isFlooded); void node_getResults(int node, double wt, float x[]); -// --- coupling functions +//----------------------------------------------------------------------------- +// Coupling Methods +//----------------------------------------------------------------------------- int coupling_setOpening(int j, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); void coupling_deleteOpening(int j, int idx); +int coupling_isNodeCoupled(int j); void coupling_execute(double tStep); void coupling_deleteOpenings(int node); void coupling_setOldState(int j); diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 92b71ee4e..59560c277 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1285,3 +1285,17 @@ int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, Co, Cfw, Csw); return(errcode); } + +int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled) +// +// Input: nodeID = Index of desired node +// Return: API error +// Purpose: Get the coupling status of a node. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + *iscoupled = coupling_isNodeCoupled(nodeID); + return(0); +} From d815056dc234a947d239d969a9ba75dd0726b7f5 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 11:36:15 -0600 Subject: [PATCH 35/45] refactor API call for setOpening --- src/toolkitAPI.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 59560c277..44b26eb1a 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1272,6 +1272,8 @@ int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, // Purpose: Sets Node opening parameters. { int errcode; + double u_A, u_l; + // Check if Open if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); // Check if Simulation is Running @@ -1279,10 +1281,9 @@ int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, // Check if object index is within bounds if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); - errcode = coupling_setOpening(nodeID, idx, oType, - A / ( UCF(LENGTH) * UCF(LENGTH) ), - l / UCF(LENGTH), - Co, Cfw, Csw); + u_A = A / ( UCF(LENGTH) * UCF(LENGTH) ); + u_l = l / UCF(LENGTH); + errcode = coupling_setOpening(nodeID, idx, oType, u_A, u_l, Co, Cfw, Csw); return(errcode); } From 3cb37c4d7d201a1f4de78722892f617cdfba4e94 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 11:39:04 -0600 Subject: [PATCH 36/45] init overland area and depth --- src/node.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/node.c b/src/node.c index 564649d68..ff7fd9c15 100644 --- a/src/node.c +++ b/src/node.c @@ -247,6 +247,8 @@ void node_initState(int j) Node[j].oldLatFlow = 0.0; Node[j].newLatFlow = 0.0; Node[j].losses = 0.0; //(5.1.007) + Node[j].couplingArea = 0.0; //coupling + Node[j].overlandDepth = 0.0; //coupling Node[j].couplingInflow = 0.0; //coupling From 5a3f0b30c4836aeb06e00be7ed8cd105e92c9280 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 12:39:00 -0600 Subject: [PATCH 37/45] add API function to get an opening parameter --- include/toolkitAPI.h | 1 + src/enums.h | 10 +++++++++- src/toolkitAPI.c | 45 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/include/toolkitAPI.h b/include/toolkitAPI.h index 289363f4a..ae6ce5946 100644 --- a/include/toolkitAPI.h +++ b/include/toolkitAPI.h @@ -96,6 +96,7 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage); int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); +int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *value); int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled); #ifdef __cplusplus diff --git a/src/enums.h b/src/enums.h index 362c54d8c..9c2c8e892 100644 --- a/src/enums.h +++ b/src/enums.h @@ -472,9 +472,17 @@ enum NoneAllType { ALL, SOME}; -enum SurfaceCouplingType { +enum OverlandCouplingType { NO_COUPLING, NO_COUPLING_FLOW, ORIFICE_COUPLING, FREE_WEIR_COUPLING, SUBMERGED_WEIR_COUPLING}; + +enum OpeningParams { + OPENING_TYPE, + OPENING_AREA, + OPENING_LENGTH, + ORIFICE_COEFF, + FREE_WEIR_COEFF, + SUBMERGED_WEIR_COEFF}; diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 44b26eb1a..af6c5bf6a 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1287,6 +1287,51 @@ int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, return(errcode); } +int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *value) +// +// Input: nodeID = Index of desired node +// idx = opening's index +// Param = parameter to get (enum OpeningParams, type excluded) +// Output value = value to be output +// Return: API Error +// Purpose: Get Node opening parameters. +{ + TCoverOpening* opening; + + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + // --- check if an opening with this index exists + opening = Node[nodeID].coverOpening; + while ( opening ) + { + if ( opening->ID == idx ) break; + opening = opening->next; + } + // --- if it doesn't, return an error + if ( opening == NULL ) return(ERR_API_OBJECT_INDEX); + + + switch(Param) + { + // area + case OPENING_AREA: *value = opening->area * UCF(LENGTH) * UCF(LENGTH); break; + // length + case OPENING_LENGTH: *value = opening->length * UCF(LENGTH); break; + // coeffOrifice + case ORIFICE_COEFF: *value = opening->coeffOrifice; break; + // coeffFreeWeir + case FREE_WEIR_COEFF: *value = opening->coeffFreeWeir; break; + // coeffSubWeir + case SUBMERGED_WEIR_COEFF: *value = opening->coeffSubWeir; break; + // Type not available + default: return(ERR_API_OUTBOUNDS); + } + return(0); +} + int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled) // // Input: nodeID = Index of desired node From 6bb747b403ef1cd1645e6d05d86c578e5b99454b Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 15:54:54 -0600 Subject: [PATCH 38/45] refactor getNodeOpeningParam --- src/toolkitAPI.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index af6c5bf6a..6dc8b8854 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1296,13 +1296,13 @@ int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *v // Return: API Error // Purpose: Get Node opening parameters. { - TCoverOpening* opening; - // Check if Open if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); // Check if object index is within bounds if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + TCoverOpening* opening; + // --- check if an opening with this index exists opening = Node[nodeID].coverOpening; while ( opening ) @@ -1313,7 +1313,6 @@ int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *v // --- if it doesn't, return an error if ( opening == NULL ) return(ERR_API_OBJECT_INDEX); - switch(Param) { // area From 88af31bc337c583eb8a158c3f34e3996ce228aa2 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 16:21:23 -0600 Subject: [PATCH 39/45] add API functions for openings --- include/toolkitAPI.h | 3 ++ src/toolkitAPI.c | 89 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/include/toolkitAPI.h b/include/toolkitAPI.h index ae6ce5946..0b07117b1 100644 --- a/include/toolkitAPI.h +++ b/include/toolkitAPI.h @@ -97,6 +97,9 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage); int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *value); +int DLLEXPORT swmm_getNodeOpeningFlow(int nodeID, int idx, double *inflow); +int DLLEXPORT swmm_getNodeOpeningType(int nodeID, int idx, int *type); +int DLLEXPORT swmm_getOpeningCouplingType(int nodeID, int idx, int *coupling); int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled); #ifdef __cplusplus diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 6dc8b8854..204173292 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1331,6 +1331,95 @@ int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *v return(0); } +int DLLEXPORT swmm_getNodeOpeningFlow(int nodeID, int idx, double *inflow) +// +// Input: nodeID = Index of desired node +// idx = opening's index +// Output inflow = inflow to be output +// Return: API Error +// Purpose: Get opening inflow. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if Simulation is Running + if(swmm_IsStartedFlag() == FALSE) return(ERR_API_SIM_NRUNNING); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + TCoverOpening* opening; + + // --- check if an opening with this index exists + opening = Node[nodeID].coverOpening; + while ( opening ) + { + if ( opening->ID == idx ) break; + opening = opening->next; + } + // --- if it doesn't, return an error + if ( opening == NULL ) return(ERR_API_OBJECT_INDEX); + + *inflow = opening->newInflow * UCF(FLOW); + return(0); +} + +int DLLEXPORT swmm_getNodeOpeningType(int nodeID, int idx, int *type) +// +// Input: nodeID = Index of desired node +// idx = opening's index +// Output type = opening type to be output +// Return: API Error +// Purpose: Get opening type. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + TCoverOpening* opening; + + // --- check if an opening with this index exists + opening = Node[nodeID].coverOpening; + while ( opening ) + { + if ( opening->ID == idx ) break; + opening = opening->next; + } + // --- if it doesn't, return an error + if ( opening == NULL ) return(ERR_API_OBJECT_INDEX); + + *type = opening->type; + return(0); +} + +int DLLEXPORT swmm_getOpeningCouplingType(int nodeID, int idx, int *coupling) +// +// Input: nodeID = Index of desired node +// idx = opening's index +// Output coupling = coupling type to be output +// Return: API Error +// Purpose: Get opening coupling type. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + TCoverOpening* opening; + + // --- check if an opening with this index exists + opening = Node[nodeID].coverOpening; + while ( opening ) + { + if ( opening->ID == idx ) break; + opening = opening->next; + } + // --- if it doesn't, return an error + if ( opening == NULL ) return(ERR_API_OBJECT_INDEX); + + *coupling = opening->couplingType; + return(0); +} + int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled) // // Input: nodeID = Index of desired node From e8c21932fccfbea6de574ca3cfa65192d89d9a28 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 16:44:44 -0600 Subject: [PATCH 40/45] add missing breaks in findCouplingInflow --- src/coupling.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/coupling.c b/src/coupling.c index 3a0ddd2b7..1f2f8bfbb 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -347,13 +347,16 @@ void opening_findCouplingInflow(TCoverOpening* opening, double crestElev, case ORIFICE_COUPLING: orif_v = sqrt(2 * GRAVITY * headDiff); u_couplingFlow = orificeCoeff * overflowArea * orif_v; + break; case FREE_WEIR_COUPLING: u_couplingFlow = (2/3.) * freeWeirCoeff * weirWidth * pow(depthUp, 3/2.) * sqrt(2 * GRAVITY); + break; case SUBMERGED_WEIR_COUPLING: sweir_v = sqrt(2. * GRAVITY * depthUp); u_couplingFlow = subWeirCoeff * weirWidth * depthUp * sweir_v; - default: u_couplingFlow = 0.0; + break; + default: u_couplingFlow = 0.0; break; } // --- Flow into the node is positive opening->newInflow = copysign(u_couplingFlow, overlandHead - nodeHead); From 37e96fff793040a00972fdd0b2c801b772b4007e Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 17:25:00 -0600 Subject: [PATCH 41/45] add a method for counting node openings --- include/toolkitAPI.h | 1 + src/coupling.c | 24 +++++++++++++++++++++++- src/funcs.h | 1 + src/toolkitAPI.c | 18 ++++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/include/toolkitAPI.h b/include/toolkitAPI.h index 0b07117b1..86adca6d6 100644 --- a/include/toolkitAPI.h +++ b/include/toolkitAPI.h @@ -100,6 +100,7 @@ int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *v int DLLEXPORT swmm_getNodeOpeningFlow(int nodeID, int idx, double *inflow); int DLLEXPORT swmm_getNodeOpeningType(int nodeID, int idx, int *type); int DLLEXPORT swmm_getOpeningCouplingType(int nodeID, int idx, int *coupling); +int DLLEXPORT swmm_getOpeningsNum(int nodeID, int *num); int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled); #ifdef __cplusplus diff --git a/src/coupling.c b/src/coupling.c index 1f2f8bfbb..e651c429c 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -138,7 +138,7 @@ int coupling_isNodeCoupled(int j) // // Input: j = node index // Output: returns the coupling status of a node (yes/no) -// Purpose: if at least one opening is coupled, return yes. +// Purpose: if at least one opening is coupled, return TRUE. // { int isCoupled = FALSE; @@ -232,6 +232,28 @@ int coupling_setOpening(int j, int idx, int oType, double A, double l, return(errcode); } + +//============================================================================= + +int coupling_countOpenings(int j) +// +// Input: j = node index +// Output: number of openings in the node +// Purpose: count the number of openings a node have. +// +{ + int openingCounter = 0; + TCoverOpening* opening; + + opening = Node[j].coverOpening; + while ( opening ) + { + if ( opening ) openingCounter++; + opening = opening->next; + } + return(openingCounter); +} + //============================================================================= void coupling_deleteOpening(int j, int idx) diff --git a/src/funcs.h b/src/funcs.h index 9e8eaf87a..02748069b 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -398,6 +398,7 @@ void node_getResults(int node, double wt, float x[]); //----------------------------------------------------------------------------- int coupling_setOpening(int j, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); +int coupling_countOpenings(int j); void coupling_deleteOpening(int j, int idx); int coupling_isNodeCoupled(int j); void coupling_execute(double tStep); diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 204173292..d9752a452 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1420,6 +1420,24 @@ int DLLEXPORT swmm_getOpeningCouplingType(int nodeID, int idx, int *coupling) return(0); } +int DLLEXPORT swmm_getOpeningsNum(int nodeID, int *num) +// +// Input: nodeID = Index of desired node +// idx = opening's index +// Output coupling = coupling type to be output +// Return: API Error +// Purpose: Get opening coupling type. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + *num = coupling_countOpenings(nodeID); + + return(0); +} + int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled) // // Input: nodeID = Index of desired node From 199850c68235ba583c201834ba607b492322796e Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 18:07:06 -0600 Subject: [PATCH 42/45] add func to get the list of indices of the openings of a node --- include/toolkitAPI.h | 1 + src/toolkitAPI.c | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/include/toolkitAPI.h b/include/toolkitAPI.h index 86adca6d6..a31f3c993 100644 --- a/include/toolkitAPI.h +++ b/include/toolkitAPI.h @@ -101,6 +101,7 @@ int DLLEXPORT swmm_getNodeOpeningFlow(int nodeID, int idx, double *inflow); int DLLEXPORT swmm_getNodeOpeningType(int nodeID, int idx, int *type); int DLLEXPORT swmm_getOpeningCouplingType(int nodeID, int idx, int *coupling); int DLLEXPORT swmm_getOpeningsNum(int nodeID, int *num); +int DLLEXPORT swmm_getOpeningsIndices(int nodeID, int arr_size, int *arr); int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled); #ifdef __cplusplus diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index d9752a452..eb70559c4 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1426,7 +1426,7 @@ int DLLEXPORT swmm_getOpeningsNum(int nodeID, int *num) // idx = opening's index // Output coupling = coupling type to be output // Return: API Error -// Purpose: Get opening coupling type. +// Purpose: Get the number of openings of a node. { // Check if Open if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); @@ -1438,6 +1438,40 @@ int DLLEXPORT swmm_getOpeningsNum(int nodeID, int *num) return(0); } +int DLLEXPORT swmm_getOpeningsIndices(int nodeID, int arr_size, int *arr) +// +// Input: nodeID = Index of desired node +// arr_size = number of openings +// Output arr = an array of size arr_size +// Return: API Error +// Purpose: Get the indices of all the openings in the node. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + // Check if array size is correct + int num; + swmm_getOpeningsNum(nodeID, &num); + if (num != arr_size) return(ERR_API_OBJECT_INDEX); + + int i = 0; + TCoverOpening* opening; + + opening = Node[nodeID].coverOpening; + while ( opening ) + { + if ( opening ) + { + arr[i] = opening->ID; + i++; + } + opening = opening->next; + } + + return(0); +} + int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled) // // Input: nodeID = Index of desired node From e09a327c605e74c37fc066e356e73fa79b3dfc7a Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Mon, 11 Dec 2017 20:10:38 -0600 Subject: [PATCH 43/45] add API function to delete an opening. Not working yet --- include/toolkitAPI.h | 1 + src/coupling.c | 11 ++--------- src/toolkitAPI.c | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 9 deletions(-) diff --git a/include/toolkitAPI.h b/include/toolkitAPI.h index a31f3c993..e3fca8e71 100644 --- a/include/toolkitAPI.h +++ b/include/toolkitAPI.h @@ -96,6 +96,7 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage); int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); +int DLLEXPORT swmm_deleteNodeOpening(int nodeID, int idx); int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *value); int DLLEXPORT swmm_getNodeOpeningFlow(int nodeID, int idx, double *inflow); int DLLEXPORT swmm_getNodeOpeningType(int nodeID, int idx, int *type); diff --git a/src/coupling.c b/src/coupling.c index e651c429c..2c32675a3 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -261,17 +261,10 @@ void coupling_deleteOpening(int j, int idx) // Input: j = node index // idx = opening index // Output: none -// Purpose: deletes an opening from a node. +// Purpose: delete an opening from a node. // { - TCoverOpening* opening; - - opening = Node[j].coverOpening; - while ( opening ) - { - if ( opening->ID == idx ) free(opening); - opening = opening->next; - } + // need to find the correct way to do it and preserve linked list. } //============================================================================= diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index eb70559c4..cfbc9e753 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1287,6 +1287,24 @@ int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, return(errcode); } +int DLLEXPORT swmm_deleteNodeOpening(int nodeID, int idx) +// +// Input: nodeID = Index of desired node +// idx = opening's index +// Return: API Error +// Purpose: Sets Node opening parameters. +{ + // Check if Open + if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); + // Check if Simulation is Running + if(swmm_IsStartedFlag() == TRUE) return(ERR_API_SIM_NRUNNING); + // Check if object index is within bounds + if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + + coupling_deleteOpening(nodeID, idx); + return(0); +} + int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *value) // // Input: nodeID = Index of desired node From 64bc148adf5101d73608c43cc68fcfd497ba201e Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Thu, 22 Feb 2018 13:28:14 -0600 Subject: [PATCH 44/45] add doxygen documentation to coupling API functions --- include/toolkitAPI.h | 76 +++++++++++++++++++++++++++++++++++++++++++- src/toolkitAPI.c | 8 ++--- 2 files changed, 79 insertions(+), 5 deletions(-) diff --git a/include/toolkitAPI.h b/include/toolkitAPI.h index cdd0561fa..53e1e5906 100644 --- a/include/toolkitAPI.h +++ b/include/toolkitAPI.h @@ -148,7 +148,7 @@ typedef enum { SM_NODEFLOOD = 4, /**< Flooding Rate */ SM_NODEDEPTH = 5, /**< Node Depth */ SM_NODEHEAD = 6, /**< Node Head */ - SM_LATINFLOW = 7 /**< Lateral Inflow Rate */ + SM_LATINFLOW = 7, /**< Lateral Inflow Rate */ SM_COUPINFLOW = 8 /**< Coupling Inflow Rate */ } SM_NodeResult; @@ -645,15 +645,89 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage); // Coupling API //------------------------------- +/** + @brief Set an opening for specified node. + @param nodeID The index of a node + @param idx The index of an opening + @param oType The opening's type + @param A The opening's area + @param l The opening's length + @param Co The opening's orifice coefficient + @param Cfw The opening's free weir coefficient + @param Csw The opening's submerged weir coefficient + @return Error code +*/ int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); + +/** + @brief Remove an opening from a node. + @param nodeID The index of a node + @param idx The index of an opening + @return Error code +*/ int DLLEXPORT swmm_deleteNodeOpening(int nodeID, int idx); + +/** + @brief Get a node opening's parameter. + @param nodeID The index of a node + @param idx The index of an opening + @param Param The opening's parameter to be retrieved (from enum @ref OpeningParams) + @param[out] value The value of the opening's property + @return Error code +*/ int DLLEXPORT swmm_getNodeOpeningParam(int nodeID, int idx, int Param, double *value); + +/** + @brief Get a node opening's inflow rate. + @param nodeID The index of a node + @param idx The index of an opening + @param[out] inflow The inflow rate + @return Error code +*/ int DLLEXPORT swmm_getNodeOpeningFlow(int nodeID, int idx, double *inflow); + +/** + @brief Get a node opening's type. + @param nodeID The index of a node + @param idx The index of an opening + @param[out] type The opening type + @return Error code +*/ int DLLEXPORT swmm_getNodeOpeningType(int nodeID, int idx, int *type); + +/** + @brief Get a node opening's coupling type. + @param nodeID The index of a node + @param idx The index of an opening + @param[out] coupling The opening coupling type (from enum @ref OverlandCouplingType) + @return Error code +*/ int DLLEXPORT swmm_getOpeningCouplingType(int nodeID, int idx, int *coupling); + +/** + @brief Get the number of openings in a node. + @param nodeID The index of a node + @param[out] num The number of openings in the given node. + @return Error code +*/ int DLLEXPORT swmm_getOpeningsNum(int nodeID, int *num); + +/** + @brief Get the indices of all the openings in a node. + @param nodeID The index of a node + @param arr_size The size of the results array (from @ref swmm_getOpeningsNum) + @param[out] arr An array of the openings indices + @return Error code +*/ int DLLEXPORT swmm_getOpeningsIndices(int nodeID, int arr_size, int *arr); + +/** + @brief Get the coupling status of a node. + @param nodeID The index of a node + @param[out] iscoupled The coupling status of the node. + @return Error code +*/ int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled); #ifdef __cplusplus diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index d23615281..8e4b344af 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1422,8 +1422,8 @@ int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, // Input: nodeID = Index of desired node // idx = opening's index // otype = type of opening (grate, etc). Not used yet -// A = area of the opening (ft2) -// l = length of the opening (~circumference, ft) +// A = area of the opening +// l = length of the opening (~circumference) // Co = orifice coefficient // Cfw = free weir coefficient // Csw = submerged weir coefficient @@ -1451,8 +1451,8 @@ int DLLEXPORT swmm_deleteNodeOpening(int nodeID, int idx) // // Input: nodeID = Index of desired node // idx = opening's index -// Return: API Error -// Purpose: Sets Node opening parameters. +// Return: Error code +// Purpose: Remove an opening from a node. { // Check if Open if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); From 164ced1fd83143ee8d3ff3e39aa73d9716c50513 Mon Sep 17 00:00:00 2001 From: Laurent Courty Date: Thu, 22 Feb 2018 18:24:37 -0600 Subject: [PATCH 45/45] add funcs to open and close an opening --- include/toolkitAPI.h | 16 +++++++++++ src/coupling.c | 64 ++++++++++++++++++++++++++++++++++++++++++++ src/funcs.h | 2 ++ src/toolkitAPI.c | 52 +++++++++++++++++++++++++++++++++++ 4 files changed, 134 insertions(+) diff --git a/include/toolkitAPI.h b/include/toolkitAPI.h index 53e1e5906..7b9fb1956 100644 --- a/include/toolkitAPI.h +++ b/include/toolkitAPI.h @@ -660,6 +660,22 @@ int DLLEXPORT swmm_setOutfallStage(int index, double stage); int DLLEXPORT swmm_setNodeOpening(int nodeID, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); +/** + @brief Open an opening that was previously closed. + @param nodeID The index of a node + @param idx The index of an opening + @return Error code +*/ +int DLLEXPORT swmm_openOpening(int nodeID, int idx); + +/** + @brief Close an opening. + @param nodeID The index of a node + @param idx The index of an opening + @return Error code +*/ +int DLLEXPORT swmm_closeOpening(int nodeID, int idx); + /** @brief Remove an opening from a node. @param nodeID The index of a node diff --git a/src/coupling.c b/src/coupling.c index 2c32675a3..4b71fc34a 100644 --- a/src/coupling.c +++ b/src/coupling.c @@ -79,6 +79,8 @@ void coupling_findNodeInflow(int j, double tStep) opening = Node[j].coverOpening; while ( opening ) { + // --- do nothing if not coupled + if ( opening->couplingType == NO_COUPLING ) continue; // --- compute types and inflows opening_findCouplingType(opening, crestElev, nodeHead, overlandHead); opening_findCouplingInflow(opening, crestElev, nodeHead, overlandHead); @@ -160,6 +162,68 @@ int coupling_isNodeCoupled(int j) //============================================================================= +int coupling_closeOpening(int j, int idx) +// +// Input: j = node index +// idx = opening index +// Output: Error code +// Purpose: Close an opening +// +{ + int errcode = 0; + TCoverOpening* opening; // opening object + + // --- Find the opening + opening = Node[j].coverOpening; + while ( opening ) + { + if ( opening->ID == idx ) break; + opening = opening->next; + } + // --- if opening doesn't exist, return an error + if ( opening == NULL ) + { + return(ERR_API_OBJECT_INDEX); + } + + // --- Close the opening + opening->couplingType = NO_COUPLING; + return 0; +} + +//============================================================================= + +int coupling_openOpening(int j, int idx) +// +// Input: j = node index +// idx = opening index +// Output: Error code +// Purpose: Open an opening +// +{ + int errcode = 0; + TCoverOpening* opening; // opening object + + // --- Find the opening + opening = Node[j].coverOpening; + while ( opening ) + { + if ( opening->ID == idx ) break; + opening = opening->next; + } + // --- if opening doesn't exist, return an error + if ( opening == NULL ) + { + return(ERR_API_OBJECT_INDEX); + } + + // --- Open the opening + opening->couplingType = NO_COUPLING_FLOW; + return 0; +} + +//============================================================================= + void coupling_adjustInflows(int j, double inflowAdjustingFactor) // // Input: j = node index diff --git a/src/funcs.h b/src/funcs.h index 19331cb83..a2b08af91 100644 --- a/src/funcs.h +++ b/src/funcs.h @@ -388,6 +388,8 @@ void node_getResults(int node, double wt, float x[]); int coupling_setOpening(int j, int idx, int oType, double A, double l, double Co, double Cfw, double Csw); int coupling_countOpenings(int j); +int coupling_openOpening(int j, int idx); +int coupling_closeOpening(int j, int idx); void coupling_deleteOpening(int j, int idx); int coupling_isNodeCoupled(int j); void coupling_execute(double tStep); diff --git a/src/toolkitAPI.c b/src/toolkitAPI.c index 8e4b344af..b44fdf44d 100644 --- a/src/toolkitAPI.c +++ b/src/toolkitAPI.c @@ -1660,6 +1660,58 @@ int DLLEXPORT swmm_getNodeIsCoupled(int nodeID, int *iscoupled) if(swmm_IsOpenFlag() == FALSE) return(ERR_API_INPUTNOTOPEN); // Check if object index is within bounds if (nodeID < 0 || nodeID >= Nobjects[NODE]) return(ERR_API_OBJECT_INDEX); + *iscoupled = coupling_isNodeCoupled(nodeID); + return(0); } + + +int DLLEXPORT swmm_closeOpening(int nodeID, int idx) +// +// Input: nodeID = Index of desired node +// Return: API error +// Purpose: Close an opening. +{ + int errcode = 0; + + // Check if Open + if (swmm_IsOpenFlag() == FALSE) + { + errcode = ERR_API_INPUTNOTOPEN; + } + // Check if object index is within bounds + else if (nodeID < 0 || nodeID >= Nobjects[NODE]) + { + errcode = ERR_API_OBJECT_INDEX; + } + + // Close the opening + errcode = coupling_closeOpening(nodeID, idx); + return errcode; +} + + +int DLLEXPORT swmm_openOpening(int nodeID, int idx) +// +// Input: nodeID = Index of desired node +// Return: API error +// Purpose: Open an opening. +{ + int errcode = 0; + + // Check if Open + if (swmm_IsOpenFlag() == FALSE) + { + errcode = ERR_API_INPUTNOTOPEN; + } + // Check if object index is within bounds + else if (nodeID < 0 || nodeID >= Nobjects[NODE]) + { + errcode = ERR_API_OBJECT_INDEX; + } + + // Close the opening + errcode = coupling_closeOpening(nodeID, idx); + return errcode; +}