@@ -145,47 +145,47 @@ def eval_f(self, u, t):
145145 self .work_counters ['rhs' ]()
146146 return f
147147
148- def solve_system (self , rhs , factor , u0 , t ):
148+ def get_non_linear_Jacobian (self , u ):
149149 """
150- Simple Newton solver for (I-factor*f)(u) = rhs
150+ Evaluate the non-linear part of the Jacobian only
151151
152152 Args:
153- rhs (dtype_f): right-hand side
154- factor (float): abbrev. for the local stepsize (or any other factor required)
155- u0 (dtype_u): initial guess for the iterative solver
156- t (float): current time (e.g. for time-dependent BCs)
153+ u (dtype_u): Current solution
157154
158155 Returns:
159- dtype_u: solution as mesh
156+ scipy.sparse.csc: The derivative of the non-linear part of the solution w.r.t. to the solution.
160157 """
158+ u_thresh = self .params .u_thresh
159+ u_max = self .params .u_max
160+ Q_max = self .params .Q_max
161+ me = self .dtype_u (self .init )
161162
162- def get_non_linear_Jacobian (u ):
163- """
164- Evaluate the non-linear part of the Jacobian only
163+ me [:] = Q_max / (u_max - u_thresh )
164+ me [u < u_thresh ] = 0
165+ me [u > u_max ] = 0
166+ me [self .leak ] = 0
165167
166- Args:
167- u (dtype_u): Current solution
168+ # boundary conditions
169+ me [0 ] = 0.0
170+ me [- 1 ] = 0.0
168171
169- Returns:
170- scipy.sparse.csc: The derivative of the non-linear part of the solution w.r.t. to the solution.
171- """
172- u_thresh = self .params .u_thresh
173- u_max = self .params .u_max
174- Q_max = self .params .Q_max
175- me = self .dtype_u (self .init )
172+ me [:] /= self .params .Cv
176173
177- me [:] = Q_max / (u_max - u_thresh )
178- me [u < u_thresh ] = 0
179- me [u > u_max ] = 0
180- me [self .leak ] = 0
174+ return sp .diags (me , format = 'csc' )
181175
182- # boundary conditions
183- me [ 0 ] = 0.0
184- me [ - 1 ] = 0.0
176+ def solve_system ( self , rhs , factor , u0 , t ):
177+ """
178+ Simple Newton solver for (I-factor*f)(u) = rhs
185179
186- me [:] /= self .params .Cv
180+ Args:
181+ rhs (dtype_f): right-hand side
182+ factor (float): abbrev. for the local stepsize (or any other factor required)
183+ u0 (dtype_u): initial guess for the iterative solver
184+ t (float): current time (e.g. for time-dependent BCs)
187185
188- return sp .diags (me , format = 'csc' )
186+ Returns:
187+ dtype_u: solution as mesh
188+ """
189189
190190 u = self .dtype_u (u0 )
191191 res = np .inf
@@ -209,7 +209,7 @@ def get_non_linear_Jacobian(u):
209209 break
210210
211211 # assemble Jacobian J of G
212- J = self .Id - factor * (self .A + get_non_linear_Jacobian (u ))
212+ J = self .Id - factor * (self .A + self . get_non_linear_Jacobian (u ))
213213
214214 # solve the linear system
215215 if self .params .direct_solver :
@@ -251,6 +251,19 @@ def u_exact(self, t, u_init=None, t_init=None):
251251
252252 if t > 0 :
253253
254+ def jac (t , u ):
255+ """
256+ Get the Jacobian for the implicit BDF method to use in `scipy.odeint`
257+
258+ Args:
259+ t (float): The current time
260+ u (dtype_u): Current solution
261+
262+ Returns:
263+ scipy.sparse.csc: The derivative of the non-linear part of the solution w.r.t. to the solution.
264+ """
265+ return self .A + self .get_non_linear_Jacobian (u )
266+
254267 def eval_rhs (t , u ):
255268 """
256269 Function to pass to `scipy.solve_ivp` to evaluate the full RHS
@@ -264,7 +277,7 @@ def eval_rhs(t, u):
264277 """
265278 return self .eval_f (u .reshape (self .init [0 ]), t ).flatten ()
266279
267- me [:] = self .generate_scipy_reference_solution (eval_rhs , t , u_init , t_init )
280+ me [:] = self .generate_scipy_reference_solution (eval_rhs , t , u_init , t_init , method = 'BDF' , jac = jac )
268281 return me
269282
270283
@@ -326,6 +339,19 @@ def u_exact(self, t, u_init=None, t_init=None):
326339
327340 if t > 0 :
328341
342+ def jac (t , u ):
343+ """
344+ Get the Jacobian for the implicit BDF method to use in `scipy.odeint`
345+
346+ Args:
347+ t (float): The current time
348+ u (dtype_u): Current solution
349+
350+ Returns:
351+ scipy.sparse.csc: The derivative of the non-linear part of the solution w.r.t. to the solution.
352+ """
353+ return self .A
354+
329355 def eval_rhs (t , u ):
330356 """
331357 Function to pass to `scipy.solve_ivp` to evaluate the full RHS
@@ -340,5 +366,5 @@ def eval_rhs(t, u):
340366 f = self .eval_f (u .reshape (self .init [0 ]), t )
341367 return (f .impl + f .expl ).flatten ()
342368
343- me [:] = self .generate_scipy_reference_solution (eval_rhs , t , u_init , t_init )
369+ me [:] = self .generate_scipy_reference_solution (eval_rhs , t , u_init , t_init , method = 'BDF' , jac = jac )
344370 return me
0 commit comments