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

org.openlca.validation.FlowDirectionCheck Maven / Gradle / Ivy

The newest version!
package org.openlca.validation;

import gnu.trove.map.hash.TLongByteHashMap;
import gnu.trove.map.hash.TLongObjectHashMap;
import gnu.trove.set.hash.TLongHashSet;
import org.openlca.core.database.FlowDao;
import org.openlca.core.database.NativeSql;
import org.openlca.core.model.FlowType;
import org.openlca.core.model.ModelType;
import org.openlca.core.model.descriptors.FlowDescriptor;

class FlowDirectionCheck implements Runnable {

	private final Validation v;
	private boolean foundErrors = false;

	FlowDirectionCheck(Validation v) {
		this.v = v;
	}

	@Override
	public void run() {
		try {
			var flows = new FlowDao(v.db).descriptorMap();

			// collect the IDs of quantitative references
			var qrefs = new TLongHashSet();
			var qrefQuery = "select f_quantitative_reference from tbl_processes";
			NativeSql.on(v.db).query(qrefQuery, r -> {
				qrefs.add(r.getLong(1));
				return true;
			});

			checkDirections(flows, qrefs);
			if (!foundErrors && !v.wasCanceled()) {
				v.ok("checked flow directions");
			}
		} catch (Exception e) {
			v.error("error in flow direction check", e);
		} finally {
			v.workerFinished();
		}
	}

	private void checkDirections(
		TLongObjectHashMap flows, TLongHashSet qrefs) {
		if (v.wasCanceled())
			return;

		var sql = "select " +
			/* 1 */ "id, " +
			/* 2 */ "f_owner, " +
			/* 3 */ "f_flow, " +
			/* 4 */ "is_input from tbl_exchanges";

		// the found directions of the elementary flows
		var directions = new TLongByteHashMap();
		byte input = (byte) 1;
		byte output = (byte) 2;
		byte error = (byte) 4;

		NativeSql.on(v.db).query(sql, r -> {
			var exchangeId = r.getLong(1);
			var processId = r.getLong(2);
			var flowId = r.getLong(3);
			var isInput = r.getBoolean(4);

			var flow = flows.get(flowId);
			// missing flows are reported in the ref-checks
			if (flow == null || flow.flowType == null)
				return !v.wasCanceled();
			var flowType = flow.flowType;

			if (qrefs.contains(exchangeId)) {
				checkRef(processId, flowType, isInput);

			} else if (flowType == FlowType.ELEMENTARY_FLOW) {
				byte direction = directions.get(flowId);
				if (direction == 0) {
					directions.put(flowId, isInput ? input : output);
				} else if ((direction == input && !isInput)
					|| (direction == output && isInput)) {
					directions.put(flowId, error);
					v.error(flowId, ModelType.FLOW,
						"elementary flow is used as input and output of processes");
					foundErrors = true;
				}
			}

			return !v.wasCanceled();
		});
	}

	private void checkRef(long processId, FlowType type, boolean isInput) {
		if ((type == FlowType.PRODUCT_FLOW && !isInput)
			|| (type == FlowType.WASTE_FLOW && isInput))
			return;
		v.warning(processId, ModelType.PROCESS,
			"the quantitative reference is not a product output or waste input");
		foundErrors = true;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy