# How to implement periodic boundary conditions with callbacks?

**URL:** <https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493>\
**Category:** Specific Domains\
**Tags:** question, diffeq\
**Created:** [August 4, 2023, 3:42pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493 "2023-08-04T15:42:57Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![roi.holtzman](https://avatars.discourse-cdn.com/v4/letter/r/f05b48/32.png) [@roi.holtzman](https://discourse.julialang.org/u/roi.holtzman)\
**Post date:** [August 4, 2023, 3:42pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/1 "2023-08-04T15:42:58Z")

</div>

I am trying to use 2 callbacks when solving a differential equation.  
I am trying to solve for a pendulum, so I have a cyclic coordinate that goes from (-\pi, \pi). So when the coordinate goes above \pi I want it to shift by -2\pi, and when it goes below -\pi I want it to shift by +2\pi.

I tried to have two callbacks:

```julia
function condition_pi(u, t, integrator) 
    u[1] - π
end

function condition_min_pi(u, t, integrator) 
    u[1] + π
end

function affect_pi!(integrator)
    integrator.u[1] = integrator.u[1] - 2π
end

function affect_min_pi!(integrator)
    integrator.u[1] = integrator.u[1] + 2π
end

cb_pi = ContinuousCallback(condition_pi, affect_pi!)
cb_min_pi = ContinuousCallback(condition_min_pi, affect_min_pi!)
cb_set = CallbackSet(cb_pi, cb_min_pi)

```

This does not work. I think the reason is that when the solution hits x=\pi, it sends it back by -2\pi, which then makes it less than -\pi, and then it wants to send it forward by +2\pi, and there is an infinite loop.

So the question is, how can I implement these boundary conditions?

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 4, 2023, 3:52pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/2 "2023-08-04T15:52:54Z")

</div>

> [@roi.holtzman](#):
>
> So when the coordinate goes above \pi I want it to shift by -2\pi, and when it goes below -\pi I want it to shift by +2\pi.

Seems a lot easier to allow your angles \theta to be arbitrary, write your equations in terms of functions like \sin(\theta) that are insensitive to shifts of 2\pi, and then transform the coordinates modulo 2\pi afterwards if you like (e.g. for plotting solutions).

---

<div class="post-metadata">

**Author:** ![tomaklutfu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomaklutfu/32/2411_2.png) [@tomaklutfu](https://discourse.julialang.org/u/tomaklutfu)\
**Post date:** [August 4, 2023, 3:56pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/3 "2023-08-04T15:56:37Z")

</div>

AFAIK, you need to set `affect_neg` argument to `nothing`.

---

<div class="post-metadata">

**Author:** ![roi.holtzman](https://avatars.discourse-cdn.com/v4/letter/r/f05b48/32.png) [@roi.holtzman](https://discourse.julialang.org/u/roi.holtzman)\
**Post date:** [August 4, 2023, 3:58pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/4 "2023-08-04T15:58:59Z")

</div>

I know. But I have other reasons that I want the coordinate to be between (-\pi, \pi). I have some functions that cannot be defined beyond this range.

---

<div class="post-metadata">

**Author:** ![roi.holtzman](https://avatars.discourse-cdn.com/v4/letter/r/f05b48/32.png) [@roi.holtzman](https://discourse.julialang.org/u/roi.holtzman)\
**Post date:** [August 4, 2023, 3:59pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/5 "2023-08-04T15:59:47Z")

</div>

What is `affect_neg`? I couldn’t find it in the documentation.

---

<div class="post-metadata">

**Author:** ![bensetterholm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bensetterholm/32/12792_2.png) [@bensetterholm](https://discourse.julialang.org/u/bensetterholm)\
**Post date:** [August 4, 2023, 3:59pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/6 "2023-08-04T15:59:54Z")

</div>

If you can change your calculation domain to go from [0, 2π) instead, then you can simply do

```julia
u -> mod(u[1], 2π)

```

---

<div class="post-metadata">

**Author:** ![roi.holtzman](https://avatars.discourse-cdn.com/v4/letter/r/f05b48/32.png) [@roi.holtzman](https://discourse.julialang.org/u/roi.holtzman)\
**Post date:** [August 4, 2023, 4:03pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/7 "2023-08-04T16:03:08Z")

</div>

This would be a pain for me since I have some other complicated functions that are defined for the range (-\pi, \pi).

---

<div class="post-metadata">

**Author:** ![tomaklutfu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomaklutfu/32/2411_2.png) [@tomaklutfu](https://discourse.julialang.org/u/tomaklutfu)\
**Post date:** [August 4, 2023, 4:03pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/8 "2023-08-04T16:03:43Z")

</div>

Callbacks have both increasing and decreasing crossing `affect`s. You don’t want negative crossing. By default, they are both set to the same `affect`.

> [@roi.holtzman](#):
>
> `ContinuousCallback(condition_pi, affect_pi!)`

---

<div class="post-metadata">

**Author:** ![bensetterholm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bensetterholm/32/12792_2.png) [@bensetterholm](https://discourse.julialang.org/u/bensetterholm)\
**Post date:** [August 4, 2023, 4:06pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/9 "2023-08-04T16:06:42Z")

</div>

Would this be numerically accurate enough for your usecase?

```julia
u -> mod(u[1] + π, 2π) - π

```

---

<div class="post-metadata">

**Author:** ![roi.holtzman](https://avatars.discourse-cdn.com/v4/letter/r/f05b48/32.png) [@roi.holtzman](https://discourse.julialang.org/u/roi.holtzman)\
**Post date:** [August 4, 2023, 4:09pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/10 "2023-08-04T16:09:25Z")

</div>

> [@tomaklutfu](#):
>
> Callbacks have both increasing and decreasing crossing `affect`s. You don’t want negative crossing. By default, they are both set to the same `affect`.

Could you elaborate? I don’t understand what you mean.

---

<div class="post-metadata">

**Author:** ![roi.holtzman](https://avatars.discourse-cdn.com/v4/letter/r/f05b48/32.png) [@roi.holtzman](https://discourse.julialang.org/u/roi.holtzman)\
**Post date:** [August 4, 2023, 4:11pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/11 "2023-08-04T16:11:14Z")

</div>

Nice idea!  
I will try, though I need very good numerical accuracy.

---

<div class="post-metadata">

**Author:** ![tomaklutfu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomaklutfu/32/2411_2.png) [@tomaklutfu](https://discourse.julialang.org/u/tomaklutfu)\
**Post date:** [August 4, 2023, 4:11pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/12 "2023-08-04T16:11:33Z")

</div>

Check the `affect!` and `affect_neg!` arguments here:  
[https://docs.sciml.ai/DiffEqDocs/stable/features/callback\_functions/#ContinuousCallback](https://docs.sciml.ai/DiffEqDocs/stable/features/callback_functions/#ContinuousCallback)

---

<div class="post-metadata">

**Author:** ![roi.holtzman](https://avatars.discourse-cdn.com/v4/letter/r/f05b48/32.png) [@roi.holtzman](https://discourse.julialang.org/u/roi.holtzman)\
**Post date:** [August 4, 2023, 4:20pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/13 "2023-08-04T16:20:50Z")

</div>

Thanks!  
That actually works:

> [@tomaklutfu](#):
>
> Check the `affect!` and `affect_neg!` arguments here:  
> [Event Handling and Callback Functions · DifferentialEquations.jl](https://docs.sciml.ai/DiffEqDocs/stable/features/callback_functions/#ContinuousCallback)

Here is the code:

```julia
function affect_pi!(integrator)
    integrator.u[1] = integrator.u[1] - 2π
end

function affect_pi_neg!(integrator)
    integrator.u[1] = integrator.u[1]
end

function affect_min_pi!(integrator)
    integrator.u[1] = integrator.u[1]
end

function affect_min_pi_neg!(integrator)
    integrator.u[1] = integrator.u[1] + 2π
end

cb_pi = ContinuousCallback(condition_pi, affect_pi!, affect_pi_neg!)
cb_min_pi = ContinuousCallback(condition_min_pi, affect_min_pi!, affect_min_pi_neg!)

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [August 4, 2023, 8:19pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/14 "2023-08-04T20:19:45Z")

</div>

> [@roi.holtzman](#):
>
> I have some functions that cannot be defined beyond this range.

Why not just call `ũ = mod2pi(u[1] + π) - π` before calling those functions? Why does the ODE solver have to know that you are interpreting a coordinate cyclically?

---

<div class="post-metadata">

**Author:** ![roi.holtzman](https://avatars.discourse-cdn.com/v4/letter/r/f05b48/32.png) [@roi.holtzman](https://discourse.julialang.org/u/roi.holtzman)\
**Post date:** [August 4, 2023, 8:34pm UTC](https://discourse.julialang.org/t/how-to-implement-periodic-boundary-conditions-with-callbacks/102493/15 "2023-08-04T20:34:00Z")

</div>

> [@stevengj](#):
>
> Why not just call `ũ = mod2pi(u[1] + π) - π` before calling those functions? Why does the ODE solver have to know that you are interpreting a coordinate cyclically?

That’s also a nice idea. I tested this, but it works less well than using the callback. Perhaps it’s an issue of the numerical accuracy of mod?  
I am using `ArbFloat` to solve to try to achieve good accuracy.
