package org.openlca.app.editors.systems; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import org.eclipse.jface.wizard.WizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StackLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.openlca.app.M; import org.openlca.app.Preferences; import org.openlca.app.db.Database; import org.openlca.app.rcp.images.Icon; import org.openlca.app.util.Controls; import org.openlca.app.util.Error; import org.openlca.app.util.UI; import org.openlca.app.viewers.combo.AllocationMethodViewer; import org.openlca.app.viewers.combo.ImpactMethodViewer; import org.openlca.app.viewers.combo.NwSetComboViewer; import org.openlca.core.database.ImpactMethodDao; import org.openlca.core.database.NwSetDao; import org.openlca.core.math.CalculationSetup; import org.openlca.core.model.AllocationMethod; import org.openlca.core.model.ProductSystem; import org.openlca.core.model.descriptors.ImpactMethodDescriptor; import org.openlca.core.model.descriptors.NwSetDescriptor; import org.python.google.common.base.Strings; import org.slf4j.LoggerFactory; /** * Page for setting the calculation properties of a product system. Class must * be public in order to allow data-binding. */ class CalculationWizardPage extends WizardPage { private AllocationMethodViewer allocationViewer; private ImpactMethodViewer methodViewer; private NwSetComboViewer nwViewer; private Text iterationText; private Button costCheck; private Button dqAssessment; private Composite optionStack; private Composite monteCarloOptions; private Composite commonOptions; private Map<CalculationType, Button> calculationRadios = new HashMap<>(); private CalculationType type; private int iterationCount; public CalculationWizardPage() { super(CalculationWizardPage.class.getCanonicalName()); setTitle(M.CalculationProperties); setDescription(M.CalculationWizardDescription); setImageDescriptor(Icon.CALCULATION_WIZARD.descriptor()); setPageComplete(true); } @Override public void createControl(Composite parent) { Composite body = new Composite(parent, SWT.NULL); UI.gridLayout(body, 2, 10, 10); setControl(body); createSelections(body); new Label(body, SWT.NONE); UI.gridData(new Label(body, SWT.SEPARATOR | SWT.HORIZONTAL), true, false); new Label(body, SWT.NONE); optionStack = new Composite(body, SWT.NULL); StackLayout optionsLayout = new StackLayout(); optionStack.setLayout(optionsLayout); createMonteCarloOptions(optionStack); createCommonOptions(optionStack); optionsLayout.topControl = commonOptions; new Label(body, SWT.NONE); loadDefaults(); } private void createSelections(Composite parent) { createAllocationViewer(parent); createMethodComboViewer(parent); UI.formLabel(parent, M.NormalizationAndWeightingSet); nwViewer = new NwSetComboViewer(parent); nwViewer.setDatabase(Database.get()); UI.formLabel(parent, M.CalculationType); createRadios(parent); } private void createRadios(Composite parent) { Composite composite = new Composite(parent, SWT.NO_RADIO_GROUP); CalculationType[] types = getCalculationTypes(); UI.gridLayout(composite, types.length, 10, 0); for (CalculationType cType : types) { Button button = new Button(composite, SWT.RADIO); button.setText(getLabel(cType)); calculationRadios.put(cType, button); Controls.onSelect(button, e -> { type = cType; updateOptions(); for (Entry<CalculationType, Button> entry : calculationRadios.entrySet()) { Button b = entry.getValue(); b.setSelection(cType == entry.getKey()); } }); } } private void updateOptions() { if (type == CalculationType.MONTE_CARLO) { setTopControl(optionStack, monteCarloOptions); } else { setTopControl(optionStack, commonOptions); } } private void setTopControl(Composite stack, Composite control) { StackLayout layout = (StackLayout) stack.getLayout(); layout.topControl = control; stack.layout(); } private void createCommonOptions(Composite parent) { commonOptions = new Composite(parent, SWT.NULL); UI.gridLayout(commonOptions, 1, 10, 0); costCheck = new Button(commonOptions, SWT.CHECK); costCheck.setSelection(false); costCheck.setText(M.IncludeCostCalculation); dqAssessment = new Button(commonOptions, SWT.CHECK); dqAssessment.setSelection(false); dqAssessment.setText(M.AssessDataQuality); Controls.onSelect(dqAssessment, e -> dqAssessmentChanged()); } private void createMonteCarloOptions(Composite parent) { monteCarloOptions = new Composite(parent, SWT.NULL); UI.gridLayout(monteCarloOptions, 2, 10, 0); Label label = UI.formLabel(monteCarloOptions, M.NumberOfIterations); UI.gridData(label, false, false); iterationText = new Text(monteCarloOptions, SWT.BORDER); UI.gridData(iterationText, false, false).widthHint = 80; iterationText.addModifyListener(e -> numberOfRunsChanged()); } private void numberOfRunsChanged() { String text = iterationText.getText(); try { iterationCount = Integer.parseInt(text); } catch (Exception e2) { Error.showBox(M.InvalidNumber, text + " " + M.IsNotValidNumber); } } private CalculationType[] getCalculationTypes() { return new CalculationType[] { CalculationType.QUICK, CalculationType.ANALYSIS, CalculationType.REGIONALIZED, CalculationType.MONTE_CARLO }; } private String getLabel(CalculationType type) { switch (type) { case ANALYSIS: return M.Analysis; case MONTE_CARLO: return M.MonteCarloSimulation; case QUICK: return M.QuickResults; case REGIONALIZED: return M.RegionalizedLCIA; default: return M.Unknown; } } private void createAllocationViewer(Composite parent) { UI.formLabel(parent, M.AllocationMethod); allocationViewer = new AllocationMethodViewer(parent, AllocationMethod.values()); allocationViewer.setNullable(false); allocationViewer.select(AllocationMethod.NONE); } private void createMethodComboViewer(Composite parent) { UI.formLabel(parent, M.ImpactAssessmentMethod); methodViewer = new ImpactMethodViewer(parent); methodViewer.setNullable(true); methodViewer.setInput(Database.get()); methodViewer.addSelectionChangedListener((selection) -> nwViewer.setInput(methodViewer.getSelected())); } private void loadDefaults() { AllocationMethod allocationMethod = getDefaultAllocationMethod(); allocationViewer.select(allocationMethod); ImpactMethodDescriptor method = getDefaultImpactMethod(); if (method != null) methodViewer.select(method); NwSetDescriptor nwset = getDefaultNwSet(); if (nwset != null) nwViewer.select(nwset); type = getDefaultValue(CalculationType.class, CalculationType.QUICK); calculationRadios.get(type).setSelection(true); String itCount = Preferences.get("calc.numberOfRuns"); if (Strings.isNullOrEmpty(itCount)) itCount = "100"; iterationText.setText(itCount); boolean withCosts = getDefaultBoolean("calc.costCalculation"); costCheck.setSelection(withCosts); boolean doDqAssessment = getDefaultBoolean("calc.dqAssessment"); dqAssessment.setSelection(doDqAssessment); updateOptions(); if (type == CalculationType.MONTE_CARLO) return; dqAssessmentChanged(); } private void dqAssessmentChanged() { if (getControl().isVisible()) getContainer().updateButtons(); } @Override public boolean canFlipToNextPage() { if (!isPageComplete()) return false; return dqAssessment.getSelection(); } private AllocationMethod getDefaultAllocationMethod() { String val = Preferences.get("calc.allocation.method"); if (val == null) return AllocationMethod.NONE; for (AllocationMethod method : AllocationMethod.values()) { if (method.name().equals(val)) return method; } return AllocationMethod.NONE; } private ImpactMethodDescriptor getDefaultImpactMethod() { String val = Preferences.get("calc.impact.method"); if (val == null || val.isEmpty()) return null; try { ImpactMethodDao dao = new ImpactMethodDao(Database.get()); for (ImpactMethodDescriptor d : dao.getDescriptors()) { if (val.equals(d.getRefId())) return d; } } catch (Exception e) { LoggerFactory.getLogger(getClass()).error("failed to load LCIA methods", e); } return null; } private NwSetDescriptor getDefaultNwSet() { String val = Preferences.get("calc.nwset"); if (val == null || val.isEmpty()) return null; ImpactMethodDescriptor method = methodViewer.getSelected(); if (method == null) return null; try { NwSetDao dao = new NwSetDao(Database.get()); for (NwSetDescriptor d : dao.getDescriptorsForMethod(method.getId())) { if (val.equals(d.getRefId())) return d; } } catch (Exception e) { LoggerFactory.getLogger(getClass()).error("failed to load NW sets", e); } return null; } private boolean getDefaultBoolean(String option) { String value = Preferences.get(option); if (value == null) return false; return "true".equals(value.toLowerCase()); } private <T extends Enum<T>> T getDefaultValue(Class<T> type, T defaultValue) { String name = Preferences.get("calc." + type.getSimpleName()); if (Strings.isNullOrEmpty(name)) return defaultValue; T value = Enum.valueOf(type, name); if (value == null) return defaultValue; return value; } public CalculationSetup getSetup(ProductSystem system) { CalculationSetup setUp = new CalculationSetup(system); setUp.withCosts = costCheck.getSelection(); setUp.allocationMethod = allocationViewer.getSelected(); setUp.impactMethod = methodViewer.getSelected(); NwSetDescriptor set = nwViewer.getSelected(); setUp.nwSet = set; setUp.numberOfRuns = iterationCount; setUp.parameterRedefs.addAll(system.getParameterRedefs()); return setUp; } public CalculationType getCalculationType() { return type; } public boolean doDqAssessment() { return dqAssessment.getSelection(); } }