oop-labs-collection/labs/6/Main.java

451 lines
14 KiB
Java

/*
* %W% %E% Dymik739
* Email: dymik739@109.86.70.81
*
* Copyright (C) 2023 FIOT Dev Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import java.util.Arrays;
/**
* Main class that controls all the devices and regulates vent power.
*
* @author Dymik739
* @since 0.3
*/
public class Main {
/**
* Defines the ServerRack power consumption at which the vent
* power is enabled.
*/
private static final float VENT_START_POWER = 240f;
/**
* Defines the ServerRack power consumption at which the vent
* power is disabled.
*/
private static final float VENT_STOP_POWER = 185f;
/** Defines magic number for real-time TTY output mode */
private static final int TTY_LIVE_MONITORING_MODE = 0;
/**
* Defines magic number for raw graph output mode for current
* power consumption and vent RPM
*/
private static final int POWER_RPM_GRAPH_MODE = 1;
/** Defines magic number for raw graph output mode for total consumption */
private static final int TOTAL_CONSUMPTION_GRAPH_MODE = 2;
/**
* Defines magic number for raw graph output mode for vent rpm and
* power consumption relation
*/
private static final int VENT_POWER_RPM_GRAPH_MODE = 1;
/** Defines the amount of simulation samples to get per every second */
private static final int TICKS_PER_SECOND = 960;
/** Defines the time simulation will run for (in seconds) */
private static final int SIMULATION_TIME = 240;
/**
* Main method for containing the devices, performing all
* checks and controlling power supply to all the appliances.
*
* @param args accepts CLI arguments.
*/
public static void main(String[] args) {
float ventConsumed = 0f;
float totalPowerConsumed = 0f;
int outputMode = parseMode(args);
int liveStatsOutputDelay = parseOutputDelay(args);
float[] searchRange = parseSearchRange(args);
Vent vent = new Vent(false); // defining vent as a special appliance
Appliance[] devices = {
new ServerRack(false),
new ServerRack(false),
new RPI(false),
new Dishwasher(false)
};
devices[2].plug(); // turning on RPI right away
// (RPI stands for Raspberry Pi)
// letting the simulation run
for (int i = 1; i <= SIMULATION_TIME*TICKS_PER_SECOND; i++) {
step(vent, devices, (float) 1/TICKS_PER_SECOND); // stepping time
// performing accounting
ventConsumed += vent.getPowerConsumption() / TICKS_PER_SECOND;
totalPowerConsumed += getTotalPowerConsumption(vent, devices)
/ TICKS_PER_SECOND / 3600;
// outputting the data in the desired format
if (outputMode == TTY_LIVE_MONITORING_MODE) {
System.out.print("Time: " + floatFormat((float)i/TICKS_PER_SECOND, 2, 2)
+ "; " + getStats(vent, devices) + "; vent avg = "
+ floatFormat(ventConsumed/TICKS_PER_SECOND/i, 4, 1)
+ "W; total = "
+ floatFormat(totalPowerConsumed, 4, 3) + "W\r");
} else if (outputMode == POWER_RPM_GRAPH_MODE) {
System.out.println(getTotalPowerConsumption(vent, devices)
+ " " + vent.getRPM()/10);
} else if (outputMode == TOTAL_CONSUMPTION_GRAPH_MODE) {
System.out.println(totalPowerConsumed);
} else if (outputMode == VENT_POWER_RPM_GRAPH_MODE) {
System.out.println(vent.getRPM()/10 + " "
+ vent.getPowerConsumption());
}
adjustVentPower(devices, vent);
managePower(i, devices);
if ((outputMode == TTY_LIVE_MONITORING_MODE)
&& (liveStatsOutputDelay != 0)) {
try {
Thread.sleep(liveStatsOutputDelay);
} catch (Exception e) {
System.exit(0);
}
}
}
if (outputMode == TTY_LIVE_MONITORING_MODE) {
Appliance[] totalDevices = new Appliance[devices.length + 1];
for (int i = 0; i < devices.length; i++) {
totalDevices[i] = devices[i];
}
totalDevices[devices.length] = vent;
System.out.println("\nCurrently devices draw "
+ floatFormat(getTotalPowerConsumption(totalDevices), 4, 2)
+ "W from the power lines.");
Arrays.sort(totalDevices);
System.out.println("\nArray of appliances, sorted by the power "
+ "consumption:");
printAppliances(totalDevices);
Appliance[] foundItems = filterByRadiation(totalDevices, searchRange);
if (foundItems.length == 0) {
System.out.println("\nCould not find any devices that match "
+ "your request (" + searchRange[0] + "-"
+ searchRange[1] + ").");
} else {
System.out.println("\nFound items:");
printAppliances(foundItems);
}
}
}
/**
* Method which decides on how to manage the vent power supply.
* It looks at power consumption of every ServerRack device
* and:
* - turns the vent on if ANY of them meet the VENT_START_POWER threshold
* - turns the vent off if ALL of them meet the VENT_STOP_POWER threshold
*
* @param devices list of devices to look at.
* @param vent vent to manage power for.
*/
public static void adjustVentPower(Appliance[] devices, Vent vent) {
for (Appliance i : devices) {
if ("ServerRack".equals(i.getType())
&& (i.getPowerConsumption() > VENT_START_POWER)) {
vent.plug();
return;
}
}
for (Appliance i : devices) {
if ("ServerRack".equals(i.getType())
&& !(i.getPowerConsumption() < VENT_STOP_POWER)) {
return;
}
}
vent.unplug();
}
/**
* Method that plugs in and out the devices in a predefined manner.
*
* @param i current simulation time.
* @param devices device list to control.
*/
public static void managePower(int i, Appliance[] devices) {
if (i == 25 * TICKS_PER_SECOND) {
devices[1].plug();
} else if (i == 35 * TICKS_PER_SECOND) {
devices[0].plug();
} else if (i == 50 * TICKS_PER_SECOND) {
devices[0].unplug();
} else if (i == 60 * TICKS_PER_SECOND) {
devices[3].plug();
} else if (i == 130 * TICKS_PER_SECOND) {
devices[0].plug();
}
}
/**
* Method for printing out a gives array of appliances.
*
* @param devices appliance array to print out.
*/
public static void printAppliances(Appliance[] devices) {
for (Appliance i : devices) {
System.out.println(i);
}
}
/**
* Method for selecting devices based on their radiation levels.
*
* @param totalDevices devices to select from
* @param searchRange search boundaries
*
* @return Appliance array containing found items
*/
public static Appliance[] filterByRadiation(Appliance[] totalDevices, float[] searchRange) {
int l = -1;
int r = totalDevices.length;
boolean barrierFound;
barrierFound = false;
for (int i = totalDevices.length-1; i >= 0; i--) {
if (totalDevices[i].getRadiationAmount() < searchRange[0]) {
l = i;
barrierFound = true;
break;
}
}
if (!barrierFound) {
l = -1;
}
barrierFound = false;
for (int i = 0; i < totalDevices.length; i++) {
if (totalDevices[i].getRadiationAmount() > searchRange[1]) {
r = i;
barrierFound = true;
break;
}
}
if (!barrierFound) {
r = totalDevices.length;
}
if (l < -1 || l >= totalDevices.length || l >= r
|| r < 1 || r >= totalDevices.length + 1 || (r-l) == 1) {
Appliance[] foundItems = new Appliance[0];
return foundItems;
} else {
Appliance[] foundItems = new Appliance[r-l-1];
for (int i = l+1; i < r; i++) {
foundItems[i-l-1] = totalDevices[i];
}
return foundItems;
}
}
/**
* Method for extracting output mode setting set from CLI.
*
* @param args CLI args array to use.
*
* @return int representing requested mode.
*/
public static int parseMode(String[] args) {
for (String i : args) {
if ("--power-rpm-graph".equals(i)) {
return POWER_RPM_GRAPH_MODE;
} else if ("--total-consumption-graph".equals(i)) {
return TOTAL_CONSUMPTION_GRAPH_MODE;
} else if ("--vent-monitoring-graph".equals(i)) {
return VENT_POWER_RPM_GRAPH_MODE;
}
}
return TTY_LIVE_MONITORING_MODE;
}
/**
* Method for extracting output delay setting set from CLI.
*
* @param args CLI args array to use.
*
* @return delay in miliseconds.
*/
public static int parseOutputDelay(String[] args) {
for (int i = 0; i < args.length; i++) {
if ("--output-delay".equals(args[i])) {
return Integer.parseInt(args[i+1]);
}
}
return (int) (1000 / TICKS_PER_SECOND);
}
/**
* Method for extracting output delay setting set from CLI.
*
* @param args CLI args array to use.
*
* @return delay in miliseconds.
*/
public static float[] parseSearchRange(String[] args) {
for (int i = 0; i < args.length; i++) {
if ("--search".equals(args[i])) {
String[] rawParams = args[i+1].split("-");
float[] bakedParams = new float[2];
for (int j = 0; j < 2; j++) {
bakedParams[j] = Float.parseFloat(rawParams[j]);
}
return bakedParams;
}
}
float[] bakedParams = {0f, 0f};
return bakedParams;
}
/**
* Method for performing the simulation. Runs the respective .step()
* methods on all of the given appliances.
*
* @param vent vent object to process
* @param devices devices array to process
* @param seconds delta time to move forward.
*/
public static void step(Vent vent, Appliance[] devices, float seconds) {
vent.step(seconds);
for (Appliance i : devices) {
i.step(seconds, vent.getRPM());
}
}
/**
* Method for collecting the overall usage statistics to make it
* easy to output status line during TTY mode execution.
*
* @param vent vent object to track
* @param devices devices array to track
*
* @return String containing current stats for all the devices
*/
public static String getStats(Vent vent, Appliance[] devices) {
float[] powerConsumption = new float[devices.length];
float totalPowerConsumption = 0;
for (int i = 0; i < devices.length; i++) {
powerConsumption[i] = devices[i].getPowerConsumption();
totalPowerConsumption += devices[i].getPowerConsumption();
}
String result = "PPD: ";
for (float i : powerConsumption) {
result += String.format(floatFormat(i, 3, 1) + "W ");
}
float powerLinesDraw = totalPowerConsumption
+ vent.getPowerConsumption();
result += "; Vent: " + floatFormat(vent.getPowerConsumption(), 3, 1)
+ "W, " + floatFormat(vent.getRPM(), 5, 0)
+ " RPM; Total power: " + floatFormat(powerLinesDraw, 4, 1)
+ "W";
return result;
}
/**
* Overloaded method for calculating the total power consumption
* (devices + the vent).
*
* @param vent vent to account
* @param devices array of devices to account
*
* @return sum of all the .getPowerConsumption() returned from devices
*/
public static float getTotalPowerConsumption(Vent vent,
Appliance[] devices) {
float result = vent.getPowerConsumption();
for (Appliance a : devices) {
result += a.getPowerConsumption();
}
return result;
}
/**
* Overloaded method for calculating the total power consumption
* (devices only).
*
* @param devices array of devices to account
*
* @return sum of all the .getPowerConsumption() returned from devices
*/
public static float getTotalPowerConsumption(Appliance[] devices) {
float result = 0;
for (Appliance a : devices) {
result += a.getPowerConsumption();
}
return result;
}
/**
* Custom method which adds the support for arbitrary formatting of float
* numbers.
*
* @param num value to format
* @param leading amount of digits before period to print
* @param trailing amount of digits after perio to print
*
* @return String with formatted result
*/
public static String floatFormat(float num, int leading, int trailing) {
String newNum = String.format("%0" + leading + "." + trailing + "f", num);
int targetLength = leading + trailing + 1;
for (int i = newNum.length(); i < targetLength; i++) {
newNum = "0" + newNum;
}
return newNum;
}
}