/*5/5/14, JTC, added persistent species data for players; system parameter masterSpeciesList, replaces mSpecies. Get previous timestep biomass for all species from web service*/ public HashMap<Integer, SpeciesZoneType> getPrediction( String networkOrManipulationId, int startTimestep, int runTimestep, Map<Integer, Integer> addSpeciesNodeList, ZoneNodes zoneNodes) throws SimulationException { long milliseconds = System.currentTimeMillis(); Log.printf("\nPrediction at %d\n", startTimestep); // Get previous timestep biomass for all species from web service // JTC, use new HashMap containing all current settings from zoneNodes, masterSpeciesList // HJR changing to make a deep copy here , I am getting a null while iterating HashMap<Integer, SpeciesZoneType> masterSpeciesList = new HashMap<Integer, SpeciesZoneType>(zoneNodes.getNodes()); HashMap<Integer, SpeciesZoneType> mNewSpecies = new HashMap<Integer, SpeciesZoneType>(); // JTC, mUpdateBiomass renamed from mUpdateSpecies HashMap<Integer, SpeciesZoneType> mUpdateBiomass = new HashMap<Integer, SpeciesZoneType>(); // JTC, added new update type, mUpdateParams HashMap<Integer, SpeciesZoneType> mUpdateParams = new HashMap<Integer, SpeciesZoneType>(); SpeciesZoneType szt; String nodeConfig = null; SimJob job = new SimJob(); // {70=2494, 5=2000, 42=240, 14=1752, 31=1415} for (int node_id : addSpeciesNodeList.keySet()) { int addedBiomass = addSpeciesNodeList.get(node_id); if (!masterSpeciesList.containsKey(node_id)) { szt = createSpeciesZoneType(node_id, addedBiomass); mNewSpecies.put(node_id, szt); // jtc - 04/19/15 masterSpeciesList.put(node_id, szt); } else { szt = masterSpeciesList.get(node_id); szt.setCurrentBiomass(Math.max(0, szt.getCurrentBiomass() + addedBiomass)); szt.setBiomassUpdated(true); } } // //JTC, separated this to capture biomass updates made to ZoneNodes that // //are not received through addSpeciesNodeList (biomass and param updates) // for (SpeciesZoneType species : masterSpeciesList.values()) { // //param update also updates biomass, so insert into that list // //preferentially; o/w use biomass update list // if (species.paramUpdated) { // mUpdateParams.put(species.getNodeIndex(), species); // species.setParamUpdated(false); // } else if (species.biomassUpdated) { // mUpdateBiomass.put(species.getNodeIndex(), species); // species.setBiomassUpdated(false); // } // } // Insert new species using web services if (!mNewSpecies.isEmpty()) { zoneNodes.addNodes(mNewSpecies); } try { nodeConfig = addMultipleSpeciesType( mNewSpecies, masterSpeciesList, startTimestep, false, networkOrManipulationId); } catch (Exception ex) { Log.println_e(ex.getMessage()); } // // Update biomass changes to existing species using web services // if (!mUpdateBiomass.isEmpty()) { // List<NodeBiomass> lNodeBiomass = new ArrayList<NodeBiomass>(); // for (SpeciesZoneType s : mUpdateBiomass.values()) { // Log.printf("Updating Biomass: [%d] %s %f\n", s.getNodeIndex(), s.getName(), // s.getCurrentBiomass() / Constants.BIOMASS_SCALE); // lNodeBiomass.add(new NodeBiomass( // s.getCurrentBiomass() / Constants.BIOMASS_SCALE, s.getNodeIndex())); // } // try { //// updateBiomass(networkOrManipulationId, lNodeBiomass, startTimestep); // } catch (Exception ex) { // Log.println_e(ex.getMessage()); // } // } // // JTC Update changes to existing species parameters using web services (also // // resubmits biomass, but couldn't find a way to do params w/o biomass // if (!mUpdateParams.isEmpty()) { // try { //// increaseMultipleSpeciesType( //// mUpdateBiomass, //// masterSpeciesList, //// startTimestep, //// false, //// networkOrManipulationId //// ); // } catch (Exception ex) { // Log.println_e(ex.getMessage()); // } // } // run(startTimestep, runTimestep, networkOrManipulationId); // get new predicted biomass try { // JTC - changed variable from "mSpecies = " to "mUpdateBiomass = " // mUpdateBiomass = getBiomass(networkOrManipulationId, 0, startTimestep + runTimestep); if (!masterSpeciesList.isEmpty() || !mNewSpecies.isEmpty()) { mUpdateBiomass = submitManipRequest("ATN", nodeConfig, startTimestep + runTimestep, false, null); } } catch (Exception ex) { Log.println_e(ex.getMessage()); return null; } // getBiomassInfo(networkOrManipulationId); // JTC - add loop to update persistent player species biomass information SpeciesZoneType updS; for (SpeciesZoneType priorS : masterSpeciesList.values()) { System.out.println("priorS.nodeIndex " + priorS.nodeIndex); updS = mUpdateBiomass.get(priorS.nodeIndex); if (updS != null && updS.currentBiomass != 0) { masterSpeciesList .get(priorS.nodeIndex) .setCurrentBiomass(Math.ceil(updS.getCurrentBiomass())); } // else { // zoneNodes.removeNode(priorS.nodeIndex); // } } Log.printf( "Total Time (Get Prediction): %.2f seconds", Math.round((System.currentTimeMillis() - milliseconds) / 10.0) / 100.0); return (HashMap) zoneNodes.getNodes(); }
// loop through current job/results, assembling dataset private HashMap<Integer, SpeciesZoneType> genSpeciesDataset( SimJob job, EcosystemTimesteps ecosysTimesteps, Map<Integer, NodeRelationships> ecosysRelationships) { // calc information relevant to entire ecosystem int speciesCnt = ecosysTimesteps.getNodeList().size(); // Number of species int timesteps = ecosysTimesteps.getTimesteps(); // Maximum number of timesteps to run simulation int timestepsToSave = 0; // Number of timesteps of data to save to output file int[] matchingTimesteps = null; // Array of matching timesteps returned by findMatchingTimesteps() // read in link parameters; this was explicitly configured to allow // manipulation of link parameter values, but no manipulation is // performed in this version LinkParams lPs = new LinkParams(propertiesConfig); // loop through node values and assemble summary data int[] speciesID = new int[speciesCnt]; SimJobSZT[] sztArray = new SimJobSZT[speciesCnt]; int spNum = 0; for (NodeTimesteps nodeTimesteps : ecosysTimesteps.getTimestepMapValues()) { SimJobSZT sjSzt = job.getSpeciesZoneByNodeId(nodeTimesteps.getNodeId()); sztArray[spNum] = sjSzt; speciesID[spNum] = sjSzt.getNodeIndex(); spNum++; } // define objects to track species' contributions double[][][] contribs = new double[timesteps][speciesCnt][speciesCnt]; double[][] calcBiomass = new double[timesteps][speciesCnt]; double[][] contribsT; // current timestep // note: WebServices ATN Model uses B0 with default = 0.5. This presumes // that biomasses are small, i.e. < 1.0. Division by biomassScale // here is consistent with usage in WoB_Server.SimulationEngine to // normalize biomasses. // need to store bm as it varies over time through integration; // start with initial bm for each species double[] currBiomass = new double[speciesCnt]; for (int i = 0; i < speciesCnt; i++) { NodeTimesteps nodeTimeSteps = ecosysTimesteps.getTimestepMap().get(speciesID[i]); // manually set biomass vals for excluded initial timesteps; this // includes the first value to be used as input currBiomass[i] = nodeTimeSteps.getBiomass(initTimeIdx) / biomassScale; calcBiomass[0][i] = currBiomass[i]; } if (Constants.useCommonsMathIntegrator) { // Use Apache Commons Math GraggBulirschStoerIntegrator FirstOrderIntegrator integrator = new GraggBulirschStoerIntegrator( 1.0e-8, // minimal step 100.0, // maximal step ATNEquations.EXTINCT, // allowed absolute error 1.0e-10); // allowed relative error // Set up the ATN equations based on the current food web and parameters ATNEquations ode = new ATNEquations(sztArray, ecosysRelationships, lPs); ATNEventHandler eventHandler = new ATNEventHandler(ode); // FIXME: Choose best parameter values integrator.addEventHandler( new EventFilter(eventHandler, FilterType.TRIGGER_ONLY_DECREASING_EVENTS), 1, // maximal time interval between switching function checks (this interval prevents // missing sign changes in case the integration steps becomes very large) 0.0001, // convergence threshold in the event time search 1000, // upper limit of the iteration count in the event time search new BisectionSolver()); // Set up the StepHandler, which is triggered at each time step by the integrator, // and copies the current biomass of each species into calcBiomass[timestep]. // See the "Continuous Output" section of // https://commons.apache.org/proper/commons-math/userguide/ode.html FixedStepHandler fixedStepHandler = new FixedStepHandler() { public void init(double t0, double[] y0, double t) {} private int timestep = 0; public void handleStep(double t, double[] y, double[] yDot, boolean isLast) { // Ensure we don't go past the last time step due to rounding error if (timestep < calcBiomass.length) { System.arraycopy(y, 0, calcBiomass[timestep], 0, speciesCnt); } timestep++; } }; StepHandler stepHandler = new StepNormalizer(timeIntvl, fixedStepHandler); integrator.addStepHandler(stepHandler); // Run the integrator to compute the biomass time series integrator.integrate(ode, 0.0, currBiomass, timeIntvl * timesteps, currBiomass); if (eventHandler.integrationWasStopped()) { timestepsToSave = (int) (eventHandler.getTimeStopped() / timeIntvl); } else { // Check for an oscillating steady state, // and only save the data through the first period of the oscillation matchingTimesteps = findMatchingTimesteps(calcBiomass, timesteps - 1); System.err.println("\nmatchingTimesteps = " + Arrays.toString(matchingTimesteps)); // Save timesteps up through the second matching timestep, // or all timesteps if there was no second matching timestep. if (matchingTimesteps[1] != -1) { timestepsToSave = matchingTimesteps[1] + 1; } else { timestepsToSave = timesteps; } } } else { // Use BulirschStoerIntegration // create integration object boolean isTest = false; BulirschStoerIntegration bsi = new BulirschStoerIntegration( timeIntvl, speciesID, sztArray, ecosysRelationships, lPs, maxBSIErr, equationSet); // calculate delta-biomass and biomass "contributions" from each related // species for (int t = initTimeIdx + 1; t < timesteps; t++) { boolean success = bsi.performIntegration(time(initTime, t), currBiomass); if (!success) { System.out.printf("Integration failed to converge, t = %d\n", t); System.out.print(bsi.extrapArrayToString(biomassScale)); break; } currBiomass = bsi.getYNew(); System.arraycopy(currBiomass, 0, calcBiomass[t], 0, speciesCnt); contribsT = bsi.getContribs(); for (int i = 0; i < speciesCnt; i++) { System.arraycopy(contribsT[i], 0, contribs[t - 1][i], 0, speciesCnt); } } // timestep loop } if (useHDF5) { saveHDF5OutputFile( calcBiomass, speciesID, matchingTimesteps, job.getNode_Config(), timestepsToSave); return null; } double[][] webServicesData = new double[speciesCnt][timesteps]; if (Constants.useSimEngine) { // We need the webServicesData only for marginOfErrorCalculation // extract timestep data from CSV Functions.extractCSVDataRelns(job.getCsv(), ecosysTimesteps, ecosysRelationships); spNum = 0; for (NodeTimesteps nodeTimesteps : ecosysTimesteps.getTimestepMapValues()) { // copy nodetimestep data to local array for easier access System.arraycopy(nodeTimesteps.getBiomassArray(), 0, webServicesData[spNum], 0, timesteps); spNum++; } } // output data // A. print header psATN.printf("timesteps"); for (int i = 0; i < timesteps; i++) { psATN.printf(",%d", i); } psATN.println(); /* Convert to CSV String */ String biomassCSV = ""; biomassCSV = "Manipulation_id: " + job.getATNManipulationId() + "\n\n"; int maxTimestep = job.getTimesteps(); // Create Timestep Labels for (int j = 1; j <= maxTimestep; j++) { biomassCSV += "," + j; } HashMap<Integer, SpeciesZoneType> mSpecies = new HashMap<Integer, SpeciesZoneType>(); // loop through each species for (int i = 0; i < speciesCnt; i++) { if (Constants.useSimEngine) { psATN.printf("i.%d.sim", speciesID[i]); // B. print WebServices simulation data for species for (int t = 0; t < timesteps; t++) { psATN.printf(",%9.0f", webServicesData[i][t]); } psATN.println(); } // B. print combined biomass contributions (i.e. locally calculated biomass) // for current species. psATN.printf("i.%d.calc", speciesID[i]); for (int t = 0; t < timesteps; t++) { psATN.printf(",%9.0f", calcBiomass[t][i] * biomassScale); } psATN.println(); // //C. print individual biomass contributions from other species // for (int j = 0; j < speciesCnt; j++) { // psATN.printf("i.%d.j.%d.", speciesID[i], speciesID[j]); // for (int t = 0; t < timesteps; t++) { // psATN.printf(",%9.0f", contribs[t][i][j] * biomassScale); // } // psATN.println(); // } float extinction = 1.E-15f; SimJobSZT sjSzt = job.getSpeciesZoneByNodeId(speciesID[i]); // add nodes to list in the order that they are received from infos String name = sjSzt.getName().replaceAll(",", " ") + " [" + sjSzt.getNodeIndex() + "]"; String tempStr = name; for (int t = 0; t < maxTimestep; t++) { tempStr += ","; double biomass = calcBiomass[t][i] * biomassScale; if (biomass > 0) { tempStr += biomass > extinction ? Math.ceil(biomass) : 0; } if (t == maxTimestep - 1) { SpeciesZoneType szt = null; if (!mSpecies.containsKey(sjSzt.getNodeIndex())) { szt = new SpeciesZoneType(sjSzt.getName(), sjSzt.getNodeIndex(), 0, 0, biomass, null); mSpecies.put(sjSzt.getNodeIndex(), szt); } else { // update existing species current biomass szt = mSpecies.get(sjSzt.getNodeIndex()); szt.setCurrentBiomass(biomass); } } } biomassCSV += "\n" + tempStr; } // Append node config to the ATN CSV psATN.println(); psATN.println("\"node-config: " + job.getNode_Config() + "\""); biomassCSV += "\n\n"; biomassCSV += job.getConsumeMap().toString() + "\n\n"; biomassCSV += job.getPathTable().toString(); job.setBiomassCsv(biomassCSV); // System.out.println(biomassCSV); return mSpecies; }