/*
* 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.network.structures;
import org.addition.epanet.Constants;
import org.addition.epanet.network.FieldsMap;
import org.addition.epanet.network.PropertiesMap;
import org.addition.epanet.network.io.Keywords;
import org.addition.epanet.util.ENException;
import org.addition.epanet.util.Utilities;
import java.util.ArrayList;
import java.util.List;
/**
* Hydraulic link structure (pipe)
*/
public class Link implements Comparable<Link> {
/**
* Init links flow resistance values.
*
* @param formflag
* @param hexp
* @throws org.addition.epanet.util.ENException
*
*/
public void initResistance(PropertiesMap.FormType formflag, Double hexp) {
double e, d, L;
this.setFlowResistance(Constants.CSMALL);
switch (this.getType()) {
case CV:
case PIPE:
e = this.getRoughness();
d = this.getDiameter();
L = this.getLenght();
switch (formflag) {
case HW:
this.setFlowResistance(4.727 * L / Math.pow(e, hexp) / Math.pow(d, 4.871));
break;
case DW:
this.setFlowResistance(L / 2.0 / 32.2 / d / Math.pow(Constants.PI * Math.pow(d, 2) / 4.0, 2));
break;
case CM:
this.setFlowResistance(Math.pow(4.0 * e / (1.49 * Constants.PI * d * d), 2) *
Math.pow((d / 4.0), -1.333) * L);
}
break;
case PUMP:
this.setFlowResistance(Constants.CBIG);
break;
}
}
/**
* Type of link
*/
static public enum LinkType {
/**
* Pipe with check valve.
*/
CV(0, Keywords.w_CV),
/**
* Flow control valve.
*/
FCV(6, Keywords.w_FCV),
/**
* General purpose valve.
*/
GPV(8, Keywords.w_GPV),
/**
* Pressure breaker valve.
*/
PBV(5, Keywords.w_PBV),
/**
* Regular pipe.
*/
PIPE(1, Keywords.w_PIPE),
/**
* Pressure reducing valve.
*/
PRV(3, Keywords.w_PRV),
/**
* Pressure sustaining valve.
*/
PSV(4, Keywords.w_PSV),
/**
* Pump.
*/
PUMP(2, Keywords.w_PUMP),
/**
* Throttle control valve.
*/
TCV(7, Keywords.w_TCV);
public static LinkType parse(String text) {
for (LinkType type : LinkType.values())
if (Utilities.match(text, type.parseStr)) return type;
return null;
}
/**
* Sequencial ID.
*/
public final int id;
/**
* Valve type string.
*/
public final String parseStr;
;
private LinkType(int val, String str) {
id = val;
parseStr = str;
}
}
/**
* Link/Tank/Pump status
*/
static public enum StatType {
/**
* Valve active (partially open).
*/
ACTIVE(4, Keywords.w_ACTIVE, Keywords.t_ACTIVE),
/**
* Closed.
*/
CLOSED(2, Keywords.w_CLOSED, Keywords.t_CLOSED),
/**
* Tank emptying.
*/
EMPTYING(9, "", Keywords.t_EMPTYING),
/**
* Tank filling.
*/
FILLING(8, "", Keywords.t_FILLING),
/**
* Open.
*/
OPEN(3, Keywords.w_OPEN, Keywords.t_OPEN),
/**
* Temporarily closed.
*/
TEMPCLOSED(1, "", Keywords.t_TEMPCLOSED),
/**
* FCV cannot supply flow.
*/
XFCV(6, "", Keywords.t_XFCV),
/**
* Pump exceeds maximum flow.
*/
XFLOW(5, "", Keywords.t_XFLOW),
/**
* Pump cannot deliver head (closed).
*/
XHEAD(0, "", Keywords.t_XHEAD),
/**
* Valve cannot supply pressure.
*/
XPRESSURE(7, "", Keywords.t_XPRESSURE);
/**
* Sequencial id.
*/
public final int id;
/**
* Parse string.
*/
public final String parseStr;
/**
* Report string.
*/
public final String reportStr;
private StatType(int val, String str, String rep) {
id = val;
parseStr = str;
reportStr = rep;
}
}
/**
* Initial species concentrations.
*/
private double[] c0;
/**
* Link comment (parsed from INP or excel file)
*/
private String comment;
/**
* Link diameter (feet).
*/
private double diameter;
/**
* First node.
*/
private Node first;
/**
* Link name.
*/
private String ID;
/**
* Bulk react. coeff.
*/
private double kb;
/**
* Minor loss coeff.
*/
private double km;
/**
* Wall react. coeff.
*/
private double kw;
/**
* Link length (feet).
*/
private double lenght;
/**
* Kinetic parameter values.
*/
private double[] param;
/**
* Flow resistance.
*/
private double resistance;
/**
* Roughness factor.
*/
private double roughness;
/**
* Link report flag.
*/
private boolean rptFlag;
/**
* Second node.
*/
private Node second;
/**
* Link status.
*/
private StatType status;
/**
* Link subtype.
*/
private LinkType type;
/**
* List of points for link path rendering.
*/
private List<Point> vertices;
public Link() {
comment = "";
vertices = new ArrayList<Point>();
type = LinkType.CV;
status = StatType.XHEAD;
}
public double[] getC0() {
return c0;
}
public String getComment() {
return comment;
}
public double getDiameter() {
return diameter;
}
public Node getFirst() {
return first;
}
public double getFlowResistance() {
return resistance;
}
public String getId() {
return ID;
}
public double getKb() {
return kb;
}
public double getKm() {
return km;
}
public double getKw() {
return kw;
}
public double getLenght() {
return lenght;
}
public double getNUDiameter(PropertiesMap.UnitsType type) {
return NUConvert.revertDiameter(type, diameter);
}
public double getNULength(PropertiesMap.UnitsType type) {
return NUConvert.revertDistance(type, lenght);
}
public double getNURoughness(PropertiesMap.FlowUnitsType fType, PropertiesMap.PressUnitsType pType, double SpGrav) {
switch (getType()) {
case FCV:
return NUConvert.revertFlow(fType, roughness);
case PRV:
case PSV:
case PBV:
return NUConvert.revertPressure(pType, SpGrav, roughness);
}
return roughness;
}
public double[] getParam() {
return param;
}
public double getRoughness() {
return roughness;
}
public Node getSecond() {
return second;
}
public StatType getStat() {
return status;
}
public LinkType getType() {
return type;
}
public List<Point> getVertices() {
return vertices;
}
public boolean isRptFlag() {
return rptFlag;
}
public void setC0(double[] c0) {
this.c0 = c0;
}
public void setComment(String comment) {
this.comment = comment;
}
public void setDiameter(double diameter) {
this.diameter = diameter;
}
public void setDiameterAndUpdate(double diameter, org.addition.epanet.network.Network net) throws ENException {
double realkm = km * Math.pow(this.diameter, 4.0) / 0.02517;
this.diameter = diameter;
km = 0.02517 * realkm / Math.pow(diameter, 4);
initResistance(net.getPropertiesMap().getFormflag(), net.getPropertiesMap().getHexp());
}
public void setFirst(Node n1) {
first = n1;
}
public void setFlowResistance(double r) {
this.resistance = r;
}
public void setId(String id) {
ID = id;
}
public void setKb(double kb) {
this.kb = kb;
}
public void setKm(double km) {
this.km = km;
}
public void setKw(double kw) {
this.kw = kw;
}
public void setLenght(double len) {
this.lenght = len;
}
public void setNUDiameter(PropertiesMap.UnitsType type, double value) {
diameter = NUConvert.convertDistance(type, value);
}
public void setNULenght(PropertiesMap.UnitsType type, double value) {
lenght = NUConvert.convertDistance(type, value);
}
public void setParam(double[] param) {
this.param = param;
}
public void setReportFlag(boolean rptFlag) {
this.rptFlag = rptFlag;
}
public void setRoughness(double kc) {
this.roughness = kc;
}
public void setSecond(Node n2) {
second = n2;
}
public void setStatus(StatType stat) {
this.status = stat;
}
public void setType(LinkType type) {
this.type = type;
}
// @Override
// public boolean equals(Object o) {
// if (this == o) return true;
// if (o == null || getClass() != o.getClass()) return false;
//
// Link link = (Link) o;
//
// if (ID != null ? !ID.equals(link.ID) : link.ID != null) return false;
//
// return true;
// }
@Override
public int hashCode() {
return ID != null ? ID.hashCode() : 0;
}
public int compareTo(Link o) {
return ID.compareTo(o.ID);
}
}