# Setting an upper and lower limit on a differential equation

**URL:** <https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144>\
**Category:** General Usage\
**Created:** [June 10, 2020, 4:50pm UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144 "2020-06-10T16:50:26Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 10, 2020, 4:50pm UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/1 "2020-06-10T16:50:26Z")

</div>

This is the last piece I need for my model to work, yet the result keeps going over what I thought I had set the limit to.

The simplified scenario is: there is a fishing boat - on the boat work is done - the amount of work depends on the money gained from fishing. There is a limit to how much or how little work is done on the boat. If the upper limit (`max_work`) is reached a new boat is bought, and if the lower limit (`min_work`) is reached a boat is sold. (Boat buying/selling is a different equation but I wanted to give more background)

```julia
...
            if (revenue - cost) > 0.0
                limit = max_work
                effect = abs(max(0.0, (limit - work)))
            else
                limit = clearance_min
                effect = abs(min(0.0, (limit - work)))
            end
            du[work] = 365.25*µ*(revenue - cost)*effect
            work = u[work]
...

```

But this doesn’t work, so I tried

```julia
            if (revenue - cost) > 0.0
                limit = max_work
                effect = abs(max(0.0, (limit - work)))
            else
                limit = min_work
                effect = abs(min(0.0, (limit - work)))
            end
            du[work] = 365.25*µ*(revenue - cost)*effect
            work = u[work]
            if work > max_work
                work = max_work
                u[work] = max_work
            end
            if work < min_work
                work = min_work
                u[work] = min_work
            end

```

And this does not work either. `y3` is the upper limit, `u84` is work.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/4/d/4d74d457cd01338f38ea1076fb63680b5a6726ab.png)

---

<div class="post-metadata">

**Author:** ![pjentsch0](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/pjentsch0/32/15148_2.png) [@pjentsch0](https://discourse.julialang.org/u/pjentsch0)\
**Post date:** [June 10, 2020, 4:57pm UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/2 "2020-06-10T16:57:21Z")

</div>

See [DiffEqCallbacks.jl](https://github.com/SciML/DiffEqCallbacks.jl), specifically the

```julia
GeneralDomain(g, u=nothing; nlsolve=NLSOLVEJL_SETUP(), save=true,
                       abstol=nothing, scalefactor=nothing, autonomous=numargs(g)==2,
                       nlopts=Dict(:ftol => 10*eps()))

```

which fixes the solution into a domain. From the docs: “Domains are specified by in-place functions `g(u, resid)` or `g(t, u, resid)` that calculate residuals of a state vector `u` at time `t` relative to that domain. As for `PositiveDomain` , steps are accepted if residuals of the extrapolated values at the next time step are below a certain tolerance.”

I think that should do what you are looking for.

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 11, 2020, 6:19am UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/3 "2020-06-11T06:19:56Z")

</div>

Thank you for your reply. What is the reason for not being able to set the limit mathematically?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 11, 2020, 6:36am UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/4 "2020-06-11T06:36:46Z")

</div>

If your ODE actually goes over the limit, what would this even mean? Do you have an analytical result that says the solution should never go over that limit? The first thing you might want to do is reduce the tolerances a little bit.

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 11, 2020, 8:21am UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/5 "2020-06-11T08:21:28Z")

</div>

If I understand your question, the ODE should not be possible to go over the limit. This is due to how the system is designed. I have three base work scenarios: revenue driven, cost minimization, and static, or in-between the other two. A fourth scenario, the one I am trying to plot now, is adaptive based on profit (revenue - cost). It should not be able to go over the system’s maximum work rate.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/c/2/c24a3abb02cfd8594c981c71a84edd3056674ef0.png)

My solver is defined as

```julia
    fishing_sol = solve(fishing_prob, alg = CVODE_BDF(), abstol = 1e-6, reltol = 1e-3, callback=cb_set)

```

I will try reducing the tolerances. Do I need to also state error tolerances in a saving callback?

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 11, 2020, 8:27am UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/6 "2020-06-11T08:27:57Z")

</div>

> [@HelgavonLichtenstein](#):
>
> I will try reducing the tolerances. Do I need to also state error tolerances in a saving callback?

nope

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 11, 2020, 8:31am UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/7 "2020-06-11T08:31:35Z")

</div>

Reducing tolerances (`abstol = 1e-5, reltol = 1e-2`) makes it wiggle around near the end, but the issue remains.

 ![image](https://global.discourse-cdn.com/julialang/original/3X/d/6/d639d4dce5697be5aeab1edd0d930fa5976b41ba.png)

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 11, 2020, 9:00am UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/8 "2020-06-11T09:00:48Z")

</div>

No, reduce the numbers: `abstol=1e-8,reltol=1e-8`.

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 11, 2020, 9:14am UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/9 "2020-06-11T09:14:32Z")

</div>

Right. Sorry, my mistake.

It doesn’t change much I’m afraid.

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 11, 2020, 12:00pm UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/10 "2020-06-11T12:00:58Z")

</div>

This is becoming very complicated.

Is this the correct way to define `GeneralDomain`?

```julia
function g(u, resid)
  resid[end] = max(0, u[work] - max_work)
end

new_cb = GeneralDomain(g, u=nothing; nlsolve=NLSOLVEJL_SETUP())

```

And now I need to define `NLSOLVEJL_SETUP` but it feels this is over my head. [https://docs.sciml.ai/release-5.0/features/linear\_nonlinear.html#Nonlinear-Solvers:-nlsolve-Specification-1](https://docs.sciml.ai/release-5.0/features/linear_nonlinear.html#Nonlinear-Solvers:-nlsolve-Specification-1)

I still don’t understand why it’s not possible to define the limits mathematically.

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 11, 2020, 5:43pm UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/11 "2020-06-11T17:43:10Z")

</div>

> [@HelgavonLichtenstein](#):
>
> I still don’t understand why it’s not possible to define the limits mathematically.

Because the ODE has a unique solution given by `u' = f(u,p,t)`. Mathematically, the only way to add limits to the ODE are if the limits are larger than the solution. This means that numerically the limits only make sense to restrict the function to the true limits of the true `u(t)`: you cannot numerically add limits that will change `u(t)`, because then the solver will exit and fail when it realizes that the problem is not well-posed.

> [@HelgavonLichtenstein](#):
>
> It doesn’t change much I’m afraid.

This should be correct to about 5-6 decimal places, so if that’s still above where you want, you need to look at the formulation of the model.

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 11, 2020, 9:03pm UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/12 "2020-06-11T21:03:05Z")

</div>

Using a callback to change the values gets the required effect…

```julia
function condition_cl(bioS, t, integrator)
  max_work - bioS[end]
end

function affect_cl!(integrator)
      integrator.u[end] = max_work - 0.001
end

```

…but looks suspicious

 ![image](https://global.discourse-cdn.com/julialang/original/3X/a/b/ab3798146bb2a27db687b2426fe68fe637d14711.png)

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 11, 2020, 9:05pm UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/13 "2020-06-11T21:05:50Z")

</div>

It looks like the true solution goes over that “limit”. Are you sure the equation is purely conservative enough to allow for that limit to hold?

---

<div class="post-metadata">

**Author:** ![HelgavonLichtenstein](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/helgavonlichtenstein/32/5005_2.png) [@HelgavonLichtenstein](https://discourse.julialang.org/u/HelgavonLichtenstein)\
**Post date:** [June 12, 2020, 12:13pm UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/14 "2020-06-12T12:13:45Z")

</div>

My colleague figured it out - things were not defined in the right order and stuff was being calculated with the wrong values. 🙃

---

<div class="post-metadata">

**Author:** ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)\
**Post date:** [June 12, 2020, 2:56pm UTC](https://discourse.julialang.org/t/setting-an-upper-and-lower-limit-on-a-differential-equation/41144/15 "2020-06-12T14:56:51Z")

</div>

Good to hear it’s all working now. Good luck!
