1c4762a1bSJed Brown #include "water.h" 2c4762a1bSJed Brown #include <string.h> 3c4762a1bSJed Brown #include <ctype.h> 4c4762a1bSJed Brown 5d71ae5a4SJacob Faibussowitsch PetscErrorCode PumpHeadCurveResidual(SNES snes, Vec X, Vec F, void *ctx) 6d71ae5a4SJacob Faibussowitsch { 7c4762a1bSJed Brown const PetscScalar *x; 8c4762a1bSJed Brown PetscScalar *f; 9c4762a1bSJed Brown Pump *pump = (Pump *)ctx; 10c4762a1bSJed Brown PetscScalar *head = pump->headcurve.head, *flow = pump->headcurve.flow; 11c4762a1bSJed Brown PetscInt i; 12c4762a1bSJed Brown 13c4762a1bSJed Brown PetscFunctionBegin; 149566063dSJacob Faibussowitsch PetscCall(VecGetArrayRead(X, &x)); 159566063dSJacob Faibussowitsch PetscCall(VecGetArray(F, &f)); 16c4762a1bSJed Brown 17c4762a1bSJed Brown f[0] = f[1] = f[2] = 0; 18c4762a1bSJed Brown for (i = 0; i < pump->headcurve.npt; i++) { 19c4762a1bSJed Brown f[0] += x[0] - x[1] * PetscPowScalar(flow[i], x[2]) - head[i]; /* Partial w.r.t x[0] */ 20c4762a1bSJed Brown f[1] += (x[0] - x[1] * PetscPowScalar(flow[i], x[2]) - head[i]) * -1 * PetscPowScalar(flow[i], x[2]); /* Partial w.r.t x[1] */ 21c4762a1bSJed Brown f[2] += (x[0] - x[1] * PetscPowScalar(flow[i], x[2]) - head[i]) * -1 * x[1] * x[2] * PetscPowScalar(flow[i], x[2] - 1); /* Partial w.r.t x[2] */ 22c4762a1bSJed Brown } 23c4762a1bSJed Brown 249566063dSJacob Faibussowitsch PetscCall(VecRestoreArrayRead(X, &x)); 259566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(F, &f)); 26c4762a1bSJed Brown 27*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 28c4762a1bSJed Brown } 29c4762a1bSJed Brown 30d71ae5a4SJacob Faibussowitsch PetscErrorCode SetPumpHeadCurveParams(Pump *pump) 31d71ae5a4SJacob Faibussowitsch { 32c4762a1bSJed Brown SNES snes; 33c4762a1bSJed Brown Vec X, F; 34c4762a1bSJed Brown PetscScalar *head, *flow, *x; 35c4762a1bSJed Brown SNESConvergedReason reason; 36c4762a1bSJed Brown 37c4762a1bSJed Brown PetscFunctionBegin; 38c4762a1bSJed Brown head = pump->headcurve.head; 39c4762a1bSJed Brown flow = pump->headcurve.flow; 40c4762a1bSJed Brown if (pump->headcurve.npt == 1) { 41c4762a1bSJed Brown /* Single point head curve, set the other two data points */ 42c4762a1bSJed Brown flow[1] = 0; 43c4762a1bSJed Brown head[1] = 1.33 * head[0]; /* 133% of design head -- From EPANET manual */ 44c4762a1bSJed Brown flow[2] = 2 * flow[0]; /* 200% of design flow -- From EPANET manual */ 45c4762a1bSJed Brown head[2] = 0; 46c4762a1bSJed Brown pump->headcurve.npt += 2; 47c4762a1bSJed Brown } 48c4762a1bSJed Brown 499566063dSJacob Faibussowitsch PetscCall(SNESCreate(PETSC_COMM_SELF, &snes)); 50c4762a1bSJed Brown 519566063dSJacob Faibussowitsch PetscCall(VecCreate(PETSC_COMM_SELF, &X)); 529566063dSJacob Faibussowitsch PetscCall(VecSetSizes(X, 3, 3)); 539566063dSJacob Faibussowitsch PetscCall(VecSetFromOptions(X)); 549566063dSJacob Faibussowitsch PetscCall(VecDuplicate(X, &F)); 55c4762a1bSJed Brown 569566063dSJacob Faibussowitsch PetscCall(SNESSetFunction(snes, F, PumpHeadCurveResidual, (void *)pump)); 579566063dSJacob Faibussowitsch PetscCall(SNESSetJacobian(snes, NULL, NULL, SNESComputeJacobianDefault, NULL)); 589566063dSJacob Faibussowitsch PetscCall(SNESSetFromOptions(snes)); 59c4762a1bSJed Brown 609566063dSJacob Faibussowitsch PetscCall(VecGetArray(X, &x)); 619371c9d4SSatish Balay x[0] = head[1]; 629371c9d4SSatish Balay x[1] = 10; 639371c9d4SSatish Balay x[2] = 3; 649566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(X, &x)); 65c4762a1bSJed Brown 669566063dSJacob Faibussowitsch PetscCall(SNESSolve(snes, NULL, X)); 67c4762a1bSJed Brown 689566063dSJacob Faibussowitsch PetscCall(SNESGetConvergedReason(snes, &reason)); 697a46b595SBarry Smith PetscCheck(reason >= 0, PETSC_COMM_SELF, PETSC_ERR_CONV_FAILED, "Pump head curve did not converge"); 70c4762a1bSJed Brown 719566063dSJacob Faibussowitsch PetscCall(VecGetArray(X, &x)); 72c4762a1bSJed Brown pump->h0 = x[0]; 73c4762a1bSJed Brown pump->r = x[1]; 74c4762a1bSJed Brown pump->n = x[2]; 759566063dSJacob Faibussowitsch PetscCall(VecRestoreArray(X, &x)); 76c4762a1bSJed Brown 779566063dSJacob Faibussowitsch PetscCall(VecDestroy(&X)); 789566063dSJacob Faibussowitsch PetscCall(VecDestroy(&F)); 799566063dSJacob Faibussowitsch PetscCall(SNESDestroy(&snes)); 80*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 81c4762a1bSJed Brown } 82c4762a1bSJed Brown 83d71ae5a4SJacob Faibussowitsch int LineStartsWith(const char *a, const char *b) 84d71ae5a4SJacob Faibussowitsch { 85c4762a1bSJed Brown if (strncmp(a, b, strlen(b)) == 0) return 1; 86c4762a1bSJed Brown return 0; 87c4762a1bSJed Brown } 88c4762a1bSJed Brown 89d71ae5a4SJacob Faibussowitsch int CheckDataSegmentEnd(const char *line) 90d71ae5a4SJacob Faibussowitsch { 919371c9d4SSatish Balay if (LineStartsWith(line, "[JUNCTIONS]") || LineStartsWith(line, "[RESERVOIRS]") || LineStartsWith(line, "[TANKS]") || LineStartsWith(line, "[PIPES]") || LineStartsWith(line, "[PUMPS]") || LineStartsWith(line, "[CURVES]") || LineStartsWith(line, "[VALVES]") || LineStartsWith(line, "[PATTERNS]") || LineStartsWith(line, "[VALVES]") || LineStartsWith(line, "[QUALITY]") || LineStartsWith(line, "\n") || LineStartsWith(line, "\r\n")) { 92c4762a1bSJed Brown return 1; 93c4762a1bSJed Brown } 94c4762a1bSJed Brown return 0; 95c4762a1bSJed Brown } 96c4762a1bSJed Brown 97c4762a1bSJed Brown /* Gets the file pointer positiion for the start of the data segment and the 98c4762a1bSJed Brown number of data segments (lines) read 99c4762a1bSJed Brown */ 100d71ae5a4SJacob Faibussowitsch PetscErrorCode GetDataSegment(FILE *fp, char *line, fpos_t *data_segment_start_pos, PetscInt *ndatalines) 101d71ae5a4SJacob Faibussowitsch { 102c4762a1bSJed Brown PetscInt data_segment_end; 103c4762a1bSJed Brown PetscInt nlines = 0; 104c4762a1bSJed Brown 105c4762a1bSJed Brown PetscFunctionBegin; 106c4762a1bSJed Brown data_segment_end = 0; 107c4762a1bSJed Brown fgetpos(fp, data_segment_start_pos); 10808401ef6SPierre Jolivet PetscCheck(fgets(line, MAXLINE, fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Cannot read data segment from file"); 109c4762a1bSJed Brown while (LineStartsWith(line, ";")) { 110c4762a1bSJed Brown fgetpos(fp, data_segment_start_pos); 11108401ef6SPierre Jolivet PetscCheck(fgets(line, MAXLINE, fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Cannot read data segment from file"); 112c4762a1bSJed Brown } 113c4762a1bSJed Brown while (!data_segment_end) { 11408401ef6SPierre Jolivet PetscCheck(fgets(line, MAXLINE, fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Cannot read data segment from file"); 115c4762a1bSJed Brown nlines++; 116c4762a1bSJed Brown data_segment_end = CheckDataSegmentEnd(line); 117c4762a1bSJed Brown } 118c4762a1bSJed Brown *ndatalines = nlines; 119*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 120c4762a1bSJed Brown } 121c4762a1bSJed Brown 122d71ae5a4SJacob Faibussowitsch PetscErrorCode WaterReadData(WATERDATA *water, char *filename) 123d71ae5a4SJacob Faibussowitsch { 124c4762a1bSJed Brown FILE *fp = NULL; 125c4762a1bSJed Brown VERTEX_Water vert; 126c4762a1bSJed Brown EDGE_Water edge; 127c4762a1bSJed Brown fpos_t junc_start_pos, res_start_pos, tank_start_pos, pipe_start_pos, pump_start_pos; 128c4762a1bSJed Brown fpos_t curve_start_pos, title_start_pos; 129c4762a1bSJed Brown char line[MAXLINE]; 130c4762a1bSJed Brown PetscInt i, j, nv = 0, ne = 0, ncurve = 0, ntitle = 0, nlines, ndata, curve_id; 131c4762a1bSJed Brown Junction *junction = NULL; 132c4762a1bSJed Brown Reservoir *reservoir = NULL; 133c4762a1bSJed Brown Tank *tank = NULL; 134c4762a1bSJed Brown Pipe *pipe = NULL; 135c4762a1bSJed Brown Pump *pump = NULL; 136c4762a1bSJed Brown PetscScalar curve_x, curve_y; 137c4762a1bSJed Brown double v1, v2, v3, v4, v5, v6; 138c4762a1bSJed Brown 139c4762a1bSJed Brown PetscFunctionBegin; 140c4762a1bSJed Brown water->nvertex = water->nedge = 0; 141c4762a1bSJed Brown fp = fopen(filename, "rb"); 142c4762a1bSJed Brown /* Check for valid file */ 14328b400f6SJacob Faibussowitsch PetscCheck(fp, PETSC_COMM_SELF, PETSC_ERR_FILE_OPEN, "Can't open EPANET data file %s", filename); 144c4762a1bSJed Brown 145c4762a1bSJed Brown /* Read file and get line numbers for different data segments */ 146c4762a1bSJed Brown while (fgets(line, MAXLINE, fp)) { 147*3ba16761SJacob Faibussowitsch if (strstr(line, "[TITLE]")) PetscCall(GetDataSegment(fp, line, &title_start_pos, &ntitle)); 148c4762a1bSJed Brown 149c4762a1bSJed Brown if (strstr(line, "[JUNCTIONS]")) { 150*3ba16761SJacob Faibussowitsch PetscCall(GetDataSegment(fp, line, &junc_start_pos, &nlines)); 151c4762a1bSJed Brown water->nvertex += nlines; 152c4762a1bSJed Brown water->njunction = nlines; 153c4762a1bSJed Brown } 154c4762a1bSJed Brown 155c4762a1bSJed Brown if (strstr(line, "[RESERVOIRS]")) { 156*3ba16761SJacob Faibussowitsch PetscCall(GetDataSegment(fp, line, &res_start_pos, &nlines)); 157c4762a1bSJed Brown water->nvertex += nlines; 158c4762a1bSJed Brown water->nreservoir = nlines; 159c4762a1bSJed Brown } 160c4762a1bSJed Brown 161c4762a1bSJed Brown if (strstr(line, "[TANKS]")) { 162*3ba16761SJacob Faibussowitsch PetscCall(GetDataSegment(fp, line, &tank_start_pos, &nlines)); 163c4762a1bSJed Brown water->nvertex += nlines; 164c4762a1bSJed Brown water->ntank = nlines; 165c4762a1bSJed Brown } 166c4762a1bSJed Brown 167c4762a1bSJed Brown if (strstr(line, "[PIPES]")) { 168*3ba16761SJacob Faibussowitsch PetscCall(GetDataSegment(fp, line, &pipe_start_pos, &nlines)); 169c4762a1bSJed Brown water->nedge += nlines; 170c4762a1bSJed Brown water->npipe = nlines; 171c4762a1bSJed Brown } 172c4762a1bSJed Brown 173c4762a1bSJed Brown if (strstr(line, "[PUMPS]")) { 174*3ba16761SJacob Faibussowitsch PetscCall(GetDataSegment(fp, line, &pump_start_pos, &nlines)); 175c4762a1bSJed Brown water->nedge += nlines; 176c4762a1bSJed Brown water->npump = nlines; 177c4762a1bSJed Brown } 178c4762a1bSJed Brown 179*3ba16761SJacob Faibussowitsch if (strstr(line, "[CURVES]")) PetscCall(GetDataSegment(fp, line, &curve_start_pos, &ncurve)); 180c4762a1bSJed Brown } 181c4762a1bSJed Brown 182c4762a1bSJed Brown /* Allocate vertex and edge data structs */ 1839566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(water->nvertex, &water->vertex)); 1849566063dSJacob Faibussowitsch PetscCall(PetscCalloc1(water->nedge, &water->edge)); 185c4762a1bSJed Brown vert = water->vertex; 186c4762a1bSJed Brown edge = water->edge; 187c4762a1bSJed Brown 188c4762a1bSJed Brown /* Junctions */ 189c4762a1bSJed Brown fsetpos(fp, &junc_start_pos); 190c4762a1bSJed Brown for (i = 0; i < water->njunction; i++) { 191c4762a1bSJed Brown int id = 0, pattern = 0; 19208401ef6SPierre Jolivet PetscCheck(fgets(line, MAXLINE, fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Cannot read junction from file"); 193c4762a1bSJed Brown vert[nv].type = VERTEX_TYPE_JUNCTION; 194c4762a1bSJed Brown junction = &vert[nv].junc; 1959371c9d4SSatish Balay ndata = sscanf(line, "%d %lf %lf %d", &id, &v1, &v2, &pattern); 1969371c9d4SSatish Balay PetscCheck(ndata >= 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read junction data"); 197c4762a1bSJed Brown vert[nv].id = id; 198c4762a1bSJed Brown junction->dempattern = pattern; 199c4762a1bSJed Brown junction->elev = (PetscScalar)v1; 200c4762a1bSJed Brown junction->demand = (PetscScalar)v2; 201c4762a1bSJed Brown junction->demand *= GPM_CFS; 202c4762a1bSJed Brown junction->id = vert[nv].id; 203c4762a1bSJed Brown nv++; 204c4762a1bSJed Brown } 205c4762a1bSJed Brown 206c4762a1bSJed Brown /* Reservoirs */ 207c4762a1bSJed Brown fsetpos(fp, &res_start_pos); 208c4762a1bSJed Brown for (i = 0; i < water->nreservoir; i++) { 209c4762a1bSJed Brown int id = 0, pattern = 0; 21008401ef6SPierre Jolivet PetscCheck(fgets(line, MAXLINE, fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Cannot read reservoir from file"); 211c4762a1bSJed Brown vert[nv].type = VERTEX_TYPE_RESERVOIR; 212c4762a1bSJed Brown reservoir = &vert[nv].res; 2139371c9d4SSatish Balay ndata = sscanf(line, "%d %lf %d", &id, &v1, &pattern); 2149371c9d4SSatish Balay PetscCheck(ndata >= 2, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read reservoir data"); 215c4762a1bSJed Brown vert[nv].id = id; 216c4762a1bSJed Brown reservoir->headpattern = pattern; 217c4762a1bSJed Brown reservoir->head = (PetscScalar)v1; 218c4762a1bSJed Brown reservoir->id = vert[nv].id; 219c4762a1bSJed Brown nv++; 220c4762a1bSJed Brown } 221c4762a1bSJed Brown 222c4762a1bSJed Brown /* Tanks */ 223c4762a1bSJed Brown fsetpos(fp, &tank_start_pos); 224c4762a1bSJed Brown for (i = 0; i < water->ntank; i++) { 225c4762a1bSJed Brown int id = 0, curve = 0; 22608401ef6SPierre Jolivet PetscCheck(fgets(line, MAXLINE, fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Cannot read data tank from file"); 227c4762a1bSJed Brown vert[nv].type = VERTEX_TYPE_TANK; 228c4762a1bSJed Brown tank = &vert[nv].tank; 2299371c9d4SSatish Balay ndata = sscanf(line, "%d %lf %lf %lf %lf %lf %lf %d", &id, &v1, &v2, &v3, &v4, &v5, &v6, &curve); 2309371c9d4SSatish Balay PetscCheck(ndata >= 7, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read tank data"); 231c4762a1bSJed Brown vert[nv].id = id; 232c4762a1bSJed Brown tank->volumecurve = curve; 233c4762a1bSJed Brown tank->elev = (PetscScalar)v1; 234c4762a1bSJed Brown tank->initlvl = (PetscScalar)v2; 235c4762a1bSJed Brown tank->minlvl = (PetscScalar)v3; 236c4762a1bSJed Brown tank->maxlvl = (PetscScalar)v4; 237c4762a1bSJed Brown tank->diam = (PetscScalar)v5; 238c4762a1bSJed Brown tank->minvolume = (PetscScalar)v6; 239c4762a1bSJed Brown tank->id = vert[nv].id; 240c4762a1bSJed Brown nv++; 241c4762a1bSJed Brown } 242c4762a1bSJed Brown 243c4762a1bSJed Brown /* Pipes */ 244c4762a1bSJed Brown fsetpos(fp, &pipe_start_pos); 245c4762a1bSJed Brown for (i = 0; i < water->npipe; i++) { 246c4762a1bSJed Brown int id = 0, node1 = 0, node2 = 0; 24708401ef6SPierre Jolivet PetscCheck(fgets(line, MAXLINE, fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Cannot read data pipe from file"); 248c4762a1bSJed Brown edge[ne].type = EDGE_TYPE_PIPE; 249c4762a1bSJed Brown pipe = &edge[ne].pipe; 250c4762a1bSJed Brown ndata = sscanf(line, "%d %d %d %lf %lf %lf %lf %s", &id, &node1, &node2, &v1, &v2, &v3, &v4, pipe->stat); 251c4762a1bSJed Brown pipe->id = id; 252c4762a1bSJed Brown pipe->node1 = node1; 253c4762a1bSJed Brown pipe->node2 = node2; 254c4762a1bSJed Brown pipe->length = (PetscScalar)v1; 255c4762a1bSJed Brown pipe->diam = (PetscScalar)v2; 256c4762a1bSJed Brown pipe->roughness = (PetscScalar)v3; 257c4762a1bSJed Brown pipe->minorloss = (PetscScalar)v4; 258c4762a1bSJed Brown edge[ne].id = pipe->id; 259c4762a1bSJed Brown if (strcmp(pipe->stat, "OPEN") == 0) pipe->status = PIPE_STATUS_OPEN; 260c4762a1bSJed Brown if (ndata < 8) { 261c4762a1bSJed Brown strcpy(pipe->stat, "OPEN"); /* default OPEN */ 262c4762a1bSJed Brown pipe->status = PIPE_STATUS_OPEN; 263c4762a1bSJed Brown } 264c4762a1bSJed Brown if (ndata < 7) pipe->minorloss = 0.; 265c4762a1bSJed Brown pipe->n = 1.85; 266c4762a1bSJed Brown pipe->k = 4.72 * pipe->length / (PetscPowScalar(pipe->roughness, pipe->n) * PetscPowScalar(0.0833333 * pipe->diam, 4.87)); 267c4762a1bSJed Brown ne++; 268c4762a1bSJed Brown } 269c4762a1bSJed Brown 270c4762a1bSJed Brown /* Pumps */ 271c4762a1bSJed Brown fsetpos(fp, &pump_start_pos); 272c4762a1bSJed Brown for (i = 0; i < water->npump; i++) { 273c4762a1bSJed Brown int id = 0, node1 = 0, node2 = 0, paramid = 0; 27408401ef6SPierre Jolivet PetscCheck(fgets(line, MAXLINE, fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Cannot read data pump from file"); 275c4762a1bSJed Brown edge[ne].type = EDGE_TYPE_PUMP; 276c4762a1bSJed Brown pump = &edge[ne].pump; 2779371c9d4SSatish Balay ndata = sscanf(line, "%d %d %d %s %d", &id, &node1, &node2, pump->param, ¶mid); 2789371c9d4SSatish Balay PetscCheck(ndata == 5, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read pump data"); 279c4762a1bSJed Brown pump->id = id; 280c4762a1bSJed Brown pump->node1 = node1; 281c4762a1bSJed Brown pump->node2 = node2; 282c4762a1bSJed Brown pump->paramid = paramid; 283c4762a1bSJed Brown edge[ne].id = pump->id; 284c4762a1bSJed Brown ne++; 285c4762a1bSJed Brown } 286c4762a1bSJed Brown 287c4762a1bSJed Brown /* Curves */ 288c4762a1bSJed Brown fsetpos(fp, &curve_start_pos); 289c4762a1bSJed Brown for (i = 0; i < ncurve; i++) { 290c4762a1bSJed Brown int icurve_id = 0; 29108401ef6SPierre Jolivet PetscCheck(fgets(line, MAXLINE, fp), PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Cannot read data curve from file"); 2929371c9d4SSatish Balay ndata = sscanf(line, "%d %lf %lf", &icurve_id, &v1, &v2); 2939371c9d4SSatish Balay PetscCheck(ndata == 3, PETSC_COMM_SELF, PETSC_ERR_FILE_READ, "Unable to read curve data"); 294c4762a1bSJed Brown curve_id = icurve_id; 295c4762a1bSJed Brown curve_x = (PetscScalar)v1; 296c4762a1bSJed Brown curve_y = (PetscScalar)v2; 297c4762a1bSJed Brown /* Check for pump with the curve_id */ 298c4762a1bSJed Brown for (j = water->npipe; j < water->npipe + water->npump; j++) { 299c4762a1bSJed Brown if (water->edge[j].pump.paramid == curve_id) { 3007a46b595SBarry Smith PetscCheck(pump->headcurve.npt != 3, PETSC_COMM_SELF, PETSC_ERR_SUP, "Pump %" PetscInt_FMT " [%" PetscInt_FMT " --> %" PetscInt_FMT "]: No support for more than 3-pt head-flow curve", pump->id, pump->node1, pump->node2); 301c4762a1bSJed Brown pump = &water->edge[j].pump; 302c4762a1bSJed Brown pump->headcurve.flow[pump->headcurve.npt] = curve_x * GPM_CFS; 303c4762a1bSJed Brown pump->headcurve.head[pump->headcurve.npt] = curve_y; 304c4762a1bSJed Brown pump->headcurve.npt++; 305c4762a1bSJed Brown break; 306c4762a1bSJed Brown } 307c4762a1bSJed Brown } 308c4762a1bSJed Brown } 309c4762a1bSJed Brown 310c4762a1bSJed Brown fclose(fp); 311c4762a1bSJed Brown 312c4762a1bSJed Brown /* Get pump curve parameters */ 313c4762a1bSJed Brown for (j = water->npipe; j < water->npipe + water->npump; j++) { 314c4762a1bSJed Brown pump = &water->edge[j].pump; 315c4762a1bSJed Brown if (strcmp(pump->param, "HEAD") == 0) { 316c4762a1bSJed Brown /* Head-flow curve */ 3179566063dSJacob Faibussowitsch PetscCall(SetPumpHeadCurveParams(pump)); 318c4762a1bSJed Brown } 319c4762a1bSJed Brown } 320*3ba16761SJacob Faibussowitsch PetscFunctionReturn(PETSC_SUCCESS); 321c4762a1bSJed Brown } 322