Actual source code: waterfunctions.c

  1: /* function subroutines used by water.c */

  3: #include "water.h"
  4: #include <petscdmnetwork.h>

  6: PetscScalar Flow_Pipe(Pipe *pipe, PetscScalar hf, PetscScalar ht)
  7: {
  8:   PetscScalar flow_pipe;

 10:   flow_pipe = PetscSign(hf - ht) * PetscPowScalar(PetscAbsScalar(hf - ht) / pipe->k, (1 / pipe->n));
 11:   return flow_pipe;
 12: }

 14: PetscScalar Flow_Pump(Pump *pump, PetscScalar hf, PetscScalar ht)
 15: {
 16:   PetscScalar flow_pump;
 17:   flow_pump = PetscPowScalar((hf - ht + pump->h0) / pump->r, (1 / pump->n));
 18:   return flow_pump;
 19: }

 21: PetscErrorCode FormFunction_Water(DM networkdm, Vec localX, Vec localF, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx)
 22: {
 23:   const PetscScalar *xarr;
 24:   const PetscInt    *cone;
 25:   PetscScalar       *farr, hf, ht, flow;
 26:   PetscInt           i, key, vnode1, vnode2, offsetnode1, offsetnode2, offset, ncomp;
 27:   PetscBool          ghostvtex;
 28:   VERTEX_Water       vertex, vertexnode1, vertexnode2;
 29:   EDGE_Water         edge;
 30:   Pipe              *pipe;
 31:   Pump              *pump;
 32:   Reservoir         *reservoir;
 33:   Tank              *tank;

 35:   PetscFunctionBegin;
 36:   /* Get arrays for the vectors */
 37:   PetscCall(VecGetArrayRead(localX, &xarr));
 38:   PetscCall(VecGetArray(localF, &farr));

 40:   for (i = 0; i < ne; i++) { /* for each edge */
 41:     /* Get the offset and the key for the component for edge number e[i] */
 42:     PetscCall(DMNetworkGetComponent(networkdm, edges[i], 0, &key, (void **)&edge, NULL));

 44:     /* Get the numbers for the vertices covering this edge */
 45:     PetscCall(DMNetworkGetConnectedVertices(networkdm, edges[i], &cone));
 46:     vnode1 = cone[0];
 47:     vnode2 = cone[1];

 49:     /* Get the components at the two vertices, their variable offsets */
 50:     PetscCall(DMNetworkGetNumComponents(networkdm, vnode1, &ncomp));
 51:     PetscCall(DMNetworkGetComponent(networkdm, vnode1, ncomp - 1, &key, (void **)&vertexnode1, NULL));
 52:     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vnode1, ncomp - 1, &offsetnode1));

 54:     PetscCall(DMNetworkGetNumComponents(networkdm, vnode2, &ncomp));
 55:     PetscCall(DMNetworkGetComponent(networkdm, vnode2, ncomp - 1, &key, (void **)&vertexnode2, NULL));
 56:     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vnode2, ncomp - 1, &offsetnode2));

 58:     /* Variables at node1 and node 2 */
 59:     hf = xarr[offsetnode1];
 60:     ht = xarr[offsetnode2];

 62:     flow = 0.0;
 63:     if (edge->type == EDGE_TYPE_PIPE) {
 64:       pipe = &edge->pipe;
 65:       flow = Flow_Pipe(pipe, hf, ht);
 66:     } else if (edge->type == EDGE_TYPE_PUMP) {
 67:       pump = &edge->pump;
 68:       flow = Flow_Pump(pump, hf, ht);
 69:     }
 70:     /* Convention: Node 1 has outgoing flow and Node 2 has incoming flow */
 71:     if (vertexnode1->type == VERTEX_TYPE_JUNCTION) farr[offsetnode1] -= flow;
 72:     if (vertexnode2->type == VERTEX_TYPE_JUNCTION) farr[offsetnode2] += flow;
 73:   }

 75:   /* Subtract Demand flows at the vertices */
 76:   for (i = 0; i < nv; i++) {
 77:     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
 78:     if (ghostvtex) continue;

 80:     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], ALL_COMPONENTS, &offset));
 81:     PetscCall(DMNetworkGetNumComponents(networkdm, vtx[i], &ncomp));
 82:     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], ncomp - 1, &key, (void **)&vertex, NULL));

 84:     if (vertex->type == VERTEX_TYPE_JUNCTION) {
 85:       farr[offset] -= vertex->junc.demand;
 86:     } else if (vertex->type == VERTEX_TYPE_RESERVOIR) {
 87:       reservoir    = &vertex->res;
 88:       farr[offset] = xarr[offset] - reservoir->head;
 89:     } else if (vertex->type == VERTEX_TYPE_TANK) {
 90:       tank         = &vertex->tank;
 91:       farr[offset] = xarr[offset] - (tank->elev + tank->initlvl);
 92:     }
 93:   }

 95:   PetscCall(VecRestoreArrayRead(localX, &xarr));
 96:   PetscCall(VecRestoreArray(localF, &farr));
 97:   PetscFunctionReturn(PETSC_SUCCESS);
 98: }

100: PetscErrorCode WaterFormFunction(SNES snes, Vec X, Vec F, void *user)
101: {
102:   DM              networkdm;
103:   Vec             localX, localF;
104:   const PetscInt *v, *e;
105:   PetscInt        nv, ne;

107:   PetscFunctionBegin;
108:   /* Get the DM attached with the SNES */
109:   PetscCall(SNESGetDM(snes, &networkdm));

111:   /* Get local vertices and edges */
112:   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &v, &e));

114:   /* Get local vectors */
115:   PetscCall(DMGetLocalVector(networkdm, &localX));
116:   PetscCall(DMGetLocalVector(networkdm, &localF));

118:   /* Scatter values from global to local vector */
119:   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
120:   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));

122:   /* Initialize residual */
123:   PetscCall(VecSet(F, 0.0));
124:   PetscCall(VecSet(localF, 0.0));

126:   PetscCall(FormFunction_Water(networkdm, localX, localF, nv, ne, v, e, NULL));

128:   PetscCall(DMRestoreLocalVector(networkdm, &localX));
129:   PetscCall(DMLocalToGlobalBegin(networkdm, localF, ADD_VALUES, F));
130:   PetscCall(DMLocalToGlobalEnd(networkdm, localF, ADD_VALUES, F));

132:   PetscCall(DMRestoreLocalVector(networkdm, &localF));
133:   PetscFunctionReturn(PETSC_SUCCESS);
134: }

136: PetscErrorCode WaterSetInitialGuess(DM networkdm, Vec X)
137: {
138:   PetscInt        nv, ne;
139:   const PetscInt *vtx, *edges;
140:   Vec             localX;

142:   PetscFunctionBegin;
143:   PetscCall(DMGetLocalVector(networkdm, &localX));

145:   PetscCall(VecSet(X, 0.0));
146:   PetscCall(DMGlobalToLocalBegin(networkdm, X, INSERT_VALUES, localX));
147:   PetscCall(DMGlobalToLocalEnd(networkdm, X, INSERT_VALUES, localX));

149:   /* Get subnetwork */
150:   PetscCall(DMNetworkGetSubnetwork(networkdm, 0, &nv, &ne, &vtx, &edges));
151:   PetscCall(SetInitialGuess_Water(networkdm, localX, nv, ne, vtx, edges, NULL));

153:   PetscCall(DMLocalToGlobalBegin(networkdm, localX, ADD_VALUES, X));
154:   PetscCall(DMLocalToGlobalEnd(networkdm, localX, ADD_VALUES, X));
155:   PetscCall(DMRestoreLocalVector(networkdm, &localX));
156:   PetscFunctionReturn(PETSC_SUCCESS);
157: }

159: PetscErrorCode GetListofEdges_Water(WATERDATA *water, PetscInt *edgelist)
160: {
161:   PetscInt  i, j, node1, node2;
162:   Pipe     *pipe;
163:   Pump     *pump;
164:   PetscBool netview = PETSC_FALSE;

166:   PetscFunctionBegin;
167:   PetscCall(PetscOptionsHasName(NULL, NULL, "-water_view", &netview));
168:   for (i = 0; i < water->nedge; i++) {
169:     if (water->edge[i].type == EDGE_TYPE_PIPE) {
170:       pipe  = &water->edge[i].pipe;
171:       node1 = pipe->node1;
172:       node2 = pipe->node2;
173:       if (netview) PetscCall(PetscPrintf(PETSC_COMM_SELF, "edge %" PetscInt_FMT ", pipe v[%" PetscInt_FMT "] -> v[%" PetscInt_FMT "]\n", i, node1, node2));
174:     } else {
175:       pump  = &water->edge[i].pump;
176:       node1 = pump->node1;
177:       node2 = pump->node2;
178:       if (netview) PetscCall(PetscPrintf(PETSC_COMM_SELF, "edge %" PetscInt_FMT ", pump v[%" PetscInt_FMT "] -> v[%" PetscInt_FMT "]\n", i, node1, node2));
179:     }

181:     for (j = 0; j < water->nvertex; j++) {
182:       if (water->vertex[j].id == node1) {
183:         edgelist[2 * i] = j;
184:         break;
185:       }
186:     }

188:     for (j = 0; j < water->nvertex; j++) {
189:       if (water->vertex[j].id == node2) {
190:         edgelist[2 * i + 1] = j;
191:         break;
192:       }
193:     }
194:   }
195:   PetscFunctionReturn(PETSC_SUCCESS);
196: }

198: PetscErrorCode SetInitialGuess_Water(DM networkdm, Vec localX, PetscInt nv, PetscInt ne, const PetscInt *vtx, const PetscInt *edges, void *appctx)
199: {
200:   PetscInt     i, offset, key;
201:   PetscBool    ghostvtex, sharedv;
202:   VERTEX_Water vertex;
203:   PetscScalar *xarr;

205:   PetscFunctionBegin;
206:   PetscCall(VecGetArray(localX, &xarr));
207:   for (i = 0; i < nv; i++) {
208:     PetscCall(DMNetworkIsGhostVertex(networkdm, vtx[i], &ghostvtex));
209:     PetscCall(DMNetworkIsSharedVertex(networkdm, vtx[i], &sharedv));
210:     if (ghostvtex || sharedv) continue;

212:     PetscCall(DMNetworkGetComponent(networkdm, vtx[i], 0, &key, (void **)&vertex, NULL));
213:     PetscCall(DMNetworkGetLocalVecOffset(networkdm, vtx[i], 0, &offset));
214:     if (vertex->type == VERTEX_TYPE_JUNCTION) {
215:       xarr[offset] = 100;
216:     } else if (vertex->type == VERTEX_TYPE_RESERVOIR) {
217:       xarr[offset] = vertex->res.head;
218:     } else {
219:       xarr[offset] = vertex->tank.initlvl + vertex->tank.elev;
220:     }
221:   }
222:   PetscCall(VecRestoreArray(localX, &xarr));
223:   PetscFunctionReturn(PETSC_SUCCESS);
224: }