All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openlca.io.simapro.csv.output.FlowClassifier Maven / Gradle / Ivy

The newest version!
package org.openlca.io.simapro.csv.output;

import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;

import org.openlca.core.io.maps.FlowMap;
import org.openlca.core.io.maps.FlowMapEntry;
import org.openlca.core.model.Category;
import org.openlca.core.model.Flow;
import org.openlca.io.simapro.csv.Compartment;
import org.openlca.simapro.csv.CsvDataSet;
import org.openlca.simapro.csv.enums.ElementaryFlowType;
import org.openlca.simapro.csv.refdata.ElementaryFlowRow;
import org.openlca.util.Strings;
import org.slf4j.LoggerFactory;

class FlowClassifier {

	private final Map compartments = new HashMap<>();
	private final Map flowCompartments = new HashMap<>();
	private final HashSet unmappedCompartments = new HashSet<>();
	private final UnitMap units;
	private final Map flowMap;

	private FlowClassifier(UnitMap units, FlowMap flowMap) {
		this.units = Objects.requireNonNull(units);
		this.flowMap = flowMap != null
				? flowMap.index()
				: null;
	}

	static FlowClassifier of(UnitMap units, FlowMap flowMap) {
		return new FlowClassifier(units, flowMap);
	}

	static FlowClassifier of(UnitMap units) {
		return new FlowClassifier(units, null);
	}

	/**
	 * Returns a flow mapping for the given flow or {@code null}.
	 */
	Mapping mappingOf(Flow flow) {
		if (flowMap == null || flow == null)
			return null;
		var mapping = flowMap.get(flow.refId);
		if (mapping == null)
			return null;
		return Mapping.of(mapping, units).orElse(null);
	}

	/**
	 * Returns the mapped compartment for the given flow or {@code null}
	 * if no compartment could be inferred.
	 */
	Compartment compartmentOf(Flow flow) {
		if (flow == null)
			return null;
		var c = flowCompartments.get(flow);
		if (c != null)
			return c;

		var mapping = mappingOf(flow);
		if (mapping != null) {
			flowCompartments.put(flow, mapping.compartment());
			return mapping.compartment;
		}

		if (flow.category == null) {
			LoggerFactory.getLogger(getClass())
					.error("elementary flow {} has no category " +
							"and cannot be mapped to SimaPro", flow.refId);
			return null;
		}
		if (unmappedCompartments.contains(flow.category)) {
			return null;
		}

		c = compartments.computeIfAbsent(flow.category, Compartment::of);
		if (c == null) {
			LoggerFactory.getLogger(getClass()).error(
					"category {} cannot mapped to SimaPro; all flows in this "
							+ "category will be skipped", flow.category.toPath());
			unmappedCompartments.add(flow.category);
			return null;
		}
		flowCompartments.put(flow, c);
		return c;
	}

	EnumMap> groupFlows() {
		var map = new EnumMap>(
				ElementaryFlowType.class);
		for (var e : flowCompartments.entrySet()) {
			var type = e.getValue().type();
			var list = map.computeIfAbsent(type, t -> new ArrayList<>());
			list.add(e.getKey());
		}
		return map;
	}

	void writeGroupsTo(CsvDataSet ds) {
		if (ds == null)
			return;

		var groups = groupFlows();
		for (var type : ElementaryFlowType.values()) {
			var group = groups.get(type);
			if (group == null || group.isEmpty())
				return;
			var rows = ds.getElementaryFlows(type);

			// duplicate names are not allowed here
			var handledNames = new HashSet();
			for (var flow : group) {

				// select name & unit
				var mapping = mappingOf(flow);
				var name = mapping == null
						? flow.name
						: mapping.flow();
				var unit = mapping == null
						? units.get(flow.getReferenceUnit())
						: units.get(mapping.unit());
				if (name == null || unit == null)
					continue;

				// skip duplicate names
				String id = name.trim().toLowerCase();
				if (handledNames.contains(id))
					continue;
				handledNames.add(id);

				// add row
				var row = new ElementaryFlowRow()
						.name(name)
						.unit(unit);
				if (mapping == null) {
					row.cas(flow.casNumber)
							.comment(flow.description);
				}
				rows.add(row);
			}
		}
	}

	/**
	 * Wraps a flow mapping entry. These mappings should be
	 * only created when they are fully qualified with all
	 * information available.
	 */
	record Mapping(
			String flow,
			String unit,
			Compartment compartment,
			double factor) {

		static Optional of(FlowMapEntry e, UnitMap units) {
			var target = e.targetFlow();
			if (target == null
					|| target.flow == null
					|| Strings.nullOrEmpty(target.flow.name)
					|| target.unit == null
					|| Strings.nullOrEmpty(target.unit.name))
				return Optional.empty();
			var unit = units.get(target.unit.name);
			var comp = Compartment.fromPath(target.flowCategory);
			if (comp == null)
				return Optional.empty();
			var mapping = new Mapping(
					target.flow.name, unit, comp, e.factor());
			return Optional.of(mapping);
		}
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy