use of org.concord.energy3d.model.SolarPanel in project energy3d by concord-consortium.
the class SolarRadiation method computeEnergyAtHour.
public void computeEnergyAtHour(final int hour) {
final Calendar today = Heliodon.getInstance().getCalendar();
final String city = (String) EnergyPanel.getInstance().getCityComboBox().getSelectedItem();
final double[] outsideAirTemperatureRange = Weather.computeOutsideTemperature(today, city);
final double outsideAirTemperature = Weather.getInstance().getOutsideTemperatureAtMinute(outsideAirTemperatureRange[1], outsideAirTemperatureRange[0], hour * 60);
for (final HousePart part : Scene.getInstance().getParts()) {
if (part instanceof Foundation) {
final Foundation foundation = (Foundation) part;
if (foundation.getHeatLoss() == null) {
continue;
}
final int n = (int) Math.round(60.0 / Scene.getInstance().getTimeStep());
final double[] heatLoss = new double[n];
final double[] passiveSolar = new double[n];
final double[] photovoltaic = new double[n];
final double[] csp = new double[n];
final int t0 = n * hour;
for (int i = 0; i < n; i++) {
final double groundHeatLoss = foundation.getHeatLoss()[t0 + i];
if (groundHeatLoss > 0) {
final double thermostat = foundation.getThermostat().getTemperature(today.get(Calendar.MONTH), today.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY, today.get(Calendar.HOUR_OF_DAY));
if (outsideAirTemperature >= thermostat) {
heatLoss[i] -= groundHeatLoss;
}
} else {
heatLoss[i] += groundHeatLoss;
}
}
double solarPotentialTotal = 0.0;
for (final HousePart child : Scene.getInstance().getParts()) {
if (child.getTopContainer() == foundation) {
child.setSolarPotentialNow(0);
if (child instanceof SolarCollector) {
((SolarCollector) child).setYieldNow(0);
}
for (int i = 0; i < n; i++) {
solarPotentialTotal += child.getSolarPotential()[t0 + i];
child.setSolarPotentialNow(child.getSolarPotentialNow() + child.getSolarPotential()[t0 + i]);
if (child instanceof Wall || child instanceof Door || child instanceof Window || child instanceof Roof) {
heatLoss[i] += child.getHeatLoss()[t0 + i];
}
if (child instanceof Window) {
final Window window = (Window) child;
passiveSolar[i] += window.getSolarPotential()[t0 + i] * window.getSolarHeatGainCoefficient();
} else if (child instanceof Mirror) {
final Mirror mirror = (Mirror) child;
final double yield = mirror.getSolarPotential()[t0 + i] * mirror.getSystemEfficiency();
csp[i] += yield;
mirror.setYieldNow(mirror.getYieldNow() + yield);
} else if (child instanceof ParabolicTrough) {
final ParabolicTrough trough = (ParabolicTrough) child;
final double yield = trough.getSolarPotential()[t0 + i] * trough.getSystemEfficiency();
csp[i] += yield;
trough.setYieldNow(trough.getYieldNow() + yield);
} else if (child instanceof ParabolicDish) {
final ParabolicDish dish = (ParabolicDish) child;
final double yield = dish.getSolarPotential()[t0 + i] * dish.getSystemEfficiency();
csp[i] += yield;
dish.setYieldNow(dish.getYieldNow() + yield);
} else if (child instanceof FresnelReflector) {
final FresnelReflector reflector = (FresnelReflector) child;
final double yield = reflector.getSolarPotential()[t0 + i] * reflector.getSystemEfficiency();
csp[i] += yield;
reflector.setYieldNow(reflector.getYieldNow() + yield);
} else if (child instanceof SolarPanel) {
final SolarPanel sp = (SolarPanel) child;
// distributed efficiency must be handled for each individual cell
final double yield = sp.getSolarPotential()[t0 + i];
photovoltaic[i] += yield;
sp.setYieldNow(sp.getYieldNow() + yield);
} else if (child instanceof Rack) {
final Rack rack = (Rack) child;
if (rack.isMonolithic()) {
// distributed efficiency must be handled for each individual cell
final double yield = rack.getSolarPotential()[t0 + i];
photovoltaic[i] += yield;
rack.setYieldNow(rack.getYieldNow() + yield);
}
}
}
}
}
double heatingTotal = 0.0;
double coolingTotal = 0.0;
double passiveSolarTotal = 0.0;
double photovoltaicTotal = 0.0;
double cspTotal = 0.0;
for (int i = 0; i < n; i++) {
if (heatLoss[i] < 0) {
heatLoss[i] -= passiveSolar[i];
} else {
heatLoss[i] = Math.max(0, heatLoss[i] - passiveSolar[i]);
}
if (heatLoss[i] > 0) {
heatingTotal += heatLoss[i];
} else {
coolingTotal -= heatLoss[i];
}
passiveSolarTotal += passiveSolar[i];
photovoltaicTotal += photovoltaic[i];
cspTotal += csp[i];
}
foundation.setSolarPotentialNow(solarPotentialTotal);
foundation.setPassiveSolarNow(passiveSolarTotal);
foundation.setPhotovoltaicNow(photovoltaicTotal);
foundation.setCspNow(cspTotal);
foundation.setHeatingNow(heatingTotal);
foundation.setCoolingNow(coolingTotal);
foundation.setTotalEnergyNow(heatingTotal + coolingTotal - photovoltaicTotal);
}
}
}
use of org.concord.energy3d.model.SolarPanel in project energy3d by concord-consortium.
the class SolarRadiation method computeOnRack.
// TODO: we probably should handle the radiation heat map visualization on the rack using a coarse grid and the energy calculation using a fine grid
private void computeOnRack(final int minute, final ReadOnlyVector3 directionTowardSun, final Rack rack) {
if (rack.getTracker() != SolarPanel.NO_TRACKER) {
final Calendar calendar = Heliodon.getInstance().getCalendar();
calendar.set(Calendar.HOUR_OF_DAY, (int) ((double) minute / (double) SolarRadiation.MINUTES_OF_DAY * 24.0));
calendar.set(Calendar.MINUTE, minute % 60);
rack.draw();
}
if (!rack.isMonolithic()) {
return;
}
final ReadOnlyVector3 normal = rack.getNormal();
if (normal == null) {
throw new RuntimeException("Normal is null");
}
int nx = Scene.getInstance().getRackNx();
int ny = Scene.getInstance().getRackNy();
final Mesh drawMesh = rack.getRadiationMesh();
final Mesh collisionMesh = (Mesh) rack.getRadiationCollisionSpatial();
MeshDataStore data = onMesh.get(drawMesh);
if (data == null) {
data = initMeshTextureDataOnRectangle(drawMesh, nx, ny);
}
final ReadOnlyVector3 offset = directionTowardSun.multiply(1, null);
final double dot = normal.dot(directionTowardSun);
double directRadiation = 0;
if (dot > 0) {
directRadiation += calculateDirectRadiation(directionTowardSun, normal);
}
final double indirectRadiation = calculateDiffuseAndReflectedRadiation(directionTowardSun, normal);
final FloatBuffer vertexBuffer = drawMesh.getMeshData().getVertexBuffer();
// (0, 0)
final Vector3 p0 = new Vector3(vertexBuffer.get(3), vertexBuffer.get(4), vertexBuffer.get(5));
// (1, 0)
final Vector3 p1 = new Vector3(vertexBuffer.get(6), vertexBuffer.get(7), vertexBuffer.get(8));
// (0, 1)
final Vector3 p2 = new Vector3(vertexBuffer.get(0), vertexBuffer.get(1), vertexBuffer.get(2));
// this is the longer side (supposed to be y)
final double d10 = p1.distance(p0);
// this is the shorter side (supposed to be x)
final double d20 = p2.distance(p0);
final Vector3 p10 = p1.subtract(p0, null).normalizeLocal();
final Vector3 p20 = p2.subtract(p0, null).normalizeLocal();
// generate the heat map first. this doesn't affect the energy calculation, it just shows the distribution of solar radiation on the rack.
// x and y must be swapped to have correct heat map texture, because nx represents rows and ny columns as we call initMeshTextureDataOnRectangle(mesh, nx, ny)
double xSpacing = d10 / nx;
double ySpacing = d20 / ny;
Vector3 u = p10;
Vector3 v = p20;
final int iMinute = minute / Scene.getInstance().getTimeStep();
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
if (EnergyPanel.getInstance().isCancelled()) {
throw new CancellationException();
}
final Vector3 u2 = u.multiply(xSpacing * (x + 0.5), null);
final Vector3 v2 = v.multiply(ySpacing * (y + 0.5), null);
final ReadOnlyVector3 p = drawMesh.getWorldTransform().applyForward(p0.add(v2, null).addLocal(u2)).addLocal(offset);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
// assuming that indirect (ambient or diffuse) radiation can always reach a grid point
double radiation = indirectRadiation;
if (dot > 0) {
final PickResults pickResults = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != collisionMesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
break;
}
}
}
if (pickResults.getNumber() == 0) {
radiation += directRadiation;
}
}
data.dailySolarIntensity[x][y] += radiation;
}
}
// now do the calculation to get the total energy generated by the cells
final double airTemperature = Weather.getInstance().getOutsideTemperatureAtMinute(dailyAirTemperatures[1], dailyAirTemperatures[0], minute);
// system efficiency
double syseff;
// output at a cell center
double output;
// cell temperature
double tcell;
final SolarPanel panel = rack.getSolarPanel();
if (Scene.getInstance().isRackModelExact()) {
// exactly model each solar cell on each solar panel
final int[] rc = rack.getSolarPanelRowAndColumnNumbers();
// numbers of solar panels in x and y directions
final int nxPanels = rc[0];
final int nyPanels = rc[1];
// numbers of solar cells on each panel in x and y directions
int nxCells, nyCells;
if (panel.isRotated()) {
nxCells = panel.getNumberOfCellsInY();
nyCells = panel.getNumberOfCellsInX();
} else {
nxCells = panel.getNumberOfCellsInX();
nyCells = panel.getNumberOfCellsInY();
}
nx = nxCells * rc[0];
ny = nyCells * rc[1];
// get the area of a solar cell. 60 converts the unit of timeStep from minute to kWh
final double a = panel.getPanelWidth() * panel.getPanelHeight() * Scene.getInstance().getTimeStep() / (panel.getNumberOfCellsInX() * panel.getNumberOfCellsInY() * 60.0);
// swap the x and y back to correct order
xSpacing = d20 / nx;
ySpacing = d10 / ny;
u = p20;
v = p10;
if (cellOutputs == null || cellOutputs.length != nx || cellOutputs[0].length != ny) {
cellOutputs = new double[nx][ny];
}
// calculate the solar radiation first without worrying about the underlying cell wiring and distributed efficiency
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
if (EnergyPanel.getInstance().isCancelled()) {
throw new CancellationException();
}
final Vector3 u2 = u.multiply(xSpacing * (x + 0.5), null);
final Vector3 v2 = v.multiply(ySpacing * (y + 0.5), null);
final ReadOnlyVector3 p = drawMesh.getWorldTransform().applyForward(p0.add(v2, null).addLocal(u2)).addLocal(offset);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
// assuming that indirect (ambient or diffuse) radiation can always reach a grid point
double radiation = indirectRadiation;
if (dot > 0) {
final PickResults pickResults = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != collisionMesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
break;
}
}
}
if (pickResults.getNumber() == 0) {
radiation += directRadiation;
}
}
cellOutputs[x][y] = radiation * a;
}
}
// Tcell = Tair + (NOCT - 20) / 80 * R, where the unit of R is mW/cm^2
final double noctFactor = (panel.getNominalOperatingCellTemperature() - 20.0) * 100.0 / (a * 80.0);
// now consider cell wiring and distributed efficiency. TODO: This is very inaccurate. The output depends on both cell wiring and panel wiring.
switch(// the ideal case that probably doesn't exist in reality
panel.getShadeTolerance()) {
case SolarPanel.HIGH_SHADE_TOLERANCE:
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
output = cellOutputs[x][y];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
rack.getSolarPotential()[iMinute] += output * syseff;
}
}
break;
case // assuming that all the cells on a panel are connected in series and all panels are connected in parallel
SolarPanel.NO_SHADE_TOLERANCE:
double min = Double.MAX_VALUE;
for (int ix = 0; ix < nxPanels; ix++) {
// panel by panel
for (int iy = 0; iy < nyPanels; iy++) {
min = Double.MAX_VALUE;
for (int jx = 0; jx < nxCells; jx++) {
// cell by cell on each panel
for (int jy = 0; jy < nyCells; jy++) {
output = cellOutputs[ix * nxCells + jx][iy * nyCells + jy];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
}
rack.getSolarPotential()[iMinute] += min * nxCells * nyCells;
}
}
break;
case // assuming each panel uses a diode bypass to connect two columns of cells
SolarPanel.PARTIAL_SHADE_TOLERANCE:
for (int ix = 0; ix < nxPanels; ix++) {
// panel by panel
for (int iy = 0; iy < nyPanels; iy++) {
min = Double.MAX_VALUE;
if (panel.isRotated()) {
// landscape: nxCells = 10, nyCells = 6
for (int jy = 0; jy < nyCells; jy++) {
// cell by cell on each panel
if (jy % 2 == 0) {
// reset min every two columns of cells
min = Double.MAX_VALUE;
}
for (int jx = 0; jx < nxCells; jx++) {
output = cellOutputs[ix * nxCells + jx][iy * nyCells + jy];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
if (jy % 2 == 1) {
rack.getSolarPotential()[iMinute] += min * 2 * nxCells;
}
}
} else {
// portrait: nxCells = 6, nyCells = 10
for (int jx = 0; jx < nxCells; jx++) {
// cell by cell on each panel
if (jx % 2 == 0) {
// reset min every two columns of cells
min = Double.MAX_VALUE;
}
for (int jy = 0; jy < nyCells; jy++) {
output = cellOutputs[ix * nxCells + jx][iy * nyCells + jy];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
if (jx % 2 == 1) {
rack.getSolarPotential()[iMinute] += min * 2 * nyCells;
}
}
}
}
}
break;
}
} else {
// for simulation speed, approximate rack model doesn't compute panel by panel and cell by cell
ySpacing = xSpacing = Scene.getInstance().getRackCellSize() / Scene.getInstance().getAnnotationScale();
// swap the x and y back to correct order
nx = Math.max(2, (int) (d20 / xSpacing));
ny = Math.max(2, (int) (d10 / ySpacing));
// nx*ny*60: dividing the total rack area by nx*ny gets the unit cell area of the nx*ny grid; 60 converts the unit of timeStep from minute to kWh
final double a = rack.getRackWidth() * rack.getRackHeight() * Scene.getInstance().getTimeStep() / (nx * ny * 60.0);
u = p20;
v = p10;
if (cellOutputs == null || cellOutputs.length != nx || cellOutputs[0].length != ny) {
cellOutputs = new double[nx][ny];
}
// calculate the solar radiation first without worrying about the underlying cell wiring and distributed efficiency
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
if (EnergyPanel.getInstance().isCancelled()) {
throw new CancellationException();
}
final Vector3 u2 = u.multiply(xSpacing * (x + 0.5), null);
final Vector3 v2 = v.multiply(ySpacing * (y + 0.5), null);
final ReadOnlyVector3 p = drawMesh.getWorldTransform().applyForward(p0.add(v2, null).addLocal(u2)).addLocal(offset);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
// assuming that indirect (ambient or diffuse) radiation can always reach a grid point
double radiation = indirectRadiation;
if (dot > 0) {
final PickResults pickResults = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != collisionMesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
break;
}
}
}
if (pickResults.getNumber() == 0) {
radiation += directRadiation;
}
}
cellOutputs[x][y] = radiation * a;
}
}
// Tcell = Tair + (NOCT - 20) / 80 * R, where the unit of R is mW/cm^2
final double noctFactor = (panel.getNominalOperatingCellTemperature() - 20.0) * 100.0 / (a * 80.0);
// now consider cell wiring and distributed efficiency. TODO: This is very inaccurate. The output depends on both cell wiring and panel wiring.
switch(panel.getShadeTolerance()) {
case // the ideal case that probably doesn't exist in reality
SolarPanel.HIGH_SHADE_TOLERANCE:
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
output = cellOutputs[x][y];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
rack.getSolarPotential()[iMinute] += output * syseff;
}
}
break;
case SolarPanel.NO_SHADE_TOLERANCE:
double min = Double.MAX_VALUE;
for (int x = 0; x < nx; x++) {
for (int y = 0; y < ny; y++) {
output = cellOutputs[x][y];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
}
rack.getSolarPotential()[iMinute] += min * ny * nx;
break;
case SolarPanel.PARTIAL_SHADE_TOLERANCE:
for (int x = 0; x < nx; x++) {
min = Double.MAX_VALUE;
for (int y = 0; y < ny; y++) {
output = cellOutputs[x][y];
tcell = airTemperature + output * noctFactor;
syseff = panel.getSystemEfficiency(tcell);
output *= syseff;
if (output < min) {
min = output;
}
}
rack.getSolarPotential()[iMinute] += min * ny;
}
break;
}
}
}
use of org.concord.energy3d.model.SolarPanel in project energy3d by concord-consortium.
the class DataViewer method viewRawData.
static void viewRawData(final java.awt.Window parent, final Graph graph, final List<HousePart> selectedParts) {
if (selectedParts == null || selectedParts.isEmpty()) {
JOptionPane.showMessageDialog(MainFrame.getInstance(), "No part is selected.", "Error", JOptionPane.ERROR_MESSAGE);
return;
}
final ArrayList<String> headers = new ArrayList<String>();
if (graph instanceof PartEnergyDailyGraph) {
headers.add("Hour");
} else if (graph instanceof PartEnergyAnnualGraph) {
headers.add("Month");
}
for (final HousePart p : selectedParts) {
if (p instanceof SolarPanel || p instanceof Rack || p instanceof Mirror) {
headers.add("Solar " + p.getId());
} else if (p instanceof Wall || p instanceof Roof || p instanceof Door) {
headers.add("Heat Gain " + p.getId());
} else if (p instanceof Window) {
headers.add("Solar " + p.getId());
headers.add("Heat Gain " + p.getId());
} else if (p instanceof Foundation) {
final Foundation foundation = (Foundation) p;
switch(foundation.getProjectType()) {
case Foundation.TYPE_PV_PROJECT:
headers.add("PV " + p.getId());
break;
case Foundation.TYPE_CSP_PROJECT:
headers.add("CSP " + p.getId());
break;
case Foundation.TYPE_BUILDING:
headers.add("Building " + p.getId());
break;
}
}
}
final String[] headersArray = new String[headers.size()];
for (int i = 0; i < headersArray.length; i++) {
headersArray[i] = headers.get(i);
}
final int m = headersArray.length;
final int n = graph.getLength();
final Object[][] column = new Object[n][m + 1];
for (int i = 0; i < n; i++) {
column[i][0] = (i + 1);
}
for (int j = 1; j < m; j++) {
final List<Double> list = graph.getData(headersArray[j]);
for (int i = 0; i < n; i++) {
column[i][j] = list.get(i);
}
}
showDataWindow("Data", column, headersArray, parent);
}
use of org.concord.energy3d.model.SolarPanel in project energy3d by concord-consortium.
the class EnergyAnnualAnalysis method updateGraph.
@Override
public void updateGraph() {
final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
if (selectedPart instanceof Foundation) {
if (graph instanceof BuildingEnergyAnnualGraph) {
final Foundation selectedBuilding = (Foundation) selectedPart;
final double window = selectedBuilding.getPassiveSolarToday();
final double solarPanel = selectedBuilding.getPhotovoltaicToday();
final double heater = selectedBuilding.getHeatingToday();
final double ac = selectedBuilding.getCoolingToday();
final double net = selectedBuilding.getTotalEnergyToday();
graph.addData("Windows", window);
graph.addData("Solar Panels", solarPanel);
graph.addData("Heater", heater);
graph.addData("AC", ac);
graph.addData("Net", net);
} else {
graph.addData("Solar", selectedPart.getSolarPotentialToday());
}
} else if (selectedPart instanceof Window) {
final Window window = (Window) selectedPart;
final double solar = selectedPart.getSolarPotentialToday() * window.getSolarHeatGainCoefficient();
graph.addData("Solar", solar);
final double[] loss = selectedPart.getHeatLoss();
double sum = 0;
for (final double x : loss) {
sum += x;
}
graph.addData("Heat Gain", -sum);
} else if (selectedPart instanceof Wall || selectedPart instanceof Roof || selectedPart instanceof Door) {
final double[] loss = selectedPart.getHeatLoss();
double sum = 0;
for (final double x : loss) {
sum += x;
}
graph.addData("Heat Gain", -sum);
} else if (selectedPart instanceof SolarPanel) {
graph.addData("Solar", ((SolarPanel) selectedPart).getYieldToday());
} else if (selectedPart instanceof Rack) {
graph.addData("Solar", ((Rack) selectedPart).getYieldToday());
}
graph.repaint();
}
use of org.concord.energy3d.model.SolarPanel in project energy3d by concord-consortium.
the class EnergyDailyAnalysis method updateGraph.
@Override
public void updateGraph() {
final int n = (int) Math.round(60.0 / Scene.getInstance().getTimeStep());
for (int i = 0; i < 24; i++) {
SolarRadiation.getInstance().computeEnergyAtHour(i);
final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
if (selectedPart instanceof Foundation) {
if (graph instanceof BuildingEnergyDailyGraph) {
final Foundation selectedBuilding = (Foundation) selectedPart;
final double window = selectedBuilding.getPassiveSolarNow();
final double solarPanel = selectedBuilding.getPhotovoltaicNow();
final double heater = selectedBuilding.getHeatingNow();
final double ac = selectedBuilding.getCoolingNow();
final double net = selectedBuilding.getTotalEnergyNow();
graph.addData("Windows", window);
graph.addData("Solar Panels", solarPanel);
graph.addData("Heater", heater);
graph.addData("AC", ac);
graph.addData("Net", net);
} else {
graph.addData("Solar", selectedPart.getSolarPotentialNow());
}
} else if (selectedPart instanceof Window) {
final Window window = (Window) selectedPart;
final double solar = selectedPart.getSolarPotentialNow() * window.getSolarHeatGainCoefficient();
graph.addData("Solar", solar);
final double[] loss = selectedPart.getHeatLoss();
final int t0 = n * i;
double sum = 0;
for (int k = t0; k < t0 + n; k++) {
sum += loss[k];
}
graph.addData("Heat Gain", -sum);
} else if (selectedPart instanceof Wall || selectedPart instanceof Roof || selectedPart instanceof Door) {
final double solar = selectedPart.getSolarPotentialNow();
graph.addData("Solar", solar);
final double[] loss = selectedPart.getHeatLoss();
final int t0 = n * i;
double sum = 0;
for (int k = t0; k < t0 + n; k++) {
sum += loss[k];
}
graph.addData("Heat Gain", -sum);
} else if (selectedPart instanceof SolarPanel) {
graph.addData("Solar", ((SolarPanel) selectedPart).getYieldNow());
} else if (selectedPart instanceof Rack) {
graph.addData("Solar", ((Rack) selectedPart).getYieldNow());
}
}
graph.repaint();
}
Aggregations