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

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

The newest version!
package org.openlca.validation;

import java.sql.ResultSet;

import gnu.trove.map.hash.TLongDoubleHashMap;
import gnu.trove.map.hash.TLongObjectHashMap;
import gnu.trove.set.hash.TLongHashSet;
import org.openlca.core.database.NativeSql;
import org.openlca.core.model.AllocationMethod;
import org.openlca.core.model.ModelType;
import org.openlca.expressions.FormulaInterpreter;
import org.openlca.util.Strings;

class AllocationCheck implements Runnable {

	private final Validation v;
	private boolean foundErrors = false;
	private FormulaInterpreter interpreter;

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

	@Override
	public void run() {
		try {
			checkFactors();
			if (!foundErrors && !v.wasCanceled()) {
				v.ok("checked allocation factors");
			}
		} catch (Exception e) {
			v.error("error in validation of allocation factors", e);
		} finally {
			v.workerFinished();
		}
	}

	private void checkFactors() {
		if (v.wasCanceled())
			return;
		var physicals = new TLongDoubleHashMap();
		var economics = new TLongDoubleHashMap();
		var causals = new TLongObjectHashMap();

		var sql = "select " +
			/* 1 */ "allocation_type, " +
			/* 2 */ "value, " +
			/* 3 */ "formula, " +
			/* 4 */ "f_process, " +
			/* 5 */ "f_exchange from tbl_allocation_factors";
		NativeSql.on(v.db).query(sql, r -> {
			var method = AllocationMethod.valueOf(r.getString(1));
			var value = valueOf(r);
			if (value == 0)
				return !v.wasCanceled();
			var process = r.getLong(4);
			if (method == AllocationMethod.PHYSICAL) {
				physicals.adjustOrPutValue(process, value, value);
			} else if (method == AllocationMethod.ECONOMIC) {
				economics.adjustOrPutValue(process, value, value);
			} else if (method == AllocationMethod.CAUSAL) {
				var exchange = r.getLong(5);
				var map = causals.get(process);
				if (map == null) {
					map = new TLongDoubleHashMap();
					causals.put(process, map);
				}
				map.adjustOrPutValue(exchange, value, value);
			}

			return !v.wasCanceled();
		});

		if (v.wasCanceled())
			return;

		var errors = new TLongHashSet();
		check(physicals, errors);
		check(economics, errors);
		for (var it = causals.iterator(); it.hasNext();) {
			it.advance();
			var processId = it.key();
			var sums = it.value();
			if (errors.contains(processId) || sums == null)
				continue;
			for (var sum = sums.iterator(); sum.hasNext();) {
				sum.advance();
				if (isNotOne(sum.value())) {
					addError(processId, errors);
					break;
				}
			}
		}
	}

	private double valueOf(ResultSet r) {
		try {
			var formula = r.getString(3);
			if (Strings.nullOrEmpty(formula))
				return r.getDouble(2);

			if (interpreter == null) {
				interpreter = Util.interpreterOf(v.db);
			}
			var process = r.getLong(4);
			return interpreter.getOrCreate(process)
				.eval(formula);
		} catch (Exception e) {
			return -1;
		}
	}

	private void check(TLongDoubleHashMap map, TLongHashSet errors) {
		for (var it = map.iterator(); it.hasNext(); ) {
			it.advance();
			var processId = it.key();
			if (errors.contains(processId))
				continue;
			if (isNotOne(it.value())) {
				addError(processId, errors);
			}
		}
	}

	private void addError(long processId, TLongHashSet errors) {
		foundErrors = true;
		errors.add(processId);
		v.error(processId, ModelType.PROCESS,
			"allocation factors do not sum up to 1");
	}

	private boolean isNotOne(double factor) {
		var v = Math.abs(factor - 1);
		return v > 1e-4;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy