<commit_before>/*
 * JaamSim Discrete Event Simulation
 * Copyright (C) 2013 Ausenco Engineering Canada Inc.
 * Copyright (C) 2016 JaamSim Software Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jaamsim.ProcessFlow;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import com.jaamsim.Graphics.DisplayEntity;
import com.jaamsim.ProbabilityDistributions.Distribution;
import com.jaamsim.Samples.SampleConstant;
import com.jaamsim.Samples.SampleInput;
import com.jaamsim.Samples.TimeSeries;
import com.jaamsim.basicsim.Entity;
import com.jaamsim.datatypes.DoubleVector;
import com.jaamsim.events.Conditional;
import com.jaamsim.events.EventManager;
import com.jaamsim.events.ProcessTarget;
import com.jaamsim.input.BooleanInput;
import com.jaamsim.input.InputErrorException;
import com.jaamsim.input.Keyword;
import com.jaamsim.input.Output;
import com.jaamsim.units.DimensionlessUnit;
import com.jaamsim.units.TimeUnit;

public class Resource extends DisplayEntity {

	@Keyword(description = "The number of equivalent resource units that are available.\n"
	                     + "If the capacity changes during the simulation run, the Resource will "
	                     + "attempt to use an increase in capacity as soon as it occurs. "
	                     + "However, a decrease in capacity will have no affect on entities that "
	                     + "have already seized Resource capacity.",
	         exampleList = {"3", "TimeSeries1", "this.attrib1"})
	private final SampleInput capacity;

	@Keyword(description = "If TRUE, the next entity to seize the resource will be chosen "
	                     + "strictly on the basis of priority and waiting time. If this entity "
	                     + "is unable to seize the resource because of other restrictions such as "
	                     + "an OperatingThreshold input or the unavailability of other resources "
	                     + "it needs to seize at the same time, then other entities with lower "
	                     + "priority or shorter waiting time will NOT be allowed to seize the "
	                     + "resource. If FALSE, the entities will be tested in the same order of "
	                     + "priority and waiting time, but the first entity that is able to seize "
	                     + "the resource will be allowed to do so.",
	         exampleList = {"TRUE"})
	private final BooleanInput strictOrder;

	private int unitsInUse;  // number of resource units that are being used at present
	private ArrayList<ResourceUser> userList;  // objects that seize this resource
	private int lastCapacity; // capacity for the resource

	//	Statistics
	protected double timeOfLastUpdate; // time at which the statistics were last updated
	protected double startOfStatisticsCollection; // time at which statistics collection was started
	protected int minUnitsInUse; // minimum observed number of units in use
	protected int maxUnitsInUse; // maximum observed number of units in use
	protected double unitSeconds;  // total time that units have been used
	protected double squaredUnitSeconds;  // total time for the square of the number of units in use
	protected int unitsSeized;    // number of units that have been seized
	protected int unitsReleased;  // number of units that have been released
	protected DoubleVector unitsInUseDist;  // entry at position n is the total time that n units have been in use

	{
		attributeDefinitionList.setHidden(false);

		capacity = new SampleInput("Capacity", "Key Inputs", new SampleConstant(1.0));
		capacity.setUnitType(DimensionlessUnit.class);
		capacity.setEntity(this);
		capacity.setValidRange(0, Double.POSITIVE_INFINITY);
		this.addInput(capacity);

		strictOrder = new BooleanInput("StrictOrder", "Key Inputs", false);
		this.addInput(strictOrder);
	}

	public Resource() {
		unitsInUseDist = new DoubleVector();
		userList = new ArrayList<>();
	}

	@Override
	public void validate() {

		boolean found = false;
		for (Entity ent : Entity.getClonesOfIterator(Entity.class, ResourceUser.class)) {
			ResourceUser ru = (ResourceUser) ent;
			if (ru.requiresResource(this))
				found = true;
		}
		if (!found)
			throw new InputErrorException( "At least one object must seize this resource." );

		if( capacity.getValue() instanceof Distribution )
			throw new InputErrorException( "The Capacity keyword cannot accept a probability distribution.");
	}

	@Override
	public void earlyInit() {
		super.earlyInit();

		unitsInUse = 0;
		lastCapacity = this.getCapacity(0.0d);

		// Clear statistics
		startOfStatisticsCollection = 0.0;
		timeOfLastUpdate = 0.0;
		minUnitsInUse = 0;
		maxUnitsInUse = 0;
		unitSeconds = 0.0;
		squaredUnitSeconds = 0.0;
		unitsSeized = 0;
		unitsReleased = 0;
		unitsInUseDist.clear();

		// Prepare a list of the objects that seize this resource
		userList.clear();
		for (Entity ent : Entity.getClonesOfIterator(Entity.class, ResourceUser.class)) {
			ResourceUser ru = (ResourceUser) ent;
			if (ru.requiresResource(this))
				userList.add(ru);
		}
	}

	@Override
	public void startUp() {
		super.startUp();

		if (capacity.getValue() instanceof SampleConstant)
			return;

		// Track any changes in the Resource's capacity
		this.waitForCapacityChange();
	}

	/**
	 * Seize the given number of units from the resource.
	 * @param n = number of units to seize
	 */
	public void seize(int n) {
		this.updateStatistics(unitsInUse, unitsInUse+n);
		unitsInUse += n;
		unitsSeized += n;
	}

	/**
	 * Release the given number of units back to the resource.
	 * @param n = number of units to release
	 */
	public void release(int m) {
		int n = Math.min(m, unitsInUse);
		this.updateStatistics(unitsInUse, unitsInUse-n);
		unitsInUse -= n;
		unitsReleased += n;
	}<commit_msg>JS: check capacity when seizing a Resource<commit_after>/*
 * JaamSim Discrete Event Simulation
 * Copyright (C) 2013 Ausenco Engineering Canada Inc.
 * Copyright (C) 2016 JaamSim Software Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.jaamsim.ProcessFlow;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import com.jaamsim.Graphics.DisplayEntity;
import com.jaamsim.ProbabilityDistributions.Distribution;
import com.jaamsim.Samples.SampleConstant;
import com.jaamsim.Samples.SampleInput;
import com.jaamsim.Samples.TimeSeries;
import com.jaamsim.basicsim.Entity;
import com.jaamsim.datatypes.DoubleVector;
import com.jaamsim.events.Conditional;
import com.jaamsim.events.EventManager;
import com.jaamsim.events.ProcessTarget;
import com.jaamsim.input.BooleanInput;
import com.jaamsim.input.InputErrorException;
import com.jaamsim.input.Keyword;
import com.jaamsim.input.Output;
import com.jaamsim.units.DimensionlessUnit;
import com.jaamsim.units.TimeUnit;

public class Resource extends DisplayEntity {

	@Keyword(description = "The number of equivalent resource units that are available.\n"
	                     + "If the capacity changes during the simulation run, the Resource will "
	                     + "attempt to use an increase in capacity as soon as it occurs. "
	                     + "However, a decrease in capacity will have no affect on entities that "
	                     + "have already seized Resource capacity.",
	         exampleList = {"3", "TimeSeries1", "this.attrib1"})
	private final SampleInput capacity;

	@Keyword(description = "If TRUE, the next entity to seize the resource will be chosen "
	                     + "strictly on the basis of priority and waiting time. If this entity "
	                     + "is unable to seize the resource because of other restrictions such as "
	                     + "an OperatingThreshold input or the unavailability of other resources "
	                     + "it needs to seize at the same time, then other entities with lower "
	                     + "priority or shorter waiting time will NOT be allowed to seize the "
	                     + "resource. If FALSE, the entities will be tested in the same order of "
	                     + "priority and waiting time, but the first entity that is able to seize "
	                     + "the resource will be allowed to do so.",
	         exampleList = {"TRUE"})
	private final BooleanInput strictOrder;

	private int unitsInUse;  // number of resource units that are being used at present
	private ArrayList<ResourceUser> userList;  // objects that seize this resource
	private int lastCapacity; // capacity for the resource

	//	Statistics
	protected double timeOfLastUpdate; // time at which the statistics were last updated
	protected double startOfStatisticsCollection; // time at which statistics collection was started
	protected int minUnitsInUse; // minimum observed number of units in use
	protected int maxUnitsInUse; // maximum observed number of units in use
	protected double unitSeconds;  // total time that units have been used
	protected double squaredUnitSeconds;  // total time for the square of the number of units in use
	protected int unitsSeized;    // number of units that have been seized
	protected int unitsReleased;  // number of units that have been released
	protected DoubleVector unitsInUseDist;  // entry at position n is the total time that n units have been in use

	{
		attributeDefinitionList.setHidden(false);

		capacity = new SampleInput("Capacity", "Key Inputs", new SampleConstant(1.0));
		capacity.setUnitType(DimensionlessUnit.class);
		capacity.setEntity(this);
		capacity.setValidRange(0, Double.POSITIVE_INFINITY);
		this.addInput(capacity);

		strictOrder = new BooleanInput("StrictOrder", "Key Inputs", false);
		this.addInput(strictOrder);
	}

	public Resource() {
		unitsInUseDist = new DoubleVector();
		userList = new ArrayList<>();
	}

	@Override
	public void validate() {

		boolean found = false;
		for (Entity ent : Entity.getClonesOfIterator(Entity.class, ResourceUser.class)) {
			ResourceUser ru = (ResourceUser) ent;
			if (ru.requiresResource(this))
				found = true;
		}
		if (!found)
			throw new InputErrorException( "At least one object must seize this resource." );

		if( capacity.getValue() instanceof Distribution )
			throw new InputErrorException( "The Capacity keyword cannot accept a probability distribution.");
	}

	@Override
	public void earlyInit() {
		super.earlyInit();

		unitsInUse = 0;
		lastCapacity = this.getCapacity(0.0d);

		// Clear statistics
		startOfStatisticsCollection = 0.0;
		timeOfLastUpdate = 0.0;
		minUnitsInUse = 0;
		maxUnitsInUse = 0;
		unitSeconds = 0.0;
		squaredUnitSeconds = 0.0;
		unitsSeized = 0;
		unitsReleased = 0;
		unitsInUseDist.clear();

		// Prepare a list of the objects that seize this resource
		userList.clear();
		for (Entity ent : Entity.getClonesOfIterator(Entity.class, ResourceUser.class)) {
			ResourceUser ru = (ResourceUser) ent;
			if (ru.requiresResource(this))
				userList.add(ru);
		}
	}

	@Override
	public void startUp() {
		super.startUp();

		if (capacity.getValue() instanceof SampleConstant)
			return;

		// Track any changes in the Resource's capacity
		this.waitForCapacityChange();
	}

	/**
	 * Seize the given number of units from the resource.
	 * @param n = number of units to seize
	 */
	public void seize(int n) {
		this.updateStatistics(unitsInUse, unitsInUse+n);
		unitsInUse += n;
		unitsSeized += n;
		if (getAvailableUnits(getSimTime()) < 0) {
			error("Capacity of resource exceeded. Capacity: %s, units in use: %s.",
					getCapacity(getSimTime()), unitsInUse);
		}
	}

	/**
	 * Release the given number of units back to the resource.
	 * @param n = number of units to release
	 */
	public void release(int m) {
		int n = Math.min(m, unitsInUse);
		this.updateStatistics(unitsInUse, unitsInUse-n);
		unitsInUse -= n;
		unitsReleased += n;
	}
{'fraction_non_alphanumeric': 0.08322923173016865, 'fraction_numerical': 0.005231105559025609, 'mean_word_length': 3.4677363097314267, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, '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': '5521350', 'n_tokens_mistral': 3737, 'n_tokens_neox': 3428, 'n_words': 1313}