diff --git a/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5DataSet.java b/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5DataSet.java new file mode 100644 index 0000000000..10f62df649 --- /dev/null +++ b/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5DataSet.java @@ -0,0 +1,9 @@ +package org.vcell.cli.run.hdf5; + +public class Hdf5DataSet { + + + public Hdf5DataSet (){ + + } +} diff --git a/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5DataSourceNonspatial.java b/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5DataSourceNonspatial.java index 6df7c0c785..ab00b2db08 100644 --- a/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5DataSourceNonspatial.java +++ b/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5DataSourceNonspatial.java @@ -1,14 +1,15 @@ package org.vcell.cli.run.hdf5; -import org.jlibsedml.Variable; - -import java.util.ArrayList; -import java.util.LinkedHashMap; +import java.util.Iterator; +import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.LinkedHashMap; + +import org.jlibsedml.Variable; /** - * Struct-class to hold list of nonspacial variable data + * Class */ public class Hdf5DataSourceNonspatial extends Hdf5DataSource { public Hdf5DataSourceNonspatial() {} @@ -16,7 +17,7 @@ public Hdf5DataSourceNonspatial() {} /** * List of all data contained within a job relevant to HDF5 formatted files */ - public List jobData = new ArrayList<>(); + public List jobData = new LinkedList<>(); /** * Struct-Subclass for holding job data @@ -28,6 +29,4 @@ public static class Hdf5JobData { */ public Map varData = new LinkedHashMap<>(); } - - } diff --git a/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5WrapperFactory.java b/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5WrapperFactory.java index 0c3dfc8144..773024bdd1 100644 --- a/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5WrapperFactory.java +++ b/vcell-cli/src/main/java/org/vcell/cli/run/hdf5/Hdf5WrapperFactory.java @@ -1,7 +1,11 @@ package org.vcell.cli.run.hdf5; import cbit.vcell.solver.Simulation; +import cbit.vcell.parser.DivideByZeroException; +import cbit.vcell.parser.Expression; import cbit.vcell.parser.ExpressionException; +import cbit.vcell.parser.SimpleSymbolTable; +import cbit.vcell.parser.SymbolTable; import cbit.vcell.solver.ode.ODESolverResultSet; import ncsa.hdf.hdf5lib.exceptions.HDF5Exception; @@ -27,6 +31,7 @@ import java.io.*; import java.nio.file.Paths; import java.util.*; +import java.util.stream.Stream; /** @@ -65,6 +70,7 @@ public Hdf5DataWrapper generateHdf5File(Map nonSpat Hdf5DataWrapper hdf5FileWrapper = new Hdf5DataWrapper(); Exception nonSpatialException = null, spatialException = null; + // Nonspacial Collection try { wrappers.addAll(this.collectNonspatialDatasets(this.sedml, nonSpatialResults, this.taskToSimulationMap, this.sedmlLocation)); } catch (Exception e){ @@ -72,6 +78,7 @@ public Hdf5DataWrapper generateHdf5File(Map nonSpat nonSpatialException = e; } + // Spacial Collection try { wrappers.addAll(this.collectSpatialDatasets(this.sedml, spatialResults, this.taskToSimulationMap, this.sedmlLocation)); } catch (Exception e){ @@ -79,6 +86,7 @@ public Hdf5DataWrapper generateHdf5File(Map nonSpat spatialException = e; } + // Error Checking if (nonSpatialException != null && nonSpatialException != null){ throw new RuntimeException("Encountered complete dataset collection failure;\nNonSpatial Reported:\n" + nonSpatialException.getMessage() + "\nSpatial Reported:\n" + spatialException.getMessage()); @@ -100,9 +108,9 @@ private List collectNonspatialDatasets(SedML sedml, Map varIDs = new ArrayList<>(); - Map values = new HashMap<>(); - int maxLengthOfAllData = 0; // We have to pad up to this value + Map> idToDataMap = new LinkedHashMap<>(); + //List varIDs = new ArrayList<>(); + //List values = new ArrayList<>(); // use the data reference to obtain the data generator DataGenerator datagen = sedml.getDataGeneratorWithId(dataset.getDataReference()); assert datagen != null; @@ -140,7 +148,7 @@ private List collectNonspatialDatasets(SedML sedml, Map collectNonspatialDatasets(SedML sedml, Map formattedData; for (TaskJob taskJob : taskJobs) { ODESolverResultSet results = nonspatialResultsHash.get(taskJob); - int column = results.findColumn(sbmlVarId); - double[] data = results.extractColumn(column); + double[] data = results.extractColumn(results.findColumn(sbmlVarId)); if (outputStartTime > 0){ double[] correctiveData = new double[outputNumberOfPoints + 1]; @@ -165,17 +172,38 @@ private List collectNonspatialDatasets(SedML sedml, Map(); + }*/ + // really ugly convert from double[] to List + formattedData = Arrays.asList(Arrays.stream(data).boxed().toArray(Double[]::new)); + idToDataMap.put(var.getId(), formattedData); + } + } + + // Missing functionality!!! We need to computer the variables into the proper values + if (idToDataMap.isEmpty()) continue; + int maxLengthOfData = 0; + List data = new LinkedList<>(); + + SimpleDataGenCalculator calc = new SimpleDataGenCalculator(datagen); + + for (List varData : idToDataMap.values()) + if (varData.size() > maxLengthOfData) + maxLengthOfData = varData.size(); + + for (int i = 0; i < maxLengthOfData; i++){ + for (String varId : idToDataMap.keySet()){ + List varData = idToDataMap.get(varId); + Double value = i >= varData.size() ? Double.NaN : varData.get(i); + calc.setArgument(varId, value); } + data.add(calc.evaluateWithCurrentArguments()); } - dataSetValues.put(dataset, values); + + //dataSetValues.put(dataset, data.stream().toArray(Double[]::new)); } // end of dataset @@ -353,6 +381,11 @@ private List getReports(List outputs){ return reports; } + /** + * Goes though references of repeated tasks, finding the "base" task that isn't repeated. + * @param task the task to check if repeated + * @return the base task (not a repeated task) + */ private AbstractTask getOriginalTask(AbstractTask task){ while (task instanceof RepeatedTask) { // We need to find the original task burried beneath. // We assume that we can never have a sequential repeated task at this point, we check for that in SEDMLImporter @@ -450,4 +483,54 @@ private static String removeVCellPrefixes(String s, String sedmlId){ return s; } + + private class SimpleDataGenCalculator { + private Expression equation; + private Map bindingMap; + + public SimpleDataGenCalculator(DataGenerator dataGen) throws ExpressionException { + this.equation = new Expression(dataGen.getMathAsString()); + this.bindingMap = new LinkedHashMap<>(); // LinkedHashMap preserves insertion order + + String[] variableArray = dataGen.getListOfVariables().stream().map(Variable::getId).toArray(String[]::new); + SymbolTable symTable = new SimpleSymbolTable(variableArray); + this.equation.bindExpression(symTable); + + for (String var : variableArray){ + bindingMap.put(var, Double.NaN); + } + } + + public void setArgument(String parameter, Double argument){ + if (!this.bindingMap.containsKey(parameter)) throw new IllegalArgumentException(String.format("\"%s\" is not a parameter of the expression", parameter)); + this.bindingMap.put(parameter, argument); + } + + public void setArguments(Map parameterToArgumentMap){ + for (String param : parameterToArgumentMap.keySet()){ + this.bindingMap.put(param, parameterToArgumentMap.get(param)); + } + } + + public double evaluateWithCurrentArguments() throws ExpressionException, DivideByZeroException { + Double[] args = this.bindingMap.values().toArray(new Double[0]); + return this.equation.evaluateVector(Stream.of(args).mapToDouble(Double::doubleValue).toArray()); + } + + public double evaluateWithProvidedArguments(Map parameterToArgumentMap) throws ExpressionException, DivideByZeroException { + List args = new LinkedList<>(); + + // Confirm we have the correct params + if (parameterToArgumentMap.size() != this.bindingMap.size()) throw new IllegalArgumentException("Incorrect number of entries."); + if (!parameterToArgumentMap.keySet().equals(this.bindingMap.keySet())) throw new IllegalArgumentException("Parameter 'keys' don't match"); + + // Prepare args + for (String param : this.bindingMap.keySet()){ // binding map, because keys are set-similar but only binding map preserves order for sure! + args.add(parameterToArgumentMap.get(param)); + } + + // Solve + return this.equation.evaluateVector(args.stream().mapToDouble(Double::doubleValue).toArray()); + } + } }