package org.openlca.app.editors.parameters;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.openlca.core.database.IDatabase;
import org.openlca.core.database.ParameterDao;
import org.openlca.core.model.Exchange;
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.Process;
import org.openlca.core.model.Uncertainty;
import org.openlca.expressions.FormulaInterpreter;
import org.openlca.expressions.Scope;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Some helper methods for evaluating formulas in the editors.
*/
public class Formulas {
private Logger log = LoggerFactory.getLogger(getClass());
private List<String> errors = new ArrayList<>();
private IDatabase db;
private Formulas(IDatabase db) {
this.db = db;
}
public static List<String> eval(IDatabase db, Process process) {
if (db == null || process == null)
return Collections.emptyList();
return new Formulas(db).eval(process);
}
public static List<String> eval(IDatabase db, ImpactMethod method) {
if (db == null || method == null)
return Collections.emptyList();
return new Formulas(db).eval(method);
}
public static List<String> eval(List<Parameter> params) {
if (params == null)
return Collections.emptyList();
return new Formulas(null).evalGlobal(params);
}
private List<String> evalGlobal(List<Parameter> params) {
try {
FormulaInterpreter interpreter = new FormulaInterpreter();
Scope scope = interpreter.getGlobalScope();
for (Parameter p : params)
bind(p, scope);
evalParams(params, scope);
} catch (Exception e) {
log.warn("unexpected error in formula evaluation", e);
}
return errors;
}
private List<String> eval(Process p) {
try {
Scope s = makeLocalScope(p.getParameters(), p.getId());
evalParams(p.getParameters(), s);
evalExchanges(p.getExchanges(), s);
} catch (Exception e) {
log.warn("unexpected error in formula evaluation", e);
}
return errors;
}
private List<String> eval(ImpactMethod m) {
try {
Scope s = makeLocalScope(m.getParameters(), m.getId());
evalParams(m.getParameters(), s);
for (ImpactCategory ic : m.getImpactCategories())
evalFactors(ic.getImpactFactors(), s);
} catch (Exception e) {
log.warn("unexpected error in formula evaluation", e);
}
return errors;
}
private void evalParams(List<Parameter> params, Scope s) {
for (Parameter param : params) {
if (param.isInputParameter())
continue;
double val = eval(param.getFormula(), s);
param.setValue(val);
}
}
private void evalExchanges(List<Exchange> exchanges, Scope s) {
for (Exchange e : exchanges) {
if (e.getAmountFormula() != null)
e.setAmountValue(eval(e.getAmountFormula(), s));
eval(e.getUncertainty(), s);
if (e.costFormula != null)
e.costValue = eval(e.costFormula, s);
}
}
private void evalFactors(List<ImpactFactor> factors, Scope s) {
for (ImpactFactor f : factors) {
if (f.getFormula() != null)
f.setValue(eval(f.getFormula(), s));
eval(f.getUncertainty(), s);
}
}
private void eval(Uncertainty u, Scope s) {
if (u == null)
return;
if (u.getParameter1Formula() != null)
u.setParameter1Value(eval(u.getParameter1Formula(), s));
if (u.getParameter2Formula() != null)
u.setParameter2Value(eval(u.getParameter2Formula(), s));
if (u.getParameter3Formula() != null)
u.setParameter3Value(eval(u.getParameter3Formula(), s));
}
private double eval(String formula, Scope s) {
if (formula == null || formula.trim().isEmpty() || s == null)
return 0;
try {
double val = s.eval(formula);
log.trace("evaluated: {} -> {}", formula, val);
return val;
} catch (Exception e) {
log.warn("failed to evaluate " + formula, e);
errors.add(formula);
return 0;
}
}
private Scope makeLocalScope(List<Parameter> params, long scopeId) {
FormulaInterpreter interpreter = new FormulaInterpreter();
ParameterDao dao = new ParameterDao(db);
Scope globalScope = interpreter.getGlobalScope();
for (Parameter p : dao.getGlobalParameters())
bind(p, globalScope);
Scope localScope = interpreter.createScope(scopeId);
for (Parameter p : params)
bind(p, localScope);
return localScope;
}
private void bind(Parameter param, Scope scope) {
if (param == null || scope == null)
return;
if (param.isInputParameter())
scope.bind(param.getName(), Double.toString(param.getValue()));
else
scope.bind(param.getName(), param.getFormula());
}
}