package org.openlca.io.ecospold2.output; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.UUID; import org.openlca.core.database.IDatabase; import org.openlca.core.database.ParameterDao; import org.openlca.core.database.ProcessDao; import org.openlca.core.model.Exchange; import org.openlca.core.model.Flow; import org.openlca.core.model.FlowType; import org.openlca.core.model.Parameter; import org.openlca.core.model.Process; import org.openlca.core.model.ProcessDocumentation; import org.openlca.core.model.ProcessType; import org.openlca.core.model.descriptors.ProcessDescriptor; import org.openlca.io.ecospold2.UncertaintyConverter; import org.openlca.util.Strings; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import spold2.Activity; import spold2.ActivityDescription; import spold2.ActivityName; import spold2.DataSet; import spold2.EcoSpold2; import spold2.ElementaryExchange; import spold2.FlowData; import spold2.IntermediateExchange; import spold2.RichText; import spold2.UserMasterData; /** * Exports a set of processes to the EcoSpold 2 data format to a directory. The * process data sets are converted to EcoSpold 2 activity data sets and written * to the sub-folder 'Activities' in a given export directory. */ public class EcoSpold2Export implements Runnable { private Logger log = LoggerFactory.getLogger(getClass()); private final File dir; private final IDatabase database; private final List<ProcessDescriptor> descriptors; private final LocationMap locationMap; private final UnitMap unitMap; private final CompartmentMap compartmentMap; private final ElemFlowMap elemFlowMap; public EcoSpold2Export(File dir, IDatabase database, List<ProcessDescriptor> descriptors) { this.dir = dir; this.database = database; this.descriptors = descriptors; this.locationMap = new LocationMap(database); this.unitMap = new UnitMap(database); this.compartmentMap = new CompartmentMap(database); this.elemFlowMap = new ElemFlowMap(database); } @Override public void run() { try { File activityDir = new File(dir, "Activities"); if (!activityDir.exists()) activityDir.mkdirs(); exportProcesses(activityDir); } catch (Exception e) { log.error("EcoSpold 2 export failed", e); } } private void exportProcesses(File activityDir) throws Exception { for (ProcessDescriptor descriptor : descriptors) { ProcessDao dao = new ProcessDao(database); Process process = dao.getForId(descriptor.getId()); ProcessDocumentation doc = process.getDocumentation(); if (process == null || doc == null) { log.warn("no process entity or documentation for {} found", descriptor); continue; } exportProcess(activityDir, process); } } private void exportProcess(File activityDir, Process process) throws Exception { DataSet dataSet = new DataSet(); dataSet.description = new ActivityDescription(); UserMasterData masterData = new UserMasterData(); dataSet.masterData = masterData; mapActivity(process, dataSet); locationMap.apply(process, dataSet); ProcessDoc.map(process, dataSet); mapExchanges(process, dataSet); mapParameters(process, dataSet); MasterData.writeIndexEntry(dataSet); String fileName = process.getRefId() == null ? UUID.randomUUID() .toString() : process.getRefId(); File file = new File(activityDir, fileName + ".spold"); EcoSpold2.write(dataSet, file); } private void mapActivity(Process process, DataSet dataSet) { Activity activity = new Activity(); dataSet.description.activity = activity; ActivityName activityName = new ActivityName(); dataSet.masterData.activityNames.add(activityName); String nameId = UUID.randomUUID().toString(); activity.activityNameId = nameId; activityName.id = nameId; String name = Strings.cut(process.getName(), 120); activity.name = name; activityName.name = name; activity.id = process.getRefId(); int type = process.getProcessType() == ProcessType.LCI_RESULT ? 2 : 1; activity.type = type; activity.specialActivityType = 0; // default activity.generalComment = RichText.of(process.getDescription()); } private void mapExchanges(Process process, DataSet ds) { if (ds.flowData == null) ds.flowData = new FlowData(); for (Exchange exchange : process.getExchanges()) { if (!isValid(exchange)) continue; Flow flow = exchange.getFlow(); UserMasterData masterData = ds.masterData; if (flow.getFlowType() == FlowType.ELEMENTARY_FLOW) { ElementaryExchange e = createElemExchange(exchange, masterData); ds.flowData.elementaryExchanges.add(e); } else { IntermediateExchange e = createIntermediateExchange(exchange, process, masterData); ds.flowData.intermediateExchanges.add(e); } } } private boolean isValid(Exchange exchange) { return exchange.getFlow() != null && exchange.getFlowPropertyFactor() != null && exchange.getUnit() != null; } private ElementaryExchange createElemExchange(Exchange exchange, UserMasterData masterData) { ElementaryExchange e2Ex = elemFlowMap.apply(exchange); if (e2Ex != null) return e2Ex; e2Ex = new ElementaryExchange(); if (exchange.isInput()) e2Ex.inputGroup = 4; else e2Ex.outputGroup = 4; Flow flow = exchange.getFlow(); e2Ex.flowId = flow.getRefId(); e2Ex.formula = flow.getFormula(); mapExchangeData(exchange, e2Ex); compartmentMap.apply(flow.getCategory(), e2Ex); unitMap.apply(exchange.getUnit(), e2Ex, masterData); MasterData.writeElemFlow(e2Ex, masterData); return e2Ex; } private IntermediateExchange createIntermediateExchange(Exchange exchange, Process process, UserMasterData masterData) { IntermediateExchange e2Ex = new IntermediateExchange(); if (exchange.isInput()) e2Ex.inputGroup = 5; else { if (Objects.equals(exchange, process.getQuantitativeReference())) e2Ex.outputGroup = 0; else if (exchange.getFlow().getFlowType() == FlowType.WASTE_FLOW) e2Ex.outputGroup = 3; else e2Ex.outputGroup = 2; } e2Ex.flowId = exchange.getFlow().getRefId(); ProcessDescriptor provider = getDefaultProvider(exchange); if (provider != null) e2Ex.activityLinkId = provider.getRefId(); mapExchangeData(exchange, e2Ex); unitMap.apply(exchange.getUnit(), e2Ex, masterData); MasterData.writeTechFlow(e2Ex, masterData); return e2Ex; } private ProcessDescriptor getDefaultProvider(Exchange exchange) { if (!exchange.isInput() || exchange.getDefaultProviderId() == 0) return null; ProcessDao dao = new ProcessDao(database); return dao.getDescriptor(exchange.getDefaultProviderId()); } private void mapExchangeData(Exchange exchange, spold2.Exchange e2Exchange) { e2Exchange.name = Strings.cut(exchange.getFlow().getName(), 120); e2Exchange.id = new UUID(exchange.getId(), 0L).toString(); e2Exchange.amount = exchange.getAmountValue(); e2Exchange.mathematicalRelation = exchange.getAmountFormula(); e2Exchange.comment = exchange.description; e2Exchange.casNumber = exchange.getFlow().getCasNumber(); e2Exchange.uncertainty = UncertaintyConverter.fromOpenLCA(exchange .getUncertainty()); } private void mapParameters(Process process, DataSet ds) { if (ds.flowData == null) ds.flowData = new FlowData(); List<Parameter> parameters = new ArrayList<>(); parameters.addAll(process.getParameters()); ParameterDao dao = new ParameterDao(database); parameters.addAll(dao.getGlobalParameters()); for (Parameter param : parameters) { spold2.Parameter e2Param = new spold2.Parameter(); e2Param.name = param.getName(); e2Param.id = new UUID(param.getId(), 0L).toString(); e2Param.amount = param.getValue(); e2Param.variableName = param.getName(); e2Param.mathematicalRelation = param.getFormula(); e2Param.isCalculatedAmount = !param.isInputParameter(); if (param.getScope() != null) e2Param.scope = param.getScope().name(); e2Param.uncertainty = UncertaintyConverter.fromOpenLCA(param .getUncertainty()); ds.flowData.parameters.add(e2Param); } } }