xref: /petsc/src/snes/tutorials/network/water/waterreaddata.c (revision c4762a1b19cd2af06abeed90e8f9d34fb975dd94)
1*c4762a1bSJed Brown #include "water.h"
2*c4762a1bSJed Brown #include <string.h>
3*c4762a1bSJed Brown #include <ctype.h>
4*c4762a1bSJed Brown 
5*c4762a1bSJed Brown PetscErrorCode PumpHeadCurveResidual(SNES snes,Vec X, Vec F,void *ctx)
6*c4762a1bSJed Brown {
7*c4762a1bSJed Brown   PetscErrorCode ierr;
8*c4762a1bSJed Brown   const PetscScalar *x;
9*c4762a1bSJed Brown   PetscScalar *f;
10*c4762a1bSJed Brown   Pump        *pump=(Pump*)ctx;
11*c4762a1bSJed Brown   PetscScalar *head=pump->headcurve.head,*flow=pump->headcurve.flow;
12*c4762a1bSJed Brown   PetscInt i;
13*c4762a1bSJed Brown 
14*c4762a1bSJed Brown   PetscFunctionBegin;
15*c4762a1bSJed Brown   ierr = VecGetArrayRead(X,&x);CHKERRQ(ierr);
16*c4762a1bSJed Brown   ierr = VecGetArray(F,&f);CHKERRQ(ierr);
17*c4762a1bSJed Brown 
18*c4762a1bSJed Brown   f[0] = f[1] = f[2] = 0;
19*c4762a1bSJed Brown   for(i=0; i < pump->headcurve.npt;i++) {
20*c4762a1bSJed Brown     f[0] +=   x[0] - x[1]*PetscPowScalar(flow[i],x[2]) - head[i]; /* Partial w.r.t x[0] */
21*c4762a1bSJed 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] */
22*c4762a1bSJed 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] */
23*c4762a1bSJed Brown   }
24*c4762a1bSJed Brown 
25*c4762a1bSJed Brown   ierr = VecRestoreArrayRead(X,&x);CHKERRQ(ierr);
26*c4762a1bSJed Brown   ierr = VecRestoreArray(F,&f);CHKERRQ(ierr);
27*c4762a1bSJed Brown 
28*c4762a1bSJed Brown   PetscFunctionReturn(0);
29*c4762a1bSJed Brown }
30*c4762a1bSJed Brown 
31*c4762a1bSJed Brown PetscErrorCode SetPumpHeadCurveParams(Pump *pump)
32*c4762a1bSJed Brown {
33*c4762a1bSJed Brown   PetscErrorCode ierr;
34*c4762a1bSJed Brown   SNES           snes;
35*c4762a1bSJed Brown   Vec            X,F;
36*c4762a1bSJed Brown   PetscScalar   *head,*flow,*x;
37*c4762a1bSJed Brown   SNESConvergedReason reason;
38*c4762a1bSJed Brown 
39*c4762a1bSJed Brown   PetscFunctionBegin;
40*c4762a1bSJed Brown   head = pump->headcurve.head;
41*c4762a1bSJed Brown   flow = pump->headcurve.flow;
42*c4762a1bSJed Brown   if(pump->headcurve.npt == 1) {
43*c4762a1bSJed Brown     /* Single point head curve, set the other two data points */
44*c4762a1bSJed Brown     flow[1] = 0;
45*c4762a1bSJed Brown     head[1] = 1.33*head[0]; /* 133% of design head -- From EPANET manual */
46*c4762a1bSJed Brown     flow[2] = 2*flow[0];    /* 200% of design flow -- From EPANET manual */
47*c4762a1bSJed Brown     head[2] = 0;
48*c4762a1bSJed Brown     pump->headcurve.npt += 2;
49*c4762a1bSJed Brown   }
50*c4762a1bSJed Brown 
51*c4762a1bSJed Brown   ierr = SNESCreate(PETSC_COMM_SELF,&snes);CHKERRQ(ierr);
52*c4762a1bSJed Brown 
53*c4762a1bSJed Brown   ierr = VecCreate(PETSC_COMM_SELF,&X);CHKERRQ(ierr);
54*c4762a1bSJed Brown   ierr = VecSetSizes(X,3,3);CHKERRQ(ierr);
55*c4762a1bSJed Brown   ierr = VecSetFromOptions(X);CHKERRQ(ierr);
56*c4762a1bSJed Brown   ierr = VecDuplicate(X,&F);CHKERRQ(ierr);
57*c4762a1bSJed Brown 
58*c4762a1bSJed Brown   ierr = SNESSetFunction(snes,F,PumpHeadCurveResidual,(void*)pump);CHKERRQ(ierr);
59*c4762a1bSJed Brown   ierr = SNESSetJacobian(snes,NULL,NULL,SNESComputeJacobianDefault,NULL);CHKERRQ(ierr);
60*c4762a1bSJed Brown   ierr = SNESSetFromOptions(snes);CHKERRQ(ierr);
61*c4762a1bSJed Brown 
62*c4762a1bSJed Brown   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
63*c4762a1bSJed Brown   x[0] = head[1]; x[1] = 10; x[2] = 3;
64*c4762a1bSJed Brown   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
65*c4762a1bSJed Brown 
66*c4762a1bSJed Brown   ierr = SNESSolve(snes,NULL,X);CHKERRQ(ierr);
67*c4762a1bSJed Brown 
68*c4762a1bSJed Brown   ierr = SNESGetConvergedReason(snes,&reason);CHKERRQ(ierr);
69*c4762a1bSJed Brown   if(reason < 0) {
70*c4762a1bSJed Brown     SETERRQ(PETSC_COMM_SELF,0,"Pump head curve did not converge\n");
71*c4762a1bSJed Brown   }
72*c4762a1bSJed Brown 
73*c4762a1bSJed Brown   ierr = VecGetArray(X,&x);CHKERRQ(ierr);
74*c4762a1bSJed Brown   pump->h0 = x[0];
75*c4762a1bSJed Brown   pump->r  = x[1];
76*c4762a1bSJed Brown   pump->n  = x[2];
77*c4762a1bSJed Brown   ierr = VecRestoreArray(X,&x);CHKERRQ(ierr);
78*c4762a1bSJed Brown 
79*c4762a1bSJed Brown   ierr = VecDestroy(&X);CHKERRQ(ierr);
80*c4762a1bSJed Brown   ierr = VecDestroy(&F);CHKERRQ(ierr);
81*c4762a1bSJed Brown   ierr = SNESDestroy(&snes);CHKERRQ(ierr);
82*c4762a1bSJed Brown   PetscFunctionReturn(0);
83*c4762a1bSJed Brown }
84*c4762a1bSJed Brown 
85*c4762a1bSJed Brown int LineStartsWith(const char *a, const char *b)
86*c4762a1bSJed Brown {
87*c4762a1bSJed Brown   if(strncmp(a, b, strlen(b)) == 0) return 1;
88*c4762a1bSJed Brown   return 0;
89*c4762a1bSJed Brown }
90*c4762a1bSJed Brown 
91*c4762a1bSJed Brown int CheckDataSegmentEnd(const char *line)
92*c4762a1bSJed Brown {
93*c4762a1bSJed Brown   if(LineStartsWith(line,"[JUNCTIONS]") || \
94*c4762a1bSJed Brown      LineStartsWith(line,"[RESERVOIRS]") || \
95*c4762a1bSJed Brown      LineStartsWith(line,"[TANKS]") || \
96*c4762a1bSJed Brown      LineStartsWith(line,"[PIPES]") || \
97*c4762a1bSJed Brown      LineStartsWith(line,"[PUMPS]") || \
98*c4762a1bSJed Brown      LineStartsWith(line,"[CURVES]") || \
99*c4762a1bSJed Brown      LineStartsWith(line,"[VALVES]") || \
100*c4762a1bSJed Brown      LineStartsWith(line,"[PATTERNS]") || \
101*c4762a1bSJed Brown      LineStartsWith(line,"[VALVES]") || \
102*c4762a1bSJed Brown      LineStartsWith(line,"[QUALITY]") || \
103*c4762a1bSJed Brown      LineStartsWith(line,"\n") || LineStartsWith(line,"\r\n")) {
104*c4762a1bSJed Brown     return 1;
105*c4762a1bSJed Brown   }
106*c4762a1bSJed Brown   return 0;
107*c4762a1bSJed Brown }
108*c4762a1bSJed Brown 
109*c4762a1bSJed Brown /* Gets the file pointer positiion for the start of the data segment and the
110*c4762a1bSJed Brown    number of data segments (lines) read
111*c4762a1bSJed Brown */
112*c4762a1bSJed Brown PetscErrorCode GetDataSegment(FILE *fp,char *line,fpos_t *data_segment_start_pos,PetscInt *ndatalines)
113*c4762a1bSJed Brown {
114*c4762a1bSJed Brown   PetscInt data_segment_end;
115*c4762a1bSJed Brown   PetscInt nlines=0;
116*c4762a1bSJed Brown 
117*c4762a1bSJed Brown   PetscFunctionBegin;
118*c4762a1bSJed Brown   data_segment_end = 0;
119*c4762a1bSJed Brown   fgetpos(fp,data_segment_start_pos);
120*c4762a1bSJed Brown   if (!fgets(line,MAXLINE,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Cannot read data segment from file");
121*c4762a1bSJed Brown   while(LineStartsWith(line,";")) {
122*c4762a1bSJed Brown     fgetpos(fp,data_segment_start_pos);
123*c4762a1bSJed Brown     if (!fgets(line,MAXLINE,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Cannot read data segment from file");
124*c4762a1bSJed Brown   }
125*c4762a1bSJed Brown   while(!data_segment_end) {
126*c4762a1bSJed Brown     if (!fgets(line,MAXLINE,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Cannot read data segment from file");
127*c4762a1bSJed Brown     nlines++;
128*c4762a1bSJed Brown     data_segment_end = CheckDataSegmentEnd(line);
129*c4762a1bSJed Brown   }
130*c4762a1bSJed Brown   *ndatalines = nlines;
131*c4762a1bSJed Brown   PetscFunctionReturn(0);
132*c4762a1bSJed Brown }
133*c4762a1bSJed Brown 
134*c4762a1bSJed Brown 
135*c4762a1bSJed Brown PetscErrorCode WaterReadData(WATERDATA *water,char *filename)
136*c4762a1bSJed Brown {
137*c4762a1bSJed Brown   FILE           *fp=NULL;
138*c4762a1bSJed Brown   PetscErrorCode ierr;
139*c4762a1bSJed Brown   VERTEX_Water   vert;
140*c4762a1bSJed Brown   EDGE_Water     edge;
141*c4762a1bSJed Brown   fpos_t         junc_start_pos,res_start_pos,tank_start_pos,pipe_start_pos,pump_start_pos;
142*c4762a1bSJed Brown   fpos_t         curve_start_pos,title_start_pos;
143*c4762a1bSJed Brown   char           line[MAXLINE];
144*c4762a1bSJed Brown   PetscInt       i,j,nv=0,ne=0,ncurve=0,ntitle=0,nlines,ndata,curve_id;
145*c4762a1bSJed Brown   Junction       *junction=NULL;
146*c4762a1bSJed Brown   Reservoir      *reservoir=NULL;
147*c4762a1bSJed Brown   Tank           *tank=NULL;
148*c4762a1bSJed Brown   Pipe           *pipe=NULL;
149*c4762a1bSJed Brown   Pump           *pump=NULL;
150*c4762a1bSJed Brown   PetscScalar    curve_x,curve_y;
151*c4762a1bSJed Brown   double         v1,v2,v3,v4,v5,v6;
152*c4762a1bSJed Brown 
153*c4762a1bSJed Brown   PetscFunctionBegin;
154*c4762a1bSJed Brown   water->nvertex = water->nedge = 0;
155*c4762a1bSJed Brown   fp = fopen(filename,"rb");
156*c4762a1bSJed Brown   /* Check for valid file */
157*c4762a1bSJed Brown   if (!fp) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_FILE_OPEN,"Can't open EPANET data file %s",filename);
158*c4762a1bSJed Brown 
159*c4762a1bSJed Brown   /* Read file and get line numbers for different data segments */
160*c4762a1bSJed Brown   while(fgets(line,MAXLINE,fp)) {
161*c4762a1bSJed Brown 
162*c4762a1bSJed Brown     if (strstr(line,"[TITLE]")) {
163*c4762a1bSJed Brown       GetDataSegment(fp,line,&title_start_pos,&ntitle);
164*c4762a1bSJed Brown     }
165*c4762a1bSJed Brown 
166*c4762a1bSJed Brown     if (strstr(line,"[JUNCTIONS]")) {
167*c4762a1bSJed Brown       GetDataSegment(fp,line,&junc_start_pos,&nlines);
168*c4762a1bSJed Brown       water->nvertex += nlines;
169*c4762a1bSJed Brown       water->njunction = nlines;
170*c4762a1bSJed Brown     }
171*c4762a1bSJed Brown 
172*c4762a1bSJed Brown     if (strstr(line,"[RESERVOIRS]")) {
173*c4762a1bSJed Brown       GetDataSegment(fp,line,&res_start_pos,&nlines);
174*c4762a1bSJed Brown       water->nvertex += nlines;
175*c4762a1bSJed Brown       water->nreservoir = nlines;
176*c4762a1bSJed Brown     }
177*c4762a1bSJed Brown 
178*c4762a1bSJed Brown     if (strstr(line,"[TANKS]")) {
179*c4762a1bSJed Brown       GetDataSegment(fp,line,&tank_start_pos,&nlines);
180*c4762a1bSJed Brown       water->nvertex += nlines;
181*c4762a1bSJed Brown       water->ntank = nlines;
182*c4762a1bSJed Brown     }
183*c4762a1bSJed Brown 
184*c4762a1bSJed Brown     if (strstr(line,"[PIPES]")) {
185*c4762a1bSJed Brown       GetDataSegment(fp,line,&pipe_start_pos,&nlines);
186*c4762a1bSJed Brown       water->nedge += nlines;
187*c4762a1bSJed Brown       water->npipe = nlines;
188*c4762a1bSJed Brown     }
189*c4762a1bSJed Brown 
190*c4762a1bSJed Brown     if (strstr(line,"[PUMPS]")) {
191*c4762a1bSJed Brown       GetDataSegment(fp,line,&pump_start_pos,&nlines);
192*c4762a1bSJed Brown       water->nedge += nlines;
193*c4762a1bSJed Brown       water->npump = nlines;
194*c4762a1bSJed Brown     }
195*c4762a1bSJed Brown 
196*c4762a1bSJed Brown     if (strstr(line,"[CURVES]")) {
197*c4762a1bSJed Brown       GetDataSegment(fp,line,&curve_start_pos,&ncurve);
198*c4762a1bSJed Brown     }
199*c4762a1bSJed Brown   }
200*c4762a1bSJed Brown 
201*c4762a1bSJed Brown   /* Allocate vertex and edge data structs */
202*c4762a1bSJed Brown   ierr = PetscCalloc1(water->nvertex,&water->vertex);CHKERRQ(ierr);
203*c4762a1bSJed Brown   ierr = PetscCalloc1(water->nedge,&water->edge);CHKERRQ(ierr);
204*c4762a1bSJed Brown   vert = water->vertex;
205*c4762a1bSJed Brown   edge = water->edge;
206*c4762a1bSJed Brown 
207*c4762a1bSJed Brown   /* Junctions */
208*c4762a1bSJed Brown   fsetpos(fp,&junc_start_pos);
209*c4762a1bSJed Brown   for (i=0; i < water->njunction; i++) {
210*c4762a1bSJed Brown     int id=0,pattern=0;
211*c4762a1bSJed Brown     if (!fgets(line,MAXLINE,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Cannot read junction from file");
212*c4762a1bSJed Brown     vert[nv].type = VERTEX_TYPE_JUNCTION;
213*c4762a1bSJed Brown     junction = &vert[nv].junc;
214*c4762a1bSJed Brown     ndata = sscanf(line,"%d %lf %lf %d",&id,&v1,&v2,&pattern);if (ndata < 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Unable to read junction data");
215*c4762a1bSJed Brown     vert[nv].id          = id;
216*c4762a1bSJed Brown     junction->dempattern = pattern;
217*c4762a1bSJed Brown     junction->elev   = (PetscScalar)v1;
218*c4762a1bSJed Brown     junction->demand = (PetscScalar)v2;
219*c4762a1bSJed Brown     junction->demand *= GPM_CFS;
220*c4762a1bSJed Brown     junction->id = vert[nv].id;
221*c4762a1bSJed Brown     nv++;
222*c4762a1bSJed Brown   }
223*c4762a1bSJed Brown 
224*c4762a1bSJed Brown   /* Reservoirs */
225*c4762a1bSJed Brown   fsetpos(fp,&res_start_pos);
226*c4762a1bSJed Brown   for (i=0; i < water->nreservoir; i++) {
227*c4762a1bSJed Brown     int id=0,pattern=0;
228*c4762a1bSJed Brown     if (!fgets(line,MAXLINE,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Cannot read reservoir from file");
229*c4762a1bSJed Brown     vert[nv].type = VERTEX_TYPE_RESERVOIR;
230*c4762a1bSJed Brown     reservoir = &vert[nv].res;
231*c4762a1bSJed Brown     ndata = sscanf(line,"%d %lf %d",&id,&v1,&pattern);if (ndata < 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Unable to read reservoir data");
232*c4762a1bSJed Brown     vert[nv].id            = id;
233*c4762a1bSJed Brown     reservoir->headpattern = pattern;
234*c4762a1bSJed Brown     reservoir->head = (PetscScalar)v1;
235*c4762a1bSJed Brown     reservoir->id   = vert[nv].id;
236*c4762a1bSJed Brown     nv++;
237*c4762a1bSJed Brown   }
238*c4762a1bSJed Brown 
239*c4762a1bSJed Brown   /* Tanks */
240*c4762a1bSJed Brown   fsetpos(fp,&tank_start_pos);
241*c4762a1bSJed Brown   for (i=0; i < water->ntank; i++) {
242*c4762a1bSJed Brown     int id=0,curve=0;
243*c4762a1bSJed Brown     if (!fgets(line,MAXLINE,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Cannot read data tank from file");
244*c4762a1bSJed Brown     vert[nv].type = VERTEX_TYPE_TANK;
245*c4762a1bSJed Brown     tank = &vert[nv].tank;
246*c4762a1bSJed Brown     ndata = sscanf(line,"%d %lf %lf %lf %lf %lf %lf %d",&id,&v1,&v2,&v3,&v4,&v5,&v6,&curve);if (ndata < 7) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Unable to read tank data");
247*c4762a1bSJed Brown     vert[nv].id       = id;
248*c4762a1bSJed Brown     tank->volumecurve = curve;
249*c4762a1bSJed Brown     tank->elev      = (PetscScalar)v1;
250*c4762a1bSJed Brown     tank->initlvl   = (PetscScalar)v2;
251*c4762a1bSJed Brown     tank->minlvl    = (PetscScalar)v3;
252*c4762a1bSJed Brown     tank->maxlvl    = (PetscScalar)v4;
253*c4762a1bSJed Brown     tank->diam      = (PetscScalar)v5;
254*c4762a1bSJed Brown     tank->minvolume = (PetscScalar)v6;
255*c4762a1bSJed Brown     tank->id        = vert[nv].id;
256*c4762a1bSJed Brown     nv++;
257*c4762a1bSJed Brown   }
258*c4762a1bSJed Brown 
259*c4762a1bSJed Brown   /* Pipes */
260*c4762a1bSJed Brown   fsetpos(fp,&pipe_start_pos);
261*c4762a1bSJed Brown   for (i=0; i < water->npipe; i++) {
262*c4762a1bSJed Brown     int id=0,node1=0,node2=0;
263*c4762a1bSJed Brown     if (!fgets(line,MAXLINE,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Cannot read data pipe from file");
264*c4762a1bSJed Brown     edge[ne].type = EDGE_TYPE_PIPE;
265*c4762a1bSJed Brown     pipe = &edge[ne].pipe;
266*c4762a1bSJed Brown     ndata = sscanf(line,"%d %d %d %lf %lf %lf %lf %s",&id,&node1,&node2,&v1,&v2,&v3,&v4,pipe->stat);
267*c4762a1bSJed Brown     pipe->id        = id;
268*c4762a1bSJed Brown     pipe->node1     = node1;
269*c4762a1bSJed Brown     pipe->node2     = node2;
270*c4762a1bSJed Brown     pipe->length    = (PetscScalar)v1;
271*c4762a1bSJed Brown     pipe->diam      = (PetscScalar)v2;
272*c4762a1bSJed Brown     pipe->roughness = (PetscScalar)v3;
273*c4762a1bSJed Brown     pipe->minorloss = (PetscScalar)v4;
274*c4762a1bSJed Brown     edge[ne].id     = pipe->id;
275*c4762a1bSJed Brown     if (strcmp(pipe->stat,"OPEN") == 0) pipe->status = PIPE_STATUS_OPEN;
276*c4762a1bSJed Brown     if (ndata < 8) {
277*c4762a1bSJed Brown       strcpy(pipe->stat,"OPEN"); /* default OPEN */
278*c4762a1bSJed Brown       pipe->status = PIPE_STATUS_OPEN;
279*c4762a1bSJed Brown     }
280*c4762a1bSJed Brown     if (ndata < 7) pipe->minorloss = 0.;
281*c4762a1bSJed Brown     pipe->n = 1.85;
282*c4762a1bSJed Brown     pipe->k = 4.72*pipe->length/(PetscPowScalar(pipe->roughness,pipe->n)*PetscPowScalar(0.0833333*pipe->diam,4.87));
283*c4762a1bSJed Brown     ne++;
284*c4762a1bSJed Brown   }
285*c4762a1bSJed Brown 
286*c4762a1bSJed Brown   /* Pumps */
287*c4762a1bSJed Brown   fsetpos(fp,&pump_start_pos);
288*c4762a1bSJed Brown   for (i=0; i < water->npump; i++) {
289*c4762a1bSJed Brown     int id=0,node1=0,node2=0,paramid=0;
290*c4762a1bSJed Brown     if (!fgets(line,MAXLINE,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Cannot read data pump from file");
291*c4762a1bSJed Brown     edge[ne].type = EDGE_TYPE_PUMP;
292*c4762a1bSJed Brown     pump = &edge[ne].pump;
293*c4762a1bSJed Brown     ndata = sscanf(line,"%d %d %d %s %d",&id,&node1,&node2,pump->param,&paramid);if (ndata != 5) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Unable to read pump data");
294*c4762a1bSJed Brown     pump->id      = id;
295*c4762a1bSJed Brown     pump->node1   = node1;
296*c4762a1bSJed Brown     pump->node2   = node2;
297*c4762a1bSJed Brown     pump->paramid = paramid;
298*c4762a1bSJed Brown     edge[ne].id   = pump->id;
299*c4762a1bSJed Brown     ne++;
300*c4762a1bSJed Brown   }
301*c4762a1bSJed Brown 
302*c4762a1bSJed Brown   /* Curves */
303*c4762a1bSJed Brown   fsetpos(fp,&curve_start_pos);
304*c4762a1bSJed Brown   for (i=0; i < ncurve; i++) {
305*c4762a1bSJed Brown     int icurve_id=0;
306*c4762a1bSJed Brown     if (!fgets(line,MAXLINE,fp)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Cannot read data curve from file");
307*c4762a1bSJed Brown     ndata = sscanf(line,"%d %lf %lf",&icurve_id,&v1,&v2);if (ndata != 3) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_FILE_READ,"Unable to read curve data");
308*c4762a1bSJed Brown     curve_id = icurve_id;
309*c4762a1bSJed Brown     curve_x  = (PetscScalar)v1;
310*c4762a1bSJed Brown     curve_y  = (PetscScalar)v2;
311*c4762a1bSJed Brown     /* Check for pump with the curve_id */
312*c4762a1bSJed Brown     for (j=water->npipe;j < water->npipe+water->npump;j++) {
313*c4762a1bSJed Brown       if(water->edge[j].pump.paramid == curve_id) {
314*c4762a1bSJed Brown 	if(pump->headcurve.npt == 3) {
315*c4762a1bSJed Brown 	  SETERRQ3(PETSC_COMM_SELF,0,"Pump %d [%d --> %d]: No support for more than 3-pt head-flow curve",pump->id,pump->node1,pump->node2);
316*c4762a1bSJed Brown 	}
317*c4762a1bSJed Brown 	pump = &water->edge[j].pump;
318*c4762a1bSJed Brown 	pump->headcurve.flow[pump->headcurve.npt] = curve_x*GPM_CFS;
319*c4762a1bSJed Brown 	pump->headcurve.head[pump->headcurve.npt] = curve_y;
320*c4762a1bSJed Brown 	pump->headcurve.npt++;
321*c4762a1bSJed Brown 	break;
322*c4762a1bSJed Brown       }
323*c4762a1bSJed Brown     }
324*c4762a1bSJed Brown   }
325*c4762a1bSJed Brown 
326*c4762a1bSJed Brown   fclose(fp);
327*c4762a1bSJed Brown 
328*c4762a1bSJed Brown   /* Get pump curve parameters */
329*c4762a1bSJed Brown   for(j=water->npipe;j < water->npipe+water->npump;j++) {
330*c4762a1bSJed Brown     pump = &water->edge[j].pump;
331*c4762a1bSJed Brown     if (strcmp(pump->param,"HEAD") == 0) {
332*c4762a1bSJed Brown       /* Head-flow curve */
333*c4762a1bSJed Brown       ierr = SetPumpHeadCurveParams(pump);CHKERRQ(ierr);
334*c4762a1bSJed Brown     }
335*c4762a1bSJed Brown   }
336*c4762a1bSJed Brown   PetscFunctionReturn(0);
337*c4762a1bSJed Brown }
338