package org.openlca.app.results.regionalized;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.openlca.core.database.IDatabase;
import org.openlca.core.database.ImpactMethodDao;
import org.openlca.core.database.ParameterDao;
import org.openlca.core.math.CalculationSetup;
import org.openlca.core.model.ImpactCategory;
import org.openlca.core.model.ImpactFactor;
import org.openlca.core.model.ImpactMethod;
import org.openlca.core.model.Parameter;
import org.openlca.core.model.ParameterRedef;
import org.openlca.core.model.descriptors.Descriptors;
import org.openlca.core.model.descriptors.FlowDescriptor;
import org.openlca.expressions.FormulaInterpreter;
import org.openlca.expressions.InterpreterException;
import org.openlca.expressions.Scope;
import org.openlca.geo.parameter.ParameterSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
class FactorCalculator {
private Logger log = LoggerFactory.getLogger(getClass());
private ParameterSet regioParams;
private Map<String, Double> inputParams = new HashMap<>();
private Map<String, String> calcParams = new HashMap<>();
FactorCalculator(ParameterSet inputParams, IDatabase db,
CalculationSetup setup) {
this.regioParams = inputParams;
initContext(db, setup);
}
private void initContext(IDatabase db, CalculationSetup setup) {
// order of the initialization is important
ParameterDao dao = new ParameterDao(db);
addToContext(dao.getGlobalParameters());
for (ParameterRedef redef : setup.parameterRedefs) {
if (redef.getContextId() == null) {
inputParams.put(redef.getName(), redef.getValue());
}
}
if (setup.impactMethod != null) {
ImpactMethodDao methodDao = new ImpactMethodDao(db);
ImpactMethod method = methodDao.getForId(setup.impactMethod.getId());
addToContext(method.getParameters());
}
}
private void addToContext(List<Parameter> params) {
for (Parameter p : params) {
if (p.isInputParameter()) {
inputParams.put(p.getName(), p.getValue());
} else {
calcParams.put(p.getName(), p.getFormula());
}
}
}
Map<FlowDescriptor, Double> calculate(ImpactCategory category, long locationId) {
Scope scope = buildScope(locationId);
Map<FlowDescriptor, Double> result = new HashMap<>();
for (ImpactFactor factor : category.getImpactFactors()) {
FlowDescriptor flow = Descriptors.toDescriptor(factor.getFlow());
if (factor.getFormula() == null) {
result.put(flow, factor.getValue());
} else {
result.put(flow, eval(factor, scope));
}
}
return result;
}
private Scope buildScope(long locationId) {
Scope scope = new FormulaInterpreter().getGlobalScope();
// again: the order of filling the scope is important
for (Entry<String, String> param : calcParams.entrySet()) {
scope.bind(param.getKey(), param.getValue());
}
for (Entry<String, Double> param : inputParams.entrySet()) {
if (param.getValue() == null)
continue;
scope.bind(param.getKey(), param.getValue().toString());
}
Map<String, Double> regioMap = regioParams.get(locationId);
for (Entry<String, Double> param : regioMap.entrySet()) {
if (param.getValue() == null)
continue;
scope.bind(param.getKey(), param.getValue().toString());
}
return scope;
}
private double eval(ImpactFactor factor, Scope scope) {
try {
return scope.eval(factor.getFormula());
} catch (InterpreterException e) {
log.error("Error evaluating formula " + factor.getFormula(), e);
}
return 0;
}
}