Evaluate dynamics¶
In this notebook we show how to use the NoPEC package to evaluate the dynamics of the state variables \(y\) and \(q\).
import numpy as np
from nopec.models import FenicsModel
from nopec.parameters import Input, ModelParameters
from nopec.tools import initializer
Define parameters¶
First, we create a ModelParameters class containing all the information about the model and its discretization.
pars = ModelParameters(
# mathematical model
x_0=0.0, # left point of domain
x_L=1.0, # right point of domain
kappa_1=lambda x: np.ones_like(x[0]), # diffusion function for y
kappa_2=lambda x: np.ones_like(x[0]), # diffusion function for q
y_0=lambda x: 5 * np.ones_like(x[0]), # initial value y(t=0)
T=2.0, # final time
# discretization parameters
discretization_model="fenics", # defines the discretization model
FE_degree=1, # degree of finite element
N_nodes_x=200, # number of discretization nodes
time_disc_met="IE", # time discretization method (in this case Implicit Euler)
K=201, # number of time steps
)
pars.model_dump()
{'x_0': 0.0,
'x_L': 1.0,
'kappa_1': <function __main__.<lambda>(x)>,
'kappa_2': <function __main__.<lambda>(x)>,
'y_0': <function __main__.<lambda>(x)>,
'T': 2.0,
'discretization_model': 'fenics',
'FE_degree': 1,
'N_nodes_x': 200,
'time_disc_met': 'IE',
'K': 201,
'damped_Newton': True,
'nonlinear_conv_tol': 1e-07}
Define the input function¶
Models need the input function \(u\). We can use the Input to create an input array from a known function. Once chosen the one of the functions in Input, we need to evaluate it on each time step, namely \(u(t_k)\).
input_array = Input.JUMP_3_AT_166(pars.tv)
input_array
array([-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3.])
One could as well define input_array directly as an array.
np.where(pars.tv <= 4 / 3, -3.0, +3.0)
array([-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3.])
Model objects¶
Models can be initialized with a ModelParameters instance and an input_array array.
model = FenicsModel(
pars=pars,
input_array=input_array,
)
model
FenicsModel(input_array=array([-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3.]), pars=ModelParameters(x_0=0.0, x_L=1.0, kappa_1=<function <lambda> at 0x704cf5cb71a0>, kappa_2=<function <lambda> at 0x704cf5cb7240>, y_0=<function <lambda> at 0x704cf5cb7060>, T=2.0, discretization_model='fenics', FE_degree=1, N_nodes_x=200, time_disc_met='IE', K=201, damped_Newton=True, nonlinear_conv_tol=1e-07))
As the information of what discretization method is used is already present in ModelParameters.discretization_method, we can use the nopec.setup.initializer function to create the model corresponding to the requested discretization method.
initializer(pars, input_array)
FenicsModel(input_array=array([-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3., -3.,
-3., -3., -3., -3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3., 3.,
3., 3., 3., 3., 3., 3.]), pars=ModelParameters(x_0=0.0, x_L=1.0, kappa_1=<function <lambda> at 0x704cf5cb71a0>, kappa_2=<function <lambda> at 0x704cf5cb7240>, y_0=<function <lambda> at 0x704cf5cb7060>, T=2.0, discretization_model='fenics', FE_degree=1, N_nodes_x=200, time_disc_met='IE', K=201, damped_Newton=True, nonlinear_conv_tol=1e-07))
input_array.shape
(201,)
%%time
Y_h, Q_h = model.state([3, 3, 3, 3])
CPU times: user 10.1 s, sys: 58.8 ms, total: 10.2 s
Wall time: 2.43 s
Q_h
array([[ 0. , 0. , 0. , ..., 0. ,
0. , 0. ],
[ 0.00209827, 0.00209534, 0.00209253, ..., -0.00195011,
-0.00195218, -0.00195425],
[ 0.00419666, 0.0041908 , 0.00418518, ..., -0.00390034,
-0.00390448, -0.00390863],
...,
[ 0.58739399, 0.58689571, 0.58643214, ..., -0.56603256,
-0.56633984, -0.56664779],
[ 0.59234108, 0.59184271, 0.59137905, ..., -0.57097638,
-0.5712837 , -0.57159171],
[ 0.59732337, 0.59682497, 0.59636129, ..., -0.57595757,
-0.57626491, -0.57657294]], shape=(201, 200))
import matplotlib.pyplot as plt
plt.plot(model.FE.Omega.geometry.x[:, 0], Q_h[:, 0])
[<matplotlib.lines.Line2D at 0x704cf113e7b0>]