/*
* JGrass - Free Open Source Java GIS http://www.jgrass.org
* (C) HydroloGIS - www.hydrologis.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser 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 Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jgrasstools.hortonmachine.modules.networktools.epanet.core;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import com.sun.jna.Native;
import com.sun.jna.NativeLibrary;
/**
* A wrapper for epanet functions.
*
* @author Andrea Antonello (www.hydrologis.com)
*/
public class EpanetWrapper {
private static EpanetNativeFunctions epanet;
/**
* A warning message related to the last method called.
*/
private String warningMessage = null;
/**
* Contructor for the {@link EpanetWrapper}.
*
* <p>This also takes care to load the native library, if needed.
*
* @param lib the name of the library (ex. "epanet2_64bit").
* @param nativeLibPath the path in which to search the native library.
* If the native library is already in the java library path
* this is not needed and may be <code>null</code>
* @throws Exception if the library could not be loaded.
*/
public EpanetWrapper( String lib, String nativeLibPath ) throws Exception {
if (epanet == null) {
try {
if (nativeLibPath != null)
NativeLibrary.addSearchPath(lib, nativeLibPath);
epanet = (EpanetNativeFunctions) Native.loadLibrary(lib, EpanetNativeFunctions.class);
} catch (Exception e) {
throw new Exception("An error occurred while trying to load the epanet library.", e);
}
}
}
/**
* Get the reference to the jna native epanet instance.
*
* @return the OmsEpanet native reference.
*/
public static EpanetNativeFunctions getEpanet() {
return epanet;
}
/**
* Opens the Toolkit to analyze a particular distribution system.
*
* @param input name of an EPANET Input file.
* @param report name of an output Report file.
* @param outputBin name of an optional binary Output file.
* @throws IOException
*/
public void ENopen( String input, String report, String outputBin ) throws EpanetException {
int errcode = epanet.ENopen(input, report, outputBin);
checkError(errcode);
}
/**
* Closes down the Toolkit system (including all files being processed).
*
* <p>ENclose must be called when all processing has been completed,
* even if an error condition was encountered.
* @throws EpanetException
*/
public void ENclose() throws EpanetException {
int errcode = epanet.ENclose();
checkError(errcode);
}
/**
* Writes all current network input data to
* a file using the format of an EPANET input file.
*
* @param fileName name of the file where data is saved.
* @throws EpanetException
*/
public void ENsaveinpfile( String fileName ) throws EpanetException {
int err = epanet.ENsaveinpfile(fileName);
checkError(err);
}
/**
* Runs a complete hydraulic simulation with results for all time periods written to the binary Hydraulics file.
*
* @throws EpanetException
*/
public void ENsolveH() throws EpanetException {
int err = epanet.ENsolveH();
checkError(err);
}
/**
* Transfers results of a hydraulic simulation from the binary Hydraulics file to the
* binary Output file, where results are only reported at uniform reporting intervals.
*
* @throws EpanetException
*/
public void ENsaveH() throws EpanetException {
int err = epanet.ENsaveH();
checkError(err);
}
/**
* Opens the hydraulics analysis system.
*
* <p>Call ENopenH prior to running the first hydraulic analysis
* using the ENinitH - ENrunH - ENnextH sequence. Multiple analyses
* can be made before calling ENcloseH to close the hydraulic
* analysis system.
*
* <p>Do not call this function if ENsolveH is being used to run a
* complete hydraulic analysis.
*
* @throws EpanetException
*/
public void ENopenH() throws EpanetException {
int err = epanet.ENopenH();
checkError(err);
}
/**
* Initializes storage tank levels, link status and settings, and
* the simulation clock time prior to running a hydraulic analysis.
*
* @param saveflag 0-1 flag indicating if hydraulic results will be
* saved to the hydraulics file.
* @throws EpanetException
*/
public void ENinitH( int saveflag ) throws EpanetException {
int err = epanet.ENinitH(saveflag);
checkError(err);
}
/**
* Runs a single period hydraulic analysis, retrieving
* the current simulation clock time.
*
* <p>Use {@link #ENrunH(long[])} along with {@link #ENnextH(long[])}
* in a do..while loop to
* analyze hydraulics in each period of an extended period simulation.
* This process automatically updates the simulation clock time so
* treat t as a read-only variable.
*
* <p>{@link #ENinitH(int)} must have been called prior to running the
* ENrunH - ENnextH loop.
*
* @param time current simulation clock time in seconds. This value
* is updated by the method.
* @throws EpanetException
*/
public void ENrunH( long[] time ) throws EpanetException {
int err = epanet.ENrunH(time);
checkError(err);
}
/**
* Determines the length of time until the next hydraulic event occurs in
* an extended period simulation.
*
* @param timeStep time (in seconds) until next hydraulic event occurs or 0
* if at the end of the simulation period.
* @throws EpanetException
*/
public void ENnextH( long[] timeStep ) throws EpanetException {
int err = epanet.ENnextH(timeStep);
checkError(err);
}
/**
* Closes the hydraulic analysis system, freeing all allocated memory.
*
* <p>Call {@link #ENcloseH()} after all hydraulics analyses have been made
* using {@link #ENinitH(int)} - {@link #ENrunH(long[])} - {@link #ENnextH(long[])}.
* Do not call this function if ENsolveH is being used.
*
* @throws EpanetException
*/
public void ENcloseH() throws EpanetException {
int err = epanet.ENcloseH();
checkError(err);
}
/**
* Saves the current contents of the binary hydraulics file to a file.
*
* @param filePath name of the file where the hydraulics results should be saved.
* @throws EpanetException
*/
public void ENsavehydfile( String filePath ) throws EpanetException {
int err = epanet.ENsavehydfile(filePath);
checkError(err);
}
/**
* Uses the contents of the specified file as the current binary hydraulics file.
*
* @param filePath name of the file containing hydraulic analysis results for the current network.
* @throws EpanetException
*/
public void ENusehydfile( String filePath ) throws EpanetException {
int err = epanet.ENsavehydfile(filePath);
checkError(err);
}
/**
* @deprecated not implemented yet.
*/
public int ENsolveQ() {
return -1;
}
/**
* @deprecated not implemented yet.
*/
public int ENopenQ() {
return -1;
}
/**
* @deprecated not implemented yet.
*/
public int ENinitQ( int int1 ) {
return -1;
}
/**
* @deprecated not implemented yet.
*/
public int ENrunQ( Long lPtr1 ) {
return -1;
}
/**
* @deprecated not implemented yet.
*/
public int ENnextQ( Long lPtr1 ) {
return -1;
}
/**
* @deprecated not implemented yet.
*/
public int ENstepQ( Long lPtr1 ) {
return -1;
}
/**
* @deprecated not implemented yet.
*/
public int ENcloseQ() {
return -1;
}
/**
* @deprecated not implemented yet.
*/
public int ENwriteline( ByteBuffer charPtr1 ) {
return -1;
}
/**
* Writes a formatted text report on simulation results to the Report file.
* @throws EpanetException
*/
public void ENreport() throws EpanetException {
int err = epanet.ENreport();
checkError(err);
}
/**
* Clears any report formatting commands that either appeared in the
* [REPORT] section of the EPANET Input file or were issued with the
* ENsetreport function
*
* @throws EpanetException
*/
public void ENresetreport() throws EpanetException {
int err = epanet.ENresetreport();
checkError(err);
}
/**
* Issues a report formatting command. Formatting commands are the
* same as used in the [REPORT] section of the EPANET Input file.
*
* @param command text of a report formatting command.
* @throws EpanetException
*/
public void ENsetreport( String command ) throws EpanetException {
int err = epanet.ENsetreport(command);
checkError(err);
}
/**
* @deprecated not implemented yet
*/
public int ENgetcontrol( int int1, IntBuffer intPtr1, IntBuffer intPtr2, FloatBuffer floatPtr1, IntBuffer intPtr3,
FloatBuffer floatPtr2 ) {
return -1;
}
/**
* Retrieves the number of network components of a specified type.
*
* @param countcode {@link Components} code .
* @return number of countcode components in the network.
* @throws EpanetException
*/
public int ENgetcount( Components countcode ) throws EpanetException {
int[] count = new int[1];
int error = epanet.ENgetcount(countcode.getCode(), count);
checkError(error);
return count[0];
}
/**
* Retrieves the value of a particular analysis option.
*
* @param optionCode The {@link OptionParameterCodes}.
* @throws EpanetException
*/
public float ENgetoption( OptionParameterCodes optionCode ) throws EpanetException {
float[] optionValue = new float[1];
int error = epanet.ENgetoption(optionCode.getCode(), optionValue);
checkError(error);
return optionValue[0];
}
/**
* Retrieves the value of a specific analysis time parameter.
*
* @param timeParameterCode time parameter code.
* @return value of time parameter in seconds.
* @throws EpanetException
*/
public long ENgettimeparam( TimeParameterCodes timeParameterCode ) throws EpanetException {
long[] timeValue = new long[1];
int error = epanet.ENgettimeparam(timeParameterCode.getCode(), timeValue);
checkError(error);
return timeValue[0];
}
/**
* @deprecated not yet implemented.
*/
public int ENgetflowunits( IntBuffer intPtr1 ) {
return -1;
}
/**
* Retrieves the index of a particular time pattern.
*
* @param id pattern ID label.
* @return the pattern index.
* @throws EpanetException
*/
public int ENgetpatternindex( String id ) throws EpanetException {
int[] index = new int[1];
int error = epanet.ENgetpatternindex(id, index);
checkError(error);
return index[0];
}
/**
* Retrieves the ID label of a particular time pattern.
*
* @param index pattern index.
* @return the id label.
* @throws EpanetException
*/
public String ENgetpatternid( int index ) throws EpanetException {
ByteBuffer bb = ByteBuffer.allocate(64);
int errcode = epanet.ENgetpatternid(index, bb);
checkError(errcode);
String label = byteBuffer2String(bb);
return label;
}
/**
* @deprecated not yet implemented.
*/
public int ENgetpatternlen( int int1, IntBuffer intPtr1 ) {
return -1;
}
/**
* Retrieves the multiplier factor for a specific time period in a time pattern.
*
* @param index time pattern index.
* @param period period within time pattern.
* @return multiplier factor for the period.
* @throws EpanetException
*/
public float ENgetpatternvalue( int index, int period ) throws EpanetException {
float[] value = new float[1];
int errcode = epanet.ENgetpatternvalue(index, period, value);
checkError(errcode);
return value[0];
}
/**
* @deprecated not yet implemented.
*/
public int ENgetqualtype( IntBuffer intPtr1, IntBuffer intPtr2 ) {
return -1;
}
/**
* @deprecated not yet implemented.
*/
public int ENgeterror( int int1, ByteBuffer charPtr1, int int2 ) {
return -1;
}
/**
* Retrieves the index of a node with a specified ID.
*
* @param id the node id.
* @return the node index.
* @throws EpanetException
*/
public int ENgetnodeindex( String id ) throws EpanetException {
int[] index = new int[1];
int error = epanet.ENgetnodeindex(id, index);
checkError(error);
return index[0];
}
/**
* Retrieves the ID label of a node with a specified index.
*
* @param index the node index.
* @return the node id.
* @throws EpanetException
*/
public String ENgetnodeid( int index ) throws EpanetException {
ByteBuffer bb = ByteBuffer.allocate(64);
int errcode = epanet.ENgetnodeid(index, bb);
checkError(errcode);
String label;
label = byteBuffer2String(bb);
return label;
}
/**
* Retrieves the node-type code for a specific node.
*
* @param index the node index.
* @return the {@link NodeTypes};
* @throws EpanetException
*/
public NodeTypes ENgetnodetype( int index ) throws EpanetException {
int[] typecode = new int[1];
int error = epanet.ENgetnodetype(index, typecode);
checkError(error);
NodeTypes type = NodeTypes.forCode(typecode[0]);
return type;
}
/**
* Retrieves the value of a specific link (node?) parameter.
*
* @param index the node index.
* @param code the parameter code.
* @return the value at the node.
* @throws EpanetException
*/
public float ENgetnodevalue( int index, NodeParameters code ) throws EpanetException {
float[] nodeValue = new float[1];
int error = epanet.ENgetnodevalue(index, code.getCode(), nodeValue);
checkError(error);
return nodeValue[0];
}
/**
* Retrieves the index of a link with a specified ID.
*
* <p>Link indexes are consecutive integers starting from 1.
*
* @param id link ID label.
* @return the link index.
* @throws EpanetException
*/
public int ENgetlinkindex( String id ) throws EpanetException {
int[] index = new int[1];
int error = epanet.ENgetlinkindex(id, index);
checkError(error);
return index[0];
}
/**
* Retrieves the ID label of a link with a specified index.
*
* @param index link index.
* @return the link label.
* @throws EpanetException
*/
public String ENgetlinkid( int index ) throws EpanetException {
ByteBuffer bb = ByteBuffer.allocate(64);
int errcode = epanet.ENgetlinkid(index, bb);
checkError(errcode);
String label;
label = byteBuffer2String(bb);
return label;
}
/**
* Retrieves the link-type code for a specific link.
*
* @param index link index.
* @return the {@link LinkTypes}.
* @throws EpanetException
*/
public LinkTypes ENgetlinktype( int index ) throws EpanetException {
int[] typecode = new int[1];
int error = epanet.ENgetlinktype(index, typecode);
checkError(error);
LinkTypes type = LinkTypes.forCode(typecode[0]);
return type;
}
/**
* Retrieves the indexes of the end nodes of a specified link.
*
* <p> Node and link indexes are consecutive integers starting from 1.
*
* <p>The From and To nodes are as defined for the link in the
* EPANET input file. The actual direction of flow in the link is
* not considered.
*
* @param index the link index.
* @return the from and to node indexes as a two items array.
* @throws EpanetException
*/
public int[] ENgetlinknodes( int index ) throws EpanetException {
int[] from = new int[1];
int[] to = new int[1];
int error = epanet.ENgetlinknodes(index, from, to);
checkError(error);
return new int[]{from[0], to[0]};
}
/**
* Retrieves the value of a specific link parameter.
*
* @param index link index.
* @param param {@link LinkParameters}.
* @return the value.
* @throws EpanetException
*/
public float[] ENgetlinkvalue( int index, LinkParameters param ) throws EpanetException {
float[] value = new float[2];
int errcode = epanet.ENgetlinkvalue(index, param.getCode(), value);
checkError(errcode);
return value;
}
/**
* Get the version of OmsEpanet.
*
* @return the version of epanet.
* @throws EpanetException
*/
public int ENgetversion() throws EpanetException {
int[] version = new int[0];
int errcode = epanet.ENgetversion(version);
checkError(errcode);
return version[0];
}
/**
* @deprecated not implemented yet
*/
public int ENsetcontrol( int int1, int int2, int int3, float float1, int int4, float float2 ) {
return -1;
}
/**
* Sets the value of a parameter for a specific node.
*
* @param index node index.
* @param paramcode parameter code.
* @param value parameter value.
* @throws EpanetException
*/
public void ENsetnodevalue( int index, NodeParameters nodeParameter, float value ) throws EpanetException {
int errcode = epanet.ENsetnodevalue(index, nodeParameter.getCode(), value);
checkError(errcode);
}
/**
* Sets the value of a parameter for a specific link.
*
* @param index node index.
* @param paramcode parameter code.
* @param value parameter value.
* @throws EpanetException
*/
public void ENsetlinkvalue( int index, LinkParameters linkParameter, float value ) throws EpanetException {
int errcode = epanet.ENsetnodevalue(index, linkParameter.getCode(), value);
checkError(errcode);
}
/**
* Adds a new time pattern to the network.
*
* @param id ID label of pattern.
* @throws EpanetException
*/
public void ENaddpattern( String id ) throws EpanetException {
int errcode = epanet.ENaddpattern(id);
checkError(errcode);
}
/**
* @deprecated not implemented yet
*/
public int ENsetpattern( int int1, FloatBuffer floatPtr1, int int2 ) {
return -1;
}
/**
* @deprecated not implemented yet
*/
public int ENsetpatternvalue( int int1, int int2, float float1 ) {
return -1;
}
/**
* Sets the value of a time parameter.
*
* @param paramcode the {@link TimeParameterCodes}.
* @param timevalue value of time parameter in seconds.
* @throws EpanetException
*/
public void ENsettimeparam( TimeParameterCodes code, Long timevalue ) throws EpanetException {
int errcode = epanet.ENsettimeparam(code.getCode(), timevalue);
checkError(errcode);
}
/**
* Sets the value of a particular analysis option.
*
* @param optionCode the {@link OptionParameterCodes}.
* @param value the option value.
* @throws EpanetException
*/
public void ENsetoption( OptionParameterCodes optionCode, float value ) throws EpanetException {
int errcode = epanet.ENsetoption(optionCode.getCode(), value);
checkError(errcode);
}
/**
* @deprecated not implemented yet
*/
public int ENsetstatusreport( int int1 ) {
return -1;
}
/**
* @deprecated not implemented yet
*/
public int ENsetqualtype( int int1, ByteBuffer charPtr1, ByteBuffer charPtr2, ByteBuffer charPtr3 ) {
return -1;
}
public void checkError( int errcode ) throws EpanetException {
try {
EpanetErrors.checkError(errcode);
warningMessage = EpanetErrors.checkWarning(errcode);
} catch (EpanetException e) {
ENclose();
throw e;
}
}
public String getWarningMessage() {
return warningMessage;
}
private String byteBuffer2String( ByteBuffer bb ) {
String label;
StringBuilder sb = new StringBuilder();
byte[] array = bb.array();
for( byte b : array ) {
if (b != 0) {
sb.append((char) b);
} else {
sb.append(' ');
}
}
label = sb.toString().trim();
return label;
}
}