MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
schrodinger_flow.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2025, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11//
12// ---------------------------------------------
13// Incompressible Schrödinger Flow (ISF) Miniapp
14// ---------------------------------------------
15//
16// This miniapp introduces the Incompressible Schrödinger Flow (ISF) method,
17// an approach for simulating inviscid fluid dynamics by solving the linear
18// Schrödinger equation, leveraging the hydrodynamical analogy to quantum
19// mechanics proposed by Madelung in 1926. ISF offers a simple and efficient
20// framework, particularly effective for capturing vortex dynamics.
21// See README for more details.
22//
23// Compile with: make schrodinger_flow
24//
25// Sample runs:
26// * schrodinger_flow --leapfrog
27// * schrodinger_flow --leapfrog -o 2 -nx 16 -ny 16 -sx 8 -sy 8
28// * schrodinger_flow --leapfrog -o 4 -nx 10 -ny 10 -lr1 0.24 -lr2 0.12
29// * schrodinger_flow --jet -vd 0 -hbar 5e-2
30// schrodinger_flow --leapfrog -ms 4 -nx 8 -ny 8
31//
32// Device sample runs:
33// * schrodinger_flow -d gpu --leapfrog -nx 128 -ny 128 -hbar 5e-2
34// schrodinger_flow -d gpu --leapfrog -ms 4
35
36#include "schrodinger_flow.hpp"
37
38namespace mfem
39{
40
41// Kernel definitions for serial computations
42using Kernels = SchrodingerBaseKernels<
43 Mesh,
44 FiniteElementSpace,
45 ComplexGridFunction,
46 GridFunction,
47 BilinearForm,
48 MixedBilinearForm,
49 LinearForm>;
50
51// Crank-Nicolson solver for time stepping
52using CrankNicolsonSolver = CrankNicolsonTimeBaseSolver<
53 FiniteElementSpace,
54 SesquilinearForm,
55 ComplexGridFunction>;
56
57// Serial mesh and solvers factories
58static auto SetMesh = [](Mesh &mesh) { return Mesh(mesh); };
59static auto SetOrthoSolver = []() { return OrthoSolver(); };
60static auto SetCGSolver = []() { return CGSolver(); };
61static auto SetGMRESSolver = []() { return GMRESSolver(); };
62
63// Main solver class for Schrödinger flow
64struct SchrodingerSolver : public Kernels
65{
66 // Crank-Nicolson solver for time evolution
67 struct CrankNicolsonSchrodingerTimeSolver: public CrankNicolsonSolver
68 {
69 CrankNicolsonSchrodingerTimeSolver(FiniteElementSpace &fes,
71 real_t rtol, real_t atol, int maxiter,
72 int print_level):
73 CrankNicolsonTimeBaseSolver(fes, hbar, dt, SetGMRESSolver,
74 rtol, atol, maxiter, print_level) { }
75
76 void Mult(ComplexGridFunction &psi) override
77 {
78 R_op->Mult(psi, z);
79 gmres_solver.Mult(z, psi);
80 MFEM_VERIFY(gmres_solver.GetConverged(), "Crank Nicolson solver failed");
81 }
82 } time_1_solver, time_2_solver;
83
84public:
85 SchrodingerSolver(Options &config):
86 Kernels(config, SetMesh, SetOrthoSolver, SetCGSolver),
87 time_1_solver(h1_fes, hbar, dt, rtol, atol, max_iters, print_level),
88 time_2_solver(h1_fes, hbar, dt, rtol, atol, max_iters, print_level) { }
89
90 void Step() { time_1_solver.Mult(psi1); time_2_solver.Mult(psi2); }
91
92 void GradPsi()
93 {
94 const auto Grad_nd = [&](GridFunction &in_h1, GridFunction &out_nd)
95 {
96 grad_nd_op->Mult(in_h1, nd_gf);
97 mass_nd_cgs.Mult(nd_gf, out_nd);
98 assert(mass_nd_cgs.GetConverged());
99 };
100 const auto x_dot_Mm1 = [&](GridFunction &x, GridFunction &y)
101 {
103 };
104 const auto y_dot_Mm1 = [&](GridFunction &x, GridFunction &y)
105 {
107 };
108 const auto z_dot_Mm1 = [&](GridFunction &x, GridFunction &y)
109 {
111 };
112 Kernels::GradPsi(Grad_nd, x_dot_Mm1, y_dot_Mm1, z_dot_Mm1);
113 }
114
115 void VelocityOneForm(GridFunction &ux, GridFunction &uy, GridFunction &uz)
116 {
117 GradPsi();
118 GradPsiVelocity(hbar, ux, uy, uz);
119 }
120
121 void ComputeDivU()
122 {
123 diff_h1_op->Mult(psi1.real(), h1_gf);
125 diff_h1_op->Mult(psi2.real(), h1_gf);
127 diff_h1_op->Mult(psi1.imag(), h1_gf);
129 diff_h1_op->Mult(psi2.imag(), h1_gf);
132 }
133
134 void PoissonSolve()
135 {
136 rhs.Assemble();
138 MFEM_VERIFY(diff_h1_cgs.GetConverged(), "Km1_h1 solver did not converge");
139 }
140
141 void PressureProject() { ComputeDivU(); PoissonSolve(); GaugeTransform(); }
142};
143
144using IncompressibleFlow =
145 IncompressibleBaseFlow<SchrodingerSolver, GridFunction>;
146
147using FlowVis =
148 VisualizerBase<Mesh, GridFunction, FiniteElementSpace, SchrodingerSolver, IncompressibleFlow>;
149
150} // namespace mfem
151
152int main(int argc, char *argv[])
153{
154 Options opt(argc, argv);
155 Device device(opt.device);
156 device.Print();
157
158 SchrodingerSolver schrodinger(opt);
159 IncompressibleFlow flow(opt, schrodinger);
160 FlowVis vis(opt, schrodinger, flow, []() { return ""; });
161
162 for (int ti = 1; ti <= opt.max_steps; ti++)
163 {
164 const real_t t = ti * opt.dt;
165 const bool vis_steps = (ti % opt.vis_steps) == 0;
166 if (vis_steps) { mfem::out << "#" << ti << std::endl; }
167 flow.Step(t);
168 if (opt.visualization && vis_steps) { vis.GLVis(); vis.Save(ti, t); }
169 }
170
171 return EXIT_SUCCESS;
172}
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the Conjugate Gradient method.
Definition solvers.cpp:869
void Mult(const Vector &b, Vector &x) const override
Iterative solution of the linear system using the GMRES method.
Definition solvers.cpp:1134
bool GetConverged() const
Returns true if the last call to Mult() converged successfully.
Definition solvers.hpp:291
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
int main()
mfem::real_t real_t
IncompressibleBaseFlow< SchrodingerSolver, ParGridFunction > IncompressibleFlow
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
VisualizerBase< ParMesh, ParGridFunction, ParFiniteElementSpace, SchrodingerSolver, IncompressibleFlow > FlowVis
SchrodingerBaseKernels< ParMesh, ParFiniteElementSpace, ParComplexGridFunction, ParGridFunction, ParBilinearForm, ParMixedBilinearForm, ParLinearForm > Kernels
CrankNicolsonTimeBaseSolver< ParFiniteElementSpace, ParSesquilinearForm, ParComplexGridFunction > CrankNicolsonSolver
CrankNicolsonTimeBaseSolver(TFiniteElementSpace &fes, real_t hbar, real_t dt, std::function< GMRESSolver()> CreateGMRESSolver, real_t rtol, real_t atol, int maxiter, int print_level)
Options(int argc, char *argv[])
void GradPsiVelocity(const real_t hbar, TGridFunction &ux, TGridFunction &uy, TGridFunction &uz)
void GradPsi(Gfn &Grad_nd, Xfn &x_dot_Mm1, Yfn &y_dot_Mm1, Zfn &z_dot_Mm1)