/* * Copyright (C) 2012 Addition, Lda. (addition at addition dot pt) * * 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 http://www.gnu.org/licenses/. */ package org.addition.epanet.hydraulic.structures; import org.addition.epanet.Constants; import org.addition.epanet.network.FieldsMap; import org.addition.epanet.network.FieldsMap.Type; import org.addition.epanet.network.PropertiesMap; import org.addition.epanet.network.structures.Curve; import org.addition.epanet.network.structures.Link; import org.addition.epanet.network.structures.Link.StatType; import org.addition.epanet.network.structures.Pattern; import org.addition.epanet.network.structures.Pump; import org.addition.epanet.util.ENException; import org.addition.epanet.util.Utilities; import java.util.Collection; import java.util.List; public class SimulationPump extends SimulationLink { private double h0; // Simulated shutoff head private double flowCoefficient; // Simulated Flow coefficent private double n; // Simulated flow expoent public static class Energy { public Energy(double power, double efficiency) { this.power = power; this.efficiency = efficiency; } public double power; // Pump used power (KW) public double efficiency; // Pump effiency } public SimulationPump(Collection<SimulationNode> indexedNodes, Link ref, int idx) { super(indexedNodes, ref, idx); for (int i = 0; i < 6; i++) energy[i] = ((Pump) ref).getEnergy(0); h0 = ((Pump) ref).getH0(); flowCoefficient = ((Pump) ref).getFlowCoefficient(); n = ((Pump) ref).getN(); } private double energy[] = {0, 0, 0, 0, 0, 0}; public Pump.Type getPtype() { return ((Pump) link).getPtype(); } public double getQ0() { return ((Pump) link).getQ0(); } public double getQmax() { return ((Pump) link).getQmax(); } public double getHmax() { return ((Pump) link).getHmax(); } public Curve getHcurve() { return ((Pump) link).getHcurve(); } public Curve getEcurve() { return ((Pump) link).getEcurve(); } public Pattern getUpat() { return ((Pump) link).getUpat(); } public Pattern getEpat() { return ((Pump) link).getEpat(); } public double getEcost() { return ((Pump) link).getEcost(); } // Simulation getters and setters public double getEnergy(int id) { return energy[id];//((Pump)node).getEnergy(id); } public void setEnergy(int id, double value) { energy[id] = value; } private void setH0(double h0) { this.h0 = h0; } public double getH0() { return h0; } public double getFlowCoefficient() { return flowCoefficient; } private void setFlowCoefficient(double flowCoefficient) { this.flowCoefficient = flowCoefficient; } private void setN(double n) { this.n = n; } public double getN() { return n; } // Computes flow energy associated with this link pump. private Energy getFlowEnergy(PropertiesMap pMap, FieldsMap fMap) throws ENException { Energy ret = new Energy(0.0, 0.0); if (status.id <= StatType.CLOSED.id) { return ret; } double q = Math.abs(flow); double dh = Math.abs(first.getSimHead() - second.getSimHead()); double e = pMap.getEpump(); if (getEcurve() != null) { Curve curve = getEcurve(); e = Utilities.linearInterpolator(curve.getNpts(), curve.getX(), curve.getY(), q * fMap.getUnits(Type.FLOW)); } e = Math.min(e, 100.0); e = Math.max(e, 1.0); e /= 100.0; ret.power = dh * q * pMap.getSpGrav() / 8.814 / e * Constants.KWperHP; ret.efficiency = e; return ret; } // Accumulates pump energy usage. private double updateEnergy(PropertiesMap pMap, FieldsMap fMap, long n, double c0, double f0, double dt) throws ENException { double c = 0; //Skip closed pumps if (status.id <= StatType.CLOSED.id) return 0.0; double q = Math.max(Constants.QZERO, Math.abs(flow)); // Find pump-specific energy cost if (getEcost() > 0.0) c = getEcost(); else c = c0; if (getEpat() != null) { int m = (int) (n % (long) getEpat().getFactorsList().size()); c *= getEpat().getFactorsList().get(m); } else c *= f0; // Find pump energy & efficiency Energy energy = getFlowEnergy(pMap, fMap); // Update pump's cumulative statistics setEnergy(0, getEnergy(0) + dt); // Time on-line setEnergy(1, getEnergy(1) + energy.efficiency * dt); // Effic.-hrs setEnergy(2, getEnergy(2) + energy.power / q * dt); // kw/cfs-hrs setEnergy(3, getEnergy(3) + energy.power * dt); // kw-hrs setEnergy(4, Math.max(getEnergy(4), energy.power)); setEnergy(5, getEnergy(5) + c * energy.power * dt); // cost-hrs. return energy.power; } // Computes P & Y coeffs. for pump in the link void computePumpCoeff(FieldsMap fMap, PropertiesMap pMap) throws ENException { double h0, q, r, n; if (status.id <= StatType.CLOSED.id || setting == 0.0) { invHeadLoss = 1.0 / Constants.CBIG; flowCorrection = flow; return; } q = Math.max(Math.abs(flow), Constants.TINY); if (getPtype() == Pump.Type.CUSTOM) { Curve.Coeffs coeffs = getHcurve().getCoeff(fMap, q / setting); setH0(-coeffs.h0); setFlowCoefficient(-coeffs.r); setN(1.0); } h0 = (setting * setting) * getH0(); n = getN(); r = getFlowCoefficient() * Math.pow(setting, 2.0 - n); if (n != 1.0) r = n * r * Math.pow(q, n - 1.0); invHeadLoss = 1.0 / Math.max(r, pMap.getRQtol()); flowCorrection = flow / n + invHeadLoss * h0; } // Get new pump status // dh head gain public StatType pumpStatus(PropertiesMap pMap, double dh) throws ENException { double hmax; if (getPtype() == Pump.Type.CONST_HP) hmax = Constants.BIG; else hmax = (setting * setting) * getHmax(); if (dh > hmax + pMap.getHtol()) return (StatType.XHEAD); return (StatType.OPEN); } // Update pumps energy public static double stepEnergy(PropertiesMap pMap, FieldsMap fMap, Pattern Epat, List<SimulationPump> pumps, long htime, long hstep) throws ENException { double dt, psum = 0.0; if (pMap.getDuration() == 0) dt = 1.0; else if (htime < pMap.getDuration()) dt = (double) hstep / 3600.0; else dt = 0.0; if (dt == 0.0) return 0.0; long n = (htime + pMap.getPstart()) / pMap.getPstep(); double c0 = pMap.getEcost(); double f0 = 1.0; if (Epat != null) { long m = n % (long) Epat.getFactorsList().size(); f0 = Epat.getFactorsList().get((int) m); } for (SimulationPump pump : pumps) { psum += pump.updateEnergy(pMap, fMap, n, c0, f0, dt); } return psum; } }