Repository navigation
Replies: 2 comments 2 replies
|
Thank you for this write-up — the layering is clean and the decoder/projector 1. Decoder in Python, projector in C++ — right boundary? 2. Nonlinear loop in Python or a C++ strategy calling the decoder? 3. HROM via an application scheme overriding 4. One more observation — the 0.5% cylinder gap. Since Congrats again on the structure — the "decoder as a Python object, projector |
|
Thanks for the current status and perspectives wrap up. I'll go thought it in deep when I'm back. In the meantime, I'd like to say that I'd consider switching the |
Uh oh!
There was an error while loading. Please reload this page.
This document describes how the projection-based ROMs are organised on top of the
KratosMultiphysics.Futuresolving-strategy stack: which components exist, what each one is responsiblefor, and how they talk to each other. The implementation is in #14850.
1. The idea in one paragraph
A projection-based ROM needs three things: a decoder
u = D(q)that turns reduced coordinates into afull state, a full order operator that builds the tangent matrix
A(u)and the residualb(u), and aprojection that reduces them to a small system for
dq. In the legacy code the three live inside oneBuilderAndSolverclass per ROM variant, so every new decoder or projection means another copy of theclass. Here they are three separate components with narrow interfaces. The decoder is Python, the full
order operator is the Kratos core, and the projection is a small C++ class of this application.
2. Layers
flowchart TB subgraph L4["Workflow layer (Python)"] RM["RomManager<br/>training, basis, rom_data folder"] AN["FutureRomAnalysis<br/>wraps any AnalysisStage"] end subgraph L3["ROM solver layer (Python)"] SOL["FutureRomSolver<br/>Newton loop on q"] DEC["RomDecoder<br/>Decode(q), Jacobian(q)"] end subgraph L2["Projection layer (C++, RomApplication)"] PRJ["RomProjector<br/>build, project, solve, set solution"] end subgraph L1["Full order layer (C++, Kratos core, Future)"] SCH["StaticScheme + BlockBuilder"] DAT["ImplicitStrategyData<br/>linear system, DOF sets"] end subgraph L0["Model (C++, Kratos core)"] MP["ModelPart<br/>elements, conditions, DOFs"] end RM -. "rom_data: basis, node ids, settings" .-> AN AN --> SOL SOL --> DEC SOL --> PRJ PRJ --> SCH PRJ --> DAT SCH --> DAT SCH --> MPEach layer only calls the one below it. Nothing in the core knows about ROMs, and the projector knows
nothing about decoders.
RomManagerpython_scripts/rom_manager.pyrom_data.FutureRomAnalysispython_scripts/future/future_rom_analysis.pyrom_data.FutureRomSolverpython_scripts/future/rom_future_solver.pyqand convergence check.RomDecoder,LinearDecoderpython_scripts/future/rom_decoders.pyDecode(q) -> uandJacobian(q) -> Phi.RomProjectorfuture/rom_projector.hNumpyRomProjectorpython_scripts/future/rom_future_solver.pyStaticScheme,BlockBuilder,ImplicitStrategyDatakratos/future/solving_strategies/3. The two interfaces that matter
Decoder (Python, one class per kind of ROM):
Projector (C++
RomProjector, or its NumPy twin):The only convention shared by the two is the row ordering: row
ibelongs to the DOF with effectiveequation id
i. The ordering exists once the scheme has been initialised, which is why the solver receivesits decoder after
Initialize().4. One Newton iteration
sequenceDiagram participant S as FutureRomSolver participant D as RomDecoder participant P as RomProjector participant K as StaticScheme participant M as ModelPart S->>D: Decode(q) D-->>S: u S->>P: SetSolution(u) P->>K: Update (Dx = u - u_current) K->>M: write free DOFs, move mesh S->>P: BuildEffectiveSystem() P->>K: Build, BuildLinearSystemConstraints, ApplyLinearSystemConstraints K->>M: CalculateLocalSystem on elements and conditions S->>D: Jacobian(q) D-->>S: Phi S->>P: Project(Phi) P-->>S: A_r, b_r S->>P: SolveReduced() P-->>S: dq Note over S: q = q + dq, check |dq| / |q|Per iteration Python makes one decoder evaluation and four calls into C++. The dense basis crosses the
boundary without being copied. All loops over elements, DOFs and matrix entries are in C++.
Design decisions visible in this loop:
u = D(q), not incremented byPhi dq. For a lineardecoder both are the same; for a nonlinear decoder only the absolute form is correct.
SetSolutiongoes throughStaticScheme::Update, so fixed DOFs areskipped, constraints are honoured and the mesh is moved by the same code as in a FOM.
Phiare taken as zero insideProject, as the legacyGlobalROMBuilderAndSolverdoes. The decoder does not need to know the boundary conditions.5. Legacy and Future side by side
flowchart LR subgraph Legacy direction TB LS["Legacy strategy<br/>Newton-Raphson"] LB["XxxROMBuilderAndSolver<br/>DOF set + build + projection<br/>+ reduced solve + decoder"] LS --> LB end subgraph Future direction TB FS["FutureRomSolver"] FD["RomDecoder"] FP["RomProjector"] FK["Future StaticScheme"] FS --> FD FS --> FP FP --> FK endImplicitScheme::InitializeBuildof each classImplicitScheme::BuildProjectROMof each classRomProjector::ProjectSolveROMof each classRomProjector::SolveReducedROM_BASISmatrix on every nodeFutureRomSolver6. Where each extension goes
RomDecodersubclass, Jacobian by automatic differentiationRomProjectorHRomScheme<TScheme>overriding the virtualImplicitScheme::BuildFutureImplicitSchemeFutureRomSolverFutureRomAnalysisinstead ofRomAnalysis7. What is implemented and checked
Implemented: Galerkin projection, linear decoder, static scheme, serial and shared-memory runs.
Notes on the last two, which are run from scripts outside the repository:
move_meshon in the scheme settings, as the pressure follows the deformed surface.element_manages_time_integration), becauseFuturehas no dynamic scheme. Bossak is not available.8. Limits that come from the core
Future; the nonlinear loop is Python.ImplicitScheme::Build; the HROM can do without it (Buildis virtual andCalculateLocalSystemContributionis protected), see question 3.Futureyet.FutureRomAnalysistherefore still lets the parent analysisstage create its legacy solver to read the model and add the DOFs, and bypasses it in the solution steps.
9. Questions for discussion
RomApplication provide a C++ strategy that calls a decoder object?
HRomScheme<TScheme>that overrides the virtualBuildand assembles only theHROM entities, scaled by their weights (no core change). Would the core rather offer a hook for this (entity weights, a list
of entities to assemble, or public local contribution methods)?
FutureRomAnalysisremain a wrapper around existing analysis stages, or wait for applicationsolvers based on
Future?All reactions