Beispiel #1
0
void    writeGroundwater(void)
{
    int i, j;
    int count = 0;
    double totalSeconds = NewRunoffTime / 1000.;
    double x[9];

    if ( Nobjects[SUBCATCH] == 0 ) return;
    for ( j = 0; j < Nobjects[SUBCATCH]; j++ )
    {
        if ( Subcatch[j].groundwater != NULL ) count++;
    }
    if ( count == 0 ) return;

    WRITE("");
    WRITE("*******************");
    WRITE("Groundwater Summary");
    WRITE("*******************");
    WRITE("");
    fprintf(Frpt.file,

"\n  -----------------------------------------------------------------------------------------------------"
"\n                                            Total    Total  Maximum  Average  Average    Final    Final"
"\n                          Total    Total    Lower  Lateral  Lateral    Upper    Water    Upper    Water"
"\n                          Infil     Evap  Seepage  Outflow  Outflow   Moist.    Table   Moist.    Table");
    if ( UnitSystem == US ) fprintf(Frpt.file,
"\n  Subcatchment               in       in       in       in      %3s                ft                ft",
        FlowUnitWords[FlowUnits]);
    else fprintf(Frpt.file,
"\n  Subcatchment               mm       mm       mm       mm      %3s                 m                 m",
        FlowUnitWords[FlowUnits]);
    fprintf(Frpt.file,
"\n  -----------------------------------------------------------------------------------------------------");

    for ( j = 0; j < Nobjects[SUBCATCH]; j++ )
    {
        if ( Subcatch[j].area == 0.0 || Subcatch[j].groundwater == NULL ) continue;
        fprintf(Frpt.file, "\n  %-20s", Subcatch[j].ID);
        x[0] = Subcatch[j].groundwater->stats.infil * UCF(RAINDEPTH);
        x[1] = Subcatch[j].groundwater->stats.evap * UCF(RAINDEPTH);
        x[2] = Subcatch[j].groundwater->stats.deepFlow * UCF(RAINDEPTH);
        x[3] = Subcatch[j].groundwater->stats.latFlow * UCF(RAINDEPTH);
        x[4] = Subcatch[j].groundwater->stats.maxFlow * UCF(FLOW) * Subcatch[j].area;
        x[5] = Subcatch[j].groundwater->stats.avgUpperMoist / totalSeconds;
        x[6] = Subcatch[j].groundwater->stats.avgWaterTable * UCF(LENGTH) /
               totalSeconds;
        x[7] = Subcatch[j].groundwater->stats.finalUpperMoist;
        x[8] = Subcatch[j].groundwater->stats.finalWaterTable * UCF(LENGTH);
        for (i = 0; i < 9; i++) fprintf(Frpt.file, " %8.2f", x[i]);
    }
    WRITE("");
}
Beispiel #2
0
void climate_validate()
//
//  Input:   none
//  Output:  none
//  Purpose: validates climatological variables
//
{
    int       i;                                                               //(5.1.007)
    double    a, z, pa;

    // --- check if climate data comes from external data file                 //(5.1.007)
    if ( Wind.type == FILE_WIND || Evap.type == FILE_EVAP ||
         Evap.type == TEMPERATURE_EVAP )
    {
        if ( Fclimate.mode == NO_FILE )
        {
            report_writeErrorMsg(ERR_NO_CLIMATE_FILE, "");
        }
    }

    // --- open the climate data file                                          //(5.1.007)
    if ( Fclimate.mode == USE_FILE ) climate_openFile();                       //(5.1.007)

    // --- snow melt parameters tipm & rnm must be fractions
    if ( Snow.tipm < 0.0 ||
         Snow.tipm > 1.0 ||
         Snow.rnm  < 0.0 ||
         Snow.rnm  > 1.0 ) report_writeErrorMsg(ERR_SNOWMELT_PARAMS, "");

    // --- latitude should be between -90 & 90 degrees
    a = Temp.anglat;
    if ( a <= -89.99 ||
         a >= 89.99  ) report_writeErrorMsg(ERR_SNOWMELT_PARAMS, "");
    else Temp.tanAnglat = tan(a * PI / 180.0);

    // --- compute psychrometric constant
    z = Temp.elev / 1000.0;
    if ( z <= 0.0 ) pa = 29.9;
    else  pa = 29.9 - 1.02*z + 0.0032*pow(z, 2.4); // atmos. pressure
    Temp.gamma = 0.000359 * pa;

    // --- convert units of monthly temperature & evap adjustments             //(5.1.007)
    for (i = 0; i < 12; i++)
    {
        if (UnitSystem == SI) Adjust.temp[i] *= 9.0/5.0;
        Adjust.evap[i] /= UCF(EVAPRATE);
    }
}
Beispiel #3
0
double getVariableValue(Project* project, int varIndex)
//
//  Input:   varIndex = index of a project->GW variable
//  Output:  returns current value of project->GW variable
//  Purpose: finds current value of a project->GW variable.
//
{
    switch (varIndex)
    {
    case gwvHGW:  return project->Hgw * UCF(project,LENGTH);
	case gwvHSW:  return project->Hsw * UCF(project, LENGTH);
	case gwvHCB:  return project->Hstar * UCF(project, LENGTH);
	case gwvHGS:  return project->TotalDepth * UCF(project, LENGTH);
	case gwvKS:   return project->A.conductivity * UCF(project, RAINFALL);
	case gwvK:    return project->HydCon * UCF(project, RAINFALL);                               //(5.1.010)
    case gwvTHETA:return project->Theta;                                                //(5.1.008)
    case gwvPHI:  return project->A.porosity;                                           //(5.1.008)
	case gwvFI:   return project->Infil * UCF(project, RAINFALL);                                //(5.1.008)
	case gwvFU:   return project->UpperPerc * UCF(project, RAINFALL);                            //(5.1.008)
	case gwvA:    return project->Area * UCF(project, LANDAREA);                                 //(5.1.008)
    default:      return 0.0;
    }
}
Beispiel #4
0
void subcatch_getBuildup(int j, double tStep)
//
//  Input:   j = subcatchment index
//           tStep = time step (sec)
//  Output:  none
//  Purpose: adds to pollutant buildup on subcatchment.
//
{
    int     i;                         // land use index
    int     p;                         // pollutant index
    double  f;                         // land use fraction
    double  area;                      // land use area (acres or hectares)
    double  curb;                      // land use curb length (user units)
    double  oldBuildup;                // buildup at start of time step
    double  newBuildup;                // buildup at end of time step

    // --- consider each landuse
    for (i = 0; i < Nobjects[LANDUSE]; i++)
    {
        // --- skip landuse if not in subcatch
        f = Subcatch[j].landFactor[i].fraction;
        if ( f == 0.0 ) continue;

        // --- get land area (in acres or hectares) & curb length
        area = f * Subcatch[j].area * UCF(LANDAREA);
        curb = f * Subcatch[j].curbLength;

        // --- examine each pollutant
        for (p = 0; p < Nobjects[POLLUT]; p++)
        {
            // --- see if snow-only buildup is in effect
            if (Pollut[p].snowOnly
                    && Subcatch[j].newSnowDepth < 0.001/12.0) continue;

            // --- use land use's buildup function to update buildup amount
            oldBuildup = Subcatch[j].landFactor[i].buildup[p];
            newBuildup = landuse_getBuildup(i, p, area, curb, oldBuildup,
                                            tStep);
            newBuildup = MAX(newBuildup, oldBuildup);
            Subcatch[j].landFactor[i].buildup[p] = newBuildup;
            massbal_updateLoadingTotals(BUILDUP_LOAD, p,
                                        (newBuildup - oldBuildup));
        }
    }
}
double getVariableValue(int varIndex)
//
//  Input:   varIndex = index of a GW variable
//  Output:  returns current value of GW variable
//  Purpose: finds current value of a GW variable.
//
{
    switch (varIndex)
    {
    case gwvHGW:  return Hgw * UCF(LENGTH);
    case gwvHSW:  return Hsw * UCF(LENGTH);
    case gwvHCB:  return Hstar * UCF(LENGTH);
    case gwvHGS:  return TotalDepth * UCF(LENGTH);
    case gwvKS:   return A.conductivity * UCF(RAINFALL);
    case gwvK:    return HydCon * UCF(RAINFALL);                               //(5.1.010)
    case gwvTHETA:return Theta;                                                //(5.1.008)
    case gwvPHI:  return A.porosity;                                           //(5.1.008)
    case gwvFI:   return Infil * UCF(RAINFALL);                                //(5.1.008)
    case gwvFU:   return UpperPerc * UCF(RAINFALL);                            //(5.1.008)
    case gwvA:    return Area * UCF(LANDAREA);                                 //(5.1.008)
    default:      return 0.0;
    }
}
Beispiel #6
0
void setMeltParams(int j, int k, float x[])
//
//  Input:   j = snowmelt parameter set index
//           k = data category index
//           x = array of snow parameter values
//  Output:  none
//  Purpose: assigns values to parameters in a snow melt data set.
//
{
    int i;

    // --- snow pack melt parameters
    if ( k >= SNOW_PLOWABLE && k <= SNOW_PERV )
    {
        // --- min/max melt coeffs.
        Snowmelt[j].dhmin[k]     = x[0] * UCF(TEMPERATURE) / UCF(RAINFALL);
        Snowmelt[j].dhmax[k]     = x[1] * UCF(TEMPERATURE) / UCF(RAINFALL); 

        // --- base melt temp (deg F)
        Snowmelt[j].tbase[k]     = x[2];
        if ( UnitSystem == SI )
            Snowmelt[j].tbase[k] =  (9./5.) * Snowmelt[j].tbase[k] + 32.0;

        // --- free water fractions
        Snowmelt[j].fwfrac[k]    = x[3];

        // --- initial snow depth & free water depth
        Snowmelt[j].wsnow[k]     = x[4] / UCF(RAINDEPTH);
        Snowmelt[j].fwnow[k]     = x[5] / UCF(RAINDEPTH);

        // --- fraction of impervious area that is plowable
        if ( k == SNOW_PLOWABLE ) Snowmelt[j].snn = x[6];

        // --- min. depth for 100% areal coverage on remaining
        //     impervious area or total pervious area
        else Snowmelt[j].si[k] = x[6] / UCF(RAINDEPTH);
    }

    // --- removal parameters
    else if ( k == SNOW_REMOVAL )
    {
        Snowmelt[j].weplow = x[0];
        for (i=0; i<=4; i++) Snowmelt[j].sfrac[i] = x[i+1];
        if ( x[6] >= 0.0 ) Snowmelt[j].toSubcatch = (int)(x[6] + 0.01);
        else               Snowmelt[j].toSubcatch = -1;
    }
}
Beispiel #7
0
void  getFluxes(Project* project, double theta, double lowerDepth)
//
//  Input:   upperVolume = vol. depth of upper zone (ft)
//           upperDepth  = depth of upper zone (ft)
//  Output:  none
//  Purpose: computes water fluxes into/out of upper/lower project->GW zones.
//
{
    double upperDepth;

    // --- find upper zone depth
    lowerDepth = MAX(lowerDepth, 0.0);
    lowerDepth = MIN(lowerDepth, project->TotalDepth);
    upperDepth = project->TotalDepth - lowerDepth;

    // --- save lower depth and theta to global variables
    project->Hgw = lowerDepth;
    project->Theta = theta;

    // --- find evaporation rate from both zones
    getEvapRates(project,theta, upperDepth);

    // --- find percolation rate from upper to lower zone
    project->UpperPerc = getUpperPerc(project,theta, upperDepth);
    project->UpperPerc = MIN(project->UpperPerc, project->MaxUpperPerc);

    // --- find loss rate to deep project->GW
    if ( project->DeepFlowExpr != NULL )
        project->LowerLoss = mathexpr_eval(project, project->DeepFlowExpr, getVariableValue) /
                    UCF(project,RAINFALL);
    else
        project->LowerLoss = project->A.lowerLossCoeff * lowerDepth / project->TotalDepth;
    project->LowerLoss = MIN(project->LowerLoss, lowerDepth/project->Tstep);

    // --- find project->GW flow rate from lower zone to drainage system node
    project->GWFlow = getGWFlow(project,lowerDepth);
    if ( project->LatFlowExpr != NULL )
    {
		project->GWFlow += mathexpr_eval(project, project->LatFlowExpr, getVariableValue) / UCF(project, GWFLOW);
    }
    if ( project->GWFlow >= 0.0 ) project->GWFlow = MIN(project->GWFlow, project->MaxGWFlowPos);
    else project->GWFlow = MAX(project->GWFlow, project->MaxGWFlowNeg);
}
Beispiel #8
0
int rdii_readRdiiInflow(char* tok[], int ntoks)
//
//  Input:   tok[] = array of string tokens
//           ntoks = number of tokens
//  Output:  returns an error code
//  Purpose: reads properties of an RDII inflow from a line of input.
//
{
    int   j, k;
    float a;
    TRdiiInflow* inflow;

    // --- check for proper number of items
    if ( ntoks < 3 ) return error_setInpError(ERR_ITEMS, "");

    // --- check that node receiving RDII exists
    j = project_findObject(NODE, tok[0]);
    if ( j < 0 ) return error_setInpError(ERR_NAME, tok[0]);
    
    // --- check that RDII unit hydrograph exists
    k = project_findObject(UNITHYD, tok[1]);
    if ( k < 0 ) return error_setInpError(ERR_NAME, tok[1]);

    // --- read in sewer area value
    if ( !getFloat(tok[2], &a) || a < 0.0 )
        return error_setInpError(ERR_NUMBER, tok[2]);

    // --- create the RDII inflow object if it doesn't already exist
    inflow = Node[j].rdiiInflow;
    if ( inflow == NULL )
    {
        inflow = (TRdiiInflow *) malloc(sizeof(TRdiiInflow));
        if ( !inflow ) return error_setInpError(ERR_MEMORY, "");
    }

    // --- assign UH & area to inflow object
    inflow->unitHyd = k;
    inflow->area = a / UCF(LANDAREA);

    // --- assign inflow object to node
    Node[j].rdiiInflow = inflow;
    return 0;
}
Beispiel #9
0
void writeSubcatchRunoff()
{
    int    j;
    double a, x, r;

    if ( Nobjects[SUBCATCH] == 0 ) return;
    WRITE("");
    WRITE("***************************");
    WRITE("Subcatchment Runoff Summary");
    WRITE("***************************");
    WRITE("");
    fprintf(Frpt.file,

"\n  --------------------------------------------------------------------------------------------------------"
"\n                            Total      Total      Total      Total      Total       Total     Peak  Runoff"
"\n                           Precip      Runon       Evap      Infil     Runoff      Runoff   Runoff   Coeff");
    if ( UnitSystem == US ) fprintf(Frpt.file,
"\n  Subcatchment                 in         in         in         in         in    %8s      %3s",
        VolUnitsWords[UnitSystem], FlowUnitWords[FlowUnits]);
    else fprintf(Frpt.file,
"\n  Subcatchment                 mm         mm         mm         mm         mm    %8s      %3s",
        VolUnitsWords[UnitSystem], FlowUnitWords[FlowUnits]);
    fprintf(Frpt.file,
"\n  --------------------------------------------------------------------------------------------------------");

    for ( j = 0; j < Nobjects[SUBCATCH]; j++ )
    {
        a = Subcatch[j].area;
        if ( a == 0.0 ) continue;
        fprintf(Frpt.file, "\n  %-20s", Subcatch[j].ID);
        x = SubcatchStats[j].precip * UCF(RAINDEPTH);
        fprintf(Frpt.file, " %10.2f", x/a);
        x = SubcatchStats[j].runon * UCF(RAINDEPTH); 
        fprintf(Frpt.file, " %10.2f", x/a);
        x = SubcatchStats[j].evap * UCF(RAINDEPTH);
        fprintf(Frpt.file, " %10.2f", x/a);
        x = SubcatchStats[j].infil * UCF(RAINDEPTH); 
        fprintf(Frpt.file, " %10.2f", x/a);
        x = SubcatchStats[j].runoff * UCF(RAINDEPTH);
        fprintf(Frpt.file, " %10.2f", x/a);
        x = SubcatchStats[j].runoff * Vcf;
		fprintf(Frpt.file, "%12.2f", x);
        x = SubcatchStats[j].maxFlow * UCF(FLOW);
        fprintf(Frpt.file, " %8.2f", x);
        r = SubcatchStats[j].precip + SubcatchStats[j].runon;
        if ( r > 0.0 ) r = SubcatchStats[j].runoff / r;
        fprintf(Frpt.file, "%8.3f", r);
    }
    WRITE("");
}
Beispiel #10
0
void climate_initState()
//
//  Input:   none
//  Output:  none
//  Purpose: initializes climate state variables.
//
{
    LastDay = NO_DATE;
    Temp.tmax = MISSING;
    Snow.removed = 0.0;
    NextEvapDate = StartDate;
    NextEvapRate = 0.0;

    // --- initialize variables for time series evaporation
    if ( Evap.type == TIMESERIES_EVAP && Evap.tSeries >= 0  )
    {
        // --- initialize NextEvapDate & NextEvapRate to first entry of
        //     time series whose date <= the simulation start date
        table_getFirstEntry(&Tseries[Evap.tSeries],
                            &NextEvapDate, &NextEvapRate);
        if ( NextEvapDate < StartDate )
        {  
            setNextEvapDate(StartDate);
        }
        Evap.rate = NextEvapRate / UCF(EVAPRATE);

        // --- find the next time evaporation rates change after this
        setNextEvapDate(NextEvapDate); 
    }

////  Following section added to release 5.1.010.  ////                        //(5.1.010)
    // --- initialize variables for temperature evaporation
    if ( Evap.type == TEMPERATURE_EVAP )
    {
        Tma.maxCount = sizeof(Tma.ta) / sizeof(double);
        Tma.count = 0;
        Tma.front = 0;
        Tma.tAve = 0.0;
        Tma.tRng = 0.0;
    }
////
}
Beispiel #11
0
int gwater_readAquiferParams(int j, char* tok[], int ntoks)
//
//  Input:   j = aquifer index
//           tok[] = array of string tokens
//           ntoks = number of tokens
//  Output:  returns error message
//  Purpose: reads aquifer parameter values from line of input data
//
//  Data line contains following parameters:
//    ID, porosity, wiltingPoint, fieldCapacity,     conductivity,
//    conductSlope, tensionSlope, upperEvapFraction, lowerEvapDepth,
//    gwRecession,  bottomElev,   waterTableElev,    upperMoisture
//
{
    int   i;
    double x[12];
    char *id;

    // --- check that aquifer exists
    if ( ntoks < 12 ) return error_setInpError(ERR_ITEMS, "");
    id = project_findID(AQUIFER, tok[0]);
    if ( id == NULL ) return error_setInpError(ERR_NAME, tok[0]);

    // --- read remaining tokens as floats
    for (i = 0; i < 11; i++) x[i] = 0.0;
    for (i = 1; i < 13; i++)
    {
        if ( ! getDouble(tok[i], &x[i-1]) )
            return error_setInpError(ERR_NUMBER, tok[i]);
    }

    // --- assign parameters to aquifer object
    Aquifer[j].ID = id;
    Aquifer[j].porosity       = x[0];
    Aquifer[j].wiltingPoint   = x[1];
    Aquifer[j].fieldCapacity  = x[2];
    Aquifer[j].conductivity   = x[3] / UCF(RAINFALL);
    Aquifer[j].conductSlope   = x[4];
    Aquifer[j].tensionSlope   = x[5] / UCF(LENGTH);
    Aquifer[j].upperEvapFrac  = x[6];
    Aquifer[j].lowerEvapDepth = x[7] / UCF(LENGTH);
    Aquifer[j].lowerLossCoeff = x[8] / UCF(RAINFALL);
    Aquifer[j].bottomElev     = x[9] / UCF(LENGTH);
    Aquifer[j].waterTableElev = x[10] / UCF(LENGTH);
    Aquifer[j].upperMoisture  = x[11];
    return 0;
}
Beispiel #12
0
void setWind(DateTime theDate)
//
//  Input:   theDate = simulation date
//  Output:  none
//  Purpose: sets wind speed (mph) for a specified date.
//
{
    int yr, mon, day;

    switch ( Wind.type )
    {
      case MONTHLY_WIND:
        datetime_decodeDate(theDate, &yr, &mon, &day);
        Wind.ws = Wind.aws[mon-1] / UCF(WINDSPEED);
        break;

      case FILE_WIND:
        Wind.ws = FileValue[WIND];
        break;

      default: Wind.ws = 0.0;
    }
}
void output_saveNodeResults(double reportTime, FILE* file)
//
//  Input:   reportTime = elapsed simulation time (millisec)
//           file = ptr. to binary output file
//  Output:  none
//  Purpose: writes computed node results to binary file.
//
{
    extern TRoutingTotals StepFlowTotals;  // defined in massbal.c
    int j;

    // --- find where current reporting time lies between latest routing times
    double f = (reportTime - OldRoutingTime) /
               (NewRoutingTime - OldRoutingTime);

    // --- write node results to file
    for (j=0; j<Nobjects[NODE]; j++)
    {
        // --- retrieve interpolated results for reporting time & write to file
        node_getResults(j, f, NodeResults);
        if ( Node[j].rptFlag )                                                 //(5.0.014 - LR)
            fwrite(NodeResults, sizeof(REAL4), NnodeResults, file);            //(5.0.014 - LR)

        // --- update system-wide storage volume                               //(5.0.012 - LR)
        //SysResults[SYS_FLOODING] += NodeResults[NODE_OVERFLOW];              //(5.0.012 - LR)
        SysResults[SYS_STORAGE] += NodeResults[NODE_VOLUME];
        //if ( Node[j].degree == 0 )                                           //(5.0.012 - LR)
        //{                                                                    //(5.0.012 - LR)
        //    SysResults[SYS_OUTFLOW] += NodeResults[NODE_INFLOW];             //(5.0.012 - LR)
        //}                                                                    //(5.0.012 - LR)
    }

    // --- update system-wide flows                                            //(5.0.012 - LR)
    SysResults[SYS_FLOODING] = (REAL4) (StepFlowTotals.flooding * UCF(FLOW));  //(5.0.012 - LR)
    SysResults[SYS_OUTFLOW]  = (REAL4) (StepFlowTotals.outflow * UCF(FLOW));   //(5.0.012 - LR)
    SysResults[SYS_DWFLOW] = (REAL4)(StepFlowTotals.dwInflow * UCF(FLOW));
    SysResults[SYS_GWFLOW] = (REAL4)(StepFlowTotals.gwInflow * UCF(FLOW));
    SysResults[SYS_IIFLOW] = (REAL4)(StepFlowTotals.iiInflow * UCF(FLOW));
    SysResults[SYS_EXFLOW] = (REAL4)(StepFlowTotals.exInflow * UCF(FLOW));
    SysResults[SYS_INFLOW] = SysResults[SYS_RUNOFF] +
                             SysResults[SYS_DWFLOW] +
                             SysResults[SYS_GWFLOW] +
                             SysResults[SYS_IIFLOW] +
                             SysResults[SYS_EXFLOW];
}
Beispiel #14
0
void setEvap(DateTime theDate)
//
//  Input:   theDate = simulation date
//  Output:  none
//  Purpose: sets evaporation rate (ft/sec) for a specified date.
//
{
    int yr, mon, day, k;

    switch ( Evap.type )
    {
      case CONSTANT_EVAP:
        Evap.rate = Evap.monthlyEvap[0];
        break;

      case MONTHLY_EVAP:
        datetime_decodeDate(theDate, &yr, &mon, &day);
        Evap.rate = Evap.monthlyEvap[mon-1];
        break;

      case TIMESERIES_EVAP:
        k = Evap.tSeries;
        Evap.rate = table_tseriesLookup(&Tseries[k], theDate, TRUE);
        break;

      case FILE_EVAP:
        Evap.rate = FileValue[EVAP];
        datetime_decodeDate(theDate, &yr, &mon, &day);
        Evap.rate *= Evap.panCoeff[mon-1];
        break;

      default: Evap.rate = 0.0;
    }

    // --- convert rate from in/day (mm/day) to ft/sec
    Evap.rate /= UCF(EVAPRATE);
}
Beispiel #15
0
void massbal_getSysFlows(double f, double sysFlows[])
//
//  Input:   f = time weighting factor
//  Output:  sysFlows = array of total system flows
//  Purpose: retrieves time-weighted average of old and new system flows.
//
{
    double f1 = 1.0 - f;
    sysFlows[SYS_DWFLOW] = (f1 * OldStepFlowTotals.dwInflow +
                             f * StepFlowTotals.dwInflow) * UCF(FLOW);
    sysFlows[SYS_GWFLOW] = (f1 * OldStepFlowTotals.gwInflow +
                             f * StepFlowTotals.gwInflow) * UCF(FLOW);
    sysFlows[SYS_IIFLOW] = (f1 * OldStepFlowTotals.iiInflow +
                             f * StepFlowTotals.iiInflow) * UCF(FLOW);
    sysFlows[SYS_EXFLOW] = (f1 * OldStepFlowTotals.exInflow +
                             f * StepFlowTotals.exInflow) * UCF(FLOW);
    sysFlows[SYS_FLOODING] = (f1 * OldStepFlowTotals.flooding +
                               f * StepFlowTotals.flooding) * UCF(FLOW);
    sysFlows[SYS_OUTFLOW] = (f1 * OldStepFlowTotals.outflow +
                              f * StepFlowTotals.outflow) * UCF(FLOW);
    sysFlows[SYS_STORAGE] = (f1 * OldStepFlowTotals.finalStorage +
                              f * StepFlowTotals.finalStorage) * UCF(VOLUME);
}
Beispiel #16
0
void output_saveNodeResults(Project* project, double reportTime, FILE* file)
//
//  Input:   reportTime = elapsed simulation time (millisec)
//           file = ptr. to binary output file
//  Output:  none
//  Purpose: writes computed node results to binary file.
//
{
    //project->project->StepFlowTotals;  // defined in massbal.c
    int j;

    // --- find where current reporting time lies between latest routing times
    double f = (reportTime - project->OldRoutingTime) /
               (project->NewRoutingTime - project->OldRoutingTime);

    // --- write node results to file
    for (j=0; j<project->Nobjects[NODE]; j++)
    {
        // --- retrieve interpolated results for reporting time & write to file
        node_getResults(project,j, f, project->NodeResults);
        if ( project->Node[j].rptFlag )
            fwrite(project->NodeResults, sizeof(REAL4), project->NnodeResults, file);
        stats_updateMaxNodeDepth(project,j, project->NodeResults[NODE_DEPTH]);                 //(5.1.008)

        // --- update system-wide storage volume 
        project->SysResults[SYS_STORAGE] += project->NodeResults[NODE_VOLUME];
    }

    // --- update system-wide flows 
    project->SysResults[SYS_FLOODING] = (REAL4) (project->StepFlowTotals.flooding * UCF(project,FLOW));
	project->SysResults[SYS_OUTFLOW] = (REAL4)(project->StepFlowTotals.outflow * UCF(project, FLOW));
	project->SysResults[SYS_DWFLOW] = (REAL4)(project->StepFlowTotals.dwInflow * UCF(project, FLOW));
	project->SysResults[SYS_GWFLOW] = (REAL4)(project->StepFlowTotals.gwInflow * UCF(project, FLOW));
	project->SysResults[SYS_IIFLOW] = (REAL4)(project->StepFlowTotals.iiInflow * UCF(project, FLOW));
	project->SysResults[SYS_EXFLOW] = (REAL4)(project->StepFlowTotals.exInflow * UCF(project, FLOW));
    project->SysResults[SYS_INFLOW] = project->SysResults[SYS_RUNOFF] +
                             project->SysResults[SYS_DWFLOW] +
                             project->SysResults[SYS_GWFLOW] +
                             project->SysResults[SYS_IIFLOW] +
                             project->SysResults[SYS_EXFLOW];
}
Beispiel #17
0
int  climate_readParams(char* tok[], int ntoks)
//
//  Input:   tok[] = array of string tokens
//           ntoks = number of tokens
//  Output:  returns error code
//  Purpose: reads climate/temperature parameters from input line of data
//
//  Format of data can be
//    TIMESERIES  name
//    FILE        name
//    WINDSPEED   MONTHLY  v1  v2  ...  v12
//    WINDSPEED   FILE 
//    SNOWMELT    v1  v2  ...  v6
//    ADC         IMPERV/PERV  v1  v2  ...  v10
//
{
    int      i, j, k;
    double   x[6], y;
    DateTime aDate;

    // --- identify keyword
    k = findmatch(tok[0], TempKeyWords);
    if ( k < 0 ) return error_setInpError(ERR_KEYWORD, tok[0]);
    switch (k)
    {
      case 0: // Time series name
        // --- check that time series name exists
        if ( ntoks < 2 ) return error_setInpError(ERR_ITEMS, "");
        i = project_findObject(TSERIES, tok[1]);
        if ( i < 0 ) return error_setInpError(ERR_NAME, tok[1]);

        // --- record the time series as being the data source for temperature
        Temp.dataSource = TSERIES_TEMP;
        Temp.tSeries = i;
        break;

      case 1: // Climate file
        // --- record file as being source of temperature data
        if ( ntoks < 2 ) return error_setInpError(ERR_ITEMS, "");
        Temp.dataSource = FILE_TEMP;

        // --- save name and usage mode of external climate file
        Fclimate.mode = USE_FILE;
        sstrncpy(Fclimate.name, tok[1], MAXFNAME);

        // --- save starting date to read from file if one is provided
        Temp.fileStartDate = NO_DATE;
        if ( ntoks > 2 )
        {
            if ( *tok[2] != '*')
            {
                if ( !datetime_strToDate(tok[2], &aDate) )
                    return error_setInpError(ERR_DATETIME, tok[2]);
                Temp.fileStartDate = aDate;
            }
        }
        break;

      case 2: // Wind speeds
        // --- check if wind speeds will be supplied from climate file
        if ( strcomp(tok[1], w_FILE) )
        {
            Wind.type = FILE_WIND;
        }

        // --- otherwise read 12 monthly avg. wind speed values
        else
        {
            if ( ntoks < 14 ) return error_setInpError(ERR_ITEMS, "");
            Wind.type = MONTHLY_WIND;
            for (i=0; i<12; i++)
            {
                if ( !getDouble(tok[i+2], &y) )
                    return error_setInpError(ERR_NUMBER, tok[i+2]);
                Wind.aws[i] = y;
            }
        }
        break;

      case 3: // Snowmelt params
        if ( ntoks < 7 ) return error_setInpError(ERR_ITEMS, "");
        for (i=1; i<7; i++)
        {
            if ( !getDouble(tok[i], &x[i-1]) )
                return error_setInpError(ERR_NUMBER, tok[i]);
        }
        // --- convert deg. C to deg. F for snowfall temperature
        if ( UnitSystem == SI ) x[0] = 9./5.*x[0] + 32.0;
        Snow.snotmp = x[0];
        Snow.tipm   = x[1];
        Snow.rnm    = x[2];
        Temp.elev   = x[3] / UCF(LENGTH);
        Temp.anglat = x[4];
        Temp.dtlong = x[5] / 60.0;
        break;

      case 4:  // Areal Depletion Curve data
        // --- check if data is for impervious or pervious areas
        if ( ntoks < 12 ) return error_setInpError(ERR_ITEMS, "");
        if      ( match(tok[1], w_IMPERV) ) i = 0;
        else if ( match(tok[1], w_PERV)   ) i = 1;
        else return error_setInpError(ERR_KEYWORD, tok[1]);

        // --- read 10 fractional values
        for (j=0; j<10; j++)
        {
            if ( !getDouble(tok[j+2], &y) || y < 0.0 || y > 1.0 ) 
                return error_setInpError(ERR_NUMBER, tok[j+2]);
            Snow.adc[i][j] = y;
        }
        break;
    }
    return 0;
}
Beispiel #18
0
void  runoff_readFromFile(void)
//
//  Input:   none
//  Output:  none
//  Purpose: reads runoff results from Runoff Interface file for current time.
//
{
    int    i, j;
    int    nResults;                   // number of results per subcatch.
    int    kount;                      // count of items read from file
    float  tStep;                      // runoff time step (sec)
    TGroundwater* gw;                  // ptr. to Groundwater object

    // --- make sure not past end of file
    if ( Nsteps > MaxSteps )
    {
         report_writeErrorMsg(ERR_RUNOFF_FILE_END, "");
         return;
    }

    // --- replace old state with current one for all subcatchments
    for (j = 0; j < Nobjects[SUBCATCH]; j++) subcatch_setOldState(j);

    // --- read runoff time step
    kount = 0;
    kount += fread(&tStep, sizeof(float), 1, Frunoff.file);

    // --- compute number of results saved for each subcatchment
    nResults = MAX_SUBCATCH_RESULTS + Nobjects[POLLUT] - 1;

    // --- for each subcatchment
    for (j = 0; j < Nobjects[SUBCATCH]; j++)
    {
        // --- read vector of saved results
        kount += fread(SubcatchResults, sizeof(float), nResults, Frunoff.file);

        // --- extract hydrologic results, converting units where necessary
        //     (results were saved to file in user's units)
        Subcatch[j].newSnowDepth = SubcatchResults[SUBCATCH_SNOWDEPTH] /
                                   UCF(RAINDEPTH);
        Subcatch[j].evapLoss     = SubcatchResults[SUBCATCH_EVAP] /
                                   UCF(RAINFALL);
        Subcatch[j].infilLoss    = SubcatchResults[SUBCATCH_INFIL] /
                                   UCF(RAINFALL);
        Subcatch[j].newRunoff    = SubcatchResults[SUBCATCH_RUNOFF] /
                                   UCF(FLOW);
        gw = Subcatch[j].groundwater;
        if ( gw )
        {
            gw->newFlow    = SubcatchResults[SUBCATCH_GW_FLOW] / UCF(FLOW);
            gw->lowerDepth = Aquifer[gw->aquifer].bottomElev -
                             (SubcatchResults[SUBCATCH_GW_ELEV] / UCF(LENGTH));
            gw->theta      = SubcatchResults[SUBCATCH_SOIL_MOIST];
        }

        // --- extract water quality results
        for (i = 0; i < Nobjects[POLLUT]; i++)
        {
            Subcatch[j].newQual[i] = SubcatchResults[SUBCATCH_WASHOFF + i];
        }
    }

    // --- report error if not enough values were read
    if ( kount < 1 + Nobjects[SUBCATCH] * nResults )
    {
         report_writeErrorMsg(ERR_RUNOFF_FILE_READ, "");
         return;
    }

    // --- update runoff time clock
    OldRunoffTime = NewRunoffTime;
    NewRunoffTime = OldRunoffTime + (double)(tStep)*1000.0;
    Nsteps++;
}
Beispiel #19
0
void outfall_setOutletDepth(int j, double yNorm, double yCrit, double z)
//
//  Input:   j = node index
//           yNorm = normal flow depth in outfall conduit (ft)
//           yCrit = critical flow depth in outfall conduit (ft)
//           z = height to outfall conduit invert (ft)
//  Output:  none
//  Purpose: sets water depth at an outfall node.
//
{
    double   x, y;                     // x,y values in table
    double   yNew;                     // new depth above invert elev. (ft)
    double   stage;                    // water elevation at outfall (ft)
    int      k;                        // table index
    int      i = Node[j].subIndex;     // outfall index
    DateTime currentDate;              // current date/time in days

    switch ( Outfall[i].type )
    {
      case FREE_OUTFALL:
        if ( z > 0.0 ) Node[j].newDepth = 0.0;
        else Node[j].newDepth = MIN(yNorm, yCrit);
        return;

      case NORMAL_OUTFALL:
        if ( z > 0.0 ) Node[j].newDepth = 0.0;
        else Node[j].newDepth = yNorm;
        return;

      case FIXED_OUTFALL:
        stage = Outfall[i].fixedStage;
        break;

      case TIDAL_OUTFALL:
        k = Outfall[i].tideCurve;
        table_getFirstEntry(&Curve[k], &x, &y);
        currentDate = NewRoutingTime / MSECperDAY;
        x += ( currentDate - floor(currentDate) ) * 24.0;
        stage = table_lookup(&Curve[k], x) / UCF(LENGTH);
        break;

      case TIMESERIES_OUTFALL:
        k = Outfall[i].stageSeries;
        currentDate = StartDateTime + NewRoutingTime / MSECperDAY;
        stage = table_tseriesLookup(&Tseries[k], currentDate, TRUE) /
                UCF(LENGTH);
        break;
      default: stage = Node[j].invertElev;
    }

    // --- now determine depth at node given outfall stage elev.
 
    // --- let critical flow depth be min. of critical & normal depth
    yCrit = MIN(yCrit, yNorm);

    // --- if elev. of critical depth is below outfall stage elev. then
    //     the outfall stage determines node depth
    if ( yCrit + z + Node[j].invertElev < stage )
    {
        yNew = stage - Node[j].invertElev;
    }

    // --- otherwise if the outfall conduit lies above the outfall invert
    else if ( z > 0.0 )
    {
        // --- if the outfall stage lies below the bottom of the outfall
        //     conduit then the result is distance from node invert to stage
        if ( stage < Node[j].invertElev + z )
            yNew = MAX(0.0, (stage - Node[j].invertElev));

        // --- otherwise stage lies between bottom of conduit and critical
        //     depth in conduit so result is elev. of critical depth
        else
            yNew = z + yCrit;
    }

    // --- and for case where there is no conduit offset and outfall stage
    //     lies below critical depth, then node depth = critical depth 
    else yNew = yCrit;
    Node[j].newDepth = yNew;
}
Beispiel #20
0
void output_saveSubcatchResults(double reportTime, FILE* file)
//
//  Input:   reportTime = elapsed simulation time (millisec)
//           file = ptr. to binary output file
//  Output:  none
//  Purpose: writes computed subcatchment results to binary file.
//
{
    int      j;
    double   f;
    double   area;
    REAL4    totalArea = 0.0f; 
    DateTime reportDate = getDateTime(reportTime);
	FILE *fptr;

	// --- dbf variables
	DBFHandle	hDBF;
	char		fieldName[128];
	int			n;
	double		f1,f0;
	double		value;
	int numFields;

    // --- update reported rainfall at each rain gage
    for ( j=0; j<Nobjects[GAGE]; j++ )
    {
        gage_setReportRainfall(j, reportDate);
    }

    // --- find where current reporting time lies between latest runoff times
    f = (reportTime - OldRunoffTime) / (NewRunoffTime - OldRunoffTime);
	f1 = 1.0 - f;
	f0 = f;

    // --- write subcatchment results to file
    for ( j=0; j<Nobjects[SUBCATCH]; j++)
    {
        // --- retrieve interpolated results for reporting time & write to file
        subcatch_getResults(j, f, SubcatchResults);
        if ( Subcatch[j].rptFlag )
            fwrite(SubcatchResults, sizeof(REAL4), NsubcatchResults, file);

        // --- update system-wide results
        area = Subcatch[j].area * UCF(LANDAREA);
        totalArea += (REAL4)area;
        SysResults[SYS_RAINFALL] +=
            (REAL4)(SubcatchResults[SUBCATCH_RAINFALL] * area);
        SysResults[SYS_SNOWDEPTH] +=
            (REAL4)(SubcatchResults[SUBCATCH_SNOWDEPTH] * area);
        SysResults[SYS_EVAP] +=
            (REAL4)(SubcatchResults[SUBCATCH_EVAP] * area);
        if ( Subcatch[j].groundwater ) SysResults[SYS_EVAP] += 
            (REAL4)(Subcatch[j].groundwater->evapLoss * UCF(EVAPRATE) * area);
        SysResults[SYS_INFIL] +=
            (REAL4)(SubcatchResults[SUBCATCH_INFIL] * area);
        SysResults[SYS_RUNOFF] += (REAL4)SubcatchResults[SUBCATCH_RUNOFF];
    }

    // --- normalize system-wide results to catchment area
    if ( UnitSystem == SI ) f = (5./9.) * (Temp.ta - 32.0);
    else f = Temp.ta;
    SysResults[SYS_TEMPERATURE] = (REAL4)f;
    SysResults[SYS_EVAP]      /= totalArea;
    SysResults[SYS_RAINFALL]  /= totalArea;
    SysResults[SYS_SNOWDEPTH] /= totalArea;
    SysResults[SYS_INFIL]     /= totalArea;

	// --- open DBF
	hDBF = DBFOpen(F2Dmesh.name, "r+b");
	if( hDBF == NULL )
	{
		//TODO
		//printf( "DBFOpen(%s,\"rb+\") failed.\n", argv[1] );
		//exit( 2 );
	}

	// --- create new field name
	n=sprintf (fieldName, "h_%07.0f", (reportTime / 1000.f));
	if( DBFAddField( hDBF, fieldName, FTDouble, 12, 6 ) == -1 )
    {
		//TODO
		//printf( "DBFAddField(%s,FTDouble,%d,%d) failed.\n", fieldName, 12, 3 );
		//exit( 4 );
    }

	n=sprintf (fieldName, "V_%07.0f", (reportTime / 1000.f));
	if( DBFAddField( hDBF, fieldName, FTDouble, 12, 6 ) == -1 )
    {
		//TODO
		//printf( "DBFAddField(%s,FTDouble,%d,%d) failed.\n", fieldName, 12, 3 );
		//exit( 4 );
    }

	// --- number of existing fields
	numFields = DBFGetFieldCount( hDBF );

    // --- write subcatchment results to file
    for ( j=0; j<Nobjects[SUBCATCH]; j++)
    {
		if (Subcatch[j].isStreet)
		{

			value = ( f1 * Subcatch[j].oldGlobalDepth + f0 * Subcatch[j].newGlobalDepth ) * UCF(LENGTH);

			//Write value
			DBFWriteDoubleAttribute(hDBF, Subcatch[j].dbf_record, numFields - 2, value );

			value = ( f1 * Subcatch[j].oldVel + f0 * Subcatch[j].newVel ) * UCF(LENGTH);

			//Write value
			DBFWriteDoubleAttribute(hDBF, Subcatch[j].dbf_record, numFields - 1, value );

		}
	}

	//CLose
	DBFClose( hDBF );

	// --- create file to print outflow
	fptr = fopen(F2Doutflow.name, "a+");

	if (fptr == NULL)
	{
		printf("ERROR: Impossible to create Outflow.txt\n");
	} else {
		fprintf(fptr, "%12.3f  %12.3f\n", (reportTime / 1000.f), M2DControl.totalOutflow);

		fclose(fptr);
	}


}
Beispiel #21
0
double massbal_getQualError()
//
//  Input:   none
//  Output:  none
//  Purpose: computes water quality routing mass balance error.
//
{
    int    p;
    double maxQualError = 0.0;
    double totalInflow;
    double totalOutflow;
    double cf;

    // --- analyze each pollutant
    for (p = 0; p < Nobjects[POLLUT]; p++)
    {
        // --- get final mass stored in nodes and links
        QualTotals[p].finalStorage += massbal_getStoredMass(p);                //(5.1.008)

        // --- compute % difference between total inflow and outflow
        totalInflow  = QualTotals[p].dwInflow +
                       QualTotals[p].wwInflow +
                       QualTotals[p].gwInflow +
                       QualTotals[p].iiInflow +
                       QualTotals[p].exInflow +
                       QualTotals[p].initStorage;
        totalOutflow = QualTotals[p].flooding +
                       QualTotals[p].outflow +
                       QualTotals[p].reacted +
                       QualTotals[p].seepLoss +                                //(5.1.008)
                       QualTotals[p].finalStorage;
        QualTotals[p].pctError = 0.0;
        if ( fabs(totalInflow - totalOutflow) < 0.001 )
        {
            QualTotals[p].pctError = TINY;
        }
        else if ( totalInflow > 0.0 )
        {
            QualTotals[p].pctError = 100.0 * (1.0 - totalOutflow / totalInflow);
        }
        else if ( totalOutflow > 0.0 )
        {
            QualTotals[p].pctError = 100.0 * (totalInflow / totalOutflow - 1.0);
        }

        // --- update max. error among all pollutants
        if ( fabs(QualTotals[p].pctError) > fabs(maxQualError) )
        {
            maxQualError = QualTotals[p].pctError;
        }

        // --- convert totals to reporting units (lbs, kg, or Log(Count))
        cf = LperFT3;
        if ( Pollut[p].units == COUNT )
        {
            QualTotals[p].dwInflow     = LOG10(cf * QualTotals[p].dwInflow);
            QualTotals[p].wwInflow     = LOG10(cf * QualTotals[p].wwInflow);
            QualTotals[p].gwInflow     = LOG10(cf * QualTotals[p].gwInflow);
            QualTotals[p].iiInflow     = LOG10(cf * QualTotals[p].iiInflow);
            QualTotals[p].exInflow     = LOG10(cf * QualTotals[p].exInflow);
            QualTotals[p].flooding     = LOG10(cf * QualTotals[p].flooding);
            QualTotals[p].outflow      = LOG10(cf * QualTotals[p].outflow);
            QualTotals[p].reacted      = LOG10(cf * QualTotals[p].reacted);
            QualTotals[p].seepLoss     = LOG10(cf * QualTotals[p].seepLoss);   //(5.1.008)
            QualTotals[p].initStorage  = LOG10(cf * QualTotals[p].initStorage);
            QualTotals[p].finalStorage = LOG10(cf * QualTotals[p].finalStorage);
        }
        else
        {
            cf = cf * UCF(MASS);
            if ( Pollut[p].units == UG ) cf /= 1000.0;
            QualTotals[p].dwInflow     *= cf;
            QualTotals[p].wwInflow     *= cf; 
            QualTotals[p].gwInflow     *= cf; 
            QualTotals[p].iiInflow     *= cf; 
            QualTotals[p].exInflow     *= cf; 
            QualTotals[p].flooding     *= cf; 
            QualTotals[p].outflow      *= cf; 
            QualTotals[p].reacted      *= cf; 
            QualTotals[p].seepLoss     *= cf; 
            QualTotals[p].initStorage  *= cf; 
            QualTotals[p].finalStorage *= cf; 
        }
    }
    QualError = maxQualError;
    return maxQualError;
}
Beispiel #22
0
int subcatch_readSubareaParams(char* tok[], int ntoks)
//
//  Input:   tok[] = array of string tokens
//           ntoks = number of tokens
//  Output:  returns an error code
//  Purpose: reads subcatchment's subarea parameters from a tokenized 
//           line of input data.
//
//  Data has format:
//    Subcatch  Imperv_N  Perv_N  Imperv_S  Perv_S  PctZero  RouteTo (PctRouted)
//
{
    int    i, j, k, m;
    double x[7];

    // --- check for enough tokens
    if ( ntoks < 7 ) return error_setInpError(ERR_ITEMS, "");

    // --- check that named subcatch exists
    j = project_findObject(SUBCATCH, tok[0]);
    if ( j < 0 ) return error_setInpError(ERR_NAME, tok[0]);

    // --- read in Mannings n, depression storage, & PctZero values
    for (i = 0; i < 5; i++)
    {
        if ( ! getDouble(tok[i+1], &x[i])  || x[i] < 0.0 )
            return error_setInpError(ERR_NAME, tok[i+1]);
    }

    // --- check for valid runoff routing keyword
    m = findmatch(tok[6], RunoffRoutingWords);
    if ( m < 0 ) return error_setInpError(ERR_KEYWORD, tok[6]);

    // --- get percent routed parameter if present (default is 100)
    x[5] = m;
    x[6] = 1.0;
    if ( ntoks >= 8 )
    {
        if ( ! getDouble(tok[7], &x[6]) || x[6] < 0.0 || x[6] > 100.0 )
            return error_setInpError(ERR_NUMBER, tok[7]);
        x[6] /= 100.0;
    }

    // --- assign input values to each type of subarea
    Subcatch[j].subArea[IMPERV0].N = x[0];
    Subcatch[j].subArea[IMPERV1].N = x[0];
    Subcatch[j].subArea[PERV].N    = x[1];

    Subcatch[j].subArea[IMPERV0].dStore = 0.0;
    Subcatch[j].subArea[IMPERV1].dStore = x[2] / UCF(RAINDEPTH);
    Subcatch[j].subArea[PERV].dStore    = x[3] / UCF(RAINDEPTH);

    Subcatch[j].subArea[IMPERV0].fArea  = Subcatch[j].fracImperv * x[4] / 100.0;
    Subcatch[j].subArea[IMPERV1].fArea  = Subcatch[j].fracImperv * (1.0 - x[4] / 100.0);
    Subcatch[j].subArea[PERV].fArea     = (1.0 - Subcatch[j].fracImperv);

    // --- assume that all runoff from each subarea goes to subcatch outlet
    for (i = IMPERV0; i <= PERV; i++)
    {
        Subcatch[j].subArea[i].routeTo = TO_OUTLET;
        Subcatch[j].subArea[i].fOutlet = 1.0;
    }

    // --- modify routing if pervious runoff routed to impervious area
    //     (fOutlet is the fraction of runoff not routed)
    
    k = (int)x[5];
    if ( Subcatch[j].fracImperv == 0.0
    ||   Subcatch[j].fracImperv == 1.0 ) k = TO_OUTLET;
    if ( k == TO_IMPERV && Subcatch[j].fracImperv )
    {
        Subcatch[j].subArea[PERV].routeTo = k;
        Subcatch[j].subArea[PERV].fOutlet = 1.0 - x[6];
    }

    // --- modify routing if impervious runoff routed to pervious area
    if ( k == TO_PERV )
    {
        Subcatch[j].subArea[IMPERV0].routeTo = k;
        Subcatch[j].subArea[IMPERV1].routeTo = k;
        Subcatch[j].subArea[IMPERV0].fOutlet = 1.0 - x[6];
        Subcatch[j].subArea[IMPERV1].fOutlet = 1.0 - x[6];
    }
    return 0;
}
Beispiel #23
0
void  subcatch_getResults(int j, double f, float x[])
//
//  Input:   j = subcatchment index
//           f = weighting factor
//  Output:  x = array of results
//  Purpose: computes wtd. combination of old and new subcatchment results.
//
{
    int    p;                          // pollutant index
    int    k;                          // rain gage index
    double f1 = 1.0 - f;
    double z;
    double runoff;
    TGroundwater* gw;                  // ptr. to groundwater object

    // --- retrieve rainfall for current report period
    k = Subcatch[j].gage;
    if ( k >= 0 ) x[SUBCATCH_RAINFALL] = (float)Gage[k].reportRainfall;
    else          x[SUBCATCH_RAINFALL] = 0.0f;

    // --- retrieve snow depth
    z = ( f1 * Subcatch[j].oldSnowDepth +
          f * Subcatch[j].newSnowDepth ) * UCF(RAINDEPTH);
    x[SUBCATCH_SNOWDEPTH] = (float)z;

    // --- retrieve runoff and losses
    x[SUBCATCH_EVAP] = (float)(Subcatch[j].evapLoss * UCF(EVAPRATE));
    x[SUBCATCH_INFIL] = (float)(Subcatch[j].infilLoss * UCF(RAINFALL));
    runoff = f1 * Subcatch[j].oldRunoff + f * Subcatch[j].newRunoff;

////  Following code segement added to release 5.1.008.  ////                  //(5.1.008)
////
    // --- add any LID drain flow to reported runoff
    if ( Subcatch[j].lidArea > 0.0 )
    {
        runoff += f1 * lid_getDrainFlow(j, PREVIOUS) +
                  f * lid_getDrainFlow(j, CURRENT);
    }
////

    // --- if runoff is really small, report it as zero
    if ( runoff < MIN_RUNOFF * Subcatch[j].area ) runoff = 0.0;                //(5.1.008)
    x[SUBCATCH_RUNOFF] = (float)(runoff * UCF(FLOW));

    // --- retrieve groundwater results
    gw = Subcatch[j].groundwater;
    if ( gw )
    {
        z = (f1 * gw->oldFlow + f * gw->newFlow) * Subcatch[j].area * UCF(FLOW);
        x[SUBCATCH_GW_FLOW] = (float)z;
        z = (Aquifer[gw->aquifer].bottomElev + gw->lowerDepth) * UCF(LENGTH);
        x[SUBCATCH_GW_ELEV] = (float)z;
        z = gw->theta;
        x[SUBCATCH_SOIL_MOIST] = (float)z;
    }
    else
    {
        x[SUBCATCH_GW_FLOW] = 0.0f;
        x[SUBCATCH_GW_ELEV] = 0.0f;
        x[SUBCATCH_SOIL_MOIST]  = 0.0f;
    }

    // --- retrieve pollutant washoff
    if ( !IgnoreQuality ) for (p = 0; p < Nobjects[POLLUT]; p++ )
    {
        if ( runoff == 0.0 ) z = 0.0;
        else z = f1 * Subcatch[j].oldQual[p] + f * Subcatch[j].newQual[p];
        x[SUBCATCH_WASHOFF+p] = (float)z;
    }
}
Beispiel #24
0
int  subcatch_readParams(int j, char* tok[], int ntoks)
//
//  Input:   j = subcatchment index
//           tok[] = array of string tokens
//           ntoks = number of tokens
//  Output:  returns an error code
//  Purpose: reads subcatchment parameters from a tokenized  line of input data.
//
//  Data has format:
//    Name  RainGage  Outlet  Area  %Imperv  Width  Slope CurbLength  Snowpack  
//
{
    int    i, k, m;
    char*  id;
    double x[9];

    // --- check for enough tokens
    if ( ntoks < 8 ) return error_setInpError(ERR_ITEMS, "");

    // --- check that named subcatch exists
    id = project_findID(SUBCATCH, tok[0]);
    if ( id == NULL ) return error_setInpError(ERR_NAME, tok[0]);

    // --- check that rain gage exists
    k = project_findObject(GAGE, tok[1]);
    if ( k < 0 ) return error_setInpError(ERR_NAME, tok[1]);
    x[0] = k;

    // --- check that outlet node or subcatch exists
    m = project_findObject(NODE, tok[2]);
    x[1] = m;
    m = project_findObject(SUBCATCH, tok[2]);
    x[2] = m;
    if ( x[1] < 0.0 && x[2] < 0.0 )
        return error_setInpError(ERR_NAME, tok[2]);

    // --- read area, %imperv, width, slope, & curb length
    for ( i = 3; i < 8; i++)
    {
        if ( ! getDouble(tok[i], &x[i]) || x[i] < 0.0 )
            return error_setInpError(ERR_NUMBER, tok[i]);
    }

    // --- if snowmelt object named, check that it exists
    x[8] = -1;
    if ( ntoks > 8 )
    {
        k = project_findObject(SNOWMELT, tok[8]);
        if ( k < 0 ) return error_setInpError(ERR_NAME, tok[8]);
        x[8] = k;
    }

    // --- assign input values to subcatch's properties
    Subcatch[j].ID = id;
    Subcatch[j].gage        = (int)x[0];
    Subcatch[j].outNode     = (int)x[1];
    Subcatch[j].outSubcatch = (int)x[2];
    Subcatch[j].area        = x[3] / UCF(LANDAREA);
    Subcatch[j].fracImperv  = x[4] / 100.0;
    Subcatch[j].width       = x[5] / UCF(LENGTH);
    Subcatch[j].slope       = x[6] / 100.0;
    Subcatch[j].curbLength  = x[7];

    // --- create the snow pack object if it hasn't already been created
    if ( x[8] >= 0 )
    {
        if ( !snow_createSnowpack(j, (int)x[8]) )
            return error_setInpError(ERR_MEMORY, "");
    }
    return 0;
}
Beispiel #25
0
double massbal_getQualError()
//
//  Input:   none
//  Output:  none
//  Purpose: computes water quality routing mass balance error.
//
{
    int    j, p;
    double maxQualError = 0.0;
    double finalStorage;
    double totalInflow;
    double totalOutflow;
    double cf;

    // --- analyze each pollutant
    for (p = 0; p < Nobjects[POLLUT]; p++)
    {
        // --- get final mass stored in nodes and links
        finalStorage = 0.0;
        for (j = 0; j < Nobjects[NODE]; j++)
        {
            finalStorage += Node[j].newVolume * Node[j].newQual[p];
        }
        for (j = 0; j < Nobjects[LINK]; j++)
        {
            finalStorage += Link[j].newVolume * Link[j].newQual[p];
        }
        QualTotals[p].finalStorage = finalStorage;

        // --- compute % difference between total inflow and outflow
        totalInflow  = QualTotals[p].dwInflow +
                       QualTotals[p].wwInflow +
                       QualTotals[p].gwInflow +
                       QualTotals[p].iiInflow +
                       QualTotals[p].exInflow +
                       QualTotals[p].initStorage;
        totalOutflow = QualTotals[p].outflow +
                       QualTotals[p].pumpedVol +
                       finalStorage;
        QualTotals[p].internalOutflow = 0.0;
        if ( fabs(totalInflow - totalOutflow) < 0.001 )
        {
            QualTotals[p].internalOutflow = TINY;
        }
        else if ( totalInflow > 0.0 )
        {
            QualTotals[p].internalOutflow = 100.0 * (1.0 - totalOutflow / totalInflow);
        }
        else if ( totalOutflow > 0.0 )
        {
            QualTotals[p].internalOutflow = 100.0 * (totalInflow / totalOutflow - 1.0);
        }

        // --- update max. error among all pollutants
        if ( fabs(QualTotals[p].internalOutflow) > fabs(maxQualError) )
        {
            maxQualError = QualTotals[p].internalOutflow;
        }

        // --- convert totals to reporting units (lbs, kg, or Log(Count))
        cf = LperFT3;
        if ( Pollut[p].units == COUNT )
        {
            QualTotals[p].dwInflow     = LOG10(cf * QualTotals[p].dwInflow);
            QualTotals[p].wwInflow     = LOG10(cf * QualTotals[p].wwInflow);
            QualTotals[p].gwInflow     = LOG10(cf * QualTotals[p].gwInflow);
            QualTotals[p].iiInflow     = LOG10(cf * QualTotals[p].iiInflow);
            QualTotals[p].exInflow     = LOG10(cf * QualTotals[p].exInflow);
            QualTotals[p].outflow      = LOG10(cf * QualTotals[p].outflow);
            QualTotals[p].pumpedVol    = LOG10(cf * QualTotals[p].pumpedVol);
            QualTotals[p].initStorage  = LOG10(cf * QualTotals[p].initStorage);
            QualTotals[p].finalStorage = LOG10(cf * QualTotals[p].finalStorage);
        }
        else
        {
            cf = cf * UCF(MASS);
            if ( Pollut[p].units == UG ) cf /= 1000.0;
            QualTotals[p].dwInflow     *= cf;
            QualTotals[p].wwInflow     *= cf; 
            QualTotals[p].gwInflow     *= cf; 
            QualTotals[p].iiInflow     *= cf; 
            QualTotals[p].exInflow     *= cf; 
            QualTotals[p].outflow      *= cf; 
            QualTotals[p].pumpedVol    *= cf; 
            QualTotals[p].initStorage  *= cf; 
            QualTotals[p].finalStorage *= cf; 
        }
    }
    QualError = maxQualError;
    return maxQualError;
}
Beispiel #26
0
int evaluatePremise(struct TPremise* p, DateTime theDate, DateTime theTime,
                    DateTime elapsedTime, double tStep)
//
//  Input:   p = a control rule premise condition
//           theDate = the current simulation date
//           theTime = the current simulation time of day
//           elpasedTime = decimal days since the start of the simulation
//           tStep = current time step (days)                                  //(5.0.013 - LR)
//  Output:  returns TRUE if the condition is true or FALSE otherwise
//  Purpose: evaluates the truth of a control rule premise condition.
//
{
    int i = p->node;
    int j = p->link;
    double head;

    switch ( p->attribute )
    {
      case r_TIME:
        return checkTimeValue(p, elapsedTime, elapsedTime + tStep);

      case r_DATE:
        return checkValue(p, theDate);

      case r_CLOCKTIME:
        return checkTimeValue(p, theTime, theTime + tStep);

      case r_DAY:                                                              //(5.0.014 - LR)
        return checkValue(p, datetime_dayOfWeek(theDate));                     //(5.0.014 - LR)

      case r_MONTH:                                                            //(5.0.014 - LR)
        return checkValue(p, datetime_monthOfYear(theDate));                   //(5.0.014 - LR)

      case r_STATUS:
        if ( j < 0 || Link[j].type != PUMP ) return FALSE;
        else return checkValue(p, Link[j].setting);
        
      case r_SETTING:
        if ( j < 0 || (Link[j].type != ORIFICE && Link[j].type != WEIR) )
            return FALSE;
        else return checkValue(p, Link[j].setting);

      case r_FLOW:
        if ( j < 0 ) return FALSE;
        else return checkValue(p, Link[j].direction*Link[j].newFlow*UCF(FLOW));//(5.0.019 - LR)

      case r_DEPTH:
        if ( j >= 0 ) return checkValue(p, Link[j].newDepth*UCF(LENGTH));
        else if ( i >= 0 )
            return checkValue(p, Node[i].newDepth*UCF(LENGTH));
        else return FALSE;

      case r_HEAD:
        if ( i < 0 ) return FALSE;
        head = (Node[i].newDepth + Node[i].invertElev) * UCF(LENGTH);
        return checkValue(p, head);

      case r_INFLOW:
        if ( i < 0 ) return FALSE;
        else return checkValue(p, Node[i].newLatFlow*UCF(FLOW));

      default: return FALSE;
    }
}
Beispiel #27
0
void output_saveSubcatchResults(Project* project, double reportTime, FILE* file)
//
//  Input:   reportTime = elapsed simulation time (millisec)
//           file = ptr. to binary output file
//  Output:  none
//  Purpose: writes computed subcatchment results to binary file.
//
{
    int      j;
    double   f;
    double   area;
    REAL4    totalArea = 0.0f; 
    DateTime reportDate = getDateTime(project,reportTime);

    // --- update reported rainfall at each rain gage
    for ( j=0; j<project->Nobjects[GAGE]; j++ )
    {
        gage_setReportRainfall(project,j, reportDate);
    }

    // --- find where current reporting time lies between latest runoff times
    f = (reportTime - project->OldRunoffTime) / (project->NewRunoffTime - project->OldRunoffTime);

    // --- write subcatchment results to file
    for ( j=0; j<project->Nobjects[SUBCATCH]; j++)
    {
        // --- retrieve interpolated results for reporting time & write to file
		subcatch_getResults(project, j, f, project->SubcatchResults);
        if ( project->Subcatch[j].rptFlag )
            fwrite(project->SubcatchResults, sizeof(REAL4), project->NsubcatchResults, file);

        // --- update system-wide results
        area = project->Subcatch[j].area * UCF(project,LANDAREA);
        totalArea += (REAL4)area;
        project->SysResults[SYS_RAINFALL] +=
            (REAL4)(project->SubcatchResults[SUBCATCH_RAINFALL] * area);
        project->SysResults[SYS_SNOWDEPTH] +=
            (REAL4)(project->SubcatchResults[SUBCATCH_SNOWDEPTH] * area);
        project->SysResults[SYS_EVAP] +=
            (REAL4)(project->SubcatchResults[SUBCATCH_EVAP] * area);
        if ( project->Subcatch[j].groundwater ) project->SysResults[SYS_EVAP] += 
            (REAL4)(project->Subcatch[j].groundwater->evapLoss * UCF(project,EVAPRATE) * area);
        project->SysResults[SYS_INFIL] +=
            (REAL4)(project->SubcatchResults[SUBCATCH_INFIL] * area);
        project->SysResults[SYS_RUNOFF] += (REAL4)project->SubcatchResults[SUBCATCH_RUNOFF];
    }

    // --- normalize system-wide results to catchment area
    if ( project->UnitSystem == SI ) f = (5./9.) * (project->Temp.ta - 32.0);
    else f = project->Temp.ta;
    project->SysResults[SYS_TEMPERATURE] = (REAL4)f;
    
    f = project->Evap.rate * UCF(project,EVAPRATE);                                             //(5.1.010)
    project->SysResults[SYS_PET] = (REAL4)f;                                            //(5.1.010)

    if ( totalArea > 0.0 )                                                     //(5.1.008)
    {
        project->SysResults[SYS_EVAP]      /= totalArea;
        project->SysResults[SYS_RAINFALL]  /= totalArea;
        project->SysResults[SYS_SNOWDEPTH] /= totalArea;
        project->SysResults[SYS_INFIL]     /= totalArea;
    }
}
Beispiel #28
0
void getRainfall(DateTime currentDate)
//
//  Input:   currentDate = current calendar date/time
//  Output:  none
//  Purpose: determines rainfall at current RDII processing date.
//
//
{
    int      j;                        // rain gage index
    int      i;                        // past rainfall index
    int      month;                    // month of current date
    int      gageInterval;             // gage recording interval (sec)
    float    rainfall;                 // rainfall volume (inches or mm)
    DateTime gageDate;                 // calendar date for rain gage
    
    // --- examine each rain gage
    for (j = 0; j < Nobjects[GAGE]; j++)
    {
        // --- repeat until gage's date reaches or exceeds current date
        if ( Gage[j].isUsed == FALSE ) continue;
        while ( GageData[j].gageDate < currentDate )
        {
            // --- get rainfall volume over gage's recording interval
            //     at gage'a current date (in original depth units)
            gageDate = GageData[j].gageDate;
            gageInterval = Gage[j].rainInterval;
            gage_setState(j, gageDate);
            rainfall = Gage[j].rainfall * (float)gageInterval / 3600.0;
        
            // --- if rainfall occurs
            if ( rainfall > 0.0 )
            {
                // --- if previous dry period long enough then begin
                //     new RDII event with time period index set to 0

//////////////////////////////////////////////////////////////////////////////
//  New RDII event occurs when dry period > base of longest UH. (LR - 9/19/06)
//////////////////////////////////////////////////////////////////////////////
                //if ( GageData[j].drySeconds >= RDII_MIT )
                if ( GageData[j].drySeconds >= gageInterval * GageData[j].maxPeriods  )
                {
                    for (i=0; i<GageData[j].maxPeriods; i++)
                    {
                        GageData[j].pastRain[i] = 0.0;
                    }
                    GageData[j].period = 0;
                }
                GageData[j].drySeconds = 0;
                GageData[j].hasPastRain = TRUE;

                // --- update count of total rainfall volume (ft3)
                TotalRainVol += rainfall / UCF(RAINDEPTH) * GageData[j].area;
            }

            // --- if no rainfall, update duration of dry period
            else
            {
                GageData[j].drySeconds += gageInterval;
                if ( GageData[j].drySeconds >= 
                    gageInterval * GageData[j].maxPeriods )
                {
                    GageData[j].hasPastRain = FALSE;
                }

//////////////////////////
////  Added (LR - 9/19/06)
//////////////////////////
                else GageData[j].hasPastRain = TRUE;

            }
        
            // --- add rainfall to list of past values, wrapping
            //     array index if necessary
            if ( GageData[j].period < GageData[j].maxPeriods )
            {
                i = GageData[j].period;
            }
            else i = 0;
            GageData[j].pastRain[i] = rainfall;
            month = datetime_monthOfYear(currentDate) - 1;
            GageData[j].pastMonth[i] = (char)month;
            GageData[j].period = i + 1;

            // --- advance rain gage's date by gage recording interval
            GageData[j].gageDate = datetime_addSeconds(gageDate, gageInterval);
        }
    }
}
Beispiel #29
0
void project_validate()
//
//  Input:   none
//  Output:  none
//  Purpose: checks validity of project data.
//
{
    int i;
    int j;
    int err;

    // --- validate Curves and TimeSeries
    for ( i=0; i<Nobjects[CURVE]; i++ )
    {
         err = table_validate(&Curve[i]);
         if ( err ) report_writeErrorMsg(ERR_CURVE_SEQUENCE, Curve[i].ID);
    }
    for ( i=0; i<Nobjects[TSERIES]; i++ )
    {
        err = table_validate(&Tseries[i]);
        if ( err ) report_writeTseriesErrorMsg(err, &Tseries[i]);
    }

    // --- validate hydrology objects
    //     (NOTE: order is important !!!!)
    climate_validate();
    lid_validate();
    if ( Nobjects[SNOWMELT] == 0 ) IgnoreSnowmelt = TRUE;
    if ( Nobjects[AQUIFER]  == 0 ) IgnoreGwater   = TRUE;
    for ( i=0; i<Nobjects[GAGE]; i++ )     gage_validate(i);
    for ( i=0; i<Nobjects[AQUIFER]; i++ )  gwater_validateAquifer(i);
    for ( i=0; i<Nobjects[SUBCATCH]; i++ ) subcatch_validate(i);
    for ( i=0; i<Nobjects[SNOWMELT]; i++ ) snow_validateSnowmelt(i);

    // --- compute geometry tables for each shape curve
    j = 0;
    for ( i=0; i<Nobjects[CURVE]; i++ )
    {
        if ( Curve[i].curveType == SHAPE_CURVE )
        {
            Curve[i].refersTo = j;
            Shape[j].curve = i;
            if ( !shape_validate(&Shape[j], &Curve[i]) )
                report_writeErrorMsg(ERR_CURVE_SEQUENCE, Curve[i].ID);
            j++;
        }
    }

    // --- validate links before nodes, since the latter can
    //     result in adjustment of node depths
    for ( i=0; i<Nobjects[NODE]; i++) Node[i].oldDepth = Node[i].fullDepth;
    for ( i=0; i<Nobjects[LINK]; i++) link_validate(i);
    for ( i=0; i<Nobjects[NODE]; i++) node_validate(i);

    // --- adjust time steps if necessary
    if ( DryStep < WetStep )
    {
        report_writeWarningMsg(WARN06, "");
        DryStep = WetStep;
    }
    if ( RouteStep > (double)WetStep )
    {
        report_writeWarningMsg(WARN07, "");
        RouteStep = WetStep;
    }

    // --- adjust individual reporting flags to match global reporting flag
    if ( RptFlags.subcatchments == ALL )
        for (i=0; i<Nobjects[SUBCATCH]; i++) Subcatch[i].rptFlag = TRUE;
    if ( RptFlags.nodes == ALL )
        for (i=0; i<Nobjects[NODE]; i++) Node[i].rptFlag = TRUE;
    if ( RptFlags.links == ALL )
        for (i=0; i<Nobjects[LINK]; i++) Link[i].rptFlag = TRUE;

    // --- adjust DYNWAVE options
	if ( MinSurfArea == 0.0 ) MinSurfArea = DEFAULT_SURFAREA;
	else                      MinSurfArea /= UCF(LENGTH) * UCF(LENGTH);
    if ( HeadTol == 0.0 ) HeadTol = DEFAULT_HEADTOL;
	else                  HeadTol /= UCF(LENGTH);
	if ( MaxTrials == 0 ) MaxTrials = DEFAULT_MAXTRIALS;
}
Beispiel #30
0
int output_open(Project* project)
//
//  Input:   none
//  Output:  returns an error code
//  Purpose: writes basic project data to binary output file.
//
{
    int   j;
    int   m;
    INT4  k;
    REAL4 x;
    REAL8 z;

    // --- open binary output file
    output_openOutFile(project);
    if ( project->ErrorCode ) return project->ErrorCode;

    // --- ignore pollutants if no water quality analsis performed
    if ( project->IgnoreQuality ) project->NumPolluts = 0;
    else project->NumPolluts = project->Nobjects[POLLUT];

    // --- subcatchment results consist of Rainfall, Snowdepth, project->Evap, 
    //     Infil, Runoff, GW Flow, GW Elev, GW Sat, and Washoff
    project->NsubcatchResults = MAX_SUBCATCH_RESULTS - 1 + project->NumPolluts;

    // --- node results consist of Depth, Head, Volume, Lateral Inflow,
    //     Total Inflow, Overflow and Quality
    project->NnodeResults = MAX_NODE_RESULTS - 1 + project->NumPolluts;

    // --- link results consist of Depth, Flow, Velocity, Froude No.,
    //     Capacity and Quality
    project->NlinkResults = MAX_LINK_RESULTS - 1 + project->NumPolluts;

    // --- get number of objects reported on
    project->NumSubcatch = 0;
    project->NumNodes = 0;
    project->NumLinks = 0;
    for (j=0; j<project->Nobjects[SUBCATCH]; j++) if (project->Subcatch[j].rptFlag) project->NumSubcatch++;
    for (j=0; j<project->Nobjects[NODE]; j++) if (project->Node[j].rptFlag) project->NumNodes++;
    for (j=0; j<project->Nobjects[LINK]; j++) if (project->Link[j].rptFlag) project->NumLinks++;

    project->BytesPerPeriod = sizeof(REAL8)
        + project->NumSubcatch * project->NsubcatchResults * sizeof(REAL4)
        + project->NumNodes * project->NnodeResults * sizeof(REAL4)
        + project->NumLinks * project->NlinkResults * sizeof(REAL4)
        + MAX_SYS_RESULTS * sizeof(REAL4);
    project->Nperiods = 0;

    project->SubcatchResults = NULL;
    project->NodeResults = NULL;
    project->LinkResults = NULL;
    project->SubcatchResults = (REAL4 *) calloc(project->NsubcatchResults, sizeof(REAL4));
    project->NodeResults = (REAL4 *) calloc(project->NnodeResults, sizeof(REAL4));
    project->LinkResults = (REAL4 *) calloc(project->NlinkResults, sizeof(REAL4));
    if ( !project->SubcatchResults || !project->NodeResults || !project->LinkResults )
    {
        report_writeErrorMsg(project,ERR_MEMORY, "");
        return project->ErrorCode;
    }

    fseek(project->Fout.file, 0, SEEK_SET);
    k = MAGICNUMBER;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);   // Magic number
    k = VERSION;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);   // Version number
    k = project->FlowUnits;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);   // Flow units
    k = project->NumSubcatch;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);   // # subcatchments
    k = project->NumNodes;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);   // # nodes
    k = project->NumLinks;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);   // # links
    k = project->NumPolluts;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);   // # pollutants

    // --- save ID names of subcatchments, nodes, links, & pollutants 
    project->IDStartPos = ftell(project->Fout.file);
    for (j=0; j<project->Nobjects[SUBCATCH]; j++)
    {
        if ( project->Subcatch[j].rptFlag ) output_saveID(project->Subcatch[j].ID, project->Fout.file);
    }
    for (j=0; j<project->Nobjects[NODE];     j++)
    {
        if ( project->Node[j].rptFlag ) output_saveID(project->Node[j].ID, project->Fout.file);
    }
    for (j=0; j<project->Nobjects[LINK];     j++)
    {
        if ( project->Link[j].rptFlag ) output_saveID(project->Link[j].ID, project->Fout.file);
    }
    for (j=0; j<project->NumPolluts; j++) output_saveID(project->Pollut[j].ID, project->Fout.file);

    // --- save codes of pollutant concentration units
    for (j=0; j<project->NumPolluts; j++)
    {
        k = project->Pollut[j].units;
        fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    }

    project->InputStartPos = ftell(project->Fout.file);

    // --- save subcatchment area
    k = 1;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = INPUT_AREA;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    for (j=0; j<project->Nobjects[SUBCATCH]; j++)
    {
         if ( !project->Subcatch[j].rptFlag ) continue;
         project->SubcatchResults[0] = (REAL4)(project->Subcatch[j].area * UCF(project,LANDAREA));
         fwrite(&project->SubcatchResults[0], sizeof(REAL4), 1, project->Fout.file);
    }

    // --- save node type, invert, & max. depth
    k = 3;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = INPUT_TYPE_CODE;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = INPUT_INVERT;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = INPUT_MAX_DEPTH;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    for (j=0; j<project->Nobjects[NODE]; j++)
    {
        if ( !project->Node[j].rptFlag ) continue;
        k = project->Node[j].type;
        project->NodeResults[0] = (REAL4)(project->Node[j].invertElev * UCF(project,LENGTH));
        project->NodeResults[1] = (REAL4)(project->Node[j].fullDepth * UCF(project,LENGTH));
        fwrite(&k, sizeof(INT4), 1, project->Fout.file);
        fwrite(project->NodeResults, sizeof(REAL4), 2, project->Fout.file);
    }

    // --- save link type, offsets, max. depth, & length
    k = 5;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = INPUT_TYPE_CODE;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = INPUT_OFFSET;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = INPUT_OFFSET;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = INPUT_MAX_DEPTH;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = INPUT_LENGTH;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);

    for (j=0; j<project->Nobjects[LINK]; j++)
    {
        if ( !project->Link[j].rptFlag ) continue;
        k = project->Link[j].type;
        if ( k == PUMP )
        {
            for (m=0; m<4; m++) project->LinkResults[m] = 0.0f;
        }
        else
        {
            project->LinkResults[0] = (REAL4)(project->Link[j].offset1 * UCF(project,LENGTH));
            project->LinkResults[1] = (REAL4)(project->Link[j].offset2 * UCF(project,LENGTH));
            if ( project->Link[j].direction < 0 )
            {
                x = project->LinkResults[0];
                project->LinkResults[0] = project->LinkResults[1];
                project->LinkResults[1] = x;
            }
            if ( k == OUTLET ) project->LinkResults[2] = 0.0f;
            else project->LinkResults[2] = (REAL4)(project->Link[j].xsect.yFull * UCF(project,LENGTH));
            if ( k == CONDUIT )
            {
                m = project->Link[j].subIndex;
                project->LinkResults[3] = (REAL4)(project->Conduit[m].length * UCF(project,LENGTH));
            }
            else project->LinkResults[3] = 0.0f;
        }
        fwrite(&k, sizeof(INT4), 1, project->Fout.file);
        fwrite(project->LinkResults, sizeof(REAL4), 4, project->Fout.file);
    }

    // --- save number & codes of subcatchment result variables
    k = project->NsubcatchResults;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = SUBCATCH_RAINFALL;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = SUBCATCH_SNOWDEPTH;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = SUBCATCH_EVAP;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = SUBCATCH_INFIL;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = SUBCATCH_RUNOFF;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = SUBCATCH_GW_FLOW;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = SUBCATCH_GW_ELEV;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = SUBCATCH_SOIL_MOIST;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);

    for (j=0; j<project->NumPolluts; j++) 
    {
        k = SUBCATCH_WASHOFF + j;
        fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    }

    // --- save number & codes of node result variables
    k = project->NnodeResults;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = NODE_DEPTH;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = NODE_HEAD;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = NODE_VOLUME;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = NODE_LATFLOW;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = NODE_INFLOW;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = NODE_OVERFLOW;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    for (j=0; j<project->NumPolluts; j++)
    {
        k = NODE_QUAL + j;
        fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    }

    // --- save number & codes of link result variables
    k = project->NlinkResults;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = LINK_FLOW;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = LINK_DEPTH;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = LINK_VELOCITY;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = LINK_VOLUME;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    k = LINK_CAPACITY;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    for (j=0; j<project->NumPolluts; j++)
    {
        k = LINK_QUAL + j;
        fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    }

    // --- save number & codes of system result variables
    k = MAX_SYS_RESULTS;
    fwrite(&k, sizeof(INT4), 1, project->Fout.file);
    for (k=0; k<MAX_SYS_RESULTS; k++) fwrite(&k, sizeof(INT4), 1, project->Fout.file);

    // --- save starting report date & report step
    //     (if reporting start date > simulation start date then
    //      make saved starting report date one reporting period
    //      prior to the date of the first reported result)
    z = (double)project->ReportStep/86400.0;
    if ( project->StartDateTime + z > project->ReportStart ) z = project->StartDateTime;
    else
    {
        z = floor((project->ReportStart - project->StartDateTime)/z) - 1.0;
        z = project->StartDateTime + z*(double)project->ReportStep/86400.0;
    }
    fwrite(&z, sizeof(REAL8), 1, project->Fout.file);
    k = project->ReportStep;
    if ( fwrite(&k, sizeof(INT4), 1, project->Fout.file) < 1)
    {
        report_writeErrorMsg(project,ERR_OUT_WRITE, "");
        return project->ErrorCode;
    }
    project->OutputStartPos = ftell(project->Fout.file);
    if ( project->Fout.mode == SCRATCH_FILE ) output_checkFileSize(project);
    return project->ErrorCode;
}