package org.openlca.io.ilcd.input;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openlca.core.database.BaseEntityDao;
import org.openlca.core.database.FlowPropertyDao;
import org.openlca.core.model.AllocationMethod;
import org.openlca.core.model.Exchange;
import org.openlca.core.model.Flow;
import org.openlca.core.model.FlowProperty;
import org.openlca.core.model.FlowPropertyFactor;
import org.openlca.core.model.Process;
import org.openlca.core.model.Unit;
import org.openlca.core.model.UnitGroup;
import org.openlca.ilcd.processes.AllocationFactor;
import org.openlca.ilcd.util.ExchangeExtension;
import org.openlca.ilcd.util.ProcessBag;
import org.openlca.io.maps.FlowMapEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Maps the inputs and outputs of an ILCD process to an openLCA process.
*/
class ProcessExchanges {
private final Logger log = LoggerFactory.getLogger(getClass());
private ImportConfig config;
private List<MappedPair> mappedPairs = new ArrayList<>();
ProcessExchanges(ImportConfig config) {
this.config = config;
}
void map(ProcessBag ilcdProcess, Process process) {
mappedPairs.clear();
for (org.openlca.ilcd.processes.Exchange iExchange : ilcdProcess.getExchanges()) {
ExchangeFlow exchangeFlow = new ExchangeFlow(iExchange);
exchangeFlow.findOrImport(config);
Exchange exchange = createExchange(iExchange, exchangeFlow);
ExchangeExtension extension = new ExchangeExtension(iExchange);
if (extension.isValid())
mapExtension(extension, exchange, exchangeFlow.getFlow());
else
mapPropertyAndUnit(exchangeFlow, exchange);
if (isValid(exchange)) {
process.getExchanges().add(exchange);
mappedPairs.add(new MappedPair(exchange, iExchange));
} else {
log.warn("invalid exchange {} - not added to process {}",
exchange, process);
}
}
mapAllocation(process);
mapReferenceFlow(ilcdProcess, process);
}
private boolean isValid(Exchange exchange) {
return exchange.getFlow() != null
&& exchange.getFlowPropertyFactor() != null
&& exchange.getUnit() != null;
}
private Exchange createExchange(
org.openlca.ilcd.processes.Exchange iExchange,
ExchangeFlow exchangeFlow) {
Exchange oExchange = new ExchangeConversion(iExchange, config).map();
if (exchangeFlow.getFlow() != null) {
oExchange.setFlow(exchangeFlow.getFlow());
if (exchangeFlow.isMapped())
applyFlowAssignment(oExchange, exchangeFlow.getMapEntry());
}
return oExchange;
}
private void applyFlowAssignment(Exchange oExchange,
FlowMapEntry mapEntry) {
double amount = oExchange.getAmountValue();
double newVal = mapEntry.getConversionFactor() * amount;
oExchange.setAmountValue(newVal);
if (oExchange.getAmountFormula() != null) {
String newForm = "(" + oExchange.getAmountFormula() + ") * "
+ mapEntry.getConversionFactor();
oExchange.setAmountFormula(newForm);
}
}
private void mapPropertyAndUnit(ExchangeFlow exchangeFlow,
Exchange oExchange) {
try {
Flow flowInfo = exchangeFlow.getFlow();
FlowProperty flowProperty = flowInfo.getReferenceFlowProperty();
FlowPropertyFactor factor = flowInfo.getFactor(flowProperty);
oExchange.setFlowPropertyFactor(factor);
UnitGroup unitGroup = flowProperty.getUnitGroup();
oExchange.setUnit(unitGroup.getReferenceUnit());
} catch (Exception e) {
Logger log = LoggerFactory.getLogger(this.getClass());
log.error("Cannot get flow property or unit from database", e);
}
}
private void mapExtension(ExchangeExtension extension, Exchange exchange,
Flow flowInfo) {
// TODO: map default provider
// exchange.setDefaultProviderId(extension.getDefaultProvider());
if (extension.isAvoidedProduct()) {
exchange.setInput(true);
exchange.setAvoidedProduct(true);
}
try {
BaseEntityDao<Unit> unitDao = new BaseEntityDao<>(Unit.class,
config.db);
Unit unit = unitDao.getForRefId(extension.getUnitId());
exchange.setUnit(unit);
FlowPropertyDao propDao = new FlowPropertyDao(config.db);
FlowProperty property = propDao.getForRefId(extension
.getPropertyId());
FlowPropertyFactor factor = flowInfo.getFactor(property);
exchange.setFlowPropertyFactor(factor);
} catch (Exception e) {
Logger log = LoggerFactory.getLogger(this.getClass());
log.error("Cannot get flow property or unit from database", e);
}
}
private void mapAllocation(Process process) {
for (MappedPair p : mappedPairs) {
AllocationFactor[] factors = p.iExchange.allocations;
if (factors == null)
continue;
for (AllocationFactor iFactor : factors) {
Long productId = findMappedFlowId(iFactor.productExchangeId);
if (productId == null)
continue;
createAllocationFactor(p, productId, iFactor.fraction,
process);
}
}
}
private void createAllocationFactor(MappedPair p, long productId,
double fraction, Process process) {
Exchange oExchange = p.oExchange;
if (oExchange.getFlow() == null)
return;
org.openlca.core.model.AllocationFactor f = new org.openlca.core.model.AllocationFactor();
f.setProductId(productId);
f.setValue(fraction / 100);
if (oExchange.getFlow().getId() == productId)
f.setAllocationType(AllocationMethod.PHYSICAL);
else {
f.setAllocationType(AllocationMethod.CAUSAL);
f.setExchange(oExchange);
}
process.getAllocationFactors().add(f);
}
private Long findMappedFlowId(int iExchangeId) {
for (MappedPair p : mappedPairs) {
if (iExchangeId == p.iExchange.id) {
if (p.oExchange.getFlow() != null)
return p.oExchange.getFlow().getId();
}
}
return null;
}
private void mapReferenceFlow(ProcessBag ilcdProcess, Process process) {
Map<Integer, Exchange> map = new HashMap<>();
for (MappedPair pair : mappedPairs)
map.put(pair.iExchange.id, pair.oExchange);
new ProcessRefFlowMapper(ilcdProcess, process, map).setReferenceFlow();
}
private class MappedPair {
Exchange oExchange;
org.openlca.ilcd.processes.Exchange iExchange;
MappedPair(Exchange oExchange,
org.openlca.ilcd.processes.Exchange iExchange) {
this.oExchange = oExchange;
this.iExchange = iExchange;
}
}
}