@@ -264,15 +264,28 @@ function get_node_variables!(node_variables, u_ode,
264264end 
265265
266266""" 
267-     semidiscretize(semi::SemidiscretizationHyperbolicParabolic, tspan) 
267+     semidiscretize(semi::SemidiscretizationHyperbolicParabolic, tspan; 
268+                    jac_prototype_parabolic::Union{AbstractMatrix, Nothing} = nothing, 
269+                    colorvec_parabolic::Union{AbstractVector, Nothing} = nothing) 
268270
269271Wrap the semidiscretization `semi` as a split ODE problem in the time interval `tspan` 
270272that can be passed to `solve` from the [SciML ecosystem](https://diffeq.sciml.ai/latest/). 
271273The parabolic right-hand side is the first function of the split ODE problem and 
272274will be used by default by the implicit part of IMEX methods from the 
273275SciML ecosystem. 
276+ 
277+ Optional keyword arguments: 
278+ - `jac_prototype_parabolic`: Expected to come from [SparseConnectivityTracer.jl](https://github.com/adrhill/SparseConnectivityTracer.jl). 
279+   Specifies the sparsity structure of the parabolic function's Jacobian to enable e.g. efficient implicit time stepping. 
280+   The [`SplitODEProblem`](https://docs.sciml.ai/DiffEqDocs/stable/types/split_ode_types/#SciMLBase.SplitODEProblem) only expects the Jacobian 
281+   to be defined on the first function it takes in, which is treated implicitly. This corresponds to the parabolic right-hand side in Trixi.jl. 
282+   The hyperbolic right-hand side is expected to be treated explicitly, and therefore its Jacobian is irrelevant. 
283+ - `colorvec_parabolic`: Expected to come from [SparseMatrixColorings.jl](https://github.com/gdalle/SparseMatrixColorings.jl). 
284+   Allows for even faster Jacobian computation. Not necessarily required when `jac_prototype_parabolic` is given. 
274285""" 
275286function  semidiscretize (semi:: SemidiscretizationHyperbolicParabolic , tspan;
287+                         jac_prototype_parabolic:: Union{AbstractMatrix, Nothing}  =  nothing ,
288+                         colorvec_parabolic:: Union{AbstractVector, Nothing}  =  nothing ,
276289                        reset_threads =  true )
277290    #  Optionally reset Polyester.jl threads. See
278291    #  https://github.com/trixi-framework/Trixi.jl/issues/1583
@@ -286,15 +299,33 @@ function semidiscretize(semi::SemidiscretizationHyperbolicParabolic, tspan;
286299    #        mpi_isparallel() && MPI.Barrier(mpi_comm())
287300    #        See https://github.com/trixi-framework/Trixi.jl/issues/328
288301    iip =  true  #  is-inplace, i.e., we modify a vector when calling rhs_parabolic!, rhs!
289-     #  Note that the IMEX time integration methods of OrdinaryDiffEq.jl treat the
290-     #  first function implicitly and the second one explicitly. Thus, we pass the
291-     #  stiffer parabolic function first.
292-     return  SplitODEProblem {iip} (rhs_parabolic!, rhs!, u0_ode, tspan, semi)
302+ 
303+     #  Check if Jacobian prototype is provided for sparse Jacobian
304+     if  jac_prototype_parabolic != =  nothing 
305+         #  Convert `jac_prototype_parabolic` to real type, as seen here:
306+         #  https://docs.sciml.ai/DiffEqDocs/stable/tutorials/advanced_ode_example/#Declaring-a-Sparse-Jacobian-with-Automatic-Sparsity-Detection
307+         parabolic_ode =  SciMLBase. ODEFunction (rhs_parabolic!,
308+                                               jac_prototype =  convert .(eltype (u0_ode),
309+                                                                        jac_prototype_parabolic),
310+                                               colorvec =  colorvec_parabolic) #  coloring vector is optional
311+ 
312+         #  Note that the IMEX time integration methods of OrdinaryDiffEq.jl treat the
313+         #  first function implicitly and the second one explicitly. Thus, we pass the
314+         #  (potentially) stiffer parabolic function first.
315+         return  SplitODEProblem {iip} (parabolic_ode, rhs!, u0_ode, tspan, semi)
316+     else 
317+         #  We could also construct an `ODEFunction` explicitly without the Jacobian here,
318+         #  but we stick to the lean direct in-place functions `rhs_parabolic!` and
319+         #  let OrdinaryDiffEq.jl handle the rest
320+         return  SplitODEProblem {iip} (rhs_parabolic!, rhs!, u0_ode, tspan, semi)
321+     end 
293322end 
294323
295324""" 
296325    semidiscretize(semi::SemidiscretizationHyperbolicParabolic, tspan, 
297-                    restart_file::AbstractString) 
326+                    restart_file::AbstractString; 
327+                    jac_prototype_parabolic::Union{AbstractMatrix, Nothing} = nothing, 
328+                    colorvec_parabolic::Union{AbstractVector, Nothing} = nothing) 
298329
299330Wrap the semidiscretization `semi` as a split ODE problem in the time interval `tspan` 
300331that can be passed to `solve` from the [SciML ecosystem](https://diffeq.sciml.ai/latest/). 
@@ -303,9 +334,20 @@ will be used by default by the implicit part of IMEX methods from the
303334SciML ecosystem. 
304335
305336The initial condition etc. is taken from the `restart_file`. 
337+ 
338+ Optional keyword arguments: 
339+ - `jac_prototype_parabolic`: Expected to come from [SparseConnectivityTracer.jl](https://github.com/adrhill/SparseConnectivityTracer.jl). 
340+   Specifies the sparsity structure of the parabolic function's Jacobian to enable e.g. efficient implicit time stepping. 
341+   The [`SplitODEProblem`](https://docs.sciml.ai/DiffEqDocs/stable/types/split_ode_types/#SciMLBase.SplitODEProblem) only expects the Jacobian 
342+   to be defined on the first function it takes in, which is treated implicitly. This corresponds to the parabolic right-hand side in Trixi.jl. 
343+   The hyperbolic right-hand side is expected to be treated explicitly, and therefore its Jacobian is irrelevant. 
344+ - `colorvec_parabolic`: Expected to come from [SparseMatrixColorings.jl](https://github.com/gdalle/SparseMatrixColorings.jl). 
345+   Allows for even faster Jacobian computation. Not necessarily required when `jac_prototype_parabolic` is given. 
306346""" 
307347function  semidiscretize (semi:: SemidiscretizationHyperbolicParabolic , tspan,
308348                        restart_file:: AbstractString ;
349+                         jac_prototype_parabolic:: Union{AbstractMatrix, Nothing}  =  nothing ,
350+                         colorvec_parabolic:: Union{AbstractVector, Nothing}  =  nothing ,
309351                        reset_threads =  true )
310352    #  Optionally reset Polyester.jl threads. See
311353    #  https://github.com/trixi-framework/Trixi.jl/issues/1583
@@ -319,10 +361,26 @@ function semidiscretize(semi::SemidiscretizationHyperbolicParabolic, tspan,
319361    #        mpi_isparallel() && MPI.Barrier(mpi_comm())
320362    #        See https://github.com/trixi-framework/Trixi.jl/issues/328
321363    iip =  true  #  is-inplace, i.e., we modify a vector when calling rhs_parabolic!, rhs!
322-     #  Note that the IMEX time integration methods of OrdinaryDiffEq.jl treat the
323-     #  first function implicitly and the second one explicitly. Thus, we pass the
324-     #  stiffer parabolic function first.
325-     return  SplitODEProblem {iip} (rhs_parabolic!, rhs!, u0_ode, tspan, semi)
364+ 
365+     #  Check if Jacobian prototype is provided for sparse Jacobian
366+     if  jac_prototype_parabolic != =  nothing 
367+         #  Convert `jac_prototype_parabolic` to real type, as seen here:
368+         #  https://docs.sciml.ai/DiffEqDocs/stable/tutorials/advanced_ode_example/#Declaring-a-Sparse-Jacobian-with-Automatic-Sparsity-Detection
369+         parabolic_ode =  SciMLBase. ODEFunction (rhs_parabolic!,
370+                                               jac_prototype =  convert .(eltype (u0_ode),
371+                                                                        jac_prototype_parabolic),
372+                                               colorvec =  colorvec_parabolic) #  coloring vector is optional
373+ 
374+         #  Note that the IMEX time integration methods of OrdinaryDiffEq.jl treat the
375+         #  first function implicitly and the second one explicitly. Thus, we pass the
376+         #  (potentially) stiffer parabolic function first.
377+         return  SplitODEProblem {iip} (parabolic_ode, rhs!, u0_ode, tspan, semi)
378+     else 
379+         #  We could also construct an `ODEFunction` explicitly without the Jacobian here,
380+         #  but we stick to the lean direct in-place function `rhs_parabolic!` and
381+         #  let OrdinaryDiffEq.jl handle the rest
382+         return  SplitODEProblem {iip} (rhs_parabolic!, rhs!, u0_ode, tspan, semi)
383+     end 
326384end 
327385
328386function  rhs! (du_ode, u_ode, semi:: SemidiscretizationHyperbolicParabolic , t)
0 commit comments