use of org.concord.energy3d.model.Foundation in project energy3d by concord-consortium.
the class SolarRadiation method computeEnergyOfToday.
public void computeEnergyOfToday() {
updateTextures();
if (Scene.getInstance().getAlwaysComputeHeatFluxVectors()) {
for (final HousePart part : Scene.getInstance().getParts()) {
part.drawHeatFlux();
}
}
final Calendar today = Heliodon.getInstance().getCalendar();
final String city = (String) EnergyPanel.getInstance().getCityComboBox().getSelectedItem();
final double[] outsideTemperatureRange = Weather.computeOutsideTemperature(today, city);
for (final HousePart part : Scene.getInstance().getParts()) {
if (part instanceof Foundation) {
final Foundation foundation = (Foundation) part;
final int n = foundation.getHeatLoss().length;
final double[] heatLoss = new double[n];
final double[] passiveSolar = new double[n];
final double[] photovoltaic = new double[n];
final double[] csp = new double[n];
for (int i = 0; i < n; i++) {
final double groundHeatLoss = foundation.getHeatLoss()[i];
// In other words, geothermal energy is good in hot conditions. This is similar to passive solar energy, which is good in the winter but bad in the summer.
if (groundHeatLoss > 0) {
final double outsideTemperature = Weather.getInstance().getOutsideTemperatureAtMinute(outsideTemperatureRange[1], outsideTemperatureRange[0], i * Scene.getInstance().getTimeStep());
if (outsideTemperature >= foundation.getThermostat().getTemperature(today.get(Calendar.MONTH), today.get(Calendar.DAY_OF_WEEK) - Calendar.SUNDAY, today.get(Calendar.HOUR_OF_DAY))) {
heatLoss[i] -= groundHeatLoss;
}
} else {
heatLoss[i] += groundHeatLoss;
}
}
double solarPotentialTotal = 0;
for (final HousePart child : Scene.getInstance().getParts()) {
if (child.getTopContainer() == foundation) {
child.setSolarPotentialToday(0);
if (child instanceof SolarCollector) {
((SolarCollector) child).setYieldToday(0);
}
for (int i = 0; i < n; i++) {
solarPotentialTotal += child.getSolarPotential()[i];
child.setSolarPotentialToday(child.getSolarPotentialToday() + child.getSolarPotential()[i]);
if (child instanceof Wall || child instanceof Door || child instanceof Window || child instanceof Roof) {
heatLoss[i] += child.getHeatLoss()[i];
}
if (child instanceof Window) {
final Window window = (Window) child;
passiveSolar[i] += child.getSolarPotential()[i] * window.getSolarHeatGainCoefficient();
} else if (child instanceof SolarPanel) {
final SolarPanel sp = (SolarPanel) child;
// distributed efficiency must be handled for each individual cell
final double yield = sp.getSolarPotential()[i];
sp.setYieldToday(sp.getYieldToday() + yield);
photovoltaic[i] += yield;
} else if (child instanceof Rack) {
final Rack rack = (Rack) child;
// distributed efficiency must be handled for each individual cell
final double yield = rack.getSolarPotential()[i];
rack.setYieldToday(rack.getYieldToday() + yield);
photovoltaic[i] += yield;
} else if (child instanceof Mirror) {
final Mirror mirror = (Mirror) child;
final double yield = mirror.getSolarPotential()[i] * mirror.getSystemEfficiency();
mirror.setYieldToday(mirror.getYieldToday() + yield);
csp[i] += yield;
} else if (child instanceof ParabolicTrough) {
final ParabolicTrough trough = (ParabolicTrough) child;
final double yield = trough.getSolarPotential()[i] * trough.getSystemEfficiency();
trough.setYieldToday(trough.getYieldToday() + yield);
csp[i] += yield;
} else if (child instanceof ParabolicDish) {
final ParabolicDish dish = (ParabolicDish) child;
final double yield = dish.getSolarPotential()[i] * dish.getSystemEfficiency();
dish.setYieldToday(dish.getYieldToday() + yield);
csp[i] += yield;
} else if (child instanceof FresnelReflector) {
final FresnelReflector reflector = (FresnelReflector) child;
final double yield = reflector.getSolarPotential()[i] * reflector.getSystemEfficiency();
reflector.setYieldToday(reflector.getYieldToday() + yield);
csp[i] += yield;
}
}
}
}
if (foundation.getImportedNodes() != null) {
for (int i = 0; i < n; i++) {
solarPotentialTotal += foundation.getSolarPotential()[i];
foundation.setSolarPotentialToday(foundation.getSolarPotentialToday() + foundation.getSolarPotential()[i]);
}
}
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.setSolarPotentialToday(solarPotentialTotal);
foundation.setPassiveSolarToday(passiveSolarTotal);
foundation.setPhotovoltaicToday(photovoltaicTotal);
foundation.setCspToday(cspTotal);
foundation.setHeatingToday(heatingTotal);
foundation.setCoolingToday(coolingTotal);
foundation.setTotalEnergyToday(heatingTotal + coolingTotal - photovoltaicTotal);
}
}
}
use of org.concord.energy3d.model.Foundation in project energy3d by concord-consortium.
the class SolarRadiation method computeOnFresnelReflector.
// unlike PV solar panels, no indirect (ambient or diffuse) radiation should be included in reflection calculation
private void computeOnFresnelReflector(final int minute, final ReadOnlyVector3 directionTowardSun, final FresnelReflector reflector) {
final int nx = reflector.getNSectionLength();
final int ny = reflector.getNSectionWidth();
final Foundation target = reflector.getReceiver();
if (target != null) {
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);
reflector.draw();
}
// nx*ny*60: nx*ny is to get the unit cell area of the nx*ny grid; 60 is to convert the unit of timeStep from minute to kWh
final double a = reflector.getModuleWidth() * reflector.getLength() * Scene.getInstance().getTimeStep() / (nx * ny * 60.0);
final ReadOnlyVector3 normal = reflector.getNormal();
if (normal == null) {
throw new RuntimeException("Normal is null");
}
final Mesh mesh = reflector.getRadiationMesh();
MeshDataStore data = onMesh.get(mesh);
if (data == null) {
data = initMeshTextureDataOnRectangle(mesh, 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 FloatBuffer vertexBuffer = mesh.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));
// final Vector3 q0 = mesh.localToWorld(p0, null);
// final Vector3 q1 = mesh.localToWorld(p1, null);
// final Vector3 q2 = mesh.localToWorld(p2, null);
// System.out.println("***" + q0.distance(q1) * Scene.getInstance().getAnnotationScale() + "," + q0.distance(q2) * Scene.getInstance().getAnnotationScale());
// this is the longer side (supposed to be y)
final Vector3 u = p1.subtract(p0, null).normalizeLocal();
// this is the shorter side (supposed to be x)
final Vector3 v = p2.subtract(p0, null).normalizeLocal();
// 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)
final double xSpacing = p1.distance(p0) / nx;
final double ySpacing = p2.distance(p0) / ny;
final Vector3 absorber = target != null ? target.getSolarReceiverCenter() : null;
List<Mesh> absorberCollisionMeshes = null;
if (target != null) {
absorberCollisionMeshes = new ArrayList<Mesh>();
for (final HousePart child : target.getChildren()) {
absorberCollisionMeshes.add((Mesh) child.getRadiationCollisionSpatial());
}
final List<Roof> roofs = target.getRoofs();
if (!roofs.isEmpty()) {
for (final Roof r : roofs) {
for (final Spatial roofPart : r.getRoofPartsRoot().getChildren()) {
absorberCollisionMeshes.add((Mesh) ((Node) roofPart).getChild(6));
}
}
}
}
final int iMinute = minute / Scene.getInstance().getTimeStep();
final boolean reflectionMapOnly = Scene.getInstance().getOnlyReflectedEnergyInMirrorSolarMap();
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 = mesh.getWorldTransform().applyForward(p0.add(v2, null).addLocal(u2)).addLocal(offset);
final Ray3 pickRay = new Ray3(p, directionTowardSun);
if (dot > 0) {
final PickResults pickResults = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != mesh) {
PickingUtil.findPick(spatial, pickRay, pickResults, false);
if (pickResults.getNumber() != 0) {
break;
}
}
}
if (pickResults.getNumber() == 0) {
// for heat map generation
if (!reflectionMapOnly) {
data.dailySolarIntensity[x][y] += directRadiation;
}
// TODO: Edge losses are not considered yet
if (absorber != null) {
// TODO: This calculation is not exactly accurate as the collision detection assumes that the ray emits from a grid point on the reflector to
// the parallel position on the absorber tube -- without considering the actual direction of the reflected light
final Vector3 toAbsorber = absorber.subtract(p, null);
toAbsorber.setY(0);
final Ray3 rayToAbsorber = new Ray3(p, toAbsorber.normalize(null));
final PickResults pickResultsToAbsorber = new PrimitivePickResults();
for (final Spatial spatial : collidables) {
if (spatial != mesh) {
if (absorberCollisionMeshes == null || (absorberCollisionMeshes != null && !absorberCollisionMeshes.contains(spatial))) {
PickingUtil.findPick(spatial, rayToAbsorber, pickResultsToAbsorber, false);
if (pickResultsToAbsorber.getNumber() != 0) {
// FIXME: how to stop the ray when it hits the absorber?
break;
}
}
}
}
if (pickResultsToAbsorber.getNumber() == 0) {
final double r = directRadiation * Atmosphere.getTransmittance(toAbsorber.length() * Scene.getInstance().getAnnotationScale() * 0.001, false);
reflector.getSolarPotential()[iMinute] += r * a;
if (reflectionMapOnly) {
data.dailySolarIntensity[x][y] += r;
}
}
}
}
}
}
}
}
use of org.concord.energy3d.model.Foundation in project energy3d by concord-consortium.
the class SolarRadiation method setupImportedMeshes.
private void setupImportedMeshes() {
for (final HousePart part : Scene.getInstance().getParts()) {
if (part instanceof Foundation) {
final Foundation foundation = (Foundation) part;
final boolean nonZeroAz = !Util.isZero(foundation.getAzimuth());
final List<Node> importedNodes = foundation.getImportedNodes();
if (importedNodes != null) {
for (final Node node : importedNodes) {
for (final Spatial s : node.getChildren()) {
final Mesh m = (Mesh) s;
final UserData ud = (UserData) m.getUserData();
ReadOnlyVector3 normal = ud.getNormal();
if (nonZeroAz) {
// if the foundation is rotated, rotate the imported meshes, too, but this doesn't alter their original normals
// this must be recalculated in case the foundation has been rotated after loading
ud.setRotatedNormal(node.getRotation().applyPost(normal, null));
normal = ud.getRotatedNormal();
}
MeshDataStore data = onMesh.get(m);
if (data == null) {
// initialize mesh solar data and texture
data = initMeshTextureData(m, m, normal, true);
data.solarPotential = new double[MINUTES_OF_DAY / Scene.getInstance().getTimeStep()];
}
}
}
}
}
}
}
use of org.concord.energy3d.model.Foundation in project energy3d by concord-consortium.
the class ParabolicDishAnnualAnalysis method show.
public void show() {
final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
String s = null;
int cost = -1;
String title = "Annual Yield of All Parabolic Dishes (" + Scene.getInstance().countParts(ParabolicDish.class) + " Dishes)";
if (selectedPart != null) {
if (selectedPart instanceof ParabolicDish) {
cost = (int) CspProjectCost.getPartCost(selectedPart);
s = selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1);
title = "Annual Yield";
} else if (selectedPart instanceof Foundation) {
title = "Annual Yield of Selected Foundation (" + ((Foundation) selectedPart).countParts(ParabolicDish.class) + " Parabolic Dishes)";
} else if (selectedPart.getTopContainer() instanceof Foundation) {
title = "Annual Yield of Selected Foundation (" + selectedPart.getTopContainer().countParts(ParabolicDish.class) + " Parabolic Dishes)";
}
}
final JDialog dialog = createDialog(s == null ? title : title + ": " + s + " (Cost: $" + cost + ")");
final JMenuBar menuBar = new JMenuBar();
dialog.setJMenuBar(menuBar);
menuBar.add(createOptionsMenu(dialog, null, true, true));
menuBar.add(createRunsMenu());
dialog.setVisible(true);
}
use of org.concord.energy3d.model.Foundation in project energy3d by concord-consortium.
the class ParabolicDishAnnualAnalysis method toJson.
@Override
public String toJson() {
String s = "{\"Months\": " + getNumberOfDataPoints();
final HousePart selectedPart = SceneManager.getInstance().getSelectedPart();
if (selectedPart != null) {
if (selectedPart instanceof ParabolicDish) {
s += ", \"Parabolic Dish\": \"" + selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1) + "\"";
} else if (selectedPart instanceof Foundation) {
s += ", \"Foundation\": \"" + selectedPart.toString().substring(0, selectedPart.toString().indexOf(')') + 1) + "\"";
} else if (selectedPart.getTopContainer() instanceof Foundation) {
s += ", \"Foundation\": \"" + selectedPart.getTopContainer().toString().substring(0, selectedPart.getTopContainer().toString().indexOf(')') + 1) + "\"";
}
} else {
s += ", \"Parabolic Dish\": \"All\"";
}
final String name = "Solar";
final List<Double> data = graph.getData(name);
s += ", \"" + name + "\": {";
s += "\"Monthly\": [";
for (final Double x : data) {
s += Graph.ENERGY_FORMAT.format(x) + ",";
}
s = s.substring(0, s.length() - 1);
s += "]\n";
s += ", \"Total\": " + Graph.ENERGY_FORMAT.format(getResult(name));
s += "}";
s += "}";
return s;
}
Aggregations