# Volume-Calculation count up flow signal until a max Volume is reached

Go to solution Solved by John Brezovec,

## Recommended Posts

I have a flow in and flow out in l/h at a tank. What I´m trying to achieve is count up the flow in and flow out and get a capsule once a specific amount of liter as passed the tank, then reset and count up for next capsule.

Convert signals toStep() ? and then make a runningSum(), save as variable and stop when the volume reached.

Can that be depicted in one formula?

##### Share on other sites

• Seeq Team
• Solution

If I understand correctly, you have a Flow Signal (L/hr), and want to create a capsule every time that flow sensor sees a certain amount of material. It sounds like you want to do some math with multiple flow sensors, but I think that'll be very similar to how we can treat just one.

The problem requires us to choose an inception time -- that is, when do we first start counting? Let's assume we want to start counting every year. We can represent that by creating a periodic condition with a capsule every year. In the periodic condition tool, select a Yearly duration:

We can then do a running integral over each year using the integral function:

`\$flow.integral(\$years)`

This will end up looking like:

Then, we can generate a capsule every time a certain quantity passes through this meter (say 1000L) using some additional formula, where \$integral is the running integral we just created.

```\$reset_quantity = 1000L
floor(\$integral/\$reset_quantity).toCondition()```

They key to this formula is the floor function, which will round down to the nearest integer, allowing us to 'chop up' the integral into 1000L chunks. This will generate the blue condition below, where we have a new capsule every 1000L:

If desired, you could then do another integral on top of the blue condition to give you a running integral that resets every 1000L:

This result could also be expressed as a single formula:

```\$years = years()
\$reset_quantity = 1000 L

\$yearly_integral = \$flow.integral(\$years)
\$fill_events = floor(\$yearly_integral/\$reset_quantity).toCondition()

\$flow.integral(\$fill_events.removeLongerThan(10d))```
##### Share on other sites

thank you, that is what I was looking for

##### Share on other sites

• 1 month later...

A follow up question on this: Could the formula / logic be extended to have the \$reset_quantity not be static but been read from another capsule property?

F.e. Sum up over the year, but there are capsules each \$month which have different liters per month to be used as \$reset_quantity?

Thanks

##### Share on other sites

• Seeq Team

For that case, I'd suggest doing the running integral over each time period that has a different \$reset_quantity. In your example, if you have a different reset quantity for each month, do the running integral over each month. This will keep the behavior across reset quantities consistent since the integral will reset:

If you approach it this way, all you have to do is swap out the \$reset_quantity for a signal:

```\$months = months()
// pull your reset quantity from a capsule property to a signal
// in this case, I'm just creating a dummy signal
\$reset_quantity = \$months.toSignal('Month') * 1000

\$monthly_integral = \$flow.integral(\$months)
\$fill_events = floor(\$monthly_integral/\$reset_quantity).toCondition()

\$flow.integral(\$fill_events.removeLongerThan(10d))```
##### Share on other sites

Thanks, it runs perfectly within this example, unfortunalty my real data is different 😉

It is a continuous process which I like to chunk into UnitOperations based on Volume Calculations.

Tried to sketch my usecase:

The Problem is that on my data the capsules which have the reset information are actually to
small that the runningSum (integral) in it can reach the reset_quantity

What I´m trying to achieve:
everytime a capsule starts of the initial condition1 -> start doing the integral running sum L/min of the flow,
until a dynamic limit is reached (based on the capsule properties, per capsule on condition1, one after another)

and finally get a signal / condition(capsules)

thanks alot in advance, really appreciate all that very beneficial input from this Seeq forums

##### Share on other sites

I´m thinking about something like:

```\$condition2.transform(\$c -> // to loop over each capsule
\$c.setProperty('min_for_vol', // create a new property
floor(\$flow_integral_signal/\$c.property("Rvol")) // for the first time the liters from the this capsule-property passed on the flow signal
.toCondition()
.removeLongerThan(3d)
.ToGroup(\$c)
.pick(1).duration().convertUnits('min')
))
```

It still does not behave as I need it, but it might be in the right direction for my usecase. The generated capsules / times are way to short now.

For the floor calculation, does the capsule start also need to be defined if it should start it at the beginning of each capsule?

Next step could be to generate a signal / condition based on the new capsule property.

##### Share on other sites

• Seeq Team

So is the desired behavior to start integrating at the start of each capsule, and then only close the capsule once the flow rate has been reached? By nature of that logic you'll have overlapping or non-continuous capsules.

The issue with the formula you wrote is that \$flow_integral_signal isn't going to reset at the start of each capsule, so floor won't actually find the point that it rolls past Rvol, but instead find when the yearly integral rolls past the a multiple of Rvol.

We can take a slightly different approach and calculate what value the yearly integral needs to be before the capsule should end, find the timestamp of that event, and use that as the end key of your capsule:

```\$condition_with_reset_quantity
.move(0, 1wk) // grow the condition since a transform can only output capsules if they are within the originals
.transform(\$c -> {
// find the value of the yearly integral at the start of the capsule
\$start_value = \$yearly_integral.valueAt(\$c.startKey())
// what value should we stop the capsule at?
\$end_value = \$start_value + \$c.property('Reset Quantity')
// generate a condition internal to the transform that tells us when we reach this end value
\$cond_volume_reached = \$yearly_integral == \$end_value
// turn this condition back into a capsule so we can grab its start key
\$cap_volume_reached = \$cond_volume_reached.removeLongerThan(10d).toGroup(\$c).first()
// create the output condition. Manually reassign the Reset Quantity property
capsule(\$c.startKey(), \$cap_volume_reached.startKey())
.setProperty('Reset Quantity', \$c.property('Reset Quantity'))
})
// just to prove our capsules generated correctly
.setProperty('Delta', \$yearly_integral, delta())```

This results in a condition that looks like:

Note how each blue capsule has the same start of a pink capsule, but only ends once the corresponding volume has been achieved.

##### Share on other sites

Posted (edited)

I´m at the same time impressed by the capabilities of Seeq and thankful for your help.

Works perfectly also for my use case, only had to add one little thing (since I do not have the Unit inside the capsule property)

`\$end_value = \$start_value + (\$c.property('Rvol')).setUnits('L')`

Feeling already sorry for all my questions, but maybe one more follow up questions more:

Is it also possible that on that resulting overlapping capsules, starting with capsule 1, the durations will stay, but the start key of capsule 2 will be put directly after the end of capsule 1 and so on with all the capsules?

Edited by hanskanns
##### Share on other sites

• Seeq Team

If you do that, you're likely going to keep pushing your capsules further and further out into the future. Can you share more about the use case so I can make sure we're going down the right path?

##### Share on other sites

Thanks for asking about that John B.
It is a batch process (reactors) which then starts to be a continuous process.
The general idea is to track how long each reactor batch (based on volume calculations)
is how long (residence time) in the following UnitOperations.
What we basically calculated so far (examples above) are the timeframes when something comes
from the reactors (dynamic reset signal pink capsules, goes to the first UO -> blue capsules).
And the blue capsules are longer then the pink ones, because it is diluted and the product resides longer in that UO as the next Reactor-batch arrives...

So I was thinking it might be interessting to put that blue capsules one after another,
to basically ignore the dilution effect and just keep on the volumes, but after rethinking
that would be not a right calulation, because as you mentioned if would delay the blue capsules
more and more to the past and ignore the dilution, which is not realistic.

I hope that desciption is understandable?

##### Share on other sites

• Seeq Team

Thanks for the additional context. I agree I'm not sold on the utility of stacking the capsules end-to-end, but I figured I'd give an example of how it could be done since it may help move you in the right direction.

In much the same way we calculated when the capsule should end based on the start_value + reset_quantity, we can find when the capsule should start based on the reset quantities of all the capsules before it in the same year (since we reset the totalizer every year). In practice this adds a bit of complexity to the formula 😉

```\$grow_amount = 3wk

\$condition_with_reset_quantity
.move(-\$grow_amount, \$grow_amount) // grow the condition since a transform can only output capsules if they are within the originals
.transform(\$c -> {
\$actual_start_key = \$c.startKey() + \$grow_amount // un-grown capsule start
\$actual_end_key = \$c.endKey() - \$grow_amount // un-grown capsule end

\$actual_input_capsule = capsule(\$actual_start_key, \$actual_end_key)
\$current_year_capsule = \$years.toGroup(\$actual_input_capsule, CAPSULEBOUNDARY.overlap)
.first()
\$current_year_start = \$current_year_capsule.startKey()

// find all the reset quantity capsules that overlap the year
// then sum up all the 'Reset Quantities' for those capsules.
\$start_value = \$condition_with_reset_quantity.toGroup(capsule(\$current_year_start, \$actual_start_key+1ns), CAPSULEBOUNDARY.INTERSECT)
.forEach(\$cap -> \$cap.property('Reset Quantity'))
.sum() - \$c.property('Reset Quantity')

// what value should we stop the capsule at?
\$end_value = \$start_value + \$c.property('Reset Quantity')
// generate a condition internal to the transform that tells us when we reach this end value
\$cond_volume_reached = \$yearly_integral == \$end_value
// turn this condition back into a capsule so we can grab its start key
\$cap_volume_reached = \$cond_volume_reached.removeLongerThan(1s)
.toGroup(\$c)
.last()
// do the same thing with the start value
\$start_volume_reached = \$yearly_integral == \$start_value
\$cap_start_volume_reached = \$start_volume_reached.removelongerthan(1s)
.toGroup(\$c)
.last()

// create the output condition. Manually reassign the Reset Quantity property
capsule(\$cap_start_volume_reached.startkey(), \$cap_volume_reached.startKey())

.setProperty('Reset Quantity', \$c.property('Reset Quantity'))
.setProperty('Start Quantity', \$start_value)
.setProperty('End Quantity', \$end_value)

})```

Notice how the resultant purple capsules stack end-to-end. The first capsule property on the purple condition is the reset quantity for that capsule, the second is the volume we should start that capsule at, and the third is the volume we want to end the capsule at. As a noted before, notice how the capsules are starting to creep forward over time.

##### Share on other sites

Quote

a bit of complexity to the formula

thats good 🙂

Step by step I´m understanding how to work with capsules and formulas. Magnificent whats possible there.

Thanks again.

## Create an account or sign in to comment

You need to be a member in order to leave a comment

## Create an account

Sign up for a new account in our community. It's easy!

Register a new account