MFEM v4.9.0
Finite element discretization library
Loading...
Searching...
No Matches
pschrodinger_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 pschrodinger_flow
24//
25// Sample runs:
26// * mpirun -np 4 pschrodinger_flow --leapfrog
27// * mpirun -np 4 pschrodinger_flow --leapfrog -nx 128 -ny 128 -hbar 5e-2
28// * mpirun -np 4 pschrodinger_flow --leapfrog -o 2 -nx 32 -ny 32 -sx 8 -sy 8
29// * mpirun -np 4 pschrodinger_flow --leapfrog -o 3 -nx 32 -ny 32
30// * mpirun -np 4 pschrodinger_flow --leapfrog -o 4 -nx 16 -ny 16 -lr1 0.32 -lr2 0.16 -dt 0.1
31// * mpirun -np 4 pschrodinger_flow --jet -vd 0 -hbar 5e-2
32// mpirun -np 4 pschrodinger_flow --leapfrog -ms 4 -nx 8 -ny 8
33//
34// Device sample runs:
35// * mpirun -np 4 pschrodinger_flow -d debug --leapfrog
36// mpirun -np 4 pschrodinger_flow -d gpu --leapfrog -ms 4
37
38#include "schrodinger_flow.hpp"
39
40namespace mfem
41{
42
43// Kernel definitions for parallel computations
45 ParMesh,
52
53// Crank-Nicolson solver for time stepping
58
59// Parallel mesh and solvers factories
60static auto SetParMesh = [](Mesh &mesh) { return ParMesh(MPI_COMM_WORLD, mesh); };
61static auto SetOrthoSolver = []() { return OrthoSolver(MPI_COMM_WORLD); };
62static auto SetCGSolver = []() { return CGSolver(MPI_COMM_WORLD); };
63static auto SetGMRESSolver = []() { return GMRESSolver(MPI_COMM_WORLD); };
64
65// Main solver class for Schrödinger flow
66struct SchrodingerSolver : public Kernels
67{
68 // Crank-Nicolson solver for time evolution
69 struct CrankNicolsonSchrodingerTimeSolver: public CrankNicolsonSolver
70 {
71 Vector PSI, Z;
72 CrankNicolsonSchrodingerTimeSolver(ParFiniteElementSpace &fes,
74 real_t rtol, real_t atol, int maxiter,
75 int print_level):
76 CrankNicolsonTimeBaseSolver(fes, hbar, dt, SetGMRESSolver,
77 rtol, atol, maxiter, print_level),
78 PSI(2*fes.GetTrueVSize()),
79 Z(2*fes.GetTrueVSize()) { }
80
81 void Mult(ParComplexGridFunction &psi) override
82 {
83 psi.ParallelProject(PSI);
84 R_op->Mult(PSI, Z);
85 gmres_solver.Mult(Z, PSI);
86 psi.Distribute(PSI);
87 MFEM_VERIFY(gmres_solver.GetConverged(), "Crank Nicolson solver failed");
88 }
89 } time_1_solver, time_2_solver;
90 Vector B;
91
92public:
93 SchrodingerSolver(Options &config):
94 Kernels(config, SetParMesh, SetOrthoSolver, SetCGSolver),
95 time_1_solver(h1_fes, hbar, dt, rtol, atol, max_iters, print_level),
96 time_2_solver(h1_fes, hbar, dt, rtol, atol, max_iters, print_level),
97 B(diff_h1_cgs.Width())
98 {
99 B.UseDevice(true);
101 nodes.SetTrueVector();
102 nodes.SetFromTrueVector();
103 }
104
105 void Step() { time_1_solver.Mult(psi1); time_2_solver.Mult(psi2); }
106
107 void GradPsi()
108 {
109 const auto Grad_nd = [&](ParGridFunction &in_h1, ParGridFunction &out_nd)
110 {
111 in_h1.SetTrueVector(), in_h1.SetFromTrueVector();
112 grad_nd_op->Mult(in_h1.GetTrueVector(), nd_gf.GetTrueVector());
113 mass_nd_cgs.Mult(nd_gf.GetTrueVector(), out_nd.GetTrueVector());
114 out_nd.SetFromTrueVector();
115 };
116 const auto x_dot_Mm1 = [&](ParGridFunction &x, ParGridFunction &y)
117 {
118 x.SetTrueVector(), x.SetFromTrueVector();
119 nd_dot_x_h1_op->Mult(x.GetTrueVector(), h1_gf.GetTrueVector());
120 mass_h1_cgs.Mult(h1_gf.GetTrueVector(), y.GetTrueVector());
121 y.SetFromTrueVector();
122 };
123 const auto y_dot_Mm1 = [&](ParGridFunction &x, ParGridFunction &y)
124 {
125 x.SetTrueVector(), x.SetFromTrueVector();
126 nd_dot_y_h1_op->Mult(x.GetTrueVector(), h1_gf.GetTrueVector());
127 mass_h1_cgs.Mult(h1_gf.GetTrueVector(), y.GetTrueVector());
128 y.SetFromTrueVector();
129 };
130 const auto z_dot_Mm1 = [&](ParGridFunction &x, ParGridFunction &y)
131 {
132 x.SetTrueVector(), x.SetFromTrueVector();
133 nd_dot_z_h1_op->Mult(x.GetTrueVector(), h1_gf.GetTrueVector());
134 mass_h1_cgs.Mult(h1_gf.GetTrueVector(), y.GetTrueVector());
135 y.SetFromTrueVector();
136 };
137 Kernels::GradPsi(Grad_nd, x_dot_Mm1, y_dot_Mm1, z_dot_Mm1);
138 }
139
140 void VelocityOneForm(ParGridFunction &ux, ParGridFunction &uy,
141 ParGridFunction &uz)
142 {
143 GradPsi();
144 GradPsiVelocity(hbar, ux, uy, uz);
145 }
146
147 void ComputeDivU()
148 {
149 const auto diff_Mm1 = [&](ParGridFunction &x, ParGridFunction &y)
150 {
151 x.SetTrueVector(), x.SetFromTrueVector();
152 diff_h1_op->Mult(x.GetTrueVector(), h1_gf.GetTrueVector());
153 mass_h1_cgs.Mult(h1_gf.GetTrueVector(), y.GetTrueVector());
154 y.SetFromTrueVector();
155 };
156 diff_Mm1(psi1.real(), delta_psi1.real());
157 diff_Mm1(psi2.real(), delta_psi2.real());
158 diff_Mm1(psi1.imag(), delta_psi1.imag());
159 diff_Mm1(psi2.imag(), delta_psi2.imag());
161 }
162
163 void PoissonSolve()
164 {
165 rhs.Assemble();
166 rhs.ParallelAssemble(B);
167 diff_h1_cgs.Mult(B, q.GetTrueVector());
168 q.SetFromTrueVector();
169 MFEM_VERIFY(diff_h1_cgs.GetConverged(), "Km1_h1 solver did not converge");
170 }
171
172 void PressureProject() { ComputeDivU(); PoissonSolve(); GaugeTransform(); }
173};
174
177
178using FlowVis =
180
181} // namespace mfem
182
183int main(int argc, char *argv[])
184{
185 Mpi::Init();
186 Hypre::Init();
187
188 Options opt(argc, argv);
189 Device device(opt.device);
190 if (Mpi::Root()) { device.Print(); }
191
192 SchrodingerSolver schrodinger(opt);
193 IncompressibleFlow flow(opt, schrodinger);
194 const auto glvis_prefix = []()
195 {
196 std::ostringstream os;
197 os << "parallel " << Mpi::WorldSize() << " " << Mpi::WorldRank() << "\n";
198 return os.str();
199 };
200 FlowVis vis(opt, schrodinger, flow, glvis_prefix);
201
202 for (int ti = 1; ti <= opt.max_steps; ti++)
203 {
204 const real_t t = ti * opt.dt;
205 const bool vis_steps = (ti % opt.vis_steps) == 0;
206 if (Mpi::Root() && vis_steps) { mfem::out << "#" << ti << std::endl; }
207 flow.Step(t);
208 if (opt.visualization && vis_steps) { vis.GLVis(); vis.Save(ti, t); }
209 }
210
211 return EXIT_SUCCESS;
212}
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
Class for simulating incompressible Schrodinger flow.
bool GetConverged() const
Returns true if the last call to Mult() converged successfully.
Definition solvers.hpp:291
Mesh data type.
Definition mesh.hpp:65
void Clear()
Clear the contents of the Mesh.
Definition mesh.hpp:827
virtual void Mult(const Vector &x, Vector &y) const =0
Operator application: y=A(x).
Class for parallel bilinear form.
Abstract parallel finite element space.
Definition pfespace.hpp:31
Class for parallel grid function.
Definition pgridfunc.hpp:50
Class for parallel linear form.
Class for parallel meshes.
Definition pmesh.hpp:34
Class for parallel bilinear form using different test and trial FE spaces.
int main()
mfem::real_t real_t
int GetTrueVSize(const FieldDescriptor &f)
Get the true dof size of a field descriptor.
Definition util.hpp:829
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
SchrodingerBaseKernels< ParMesh, ParFiniteElementSpace, ParComplexGridFunction, ParGridFunction, ParBilinearForm, ParMixedBilinearForm, ParLinearForm > Kernels
CrankNicolsonTimeBaseSolver< ParFiniteElementSpace, ParSesquilinearForm, ParComplexGridFunction > CrankNicolsonSolver
Crank-Nicolson time solver for the Schrodinger equation.
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[])
Base class for Schrodinger solver kernels.
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)
Base class for visualization.