Skip to content

How to get derivative of final time with respect to a variable #451

Description

@nsteffen

Hello!

I am working on a problem where I want to propagate a trajectory using diffrax, use a discrete terminating event to end that trajectory, and then get the derivative of that final time with respect to a variable. Regardless of the problems I have tried to do this on, the gradient of the final time always ends up as zero. Below is an example where I model the simplified dynamics of a cannonball and I try to evaluate the gradient of the final time with respect to the coefficient of drag.

import jax
import jax.numpy as jnp
import diffrax as dfx
jax.config.update('jax_enable_x64', True)


def dynamics(t, y, CD):
    g = 9.80665 # m/s^2
    rho = 1.225 # kg/m^3
    S = 0.005 # m^2
    m = 1. # kg

    v = y[2]
    gam = y[3]
    
    D = (0.5*rho*v**2)*S*CD
    
    sin_gam = jnp.sin(gam)
    cos_gam = jnp.cos(gam)
    ydot = jnp.array([v*cos_gam,        # rdot
                      v*sin_gam,        # hdot
                      -D/m - g*sin_gam, # vdot
                      -(g*cos_gam)/v])  # gamdot

    return ydot


def event(state, **kwargs):
    h = state.y[1]
    return h < 0.


def obj(CD):
    t0 = 0.
    t1 = 20.
    dt0 = None
    y0 = jnp.array([0.,                 # r0
                    100.,               # h0
                    5.,                 # v0
                    jnp.deg2rad(45.)])  # gam0

    solver = dfx.Tsit5()
    stepsize_controller = dfx.ConstantStepSize()
    saveat = dfx.SaveAt(ts=jnp.linspace(t0, t1, 100))
    
    sol = dfx.diffeqsolve(dfx.ODETerm(dynamics),
                          solver,
                          t0,
                          t1,
                          0.1,
                          y0,
                          args=CD,
                          stepsize_controller=stepsize_controller,
                          max_steps=None,
                          saveat=saveat,
                          discrete_terminating_event=event,
                          adjoint=dfx.RecursiveCheckpointAdjoint(checkpoints=100)
                          )
    
    ts = sol.ts[jnp.where(jnp.isfinite(sol.ts))]    
    return ts[-1]


if __name__ == '__main__':
    CD = 0.5
    print(jax.grad(obj)(CD))

Is there a correct/better way to do this? Thanks in advance!

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions