// return 0 or -9 if something is not right // hard coded assumption that the data would be 2D int read_2d_arrays(StrBuffer *s, Descriptor *des, SimpleDblArray *d, int with_unit, FILE *out) { int jj=0; int cntr=0; char *t; double ss; if (with_unit) { if ( (t=s->Get_ith_Value(des[2]._key, 0 )) == NULL ) { if (out) fprintf(out,"Bummer: unable to locate keyword \"%s\" for array on line %d\n", des[2]._key, s->LineNumber()); return 0; } ss = convert_time_scale(t, Time_Descriptor); if ( ss < 0 ) { if (out) fprintf(out,"Bummer: only accept time scale of SECOND, MINUTE, HOUR for statement on line %d \n", s->LineNumber()); return 0; } d->SetScale( ss ); jj++; // move to the first one } for (; jj<s->NumPairs(); jj+=2) { // jj has been set if ( (t=s->Get_ith_Value(des[0]._key, jj))==NULL) { if (out) fprintf(out,"Bummer: unable to locate keyword \"%s\" for array on line %d\n", des[0]._key, s->LineNumber()); return 0; } if ( !is_scientific(t) ) { if (out) fprintf(out, "Bummer: invalid number found in field \"%s\" on line %d\n", des[0]._key, s->LineNumber()); return 0; } else { d->ithX(cntr) = atof(t); } if ( (t = s->Get_ith_Value(des[1]._key, jj+1))==NULL) { if (out) fprintf(out,"Bummer: unable to locate keyword \"%s\" for array on line %d\n", des[1]._key, s->LineNumber()); return 0; } if ( !is_scientific(t) ) { if (out) fprintf(out, "Bummer: invalid number found in field \"%s\" on line %d\n", des[1]._key, s->LineNumber()); return 0; } else { d->ithY(cntr++) = atof(t); } } return cntr; }
// top level function to parse the spt netlist and construct the SUBCATCHMENT object // as well as modifying the Options and Sgraph objects int read_spt_from_file(FILE* F, Subcatchment *SUB, NameStore *NODE_NAMES, SMap *HASH, FILE* out) { FirstDef rc; int r_code; int line_num, good, node_index; source_id src_id; unsigned int n_op,n_node, n_seg, n_junc, n_qs, n_ls, n_bdn; StrBuffer *Prime, *Second; SimpleDblArray dba; double *XX=NULL, *YY=NULL; FlexVec<int, SHORT_ARRY_LENGTH> qsources; // we store index only FlexVec<int, SHORT_ARRY_LENGTH> lsources; FlexVec<int, SHORT_ARRY_LENGTH> asources; ChkSum mychk; char chktmp[10]; Prime = new StrBuffer(1023); // both arrayes can automatically grow if needed Second = new StrBuffer(4095); r_code = -1; // by default, the return code indicates failure /* we first read the option blocks */ rc = def_not_found; line_num = 0; n_op = n_node = n_seg = n_junc = n_qs = n_ls = n_bdn = 0; while (1) { // first do the tally, and a rough check rc = search_block(F, &line_num, Spt_Descriptor, DES_SIZE(Spt_Descriptor), Prime, Second, out); switch (rc) { case p_options: n_op++; break; case p_node: n_node++; break; case p_segment: n_seg++; break; case p_junction: n_junc++; break; case p_qsource: n_qs++; break; case p_lateralsource: n_ls++; break; case p_boundarycondition: n_bdn++; break; case def_not_found: break; case def_error: goto back; break; default: break; } if ( rc == def_not_found ) break; } rewind(F); if (out) { fprintf(out,"[II]: Found %d nodes, %d segmetns, %d junctions, %d q_sources, %d lateral sources, %d bdn condtions, %d options in the netlist\n", n_node, n_seg, n_junc, n_qs, n_ls, n_bdn, n_op); } if ( n_node < 2 ) { if (out) fprintf(out, "Bummer: not enough node statements, unable to procced\n"); goto back; } else if ( n_seg < 1 ) { if (out) fprintf(out, "Bummer: not enough segment statements, unable to procced\n"); goto back; } else if ( n_qs < 1 ) { if (out) fprintf(out, "Bummer: not enough Q source statements, unable to procced\n"); goto back; } else if ( n_bdn < 1 ) { if (out) fprintf(out, "Bummer: not enough boundary condition statements, unable to procced\n"); goto back; } // Copy the stat into the STAT object STAT.N_Nodes() = n_node; STAT.N_Segs() = n_seg; STAT.N_Juncs() = n_junc; STAT.N_Qsrcs() = n_qs; STAT.N_Lsrcs() = n_ls; STAT.N_Bnds() = n_bdn; // do the memory allocation stuff here NODE_NAMES->Init(n_node); SUB->InitGraph(n_node, n_seg, n_junc); //Testing // allocate memory to store the boundary conditions qsources.size(n_node+10); lsources.size(n_node+10); asources.size(n_node+10); for (unsigned int jj=0; jj<n_node+10; jj++) qsources[jj]=-1; for (unsigned int jj=0; jj<n_node+10; jj++) lsources[jj]=-1; for (unsigned int jj=0; jj<n_node+10; jj++) asources[jj]=-1; // we now proess options, otherwise we use default values if ( n_op > 0 ) { char *tmp; double stoptimeunit=1.0, timestepunit=1.0, prtintervalunit=1.0; double stoptime=-1.0, timestep=0.0, prtinterval=0.0; double prtstartunit = 1.0, prtstart = 0.0; double spinuptime = 0.0; rewind(F); rc = def_not_found; line_num = 0; while (1) { rc = search_block(F, &line_num, Spt_Descriptor, DES_SIZE(Spt_Descriptor), Prime, Second, NULL); if (rc == def_not_found ) break; if (rc != p_options ) continue; // read the options, in particular UseMetric! good = Prime->Separate(out); if (good<0) { if (out) fprintf(out,"Bummer: Syntax error in netlist specification at line %d\n", line_num); goto back; } tmp = Prime->Find_Value( Op_Descriptor[0]._key); // USEMETRIC if (tmp) { OPT.UseMetric() = atoi(tmp)>0 ? 1 : 0; if (out) fprintf(out,"[II]: Metric set to %d\n", OPT.UseMetric()); } // we process unit first so that we don't have to worry later tmp = Prime->Find_Value( Op_Descriptor[2]._key); // TIMESTEPUNIT if (tmp) { timestepunit = convert_time_scale(tmp, Time_Descriptor); } if ( timestepunit < 0 ) { if (out) fprintf(out,"[WW]: only accept time unit of SECOND, MINUTE, HOUR for statement on line %d. Use default=SECOND. \n", Prime->LineNumber()); timestepunit = 1.0; } tmp = Prime->Find_Value( Op_Descriptor[1]._key); // TIMESTEP if (tmp) timestep = atof(tmp); tmp = Prime->Find_Value( Op_Descriptor[4]._key); // STOPTIMEUNIT if (tmp) { stoptimeunit = convert_time_scale(tmp, Time_Descriptor); } if ( stoptimeunit < 0 ) { if (out) fprintf(out,"Bummer:only accept time unit of SECOND, MINUTE, HOUR for statement on line %d. Use default=SECOND. \n", Prime->LineNumber()); stoptimeunit = 1.0; } tmp = Prime->Find_Value( Op_Descriptor[3]._key); // STOPTIME if (tmp) stoptime = atof(tmp); // also deal with print interval first tmp = Prime->Find_Value( Op_Descriptor[6]._key); // PRTINTERVALUNIT if (tmp) { prtintervalunit = convert_time_scale(tmp, Time_Descriptor); } if ( prtintervalunit < 0 ) { if (out) fprintf(out,"[WW]: only accept time unit of SECOND, MINUTE, HOUR for statement on line %d. Use default=SECOND. \n", Prime->LineNumber()); prtintervalunit = 1.0; } tmp = Prime->Find_Value( Op_Descriptor[8]._key); // PRTSTARTUNIT if (tmp) { prtstartunit = convert_time_scale(tmp, Time_Descriptor); } if ( prtstartunit < 0 ) { if (out) fprintf(out,"[WW]: only accept time unit of SECOND, MINUTE, HOUR for statement on line %d. Use default=SECOND. \n", Prime->LineNumber()); prtstartunit = 1.0; } tmp = Prime->Find_Value( Op_Descriptor[7]._key); // PRTSTART if (tmp) prtstart = atof(tmp); tmp = Prime->Find_Value( Op_Descriptor[5]._key); // PRTINTERVAL if (tmp) prtinterval = atof(tmp); if ( prtinterval < 0 ) { if (out) fprintf(out,"[WW]: negative print interval specified on line %d. Overwritten with zero!\n", Prime->LineNumber()); prtinterval = 0.0; } tmp = Prime->Find_Value( Op_Descriptor[9]._key); // CHECKONLY if (tmp) { OPT.CheckOnly() = atoi(tmp) > 0 ? 1 : 0; if (out) fprintf(out,"[II]: CheckOnly set to %d\n", OPT.CheckOnly()); } tmp = Prime->Find_Value( Op_Descriptor[10]._key); // SSFILE if (tmp) { STAT.SetSSFile(tmp); if (out) fprintf(out, "[II]: SSFile (SteadyState file) set to \"%s\"\n", tmp); } tmp = Prime->Find_Value( Op_Descriptor[11]._key); // Lmax if (tmp) { OPT.LMax() = atof(tmp); if (out) fprintf(out,"[II]: LMax set to %.4e\n", OPT.LMax() ); } tmp = Prime->Find_Value( Op_Descriptor[12]._key); // Lmin if (tmp) { OPT.LMin() = atof(tmp); if (out) fprintf(out,"[II]: LMin set to %.4e\n", OPT.LMin() ); } tmp = Prime->Find_Value( Op_Descriptor[13]._key); // PrintDepth if (tmp) { OPT.PrintD() = atoi(tmp) > 0 ? 1 : 0; if (out) fprintf(out,"[II]: PrtDepth set to %1d\n", OPT.PrintD() ); } tmp = Prime->Find_Value( Op_Descriptor[14]._key); // PrintSurfElev if (tmp) { OPT.PrintZ() = atoi(tmp) > 0 ? 1 : 0; if (out) fprintf(out,"[II]: PrtSurfElev set to %1d\n", OPT.PrintZ() ); } tmp = Prime->Find_Value( Op_Descriptor[15]._key); // PrintQ if (tmp) { OPT.PrintQ() = atoi(tmp) > 0 ? 1 : 0; if (out) fprintf(out,"[II]: PrtQ set to %1d\n", OPT.PrintQ() ); } tmp = Prime->Find_Value( Op_Descriptor[16]._key); // PrintA if (tmp) { OPT.PrintA() = atoi(tmp) > 0 ? 1 : 0; if (out) fprintf(out,"[II]: PrtA set to %1d\n", OPT.PrintA() ); } tmp = Prime->Find_Value( Op_Descriptor[17]._key); // PrintCoord if (tmp) { OPT.PrintXY() = atoi(tmp) > 0 ? 1 : 0; if (out) fprintf(out,"[II]: PrtCoord set to %1d\n", OPT.PrintXY() ); } tmp = Prime->Find_Value( Op_Descriptor[18]._key); // verbose if (tmp) { OPT.DebugLevel() = atoi(tmp) > 0 ? atoi(tmp) : 0; if (out) fprintf(out,"[II]: Verbose set to %1d\n", OPT.DebugLevel() ); } tmp = Prime->Find_Value( Op_Descriptor[19]._key); // epoch if (tmp) { STAT.SetEpoch(tmp); if (out) fprintf(out, "[II]: Epoch is set to %s\n", STAT.Epoch() ); } tmp = Prime->Find_Value( Op_Descriptor[20]._key); // spinup_time if (tmp) spinuptime = atof(tmp); if ( spinuptime < 0 ) { if (out) fprintf(out,"[WW]: negative spin-up time specified on line %d. Use zero instead (disabled)\n", Prime->LineNumber()); spinuptime = 0.0; } } // check if stoptime is specified (by setting default to 0), // do the scaling, // reason: we might have multiple option blocks if ( timestep < 0 ) { if (out) fprintf(out,"[WW]: negative TimeStep specified. Overwritten with zeor!\n"); } else if (timestep > 0) { timestep *= timestepunit; OPT.FixedStep() = timestep; if (out) fprintf(out,"[II]: TimeStep set to %.3e second.\n", timestep); } if ( prtinterval < 0 ) { if (out) fprintf(out,"[WW]: negative PrInterval specified. Overwritten with zero!\n"); } else if (prtinterval>0) { int tt; prtinterval *= prtintervalunit; tt = (int) round(prtinterval/60.0); tt = tt >=0 ? tt : 0; OPT.PrintInterval() = tt; if (out) fprintf(out,"[II]: PrtInterval set to %d min\n", tt); } if (prtstart < 0) { if (out) fprintf(out,"[WW]: negative PrtStart specified. Overwritten with zero!\n"); } else if ( prtstart > 0) { int tt; prtstart *= prtstartunit; tt = (int)round(prtstart/60.0); tt = tt>=0 ? tt : 0; OPT.PrintStart() = tt; if (out) fprintf(out, "[II]: PrtStart set to %d min\n", tt); } if (stoptime > 0 ) { stoptime *= stoptimeunit; OPT.StopTime() = stoptime; if (out) fprintf(out,"[II]: StopTime set to %.3e second\n", stoptime); } else { if (out) fprintf(out,"Bummer: a positive StopTime is required in order to run the simulation!\n"); goto back; } if ( spinuptime > 0 ) { int tt = (int)spinuptime; const int min_spin = 300; if ( tt > min_spin ) { OPT.SpinUpTime() = tt; if (out) fprintf(out,"[II]: SpinUpTime set to %d second\n", tt); } else { OPT.SpinUpTime() = 0; if (out) fprintf(out,"[WW]: minimal spinup time is %d seconds. Revert back to zero (spinup disabled)\n", min_spin); } } } // add nodes, check duplicate rewind(F); rc = def_not_found; line_num = 0; while (1) { char node_id[MAX_LINE_LENGTH]; char *tmp; double s0, n, h0, z0, width, slope; XsecType xtp; int num_pairs; double q0=0, a0=0; // we will deal with them later double x=-1.0, y=-1.0; // not used rc = search_block(F, &line_num, Spt_Descriptor, DES_SIZE(Spt_Descriptor), Prime, Second, NULL); // we don't check on the error flags since we have done it before if (rc == def_not_found ) break; // we added all nodes if (rc == def_error ) goto back; width = 0.0; slope = 0.0; num_pairs = 0; switch (rc) { case p_node: /* intercept and understand node */ if ( !Second->HasContent()) { if (out) fprintf(out,"Bummer: NODE statement on line %d requires a x-section specification\n", Prime->LineNumber() ); goto back; } good = Prime->Separate(out); good = Second->Separate(out); if (good <0) { if (out) fprintf(out,"Bummer: syntax error in netlist specification in line %d\n", Prime->LineNumber()); goto back; } // parse each field one by one tmp = Prime->Find_Value( Node_Descriptor[0]._key); // "id" if (!tmp) { if (out) fprintf(out, "Bummer: unable to locate field %s for the NODE statement on line %d\n", Node_Descriptor[0]._key, Prime->LineNumber()); goto back; } // the clean node id is now in node_id; strncpy(node_id, tmp, MAX_WORD_LENGTH); node_index = HASH->Check(node_id); if ( node_index != -1 ) { if (out) fprintf(out,"Bummer: duplicated NODE definition of node \"%s\" on line %d\n", node_id, Prime->LineNumber() ); goto back; } node_index = HASH->Create(node_id); NODE_NAMES->Insert(node_id, node_index); tmp = Prime->Find_Value( Node_Descriptor[1]._key); // "sR" if (!tmp) { if (out) fprintf(out, "Bummer: unable to locate field %s for the NODE statement on line %d\n", Node_Descriptor[1]._key, Prime->LineNumber()); goto back; } s0 = atof(tmp); if ( s0 < 1e-6 ) { if (out) fprintf(out, "[WW]: reference slope sR at location %s is nonpositive with value of %.4e. \n", node_id, s0); #if 0 goto back; #endif } tmp = Prime->Find_Value( Node_Descriptor[2]._key); // "n" if (!tmp) { if (out) fprintf(out, "Bummer: unable to locate field %s for the NODE statement on line %d\n", Node_Descriptor[2]._key, Prime->LineNumber()); goto back; } n = atof(tmp); if ( n < OPT.MinN() ) { if (out) fprintf(out,"[WW]: Manning's N at location %s is %.4e, less than threshold value %.4e. Supercritical flow might occur\n", node_id, n, OPT.MinN()); } tmp = Prime->Find_Value( Node_Descriptor[3]._key); // "zR" if (!tmp) { if (out) fprintf(out, "Bummer: unable to locate field %s for the NODE statement on line %d\n", Node_Descriptor[3]._key, Prime->LineNumber()); goto back; } z0 = atof(tmp); tmp = Prime->Find_Value( Node_Descriptor[4]._key); // "hR" if (!tmp) { if (out) fprintf(out, "Bummer: unable to locate field %s for the NODE statement on line %d\n", Node_Descriptor[4]._key, Prime->LineNumber()); goto back; } h0 = atof(tmp); tmp = Prime->Find_Value( Node_Descriptor[5]._key); // "xcoord" if (tmp) { x = atof(tmp); // this is optional } tmp = Prime->Find_Value( Node_Descriptor[6]._key); // "ycoord" if (tmp) { y = atof(tmp); } if ( Second->Cmp_Head(Node_Descriptor[7]._key)) { // "Trapezoidal tmp = Second->Find_Value(Trap_Descriptor[0]._key); // "bottomwidth" if (!tmp) { if (out) fprintf(out, "Bummer: %s x-section on line %d requires field %s\n", Node_Descriptor[5]._key, Second->LineNumber(), Trap_Descriptor[0]._key); goto back; } width = atof(tmp); tmp = Second->Find_Value(Trap_Descriptor[1]._key); // "slope" if (!tmp) { if (out) fprintf(out, "Bummer: %s x-section on line %d requires field %s\n", Node_Descriptor[5]._key, Second->LineNumber(), Trap_Descriptor[1]._key); goto back; } else { slope = atof(tmp); } xtp = TRAP; } else if ( Second->Cmp_Head(Node_Descriptor[8]._key)) { // "Rectangular" tmp = Second->Find_Value(Rect_Descriptor[0]._key); // "bottomwidth" if (!tmp) { if (out) fprintf(out, "Bummer: %s x-section on line %d requires field %s\n", Node_Descriptor[6]._key, Second->LineNumber(), Rect_Descriptor[0]._key); goto back; } else { width = atof(tmp); } xtp = RECT; } else if ( Second->Cmp_Head(Node_Descriptor[9]._key)) { // "XY" if ( Second->NumPairs() % 2 != 0 ) { if (out) fprintf(out,"Bummer: unbalanced XY pairs for %s statement on line %d\n", Node_Descriptor[7]._key,Second->LineNumber()); goto back; } else { // all good, copy the values dba.Reset(); num_pairs = read_2d_arrays(Second, XY_Descriptor, &dba, 0, out); if ( num_pairs <= 0 ) { if (out) fprintf(out,"Bummer: error reading 2D data specified on line %d\n", Second->LineNumber() ); goto back; } } xtp = SPLINE; } else { if (out) fprintf(out,"Bummer: NODE statement on line %d requires at least one of the x-section specification: %s, %s or %s\n", Prime->LineNumber(), Node_Descriptor[5]._key, Node_Descriptor[6]._key, Node_Descriptor[7]._key); goto back; } // at this point, all variables are ready, create the node // use node_idx, s0, n, h0, z0, dba (good) // first do scaling based UseMetric() XX = dba.X(); YY = dba.Y(); if (OPT.UseMetric() == 0 ) { if (xtp == SPLINE) { for (int jj=0; jj<num_pairs; jj++) { XX[jj] *= OPT.FtoM(); YY[jj] *= OPT.FtoM(); } } else { // RECT or TRAP, only change the bottom width, slope is dimensionless width *= OPT.FtoM(); } z0 *= OPT.FtoM(); h0 *= OPT.FtoM(); } if ( xtp == SPLINE ) { #ifdef DBGSPLINE printf("node name %s, id %d\n", node_id, (unsigned int)node_index); #endif SUB->MakeNode((unsigned int)node_index, s0, n, x, y, q0, a0, z0, h0, SPLINE, num_pairs, XX, YY); } else if (xtp == TRAP) { SUB->MakeNode((unsigned int)node_index, s0, n, x, y, q0, a0, z0, h0, TRAP, width, slope); } else if (xtp == RECT) { SUB->MakeNode((unsigned int)node_index, s0, n, x, y, q0, a0, z0, h0, RECT, width); } break; default: break; } // end switch } // while loop, find all nodes // make SUB happy SUB->AssignNodes(); // records Qsrc, Lsrc and Bdn's rewind(F); rc = def_not_found; line_num = 0; while (1) { char node_id[MAX_LINE_LENGTH]; char *tmp; int num_pairs; int loc_index, bnd_is_area; Node *node=NULL; // double geo_scale=1.0; rc = search_block(F, &line_num, Spt_Descriptor, DES_SIZE(Spt_Descriptor), Prime, Second, NULL); // we don't check on the error flags since we have done it before if (rc == def_not_found ) break; // we added all nodes if (rc == def_error ) goto back; num_pairs = 0; switch (rc) { case p_qsource: if (!Second->HasContent()) { if (out) fprintf(out,"Bummer: QSOURCE statement on line %d requires a time series specification\n", Prime->LineNumber() ); goto back; } good = Prime->Separate(out); good = Second->Separate(out); if (good<0) { if (out) fprintf(out,"Bummer: syntax error in netlist specification in line %d\n", line_num); goto back; } tmp = Prime->Find_Value( Qsource_Descriptor[0]._key); // "location" if (!tmp) { if (out) fprintf(out, "Bummer: unable to locate field %s for the QSOURCE statement on line %d\n", Qsource_Descriptor[0]._key, Prime->LineNumber()); goto back; } if ( !Second->Cmp_Head( Qsource_Descriptor[1]._key) ) { // "timeseries" if (out) fprintf(out,"Bummer: QSOURCE statement on line %d requires time series specification: %s\n", Prime->LineNumber(), Qsource_Descriptor[1]._key); goto back; } strncpy(node_id, tmp, MAX_WORD_LENGTH); loc_index = HASH->Check(node_id); if ( loc_index == -1 ) { if (out) fprintf(out, "Bummer: cannot find node \"%s\" specified on line %d\n", node_id, Prime->LineNumber()); goto back; } dba.Reset(); num_pairs = read_2d_arrays(Second, TS_Descriptor, &dba, 1, out); if ( num_pairs <= 0 ) { if (out) fprintf(out,"Bummer: error reading 2D data specified on line %d\n", Second->LineNumber() ); goto back; } // ready to insert Q source, with node and time series in dba (good), remember the // dba.Scale() field, which is the time scale XX = dba.X(); YY = dba.Y(); src_id = SUB->MakeSource(num_pairs, &XX[0], &YY[0], dba.Scale(), (OPT.UseMetric()==0?OPT.F3toM3():1.0) ); if (src_id<0) { if (out) fprintf(out,"Bummer: problem with QSource at node \"%s\" on line %d\n", node_id, Prime->LineNumber()); goto back; } if ( qsources[ loc_index] > -1 ) { if (out) fprintf(out, "Bummer: duplicated definitino of Qsource at node \"%s\"\n", node_id); goto back; } qsources[ loc_index ] = src_id; // store the index break; case p_lateralsource: if (!Second->HasContent()) { if (out) fprintf(out,"Bummer: LATERALSOURCE statement on line %d requires a time series specification\n", Prime->LineNumber() ); goto back; } good = Prime->Separate(out); good = Second->Separate(out); if (good<0) { if (out) fprintf(out,"Bummer: problem with LateralSource on line %d\n", Prime->LineNumber()); goto back; } tmp = Prime->Find_Value( Latsource_Descriptor[0]._key); // "location" if (!tmp) { if (out) fprintf(out, "Bummer: unable to locate field %s for the LATERALSOURCE statement on line %d\n", Latsource_Descriptor[0]._key, Prime->LineNumber()); goto back; } if ( !Second->Cmp_Head( Latsource_Descriptor[1]._key) ) { // "timeseries" if (out) fprintf(out,"Bummer: LATERALSOURCE statement on line %d requires time series specification: %s\n", Prime->LineNumber(), Latsource_Descriptor[1]._key); goto back; } strncpy(node_id, tmp, MAX_WORD_LENGTH); loc_index = HASH->Check(node_id); if ( loc_index == -1 ) { if (out) fprintf(out, "Bummer: cannot find node \"%s\" specified on line %d\n", node_id, Prime->LineNumber()); goto back; } dba.Reset(); num_pairs = read_2d_arrays(Second, TS_Descriptor, &dba, 1, out); if ( num_pairs <= 0 ) { if (out) fprintf(out,"Bummer: error reading 2D data specified on line %d\n", Second->LineNumber() ); goto back; } // ready to insert lateral source, with loc_index and time series in dba (good), // remember dba.Scale() XX = dba.X(); YY = dba.Y(); src_id = SUB->MakeSource(num_pairs, &XX[0], &YY[0], dba.Scale(), (OPT.UseMetric()==0?OPT.F3toM3():1.0) ); if (src_id<0) { if (out) fprintf(out,"Bummer: problem with LATERALSOURCE at node \"%s\" on line %d\n", node_id, Prime->LineNumber()); goto back; } if ( lsources[ loc_index ] > -1 ) { if (out) fprintf(out, "Bummer: duplicated definitino of LATERALSOURCE at node \"%s\"\n", node_id); goto back; } lsources[ loc_index ] = src_id; break; case p_boundarycondition: if (!Second->HasContent()) { if (out) fprintf(out,"Bummer: BOUNDARYCONDITION statement on line %d requires a time series specification\n", Prime->LineNumber() ); goto back; } good = Prime->Separate(out); good = Second->Separate(out); if (good<0) { if (out) fprintf(out,"Bummer: syntax error in BoundaryCondition Statement in line %d\n", Prime->LineNumber()); goto back; } tmp = Prime->Find_Value( Bdn_Descriptor[1]._key); // "type" if (!tmp) { if (out) fprintf(out, "Bummer: unable to locate field %s for the BOUNDARYCONDITION statement on line %d\n", Bdn_Descriptor[1]._key, Prime->LineNumber()); goto back; } if ( cmp_string(tmp, BdnType_Descriptor[0]._key) ) { // "AREA" bnd_is_area = 1; } else if (cmp_string(tmp, BdnType_Descriptor[1]._key) ) { // "DEPTH" bnd_is_area = 0; } else { if (out) fprintf(out, "Bummer: BoundaryCondition has to be either \"%s\" or \"%s\" for statement on line %d\n", BdnType_Descriptor[0]._key, BdnType_Descriptor[1]._key, Prime->LineNumber() ); goto back; } tmp = Prime->Find_Value( Bdn_Descriptor[0]._key); // "location" if (!tmp) { if (out) fprintf(out, "Bummer: unable to locate field %s for the BOUNDARYCONDITION statement on line %d\n", Bdn_Descriptor[0]._key, Prime->LineNumber()); goto back; } strncpy(node_id, tmp, MAX_WORD_LENGTH); loc_index = HASH->Check(node_id); if ( loc_index == -1 ) { if (out) fprintf(out, "Bummer: cannot find node \"%s\" specified on line %d\n", node_id, Prime->LineNumber()); goto back; } if ( !Second->Cmp_Head( Bdn_Descriptor[2]._key) ) { // "timeseries" if (out) fprintf(out,"Bummer: BOUNDARYCONDITION statement on line %d requires time series specification: %s\n", Prime->LineNumber(), Bdn_Descriptor[2]._key); goto back; } dba.Reset(); num_pairs = read_2d_arrays(Second, TS_Descriptor, &dba, 1, out); if ( num_pairs <= 0 ) { if (out) fprintf(out,"Bummer: error reading 2D data specified on line %d\n", Second->LineNumber() ); goto back; } // ready to insert Bdn condition, with loc_index and time series in dba (good), // remember dba.Scale() XX = dba.X(); YY = dba.Y(); if ( bnd_is_area == 0 ) { node = SUB->GetNode( loc_index ); if ( !node ) { if (out) fprintf(out, "Bummer: node \"%s\" not yet defined!\n", node_id); goto back; } } if ( bnd_is_area) { src_id = SUB->MakeSource(num_pairs, &XX[0], &YY[0], dba.Scale(), (OPT.UseMetric()==0?OPT.F2toM2():1.0) ); } else { FlexVec<double> tmp; tmp.size(num_pairs); node = SUB->GetNode( loc_index); for (int jj=0; jj<num_pairs;jj++) { tmp[jj]= node->GetAbyDepth( YY[jj]*(OPT.UseMetric()==0?OPT.FtoM():1.0) ); } src_id = SUB->MakeSource(num_pairs, &XX[0], &tmp[0], dba.Scale(), 1.0); } if (src_id < 0) { if (out) fprintf(out, "Bummer: problem with BoundaryCondition definition on line %d\n", Prime->LineNumber() ); goto back; } if ( asources[ loc_index] >-1 ) { if (out) fprintf(out, "Bummer: duplicated definitino of BOUNDARYCONDITION at node \"%s\"\n", node_id); goto back; } asources[ loc_index ] = src_id; break; default: break; } // end switch } // while loop, found all qsource, lsources and asources // process the rest, segments, junctions rc = def_not_found; rewind(F); line_num = 0; while (1) { int up_idx, down_idx; int up1_idx, up2_idx; double length, coef1, coef2; char *tmp; Node *fp, *tp; rc = search_block(F, &line_num, Spt_Descriptor, DES_SIZE(Spt_Descriptor), Prime, Second, NULL); if (rc == def_error) goto back; if (rc == def_not_found) break; switch ( rc ) { case p_segment: good = Prime->Separate(out); if (good<0) { if (out) fprintf(out,"Bummer: syntax error in netlist specification at line %d\n", Prime->LineNumber()); goto back; } tmp = Prime->Find_Value( Segment_Descriptor[0]._key); // "up" if ( !tmp) { if (out) fprintf(out, "Bummer: SEGMENT statement on line %d requires the \"%s\" field.\n", Prime->LineNumber(), Segment_Descriptor[0]._key); goto back; } up_idx = HASH->Check(tmp); if ( up_idx == -1 ) { if (out) fprintf(out, "Bummer: cannot find node \"%s\" specified on line %d\n", tmp, Prime->LineNumber()); goto back; } tmp = Prime->Find_Value( Segment_Descriptor[1]._key); // "down: if ( !tmp) { if (out) fprintf(out, "Bummer: SEGMENT statement on line %d requires the \"%s\" field.\n", Prime->LineNumber(), Segment_Descriptor[1]._key); goto back; } down_idx = HASH->Check(tmp); if ( down_idx == -1 ) { if (out) fprintf(out, "Bummer: cannot find node \"%s\" specified on line %d\n", tmp, Prime->LineNumber()); goto back; } tmp = Prime->Find_Value( Segment_Descriptor[2]._key); // "length" if ( !tmp ) { if (out) fprintf(out, "Bummer: SEGMENT statement on line %d requires the \"%s\" field.\n", Prime->LineNumber(), Segment_Descriptor[2]._key); goto back; } if ( !is_scientific( tmp ) ) { if (out) fprintf(out, "Bummer: invalid real value specification on line %d\n",Prime->LineNumber()); goto back; } length = atof(tmp); // ready to insert segment, use up_idx, down_idx, length, check length > 0! if ( length <= 0.0 ) { if (out) fprintf(out,"Bummer: found negative or zero length on line %d\n", Prime->LineNumber() ); goto back; } if ( length <= OPT.LMin() ) { if (out) fprintf(out,"[WW]: segment length on line %d is %.4e, less than preferred minimal %.4e\n", Prime->LineNumber(), length, OPT.LMin()); } if ( length >= OPT.LMax() ) { if (out) fprintf(out,"[WW]: segment length on line %d is %.4e, larger than preferred maxium %.4e\n", Prime->LineNumber(), length, OPT.LMax()); } if (OPT.UseMetric() == 0 ) length *= OPT.FtoM(); fp = SUB->GetNode( up_idx ); tp = SUB->GetNode( down_idx ); if (fp == NULL) { if (out) fprintf(out,"Bummer: internal error, unable to locate node at index %d for statement on line %d\n", up_idx, Prime->LineNumber()); goto back; } if (tp == NULL) { if (out) fprintf(out,"Bummer: internal error, unable to locate node at index %d for statement on line %d\n", down_idx, Prime->LineNumber()); goto back; } // in case we have a lateral source src_id = lsources[up_idx]; SUB->MakeStvEquation( up_idx, down_idx, length, src_id ); break; case p_junction: good = Prime->Separate(out); if (good<0) { if (out) fprintf(out,"Bummer: syntax error in netlist specification at line %d\n", Prime->LineNumber()); goto back; } tmp = Prime->Find_Value( Junc_Descriptor[0]._key); // "up1" if (tmp) { up1_idx = HASH->Check(tmp); if ( up1_idx == -1 ) { if (out) fprintf(out, "Bummer: cannot find node \"%s\" specified on line %d\n", tmp, Prime->LineNumber()); goto back; } } else up1_idx = -1; tmp = Prime->Find_Value( Junc_Descriptor[1]._key); // "up2: if (tmp) { up2_idx = HASH->Check(tmp); if ( up2_idx == -1 ) { if (out) fprintf(out, "Bummer: cannot find node \"%s\" specified on line %d\n", tmp, Prime->LineNumber()); goto back; } } else up2_idx = -1; tmp = Prime->Find_Value( Junc_Descriptor[2]._key); // "down" if ( !tmp) { if (out) fprintf(out, "Bummer: JUNCTION statement on line %d requires the \"%s\" field.\n", Prime->LineNumber(), Junc_Descriptor[2]._key); goto back; } down_idx = HASH->Check(tmp); if ( down_idx == -1 ) { if (out) fprintf(out, "Bummer: cannot find node \"%s\" specified on line %d\n", tmp, Prime->LineNumber()); goto back; } tmp = Prime->Find_Value( Junc_Descriptor[3]._key); // "coeff1" if (tmp) { if ( !is_scientific( tmp ) ) { if (out) fprintf(out, "Bummer: invalid real value specification on line %d\n",Prime->LineNumber()); goto back; } coef1 = atof(tmp); if ( coef1 <= 0.0 ) { if (out) fprintf(out, "Bummer: coefficient should be positive on line %d\n",Prime->LineNumber()); goto back; } } else coef1 = -1.0; tmp = Prime->Find_Value( Junc_Descriptor[4]._key); // "coeff2" if ( tmp) { if ( !is_scientific( tmp ) ) { if (out) fprintf(out, "Bummer: invalid real value specification on line %d\n",Prime->LineNumber()); goto back; } coef2 = atof(tmp); if ( coef2 <= 0.0 ) { if (out) fprintf(out, "Bummer: coefficient should be positive on line %d\n",Prime->LineNumber()); goto back; } } else coef2 = -1.0; // ready to insert junction, use up1_idx, up2_idx, down_idx, coef1, coef2, check if ( up1_idx == -1 && up2_idx == -1 ) { if (out) fprintf(out,"Bummer: at least one upstream nodes has to be specified on line %d\n", Prime->LineNumber() ); goto back; } if ( coef1 < 0 && coef2 < 0 ) { if (out) fprintf(out,"Bummer: at least one upstream coefficients has to be specified on line %d\n", Prime->LineNumber() ); goto back; } if ( (up1_idx > 0 && coef1 < 0) || ( up2_idx>0 && coef2<0 ) ) { if (out) fprintf(out,"Bummer: mismatch in upstream node and coefficient specifications on line %d\n", Prime->LineNumber()); goto back; } /* To add: distance check among three nodes, use X() and Y() of each node */ int nn[2]; double rr[2]; if ( up1_idx > 0 && up2_idx > 0 ) { // both nn[0] = up1_idx; nn[1] = up2_idx; rr[0] = coef1; rr[1] = coef2; SUB->MakeDepEquation( down_idx, 2, &nn[0], &rr[0]); } else if ( up1_idx > 0 ) { // up1 only nn[0] = up1_idx; rr[0] = coef1; SUB->MakeDepEquation( down_idx, 1, &nn[0], &rr[0]); } else { // up2 only nn[0] = up2_idx; rr[0] = coef2; SUB->MakeDepEquation( down_idx, 1, &nn[0], &rr[0]); } break; default: break; } } // insert Qsrc, lateral source and Bdn for (int jj=0; jj<STAT.N_Nodes(); jj++) { if ( qsources[jj] > -1) { if ( SUB->GetSource( qsources[jj])->GetParent() >= 0 ) { if (out) fprintf(out, "Bummer: trying to re-use qsource at node index %d\n",jj); goto back; } SUB->MakeQrSrcEquation( jj, qsources[jj] ); } } for (int jj=0; jj<STAT.N_Nodes(); jj++) { if ( asources[jj] > -1 ) { if ( SUB->GetSource( asources[jj] )->GetParent() >= 0 ) { if (out) fprintf(out, "Bummer: trying to re-use asource at node index %d\n",jj); goto back; } SUB->MakeArSrcEquation( jj, asources[jj]); break; // we assume there is only ONE BdnCondition } } r_code = 0; // only at this point we indicate everything is clean // calculate the chksum in case we are going to load something from the data for (int jj=0; jj<STAT.N_Nodes(); jj++) { mychk.add_string( NODE_NAMES->Get(jj) ); } for (int jj=0; jj<STAT.N_Nodes(); jj++) { if ( qsources[jj] > -1 ) { Source *s = (Source*)SUB->GetSource( qsources[jj] ); sprintf(chktmp, "%+.1e", s->Evaluate(0.0)); mychk.add_string(chktmp); } } for (int jj=0; jj<STAT.N_Nodes(); jj++) { if ( asources[jj] > -1 ) { Source *s = (Source*)SUB->GetSource( asources[jj]); sprintf(chktmp, "%+.1e", s->Evaluate(0.0)); mychk.add_string(chktmp); } } for (int jj=0; jj<STAT.N_Nodes(); jj++) { if ( lsources[jj] > -1 ) { Source *s = (Source*)SUB->GetSource( lsources[jj] ); sprintf(chktmp, "%+.1e", s->Evaluate(0.0)); mychk.add_string(chktmp); } } STAT.SetChkSum( mychk.HexCode() ); back: if (Prime) delete Prime; if (Second) delete Second; return r_code; }
/* Analizzatore lessicale */ TokenTypeEnum GetNextToken(const char *str, Token *token, BOOL bIsInfix) { int i; char strToken[MAXOP]; while ( 1 ) { while ( str[nNextPos++] == ' ' ) ; --nNextPos; if ( str[nNextPos] == '\0' ) { token->Type = EOL; strcpy(token->str, "\n"); nNextPos = 0; PreviousTokenType = EOL; return EOL; } else if ( is_scientific(str[nNextPos]) ) { i = 0; while ( is_scientific(strToken[i++] = str[nNextPos++]) ) if (strToken[i-1] == 'd' || strToken[i-1] == 'D') strToken[i-1] = 'e'; if ( str[nNextPos - 1] == '.' ) { while ( is_scientific(strToken[i++] = str[nNextPos++]) ) if (strToken[i-1] == 'd' || strToken[i-1] == 'D') strToken[i-1] = 'e'; strToken[i - 1] = '\0'; --nNextPos; token->Type = VALUE; strcpy(token->str, strToken); token->Value = atof(strToken); return VALUE; } else { strToken[i - 1] = '\0'; --nNextPos; token->Type = VALUE; strcpy(token->str, strToken); token->Value = atof(strToken); return VALUE; } } else if ( str[nNextPos] == '.' ) { i = 0; strToken[i++] = str[nNextPos++]; while ( is_scientific(strToken[i++] = str[nNextPos++]) ) if (strToken[i-1] == 'd' || strToken[i-1] == 'D') strToken[i-1] = 'e'; strToken[i - 1] = '\0'; --nNextPos; token->Type = VALUE; strcpy(token->str, strToken); token->Value = atof(strToken); return VALUE; } else if ( str[nNextPos] == '(' ) { token->Type = OPAREN; strcpy(token->str, "("); ++nNextPos; return OPAREN; } else if ( str[nNextPos] == ')' ) { token->Type = CPAREN; strcpy(token->str, ")"); ++nNextPos; return CPAREN; } else if ( str[nNextPos] == '+' ) { strcpy(token->str, "+"); ++nNextPos; if ( !bIsInfix ) { token->Type = PLUS; return PLUS; } else { if ( PreviousTokenType == CPAREN || PreviousTokenType == VALUE ) { token->Type = PLUS; return PLUS; } else { token->Type = UPLUS; return UPLUS; } } } else if ( str[nNextPos] == '-' ) { strcpy(token->str, "-"); ++nNextPos; if ( !bIsInfix ) { token->Type = MINUS; return MINUS; } else { if ( PreviousTokenType == CPAREN || PreviousTokenType == VALUE ) { token->Type = MINUS; return MINUS; } else { token->Type = UMINUS; return UMINUS; } } } else if ( str[nNextPos] == '~' ) { strcpy(token->str, "~"); ++nNextPos; if ( !bIsInfix ) { token->Type = UMINUS; return UMINUS; } else { token->Type = UNKNOWN; return UNKNOWN; } } else if ( str[nNextPos] == '*' ) { token->Type = MULT; strcpy(token->str, "*"); ++nNextPos; return MULT; } else if ( str[nNextPos] == '/' ) { token->Type = DIV; strcpy(token->str, "/"); ++nNextPos; return DIV; } else if ( str[nNextPos] == '^' ) { token->Type = EXP; strcpy(token->str, "^"); ++nNextPos; return EXP; } else { token->Type = UNKNOWN; token->str[0] = str[nNextPos]; token->str[1] = '\0'; ++nNextPos; return UNKNOWN; } } return EOL; }