pyswmm / pyswmm

Python Wrappers for SWMM
https://www.pyswmm.org
Other
293 stars 135 forks source link

Changing conduit roughness #157

Closed Argantonio65 closed 5 months ago

Argantonio65 commented 6 years ago

Thanks for the very nice package @bemcdonnell,

I was wondering whether it is possible to change the Manning's roughness parameter in a given conduit directly using pyswmm.

As far as I see, this is not included in the link get and change parameters.

bemcdonnell commented 6 years ago

@Argantonio65, Thanks!

I have a version of PySWMM that allows you to set the Manning's roughness of a conduit. How soon do you need this? I can merge in when I get some time.

Argantonio65 commented 6 years ago

Thanks for the fast reply. I would like to be able to change roughness values within a week time. But I would not like to put any kind of pressure on you to take time for the implementation. I think adding that functionality is very interesting for pyswmm so I would encourage you to do it eventually.

However if you do not have the time to commit in this. I could try to do it myself patching my version of the package temporally. The problem is that I'm a complete profane to the SWMM API and after searching everywhere I came to a dead end.

I suspect (maybe is more difficult and I'm totally wrong) that this could be solved by adding a @property to the Links.py as set roughness:

self._model.setLinkParam(self._linkid, LinkParams.ROUGHNESS.value, parametervalue)

And adding the ID for roughness to LinkParams in the toolkitapi.py

class LinkParams(Enum):
    offset1 = 0  # double
    offset2 = 1  # double
    q0 = 2  # double
    qLimit = 3  # double
    cLossInlet = 4  # double
    cLossOutlet = 5  # double
    cLossAvg = 6  # double
    seepRate = 7  # double
    ROUGHNESS = some ID in the SWMM.dll         

Which will become a call for the Windows SWMM .dll. However I do not know which ID value corresponds to the Roughness parameter in the SWMM API.

Is there any place where this can be looked up? Or the solution is completely different?

dickinsonre commented 6 years ago

Hello @Argantonio65 in the C code LINK.c the Manning's n for a link is read and then used to make the value for roughness - see these lines. If you change the roughness you need to go back and change the parameters calculated from the roughness (Manning's n) as well...

Conduit[k].roughFactor = GRAVITY * SQR(roughness/PHI);

// --- compute full flow through cross section
if ( Link[j].xsect.type == DUMMY ) Conduit[k].beta = 0.0;
else Conduit[k].beta = PHI * sqrt(fabs(slope)) / roughness;
Link[j].qFull = Link[j].xsect.sFull * Conduit[k].beta;
Conduit[k].qMax = Link[j].xsect.sMax * Conduit[k].beta;
bemcdonnell commented 6 years ago

@dickinsonre, with the appropriate prepping of the inputs, I believe we can just call link_validate to recalculate those parameters. Am i wrong? I'll put some code up soon so you can all look at it.

bemcdonnell commented 6 years ago

@dickinsonre, in my initial testing, this seems to be working.

int DLLEXPORT swmm_getConduitParam(int index, int Param, double *value)
//
// Input:   index = Index of desired ID
//          param = Parameter desired (Based on enum SM_ConduitProperty)
//          value = value to be output
// Return:  API Error
// Purpose: Gets Conduit Parameter
{
    int errcode = 0;
    *value = 0;
    // Check if Open
    if(swmm_IsOpenFlag() == FALSE)
    {
        errcode = ERR_API_INPUTNOTOPEN;
    }
    // Check if object index is within bounds
    else if (index < 0 || index >= Nobjects[LINK])
    {
        errcode = ERR_API_OBJECT_INDEX;
    }
    else if ( Link[index].type != CONDUIT)
    {
        errcode = ERR_API_WRONG_TYPE;
    }
    else
    {
        int k = Link[index].subIndex;
        switch (Param)
        {
            case SM_LENGTH: 
                *value = Conduit[k].length * UCF(LENGTH); break;
            case SM_ROUGHNESS:
                *value = Conduit[k].roughness; break;
            case SM_BARRELS:
                *value = (double)Conduit[k].barrels; break;
            default: errcode = ERR_API_OUTBOUNDS; break;
        }
    }
    return(errcode);
}

int DLLEXPORT swmm_setConduitParam(int index, int Param, double value)
//
// Input:   index = Index of desired ID
//          param = Parameter desired (Based on enum SM_ConduitProperty)
//          value = value to be input
// Return:  API Error
// Purpose: Sets Conduit Parameter
{
    int errcode = 0;
    int us_node, ds_node;
    // Check if Open
    if(swmm_IsOpenFlag() == FALSE)
    {
        errcode = ERR_API_INPUTNOTOPEN;
    }
    // Check if Simulation is Running
    else if(swmm_IsStartedFlag() == TRUE)
    {
        errcode = ERR_API_SIM_NRUNNING;
    }
    // Check if object index is within bounds
    else if (index < 0 || index >= Nobjects[LINK])
    {
        errcode = ERR_API_OBJECT_INDEX;
    }
    // Check if is Conduit Type
    else if ( Link[index].type != CONDUIT)
    {
        errcode = ERR_API_WRONG_TYPE;
    }
    else
    {
        int k = Link[index].subIndex;
        double elev = 0;
        switch (Param)
        {
            case SM_LENGTH: 
                Conduit[k].length = value / UCF(LENGTH); break;
            case SM_ROUGHNESS:
                Conduit[k].roughness = value; break;
            case SM_BARRELS:
                Conduit[k].barrels = (char)(int)value; break;
            default: errcode = ERR_API_OUTBOUNDS; break;
        }

        // This code re-establishes the offsets as elevations
        // since it will be reconverted back to offsets if the 
        // mode is in ELEV_OFFSET. 
        // Get node indeces (Depends of Flow Direction)
        if (Link[index].direction == 1)
        {
            us_node = Link[index].node1;
            ds_node = Link[index].node2;
        }
        else
        {
            us_node = Link[index].node2;
            ds_node = Link[index].node1;
        }
        // Set offset
        if (Param == SM_OFFSET1)
        {
            if ( LinkOffsets == ELEV_OFFSET ) elev = Node[us_node].invertElev;
            Link[index].offset1 = elev + value / UCF(LENGTH);
        }
        if (Param == SM_OFFSET2)
        {
            if ( LinkOffsets == ELEV_OFFSET ) elev = Node[ds_node].invertElev;
            Link[index].offset2 = elev + value / UCF(LENGTH);
        }
        // Re-validate link
        link_validate(index); 

    }
    return(errcode);
}
AnmaTech commented 6 years ago

HEllo;

I wonder whether it is possible to change the Manning's roughness parameter in a given conduit using last version of pyswmm?

Did you put these changes in library?

Thanks

bemcdonnell commented 6 years ago

@anmatech, let me see what I can do. I have these changes in my private fork of pyswmm. Let me see what I can do to bring them in

Argantonio65 commented 4 years ago

@bemcdonnell Was this finally merged into pyswmm? I saw that the link parameter pointers do not show roughness as an option.

Thanks a lot

bemcdonnell commented 4 years ago

@Argantonio65, circling back to your question - I haven't merged it in but if you want to take over that pull request, we can help you through the process!

juanaherran commented 2 years ago

Hello!

I would like to know if the latest version of pyswmm allows to change the roughness of the pipes.

Thanks a lot.

jennwuu commented 2 years ago

Hey @juanaherran, at the moment, you will need to adjust the model swmm input file manually before using pyswmm.

theafromhust commented 2 years ago

Hi, I wonder if the latest version of pyswmm allows to change the roughness or the diameter of the pipes.

Thanks a lot

bemcdonnell commented 5 months ago

Completed with pyswmm-v2