OpenWaterAnalytics / EPANET

The Water Distribution System Hydraulic and Water Quality Analysis Toolkit
MIT License
272 stars 201 forks source link

Copy project #760

Open zannads opened 8 months ago

zannads commented 8 months ago

The API misses the possibility of creating a new instance of an EN_Project starting from an existing one. This feature is helpful when solving staged design problems, and the evaluation of the designs at the several steps can be run in parallel. However, the designs evaluated at the different steps usually modify the previous steps. Hence, an EN_copyproject function would allow the application of the changes in the first step, then copy this modified version and apply the second interval changes, and so on... This function would also help run multiple instances of the same network in a probabilistic setup (e.g., sampling the demand from a distribution). Copying an object in memory instead of loading it from the file is more efficient.

The proposed function to be added in the "Project functions" section would look something like:

int EN_copyproject(EN_Project ph_source, EN_Project* ph_dest)

and its pseduo-implementation

int EN_copyproject(EN_Project ph_source, EN_Project* ph_dest) 
{
EN_createproject(ph_dest);
// get from ph_source unitsType and headlosstype

EN_init(ph_dest, "", "", unitsType, headlossType)

// copy element by element like you were constructing a network from scratch
/*******************
 * settings
 * nodes
 * links 
 * etc
 ******************/
}
LRossman commented 8 months ago

This feature could be implemented with a lot less code using the existing EN_saveinpfile() andEN_open() functions:

int EN_copyproject(EN_Project ph_source, EN_Project ph_dest, char *rptfile_dest, char* outfile_dest)
{
    char inpfile[MAXFNAME+1];
    int errcode = 0;

    < Sanity checks on function arguments go here>

    if (!EN_createproject(ph_dest)) return 101;
    getTmpName(inpfile);
    EN_saveinpfile(ph_source, inpfile);
    errcode = EN_open(ph_dest, inpfile, rptfile_dest, outfile_dest);
    if (errcode)
    {
        EN_deleteproject(ph_dest);
        ph_dest = NULL;
    }
    remove(inpfile);
    return errcode;
}

Note that it is necessary to provide the names of a Report and Output file to the function so that EN_open()can be used for the destination project. As part of the sanity check these names can't be the same as those used in the source project. This requirement would hold true even if an element by element approach were used to copy the source project. Granted this file-based approach is not as time-efficient as the latter, but given the prevalence of solid state drives these days and the likelihood that the copy function wouldn't be used that often, I believe it is a viable alternative.

zannads commented 8 months ago

Thank you, @LRossman, for the reply! It is a nice workaround, and it does exactly what I need. I will try it out for sure at the beginning. However, the reason behind my proposal is purely related to performance. The alternative would be to create $n$ objects from the original .inp file at the beginning and then apply the solutions to each.

As in my Ph.D. I am looking to perform optimisation of design and control variables, thus requiring many EPS simulations, I will try these approaches and get back with a comparison of the execution times. I am also happy to do it myself and contribute to the project! I agree that an element-by-element copy is a delicate operation that would require a lot of coding.