package org.openlca.app.editors.systems;
import java.lang.reflect.InvocationTargetException;
import java.math.RoundingMode;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.openlca.app.App;
import org.openlca.app.M;
import org.openlca.app.Preferences;
import org.openlca.app.db.Cache;
import org.openlca.app.db.Database;
import org.openlca.app.results.ResultEditorInput;
import org.openlca.app.results.analysis.AnalyzeEditor;
import org.openlca.app.results.quick.QuickResultEditor;
import org.openlca.app.results.regionalized.RegionalizedResultEditor;
import org.openlca.app.results.simulation.SimulationInit;
import org.openlca.app.util.Editors;
import org.openlca.app.util.Info;
import org.openlca.app.util.UI;
import org.openlca.core.math.CalculationSetup;
import org.openlca.core.math.SystemCalculator;
import org.openlca.core.math.data_quality.AggregationType;
import org.openlca.core.math.data_quality.DQCalculationSetup;
import org.openlca.core.math.data_quality.DQResult;
import org.openlca.core.math.data_quality.ProcessingType;
import org.openlca.core.model.AllocationMethod;
import org.openlca.core.model.ProductSystem;
import org.openlca.core.model.descriptors.BaseDescriptor;
import org.openlca.core.results.ContributionResult;
import org.openlca.core.results.ContributionResultProvider;
import org.openlca.core.results.FullResult;
import org.openlca.core.results.FullResultProvider;
import org.openlca.geo.RegionalizedCalculator;
import org.openlca.geo.RegionalizedResult;
import org.openlca.geo.RegionalizedResultProvider;
import org.openlca.geo.parameter.ParameterSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Wizard for setting calculation properties and run the calculation of a
* product system
*/
public class CalculationWizard extends Wizard {
private Logger log = LoggerFactory.getLogger(this.getClass());
CalculationWizardPage calculationPage;
DQSettingsPage dqSettingsPage;
ProductSystem productSystem;
public CalculationWizard(ProductSystem productSystem) {
this.productSystem = productSystem;
setNeedsProgressMonitor(true);
setWindowTitle(M.CalculationProperties);
}
public static void open(ProductSystem productSystem) {
if (productSystem == null)
return;
CalculationWizard wizard = new CalculationWizard(productSystem);
WizardDialog dialog = new WizardDialog(UI.shell(), wizard);
dialog.open();
}
@Override
public void addPages() {
calculationPage = new CalculationWizardPage();
addPage(calculationPage);
dqSettingsPage = new DQSettingsPage();
addPage(dqSettingsPage);
}
@Override
public boolean performFinish() {
CalculationSetup setup = calculationPage.getSetup(productSystem);
CalculationType type = calculationPage.getCalculationType();
DQCalculationSetup dqSetup = null;
if (calculationPage.doDqAssessment())
dqSetup = dqSettingsPage.getSetup(productSystem);
saveDefaults(setup, dqSetup, type);
try {
Calculation calculation = new Calculation(setup, type, dqSetup);
getContainer().run(true, true, calculation);
if (calculation.outOfMemory)
MemoryError.show();
return !calculation.outOfMemory;
} catch (Exception e) {
log.error("Calculation failed", e);
return false;
}
}
private ResultEditorInput getEditorInput(Object result, CalculationSetup setup,
ParameterSet parameterSet, DQResult dqResult) {
ResultEditorInput input = ResultEditorInput.create(setup, result)
.with(dqResult)
.with(parameterSet);
return input;
}
private void saveDefaults(CalculationSetup setup, DQCalculationSetup dqSetup, CalculationType type) {
if (setup == null)
return;
AllocationMethod am = setup.allocationMethod;
String amVal = am == null ? "NONE" : am.name();
Preferences.set("calc.allocation.method", amVal);
BaseDescriptor m = setup.impactMethod;
String mVal = m == null ? "" : m.getRefId();
Preferences.set("calc.impact.method", mVal);
BaseDescriptor nws = setup.nwSet;
String nwsVal = nws == null ? "" : nws.getRefId();
Preferences.set("calc.nwset", nwsVal);
saveDefault(CalculationType.class, type);
Preferences.set("calc.numberOfRuns", Integer.toString(setup.numberOfRuns));
Preferences.set("calc.costCalculation", Boolean.toString(setup.withCosts));
if (dqSetup == null) {
Preferences.set("calc.dqAssessment", "false");
return;
}
Preferences.set("calc.dqAssessment", "true");
saveDefault(AggregationType.class, dqSetup.aggregationType);
saveDefault(ProcessingType.class, dqSetup.processingType);
saveDefault(RoundingMode.class, dqSetup.roundingMode);
}
private <T extends Enum<T>> void saveDefault(Class<T> clazz, T value) {
Preferences.set("calc." + clazz.getSimpleName(), value == null ? null : value.name());
}
private class Calculation implements IRunnableWithProgress {
private CalculationSetup setup;
private CalculationType type;
private DQCalculationSetup dqSetup;
private boolean outOfMemory;
public Calculation(CalculationSetup setup, CalculationType type, DQCalculationSetup dqSetup) {
this.setup = setup;
this.type = type;
this.dqSetup = dqSetup;
}
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
outOfMemory = false;
monitor.beginTask(M.RunCalculation, IProgressMonitor.UNKNOWN);
int size = productSystem.getProcesses().size();
log.trace("calculate a {} x {} system", size, size);
try {
switch (type) {
case ANALYSIS:
analyse();
break;
case MONTE_CARLO:
simulate();
break;
case QUICK:
solve();
break;
case REGIONALIZED:
calcRegionalized();
break;
default:
break;
}
} catch (OutOfMemoryError e) {
outOfMemory = true;
}
monitor.done();
}
private void analyse() {
log.trace("run analysis");
SystemCalculator calculator = new SystemCalculator(Cache.getMatrixCache(), App.getSolver());
FullResult result = calculator.calculateFull(setup);
log.trace("calculation done, open editor");
FullResultProvider resultProvider = new FullResultProvider(result, Cache.getEntityCache());
DQResult dqResult = DQResult.calculate(Database.get(), result, dqSetup);
ResultEditorInput input = getEditorInput(resultProvider, setup, null, dqResult);
Editors.open(input, AnalyzeEditor.ID);
}
private void solve() {
log.trace("run quick calculation");
SystemCalculator calculator = new SystemCalculator(Cache.getMatrixCache(), App.getSolver());
ContributionResult result = calculator.calculateContributions(setup);
log.trace("calculation done, open editor");
ContributionResultProvider<ContributionResult> resultProvider = new ContributionResultProvider<>(result,
Cache.getEntityCache());
DQResult dqResult = DQResult.calculate(Database.get(), result, dqSetup);
ResultEditorInput input = getEditorInput(resultProvider, setup, null, dqResult);
Editors.open(input, QuickResultEditor.ID);
}
private void simulate() {
log.trace("init Monte Carlo Simulation");
SimulationInit init = new SimulationInit(setup, Cache.getMatrixCache());
init.run();
}
private void calcRegionalized() {
log.trace("calculate regionalized result");
RegionalizedCalculator calculator = new RegionalizedCalculator(setup, App.getSolver());
RegionalizedResult regioResult = calculator.calculate(Database.get(), Cache.getMatrixCache());
if (regioResult == null) {
Info.showBox("No regionalized information available for this system");
return;
}
RegionalizedResultProvider provider = new RegionalizedResultProvider();
provider.result = new FullResultProvider(regioResult.result, Cache.getEntityCache());
provider.kmlData = regioResult.kmlData;
DQResult dqResult = DQResult.calculate(Database.get(), regioResult.result, dqSetup);
ResultEditorInput input = getEditorInput(provider, setup, regioResult.parameterSet, dqResult);
Editors.open(input, RegionalizedResultEditor.ID);
}
}
}