/* * Copyright (C) 2012 Addition, Lda. (addition at addition dot pt) * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package org.addition.epanet.msx; import org.addition.epanet.msx.EnumTypes.*; import org.addition.epanet.msx.Structures.*; import java.io.*; import java.util.Hashtable; import java.util.Map; public class Project { public void loadDependencies(EpanetMSX epa) { MSX = epa.getNetwork(); reader = epa.getReader(); } Network MSX; Map<String, Integer> [] Htable; InpReader reader; // Opens an EPANET-MSX project. int MSXproj_open(File msxFile) throws IOException { int errcode = 0; //MSX.QualityOpened = false; BufferedReader buffReader = new BufferedReader(new FileReader(msxFile)); // initialize data to default values setDefaults(); // Open the MSX input file //MSX.MsxFile.setFilename(fname); //if(!MSX.MsxFile.openAsTextReader()) // return ErrorCodeType.ERR_OPEN_MSX_FILE.id; // create hash tables to look up object ID names errcode = Utilities.CALL(errcode, createHashTables()); // allocate memory for the required number of objects errcode = Utilities.CALL(errcode, reader.countMsxObjects(buffReader)); errcode = Utilities.CALL(errcode, reader.countNetObjects()); errcode = Utilities.CALL(errcode, createObjects()); buffReader.close(); buffReader = new BufferedReader(new FileReader(msxFile)); // Read in the EPANET and MSX object data errcode = Utilities.CALL(errcode, reader.readNetData()); errcode = Utilities.CALL(errcode, reader.readMsxData(buffReader)); //if (MSX.RptFile.getFilename().equals("")) // errcode = Utilities.CALL(errcode, openRptFile()); // Convert user's units to internal units errcode = Utilities.CALL(errcode, convertUnits()); // Close input file //MSX.MsxFile.close(); return errcode; } //============================================================================= // closes the current EPANET-MSX project. void MSXproj_close() { //if ( MSX.RptFile.file ) fclose(MSX.RptFile.file); //(LR-11/20/07, to fix bug 08) //MSX.RptFile.close(); //if ( MSX.HydFile.file ) fclose(MSX.HydFile.file); //if ( MSX.HydFile.getMode() == FileModeType.SCRATCH_FILE ) //remove(MSX.HydFile.name); // MSX.HydFile.remove(); //if ( MSX.TmpOutFile.getFileIO() != null && MSX.TmpOutFile.getFileIO() != MSX.OutFile.getFileIO() ) //{ // //fclose(MSX.TmpOutFile.file); // MSX.TmpOutFile.close(); // MSX.TmpOutFile.remove(); // //remove(MSX.TmpOutFile.name); //} //if ( MSX.OutFile.file ) fclose(MSX.OutFile.file); //MSX.OutFile.close(); // //if ( MSX.OutFile.getMode() == FileModeType.SCRATCH_FILE )// remove(MSX.OutFile.name); // MSX.OutFile.close(); //MSX.RptFile.file = null; //(LR-11/20/07, to fix bug 08) //MSX.HydFile.file = null; //MSX.OutFile.file = null; //MSX.TmpOutFile.file = null; deleteObjects(); deleteHashTables(); //MSX.ProjectOpened = false; } //============================================================================= // adds an object ID to the project's hash tables. int MSXproj_addObject(ObjectTypes type, String id, int n) { int result = 0; int len; String newID = id; // --- do nothing if object already exists in a hash table if ( MSXproj_findObject(type, id) > 0 ) return 0; // --- insert object's ID into the hash table for that type of object //result = HTinsert(Htable[type], newID, n); if(Htable[type.id].put(newID,n)==null) result = 1; if ( result == 0 ) result = -1; return result; } //============================================================================= // uses hash table to find index of an object with a given ID. int MSXproj_findObject(ObjectTypes type, String id) { Integer val = Htable[type.id].get(id); return val==null?-1:val; } //============================================================================= // uses hash table to find address of given string entry. String MSXproj_findID(ObjectTypes type, String id) { Integer val = Htable[type.id].get(id); return val==null?"":id; } //============================================================================= // gets the text of an error message. String MSXproj_getErrmsg(int errcode) { if ( errcode <= ErrorCodeType.ERR_FIRST.id || errcode >= ErrorCodeType.ERR_MAX.id ) return Constants.Errmsg[0]; else return Constants.Errmsg[errcode - ErrorCodeType.ERR_FIRST.id]; } // assigns default values to project variables. void setDefaults() { MSX.Title = ""; MSX.Rptflag = false; for (int i=0; i<ObjectTypes.MAX_OBJECTS.id; i++) MSX.Nobjects[i] = 0; MSX.Unitsflag = UnitSystemType.US; MSX.Flowflag = FlowUnitsType.GPM; MSX.Statflag = TstatType.SERIES; MSX.DefRtol = 0.001; MSX.DefAtol = 0.01; MSX.Solver = SolverType.EUL; MSX.Coupling = CouplingType.NO_COUPLING; MSX.AreaUnits = AreaUnitsType.FT2; MSX.RateUnits = RateUnitsType.DAYS; MSX.Qstep = 300; MSX.Rstep = 3600; MSX.Rstart = 0; MSX.Dur = 0; MSX.Node = null; MSX.Link = null; MSX.Tank = null; MSX.D = null; MSX.Q = null; MSX.H = null; MSX.Species = null; MSX.Term = null; MSX.Const = null; MSX.Pattern = null; } // Converts user's units to internal EPANET units. int convertUnits() { // Flow conversion factors (to cfs) double fcf[] = {1.0, Constants.GPMperCFS, Constants.MGDperCFS, Constants.IMGDperCFS, Constants.AFDperCFS, Constants.LPSperCFS, Constants.LPMperCFS, Constants.MLDperCFS, Constants.CMHperCFS, Constants.CMDperCFS}; // Rate time units conversion factors (to sec) double rcf[] = {1.0, 60.0, 3600.0, 86400.0}; int i, m, errcode = 0; // Conversions for length & tank volume if ( MSX.Unitsflag == UnitSystemType.US ) { MSX.Ucf[UnitsType.LENGTH_UNITS.id] = 1.0; MSX.Ucf[UnitsType.DIAM_UNITS.id] = 12.0; MSX.Ucf[UnitsType.VOL_UNITS.id] = 1.0; } else { MSX.Ucf[UnitsType.LENGTH_UNITS.id] = Constants.MperFT; MSX.Ucf[UnitsType.DIAM_UNITS.id] = 1000.0*Constants.MperFT; MSX.Ucf[UnitsType.VOL_UNITS.id] = Constants.M3perFT3; } // Conversion for surface area MSX.Ucf[UnitsType.AREA_UNITS.id] = 1.0; switch (MSX.AreaUnits) { case M2: MSX.Ucf[UnitsType.AREA_UNITS.id] = Constants.M2perFT2; break; case CM2: MSX.Ucf[UnitsType.AREA_UNITS.id] = Constants.CM2perFT2; break; } // Conversion for flow rate MSX.Ucf[UnitsType.FLOW_UNITS.id] = fcf[MSX.Flowflag.id]; MSX.Ucf[UnitsType.CONC_UNITS.id] = Constants.LperFT3; // Conversion for reaction rate time MSX.Ucf[UnitsType.RATE_UNITS.id] = rcf[MSX.RateUnits.id]; // Convert pipe diameter & length for (i=1; i<=MSX.Nobjects[ObjectTypes.LINK.id]; i++){ MSX.Link[i].setDiam( MSX.Link[i].getDiam() / MSX.Ucf[UnitsType.DIAM_UNITS.id]); MSX.Link[i].setLen(MSX.Link[i].getLen() / MSX.Ucf[UnitsType.LENGTH_UNITS.id]); } // Convert initial tank volumes for (i=1; i<=MSX.Nobjects[ObjectTypes.TANK.id]; i++){ MSX.Tank[i].setV0(MSX.Tank[i].getV0() / MSX.Ucf[UnitsType.VOL_UNITS.id]); MSX.Tank[i].setvMix(MSX.Tank[i].getvMix() / MSX.Ucf[UnitsType.VOL_UNITS.id]); } // Assign default tolerances to species for (m=1; m<=MSX.Nobjects[ObjectTypes.SPECIES.id]; m++){ if ( MSX.Species[m].getrTol() == 0.0 ) MSX.Species[m].setrTol(MSX.DefRtol); if ( MSX.Species[m].getaTol() == 0.0 ) MSX.Species[m].setaTol(MSX.DefAtol); } return errcode; } // creates multi-species data objects. int createObjects() { // Create nodes, links, & tanks MSX.Node = new Node[MSX.Nobjects[ObjectTypes.NODE.id]+1]; MSX.Link = new Link[MSX.Nobjects[ObjectTypes.LINK.id]+1]; MSX.Tank = new Tank[MSX.Nobjects[ObjectTypes.TANK.id]+1]; // Create species, terms, parameters, constants & time patterns MSX.Species = new Species[MSX.Nobjects[ObjectTypes.SPECIES.id]+1]; MSX.Term = new Term[MSX.Nobjects[ObjectTypes.TERM.id]+1]; MSX.Param = new Param[MSX.Nobjects[ObjectTypes.PARAMETER.id]+1]; MSX.Const = new Const[MSX.Nobjects[ObjectTypes.CONSTANT.id]+1]; MSX.Pattern = new Pattern[MSX.Nobjects[ObjectTypes.PATTERN.id]+1]; for(int i = 0;i<=MSX.Nobjects[ObjectTypes.CONSTANT.id];i++) MSX.Const[i] = new Const(); // Create arrays for demands, heads, & flows MSX.D = new float[MSX.Nobjects[ObjectTypes.NODE.id]+1]; MSX.H = new float[MSX.Nobjects[ObjectTypes.NODE.id]+1]; MSX.Q = new float[MSX.Nobjects[ObjectTypes.LINK.id]+1]; // create arrays for current & initial concen. of each species for each node MSX.C0 = new double[MSX.Nobjects[ObjectTypes.SPECIES.id]+1]; for (int i=1; i<=MSX.Nobjects[ObjectTypes.NODE.id]; i++) { MSX.Node[i] = new Node(MSX.Nobjects[ObjectTypes.SPECIES.id]+1); //MSX.Node[i].c = new double[MSX.Nobjects[SPECIES]+1, sizeof(double)); //MSX.Node[i].c0 = new double[MSX.Nobjects[SPECIES]+1, sizeof(double)); //MSX.Node[i].rpt = 0; } // Create arrays for init. concen. & kinetic parameter values for each link for (int i=1; i<=MSX.Nobjects[ObjectTypes.LINK.id]; i++) { MSX.Link[i] = new Link(MSX.Nobjects[ObjectTypes.SPECIES.id]+1,MSX.Nobjects[ObjectTypes.PARAMETER.id]+1); //MSX.Link[i].c0 = (double *) //calloc(MSX.Nobjects[SPECIES]+1, sizeof(double)); //MSX.Link[i].param = (double *) //calloc(MSX.Nobjects[PARAMETER]+1, sizeof(double)); //MSX.Link[i].rpt = 0; } // Create arrays for kinetic parameter values & current concen. for each tank for (int i=1; i<=MSX.Nobjects[ObjectTypes.TANK.id]; i++) { MSX.Tank[i] = new Tank(MSX.Nobjects[ObjectTypes.PARAMETER.id]+1,MSX.Nobjects[ObjectTypes.SPECIES.id]+1); //MSX.Tank[i].param = (double *) //calloc(MSX.Nobjects[PARAMETER]+1, sizeof(double)); //MSX.Tank[i].c = (double *) //calloc(MSX.Nobjects[SPECIES]+1, sizeof(double)); } // Initialize contents of each time pattern object for (int i=1; i<=MSX.Nobjects[ObjectTypes.PATTERN.id]; i++) { MSX.Pattern[i] = new Pattern(); //MSX.Pattern[i].length = 0; //MSX.Pattern[i].first = null; //MSX.Pattern[i].current = null; } // Initialize reaction rate & equil. formulas for each species for (int i=1; i<=MSX.Nobjects[ObjectTypes.SPECIES.id]; i++) { MSX.Species[i] = new Species(); //MSX.Species[i].pipeExpr = null; //MSX.Species[i].tankExpr = null; //MSX.Species[i].pipeExprType = NO_EXPR; //MSX.Species[i].tankExprType = NO_EXPR; //MSX.Species[i].precision = 2; //MSX.Species[i].rpt = 0; } // Initialize math expressions for each intermediate term for (int i=1; i<=MSX.Nobjects[ObjectTypes.TERM.id]; i++){ MSX.Term[i] = new Term(); //MSX.Term[i].expr = null; } return 0; } //============================================================================= // Deletes multi-species data objects. void deleteObjects() { //int i; ////SnumList *listItem; // // --- f//ree memory used by nodes, links, and tanks // //if (MSX.Node) for (i=1; i<=MSX.Nobjects[NODE]; i++) //{ // FREE(MSX.Node[i].c); // FREE(MSX.Node[i].c0); //} //if (MSX.Link) for (i=1; i<=MSX.Nobjects[LINK]; i++) //{ // FREE(MSX.Link[i].c0); // FREE(MSX.Link[i].param); //} //if (MSX.Tank) for (i=1; i<=MSX.Nobjects[TANK]; i++) //{ // FREE(MSX.Tank[i].param); // FREE(MSX.Tank[i].c); //} // // --- f//ree memory used by time patterns // //if (MSX.Pattern) for (i=1; i<=MSX.Nobjects[PATTERN]; i++) //{ // listItem = MSX.Pattern[i].first; // while (listItem) // { // MSX.Pattern[i].first = listItem->next; // free(listItem); // listItem = MSX.Pattern[i].first; // } //} //FREE(MSX.Pattern); // // --- f//ree memory used for hydraulics results // //FREE(MSX.D); //FREE(MSX.H); //FREE(MSX.Q); //FREE(MSX.C0); // // --- d//elete all nodes, links, and tanks // //FREE(MSX.Node); //FREE(MSX.Link); //FREE(MSX.Tank); // // --- f//ree memory used by reaction rate & equilibrium expressions // //if (MSX.Species) for (i=1; i<=MSX.Nobjects[SPECIES]; i++) //{ // // --- free the species tank expression only if it doesn't // // already point to the species pipe expression // if ( MSX.Species[i].tankExpr != MSX.Species[i].pipeExpr ) // { // mathexpr_delete(MSX.Species[i].tankExpr); // } // mathexpr_delete(MSX.Species[i].pipeExpr); //} // // --- d//elete all species, parameters, and constants // //FREE(MSX.Species); //FREE(MSX.Param); //FREE(MSX.Const); // // --- f//ree memory used by intermediate terms // //if (MSX.Term) for (i=1; i<=MSX.Nobjects[TERM]; i++) // mathexpr_delete(MSX.Term[i].expr); //FREE(MSX.Term); } // allocates memory for object ID hash tables. int createHashTables() { int j; // create a hash table for each type of object Htable = new Map[ObjectTypes.MAX_OBJECTS.id]; for (j = 0; j < ObjectTypes.MAX_OBJECTS.id ; j++){ Htable[j] = new Hashtable<String, Integer>(); } return 0; } //============================================================================= // frees memory allocated for object ID hash tables. void deleteHashTables() { //int j; // // --- f//ree the hash tables // //for (j = 0; j < MAX_OBJECTS; j++) //{ // if ( Htable[j] != null ) HTfree(Htable[j]); //} // // --- f//ree the object ID memory pool // //if ( HashPool ) //{ // AllocSetPool(HashPool); // AllocFreePool(); //} } // New function added (LR-11/20/07, to fix bug 08) //int openRptFile() //{ // if( MSX.RptFile.getFilename().equals("")) // return 0; // // //if ( MSX.RptFile.file ) fclose(MSX.RptFile.file); // MSX.RptFile.close(); // //MSX.RptFile.file = fopen(MSX.RptFile.name, "wt"); // if(!MSX.RptFile.openAsTextWriter()) // return ErrorCodeType.ERR_OPEN_RPT_FILE.id; // //if ( MSX.RptFile.file == null ) return ErrorCodeType.ERR_OPEN_RPT_FILE.id; // return 0; //} }