Skip to content

Strongly Connected Component (SCC) Scheduled Nonlinear Problems #388

@ChrisRackauckas

Description

@ChrisRackauckas

The idea is that instead of solving one giant Newton method, you can instead split it up into successive Newton solves that are then recursed based on the strongly connected components.

Screenshot 2024-03-02 222222

The algorithms of ModelingToolkit are already able to put the system in BLT form and do the tearing process to reduce the systems. I think as a general nonlinear solver, it would be good to, instead of baking this into MTK in some form, have a way to be able to express such structural systems with NonlinearSolve.jl and have MTK generate code to that interface.

I could see this happening in a few forms:

  1. We could do this on split vectors.
  2. We could do this by passing extra structural information for scheduling.

SCCNonlinearFunction((f1,f2,f3), jac = (J1,J2,J3)) would be needed for both. But the question is do you make u0 = [a1,a2,a3] where each a[i] is an array for the SCC[i], or do you make this segmented?

Effectively the question is as follows. If you do this in the segmented way, then f1(resid, a1, p), f2(resid, a1, a2, p), f3(resid, a1, a2, a3, p) is the target, i.e. each has more arguments as you go along. I could see this having some compilation difficulties, so you could just do this as fi(resid,u,p) where u is an array-of-arrays.

Or, at that point, you could just give the whole u array but with a known structure used by the solver that is not enforced in the definition of fi. For this interface, you would still have to give split scheduled functions SCCNonlinearFunction((f1,f2,f3), jac = (J1,J2,J3)), but with sizes of resid being chosen to match the size of the current nonlinear system. You could just create one resid with the maximum size of the strongly connected components, and then just use views of that in each such component. Thus SCCNonlinearProblem(f,u0, lengths, p) would just need to know the length of each SCC, and then schedule the algorithm into the cascading functions from there. This would probably need to impose an AbstractVector structure on u0, whereas the split form would be easier for handling more array types.

The split form could be nicely handled by keeping the cache of arrays of arrays but having a mapping method to_arrarr!(a,u0) that takes a flattened version of the vector into the SCC split structure. So I don't think it would necessarily have more allocations beyond the setup phase.

So of the ways to represent this, I think I'd rank:

  1. Array of arrays fi(resid,u,p)
  2. Flattened fi(resid,u,p) with sizes
  3. f1(resid, a1, p), f2(resid, a1, a2, p), f3(resid, a1, a2, a3, p)

With the last one effectively eliminated for compile time concerns. I like that the first enforces that the BLT form is respected, to an extent. Someone could still modify u, but that's always a concern 😅.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions