Coverage for pySDC/implementations/problem_classes/Piline.py: 100%
44 statements
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 12:30 +0000
« prev ^ index » next coverage.py v7.17.0, created at 2026-11-02 12:30 +0000
1import numpy as np
2from scipy.integrate import solve_ivp
4from pySDC.core.problem import Problem
5from pySDC.implementations.datatype_classes.mesh import mesh, imex_mesh
8# noinspection PyUnusedLocal
9class piline(Problem):
10 r"""
11 Pi-line model of a transmission line as three linear ODEs, IMEX with the constant source term explicit.
13 Example implementing the model of the piline. It serves as a transmission line in an energy grid. The problem of simulating the
14 piline consists of three ordinary differential equations (ODEs) with nonhomogeneous part:
16 .. math::
17 \frac{d v_{C_1} (t)}{dt} = -\frac{1}{R_s C_1}v_{C_1} (t) - \frac{1}{C_1} i_{L_\pi} (t) + \frac{V_s}{R_s C_1},
19 .. math::
20 \frac{d v_{C_2} (t)}{dt} = -\frac{1}{R_\ell C_2}v_{C_2} (t) + \frac{1}{C_2} i_{L_\pi} (t),
22 .. math::
23 \frac{d i_{L_\pi} (t)}{dt} = \frac{1}{L_\pi} v_{C_1} (t) - \frac{1}{L_\pi} v_{C_2} (t) - \frac{R_\pi}{L_\pi} i_{L_\pi} (t),
25 which can be expressed as a nonhomogeneous linear system of ODEs
27 .. math::
28 \frac{d u(t)}{dt} = A u(t) + f(t)
30 using an initial condition.
32 Parameters
33 ----------
34 Vs : float, optional
35 Voltage at the voltage source :math:`V_s`.
36 Rs : float, optional
37 Resistance of the resistor :math:`R_s` at the voltage source.
38 C1 : float, optional
39 Capacitance of the capacitor :math:`C_1`.
40 Rpi : float, optional
41 Resistance of the resistor :math:`R_\pi`.
42 Lpi : float, optional
43 Inductance of the inductor :math:`L_\pi`.
44 C2 : float, optional
45 Capacitance of the capacitor :math:`C_2`.
46 Rl : float, optional
47 Resistance of the resistive load :math:`R_\ell`.
49 Attributes
50 ----------
51 A : np.2darray
52 Coefficient matrix of the linear ODE system.
53 """
55 dtype_u = mesh
56 dtype_f = imex_mesh
58 def __init__(self, Vs=100.0, Rs=1.0, C1=1.0, Rpi=0.2, Lpi=1.0, C2=1.0, Rl=5.0):
59 """Initialization routine"""
61 nvars = 3
62 # invoke super init, passing number of dofs
63 super().__init__(init=(nvars, None, np.dtype('float64')))
64 self._makeAttributeAndRegister(
65 'nvars', 'Vs', 'Rs', 'C1', 'Rpi', 'Lpi', 'C2', 'Rl', localVars=locals(), readOnly=True
66 )
68 # compute dx and get discretization matrix A
69 self.A = np.zeros((3, 3))
70 self.A[0, 0] = -1 / (self.Rs * self.C1)
71 self.A[0, 2] = -1 / self.C1
72 self.A[1, 1] = -1 / (self.Rl * self.C2)
73 self.A[1, 2] = 1 / self.C2
74 self.A[2, 0] = 1 / self.Lpi
75 self.A[2, 1] = -1 / self.Lpi
76 self.A[2, 2] = -self.Rpi / self.Lpi
78 def eval_f(self, u, t):
79 """
80 Routine to evaluate the right-hand side of the problem.
82 Parameters
83 ----------
84 u : dtype_u
85 Current values of the numerical solution.
86 t : float
87 Current time of the numerical solution is computed.
89 Returns
90 -------
91 f : dtype_f
92 The right-hand side of the problem.
93 """
95 f = self.dtype_f(self.init, val=0.0)
96 f.impl[:] = self.A.dot(u)
97 f.expl[0] = self.Vs / (self.Rs * self.C1)
98 return f
100 def solve_system(self, rhs, factor, u0, t):
101 r"""
102 Simple linear solver for :math:`(I-factor\cdot A)\vec{u}=\vec{rhs}`.
104 Parameters
105 ----------
106 rhs : dtype_f
107 Right-hand side for the linear system.
108 factor : float
109 Abbrev. for the local stepsize (or any other factor required).
110 u0 : dtype_u
111 Initial guess for the iterative solver.
112 t : float
113 Current time (e.g. for time-dependent BCs).
115 Returns
116 -------
117 me : dtype_u
118 The solution as mesh.
119 """
121 me = self.dtype_u(self.init)
122 me[:] = np.linalg.solve(np.eye(self.nvars) - factor * self.A, rhs)
123 return me
125 def u_exact(self, t, u_init=None, t_init=None):
126 r"""
127 Routine to approximate the exact solution at time :math:`t` by ``SciPy`` as a reference.
129 Parameters
130 ----------
131 t : float
132 Time of the exact solution.
133 u_init : pySDC.problem.Piline.dtype_u
134 Initial conditions for getting the exact solution.
135 t_init : float
136 The starting time.
138 Returns
139 -------
140 me : dtype_u
141 The reference solution.
142 """
144 me = self.dtype_u(self.init)
146 # fill initial conditions
147 me[0] = 0.0 # v1
148 me[1] = 0.0 # v2
149 me[2] = 0.0 # p3
151 if t > 0.0:
152 if u_init is not None:
153 if t_init is None:
154 raise ValueError('Please supply `t_init` when you want to get the exact solution from a point that \
155is not 0!')
156 me = u_init
157 else:
158 t_init = 0.0
160 def rhs(t, u):
161 f = self.eval_f(u, t)
162 return f.impl + f.expl # evaluate only explicitly rather than IMEX
164 tol = 100 * np.finfo(float).eps
166 me[:] = solve_ivp(rhs, (t_init, t), me, rtol=tol, atol=tol).y[:, -1]
168 return me