Flipping Your Model with Goalseek

Although it is possible to figure out how to solve equations for different variables, it can become incredibly complex to do when there's a lot of variables or calculations involved.

Based on our example - where we determine how many seconds of water we have left in the tank - we want to determine how full the tank needs to be to guarantee we have at least 5 minutes of water stored.

We could work out the equation to solve this, but in this case, we're a little lazy. We are going to use goal-seeking.

Goal-seeking basically asks the system “What value would I need for A so that the value of B is C?”

In this case, we're going to ask “what level would we need in the tank to guarantee 60 seconds of water?”.

Adding Constants First

Because that time threshold has the potential to change in the future, we'll add a new constant to hold it.

MinTiming = mod.AddConstant("Tank Minimum Storage Time",60)

Adding the Goalseek

GoalSeek is a member of the Model class.

It takes three parameters - the point you want to discover (ie. the Level), the point you want to watch (the time) and the value we're watching for (the minimum timing, our 60s constant we just created).

mod.AddOutput("Min Level", lambda: mod.GoalSeek(LevelPerc,RemainingTime,MinTiming.num()),[LevelPerc,RemainingTime,MinTiming])

You can see the documentation on the GoalSeek function here.

The Results

When run, the new model gives us a Min Level output of '5', indicating that the tank needs to be at least 5% full in order to ensure there's a minute of water remaining.

If we adjust the constant to 120s instead of 60, it immediately updates to 10% rather than 5.

Full Code

import ardimodel

host = ardimodel.ModelHost()

def TankModel(mod):
    Outflow = mod.AddInput("Outgoing Flow",10)
    LevelPerc = mod.AddInput("Tank Level Perc",50)
    
    Capacity = mod.AddConstant("Tank Max Volume",12000)
    MinTiming = mod.AddConstant("Tank Minimum Storage Time",60)
    
    Volume = mod.AddOutput("Tank Volume", lambda: (LevelPerc.num() / 100) * Capacity.num(), [LevelPerc,Capacity])
    RemainingTime = mod.AddOutput("Time-To-Empty", lambda: 86300 if Outflow.num() == 0 else Volume.num() / Outflow.num(), [Outflow,Volume])
    mod.AddOutput("Min Level", lambda: mod.GoalSeek(LevelPerc,RemainingTime,MinTiming.num()),[LevelPerc,RemainingTime,MinTiming])

# Add Models Here
host.Add(ardimodel.Create("Tank",TankModel))

host.ardiurl = "localhost"
host.ardisite="default"
host.Run()

See More

That takes you through most of the basics - you're now ready to build your own models and experiment.

There are also a few tips and tricks you can try if you're making complex models.