Full-order model (FOM) adapter API

The FOM adapter is the layer standardizing how pressio queries operators from an application.

It is one of the most important features and a pivotal design in pressio.


Steady API

Intended for when your FOM application is expressed as

\[ \boldsymbol{R}(\boldsymbol{y}; \boldsymbol{\mu}) = 0 \]

where $y$ is your FOM state, and $R$ is the residual todo finish.

Synopsis

class SteadyAdapter:

  def createResidual(self):
    return np.zeros(...)

  def createApplyJacobianResult(self, operand):
    return np.zeros_like(operand)

  def residual(self, stateIn, R):
    # compute residual

  def applyJacobian(self, stateIn, operand, C):
    # compute apply Jacobian
    # for example:
    #   J = self.jacobian(stateIn)
    #   C[:]  = J.dot(operand)

Notes

The steady adapter can ONLY be used for doing steady LSPG ROMs.

See the following examples: \toadd




Continuous-time API: RHS only

Intended for when your FOM application is expressed in time-continuous form as

\[ \frac{d \boldsymbol{y}}{dt} = \boldsymbol{f}(\boldsymbol{y},t; \boldsymbol{\mu}), \quad \boldsymbol{y}(0;\boldsymbol{\mu}) = \boldsymbol{y}(\boldsymbol{\mu}), \]

where $y$ is the full-order model (FOM) state, $f$ is what we call the FOM velocity (or RHS), and $t$ is time, and, for some reason, you can/want to only expose the right-hand-side (or velocity) of your FOM application. todo finish.

Synopsis

class ContTimeFomAdapterVelocityOnly:

  # create f(y,t,...)
  def createVelocity():
    # say N is the total number of of unknowns
    return np.zeros(N)

  # compute velocity, f(y,t;...), for a given state, y, and time, t
  def velocity(self, y, t, f):
    f[:] = #compute velocity as needed

Notes

This adapter can ONLY be used for doing Galerkin ROMs with explicit time stepping.




Continuous-time API: RHS and Jacobian action

This API is intended for any system expressible in time-continuous form as above, but you expose both the right-hand-side of your FOM application as well as the action of the velocity's Jacobian on some operand (more on this later).

Synopsis

class ContTimeFomAdapterWithApplyJacobian

  # create f(y,t,...)
  def createVelocity():
    # say N is the total number of of unknowns
    return np.zeros(N)

  # create result of df/dy*B
  # B is typically a skinny dense matrix (e.g. POD modes)
  def createApplyJacobianResult(self, B):
    return np.zeros((N, B.shape[1]))

  # compute velocity, f(y,t;...), for a given state, y
  def velocity(self, y, t, f):
    f[:] = #compute velocity as needed

  # given current state y(t):
  # compute A=df/dy*B, where B is a skinny dense matrix
  # Note that we just require the *action* of the Jacobian.
  def applyJacobian(self, y, B, t, A):
    A[:,:] = # compute A = df/dy * B as needed

Notes

  • Can be used for doing Galerkin ROMs with explicit and implicit time stepping
  • Can be used for LSPG and WLS (note that LSPG and WLS only make sense for implicit time integration).




Discrete-time API

This API is intended for any system expressible in a discrete-time form as

\[ \boldsymbol{R}(\boldsymbol{y_{n+1}}, \boldsymbol{y_{n}}, \boldsymbol{y_{n-1}}, ..., t_{n+1}, dt_{n+1}; ...) = \boldsymbol{0} \]

where $y$ is the full-order model (FOM) state, $t$ is time, and $R$ is the residual. todo finish.

Synopsis

class DiscreteTimeFomAdapter

  # create R(...)
  def createDiscreteTimeResidual(self):
    return np.zeros(...)

  def createApplyDiscreteTimeJacobianResult(self, B):
    return np.zeros((..., B.shape[1]))

  def discreteTimeResidual(self, step, time, dt, R, y_np1, y_n, y_nm1 [, y_nm2]):
   R[:] = # compute discrete-time residual

  def applyDiscreteTimeJacobian(self, step, time, dt, B, A, y_np1, y_n, y_nm1 [, y_nm2]):
   A[:,:] = # compute the action A = dR/dy_np1 B

Notes

  • For doing Galerkin implicit time stepping.
  • For doing LSPG and WLS.




What can you use where?

As anticipated, not all adapters can be used for all supported ROM methods. The following table illustrates which APIs are admissible for each method.

Steady APIContinuous Time API
(RHS only)
Continuous Time API
(RHS, Jacobian action)
Discrete Time API
Galerkin Explicit SteppingNAsupportedsupportedNA
Galerkin Implicit SteppingNANAsupportedsupported
LSPG UnsteadyNANAsupportedsupported
LSPG SteadysupportedNANANA
WLS Explicit SteppingNAsupportedsupportedNA
WLS Implicit SteppingNANAsupportedsupported

Note: for LSPG there is no distinction between explicit and implicit because LSPG only makes sense for implicit time stepping. Actually, it can be shown that explicit LSPG is equivalent to explicit Galerkin.




Frequently Asked Questions