<commit_before>package sophena.calc;

import sophena.math.energetic.Buffers;
import sophena.math.energetic.Producers;
import sophena.model.HoursTrace;
import sophena.model.Producer;
import sophena.model.ProducerFunction;
import sophena.model.Project;
import sophena.model.Stats;
import sophena.model.TimeInterval;

class EnergyCalculator {

	private Project project;

	private double maxBufferCapacity = 0;

	private EnergyCalculator(Project project) {
		this.project = project;
	}

	public static EnergyResult calculate(Project project) {
		return new EnergyCalculator(project).doIt();
	}

	private EnergyResult doIt() {

		maxBufferCapacity = Buffers.maxCapacity(project.heatNet);
		double bufferLossFactor = Buffers.lossFactor(project.heatNet);
		EnergyResult r = new EnergyResult(project);
		r.bufferCapacity[0] = maxBufferCapacity;
		boolean[][] interruptions = interruptions(r);

		for (int hour = 0; hour < Stats.HOURS; hour++) {

			double requiredLoad = r.loadCurve[hour];
			double bufferCapacity = r.bufferCapacity[hour];
			double maxLoad = requiredLoad + bufferCapacity;
			double bufferPotential = maxBufferCapacity - bufferCapacity;

			double suppliedPower = 0;
			for (int k = 0; k < r.producers.length; k++) {
				if (requiredLoad <= 0)
					break;

				Producer producer = r.producers[k];
				if (producer.function == ProducerFunction.PEAK_LOAD
						&& (bufferPotential >= requiredLoad)) {
					// prefer buffer heat instead of heat from peak load boilers
					break;
				}

				if (isInterrupted(k, hour, interruptions))
					continue;
				if (maxLoad < Producers.minPower(producer, hour))
					continue;

				double power = getSuppliedPower(producer, hour,
						requiredLoad, maxLoad);
				if (power > requiredLoad) {
					bufferCapacity -= (power - requiredLoad);
				}
				suppliedPower += power;
				maxLoad -= power;
				requiredLoad -= power;
				r.producerResults[k][hour] = power;

				if (bufferPotential >= requiredLoad) {
					// take rest from buffer
					break;
				}
			}

			if (requiredLoad >= 0 && bufferPotential > 0) {
				double bufferPower = requiredLoad;
				if (bufferPotential < requiredLoad) {
					bufferPower = bufferPotential;
				}
				suppliedPower += bufferPower;
				r.suppliedBufferHeat[hour] = bufferPower;
				bufferCapacity += bufferPower;
			}

			r.suppliedPower[hour] = suppliedPower;

			// buffer capacity with buffer loss
			bufferPotential = maxBufferCapacity - bufferCapacity;
			double bufferLoss = Buffers.loss(project.heatNet,
					bufferLossFactor, bufferPotential / maxBufferCapacity);
			r.bufferLoss[hour] = bufferLoss;
			bufferCapacity = bufferCapacity + bufferLoss;
			if (bufferCapacity > maxBufferCapacity) {
				bufferCapacity = maxBufferCapacity;
			}
			if ((hour + 1) < Stats.HOURS) {
				r.bufferCapacity[hour + 1] = bufferCapacity;
			}
		}

		calcTotals(r);

		return r;
	}

	private double getSuppliedPower(Producer producer, int hour,
			double requiredLoad, double maxLoad) {
		double bMin = Producers.minPower(producer, hour);
		double bMax = Producers.maxPower(producer, hour);
		double load = producer.function == ProducerFunction.PEAK_LOAD
				? requiredLoad
				: maxLoad;
		return Math.min(Math.max(load, bMin), bMax);
	}

	private void calcTotals(EnergyResult r) {
		r.totalLoad = Stats.sum(r.loadCurve);
		for (int i = 0; i < r.producers.length; i++) {
			Producer p = r.producers[i];
			double total = Stats.sum(r.producerResults[i]);
			r.totalHeats.put(p.id, total);
			r.totalProducedHeat += total;
		}<commit_msg>#66: implemented a summer mode<commit_after>package sophena.calc;

import sophena.math.energetic.Buffers;
import sophena.math.energetic.Producers;
import sophena.model.HoursTrace;
import sophena.model.Producer;
import sophena.model.ProducerFunction;
import sophena.model.Project;
import sophena.model.Stats;
import sophena.model.TimeInterval;

class EnergyCalculator {

	private Project project;

	private double maxBufferCapacity = 0;

	private EnergyCalculator(Project project) {
		this.project = project;
	}

	public static EnergyResult calculate(Project project) {
		return new EnergyCalculator(project).doIt();
	}

	private EnergyResult doIt() {

		maxBufferCapacity = Buffers.maxCapacity(project.heatNet);
		double bufferLossFactor = Buffers.lossFactor(project.heatNet);
		EnergyResult r = new EnergyResult(project);
		r.bufferCapacity[0] = maxBufferCapacity;
		boolean[][] interruptions = interruptions(r);

		boolean loadBuffer = false; // a flag for the summer mode

		for (int hour = 0; hour < Stats.HOURS; hour++) {

			double requiredLoad = r.loadCurve[hour];
			double bufferCapacity = r.bufferCapacity[hour];
			double maxLoad = requiredLoad + bufferCapacity;
			double bufferPotential = maxBufferCapacity - bufferCapacity;

			double suppliedPower = 0;

			boolean isSummerMode = r.producers.length > 0
					&& requiredLoad < Producers.minPower(r.producers[0], hour);
			if (isSummerMode && (bufferPotential / maxBufferCapacity) > 0.9) {
				// set the load `loadBuffer` flag to false when the buffer is
				// full; because of buffer loss it may is never really full so
				// we set some arbitrary cutoff for now.
				loadBuffer = false;
			}

			for (int k = 0; k < r.producers.length; k++) {
				if (requiredLoad <= 0)
					break;

				Producer producer = r.producers[k];

				if (bufferPotential >= requiredLoad) {
					// the required load can be fully taken from the buffer.
					// we do not take any producer when we are in summer mode.
					// and no peak load producer in this case
					if (isSummerMode && !loadBuffer)
						break;
					if (producer.function == ProducerFunction.PEAK_LOAD)
						continue;
				}

				if (isSummerMode) {
					loadBuffer = true;
				}

				// check whether the producer can be taken
				if (isInterrupted(k, hour, interruptions))
					continue;
				if (maxLoad < Producers.minPower(producer, hour))
					continue;

				double power = getSuppliedPower(producer, hour,
						requiredLoad, maxLoad);
				if (power > requiredLoad) {
					bufferCapacity -= (power - requiredLoad);
				}
				suppliedPower += power;
				maxLoad -= power;
				requiredLoad -= power;
				r.producerResults[k][hour] = power;

				if (bufferPotential >= requiredLoad) {
					// take rest from buffer
					break;
				}
			} // end producer loop

			if (requiredLoad >= 0 && bufferPotential > 0) {
				double bufferPower = requiredLoad;
				if (bufferPotential < requiredLoad) {
					bufferPower = bufferPotential;
				}
				suppliedPower += bufferPower;
				r.suppliedBufferHeat[hour] = bufferPower;
				bufferCapacity += bufferPower;
			}

			r.suppliedPower[hour] = suppliedPower;

			// buffer capacity with buffer loss
			bufferPotential = maxBufferCapacity - bufferCapacity;
			double bufferLoss = Buffers.loss(project.heatNet,
					bufferLossFactor, bufferPotential / maxBufferCapacity);
			r.bufferLoss[hour] = bufferLoss;
			bufferCapacity = bufferCapacity + bufferLoss;
			if (bufferCapacity > maxBufferCapacity) {
				bufferCapacity = maxBufferCapacity;
			}
			if ((hour + 1) < Stats.HOURS) {
				r.bufferCapacity[hour + 1] = bufferCapacity;
			}

		} // end hour loop

		calcTotals(r);

		return r;
	}

	private double getSuppliedPower(Producer producer, int hour,
			double requiredLoad, double maxLoad) {
		double bMin = Producers.minPower(producer, hour);
		double bMax = Producers.maxPower(producer, hour);
		double load = producer.function == ProducerFunction.PEAK_LOAD
				? requiredLoad
				: maxLoad;
		return Math.min(Math.max(load, bMin), bMax);
	}

	private void calcTotals(EnergyResult r) {
		r.totalLoad = Stats.sum(r.loadCurve);
		for (int i = 0; i < r.producers.length; i++) {
			Producer p = r.producers[i];
			double total = Stats.sum(r.producerResults[i]);
			r.totalHeats.put(p.id, total);
			r.totalProducedHeat += total;
		}
{'fraction_non_alphanumeric': 0.10458856703409382, 'fraction_numerical': 0.0035888233786208665, 'mean_word_length': 3.6171597633136097, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '13972', 'n_tokens_mistral': 2951, 'n_tokens_neox': 2356, 'n_words': 609}