Alamo
CahnHilliard.cpp
Go to the documentation of this file.
1#include <AMReX_MLPoisson.H>
2
3#ifdef ALAMO_FFT
4#include <AMReX_FFT.H>
5#endif
6
7#include "CahnHilliard.H"
8#include "BC/Constant.H"
9#include "IO/ParmParse.H"
10#include "IC/Random.H"
11#include "Numeric/Stencil.H"
12#include "Set/Set.H"
13
14namespace Integrator
15{
20{
21 delete ic;
22 delete bc;
23}
24
26{
27 // Interface energy
28 pp.query_default("gamma",value.gamma, 0.0005);
29 // Mobility
30 pp.query_default("L", value.L, 1.0);
31 // Regridding criterion
32 pp.query_default("refinement_threshold",value.refinement_threshold, 1E100);
33
34 // initial condition for :math:`\eta`
35 pp.select_default<IC::Random>("eta.ic", value.ic, value.geom);
36 // boundary condition for :math:`\eta`
37 pp.select_default<BC::Constant>("eta.bc", value.bc, 1);
38
39 // Which method to use - realspace or spectral method.
40 pp.query_validate("method",value.method,{"realspace","spectral"});
41
42 value.RegisterNewFab(value.etanew_mf, value.bc, 1, 1, "eta",true);
43 value.RegisterNewFab(value.intermediate, value.bc, 1, 1, "int",true);
44
45 if (value.method == "realspace")
46 value.RegisterNewFab(value.etaold_mf, value.bc, 1, 1, "eta_old",false);
47}
48
49void
50CahnHilliard::Advance(int lev, Set::Scalar time, Set::Scalar dt)
51{
52 if (method == "realspace")
53 AdvanceReal(lev, time, dt);
54 else if (method == "spectral")
55 AdvanceSpectral(lev, time, dt);
56 else
57 Util::Abort(INFO,"Invalid method: ",method);
58}
59
60
61void
62CahnHilliard::AdvanceReal (int lev, Set::Scalar /*time*/, Set::Scalar dt)
63{
64 std::swap(etaold_mf[lev], etanew_mf[lev]);
65 const Set::Scalar* DX = geom[lev].CellSize();
66 for ( amrex::MFIter mfi(*etanew_mf[lev],true); mfi.isValid(); ++mfi )
67 {
68 const amrex::Box& bx = mfi.tilebox();
69 amrex::Array4<const amrex::Real> const& eta = etaold_mf[lev]->array(mfi);
70 amrex::Array4<amrex::Real> const& inter = intermediate[lev]->array(mfi);
71 amrex::Array4<amrex::Real> const& etanew = etanew_mf[lev]->array(mfi);
72
73 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
74 {
75 Set::Scalar lap_eta = Numeric::Laplacian(eta,i,j,k,0,DX);
76
77
78 inter(i,j,k) =
79 eta(i,j,k)*eta(i,j,k)*eta(i,j,k)
80 - eta(i,j,k)
81 - gamma*lap_eta;
82
83
84 etanew(i,j,k) = eta(i,j,k) - dt*inter(i,j,k); // Allen Cahn
85 });
86
87 amrex::ParallelFor (bx,[=] AMREX_GPU_DEVICE(int i, int j, int k){
88 Set::Scalar lap_inter = Numeric::Laplacian(inter,i,j,k,0,DX);
89
90 etanew(i,j,k) = eta(i,j,k) + dt*lap_inter;
91 });
92 }
93}
94
95#ifdef ALAMO_FFT
96void
97CahnHilliard::AdvanceSpectral (int lev, Set::Scalar /*time*/, Set::Scalar dt)
98{
99 //
100 // FFT Boilerplate
101 //
102 amrex::FFT::R2C my_fft(this->geom[lev].Domain());
103 auto const &[cba, cdm] = my_fft.getSpectralDataLayout();
104 const Set::Scalar* DX = geom[lev].CellSize();
105 amrex::Box const & domain = this->geom[lev].Domain();
107 AMREX_D_DECL(
108 pi_Lx = 2.0 * Set::Constant::Pi / geom[lev].Domain().length(0) / DX[0],
109 pi_Ly = 2.0 * Set::Constant::Pi / geom[lev].Domain().length(1) / DX[1],
110 pi_Lz = 2.0 * Set::Constant::Pi / geom[lev].Domain().length(2) / DX[2]);
111 Set::Scalar scaling = 1.0 / geom[lev].Domain().d_numPts();
112
113
114 //
115 // Compute the gradient of the chemical potential in realspace
116 //
117 for ( amrex::MFIter mfi(*etanew_mf[lev],true); mfi.isValid(); ++mfi )
118 {
119 const amrex::Box& bx = mfi.tilebox();
120 amrex::Array4<const amrex::Real> const& eta = etanew_mf[lev]->array(mfi);
121 amrex::Array4<amrex::Real> const& inter = intermediate[lev]->array(mfi);
122 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
123 {
124 inter(i,j,k) = eta(i,j,k)*eta(i,j,k)*eta(i,j,k) - eta(i,j,k);
125 });
126 }
127
128 intermediate[lev]->FillBoundary();
129
130 //
131 // FFT of eta
132 //
133 amrex::FabArray<amrex::BaseFab<amrex::GpuComplex<Set::Scalar> > > eta_hat_mf(cba, cdm, 1, 0);
134 my_fft.forward(*etanew_mf[lev], eta_hat_mf);
135
136 //
137 // FFT of chemical potential gradient
138 //
139 amrex::FabArray<amrex::BaseFab<amrex::GpuComplex<Set::Scalar> > > chempot_hat_mf(cba, cdm, 1, 0);
140 my_fft.forward(*intermediate[lev], chempot_hat_mf);
141
142 //
143 // Perform update in spectral coordinatees
144 //
145 //for (amrex::MFIter mfi(eta_hat_mf, amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
146 for (amrex::MFIter mfi(eta_hat_mf, false); mfi.isValid(); ++mfi)
147 {
148 const amrex::Box &bx = mfi.tilebox();
149
150 Util::Message(INFO, bx);
151
152 amrex::Array4<amrex::GpuComplex<Set::Scalar>> const & eta_hat = eta_hat_mf.array(mfi);
153 amrex::Array4<amrex::GpuComplex<Set::Scalar>> const & chempot_hat = chempot_hat_mf.array(mfi);
154
155 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int m, int n, int p) {
156
157
158 // Get spectral coordinates
159 AMREX_D_TERM(
160 Set::Scalar k1 = m * pi_Lx;,
161 Set::Scalar k2 = (n < domain.length(1)/2 ? n * pi_Ly : (n - domain.length(1)) * pi_Ly);,
162 Set::Scalar k3 = (p < domain.length(2)/2 ? p * pi_Lz : (p - domain.length(2)) * pi_Lz););
163
164
165 Set::Scalar lap = AMREX_D_TERM(k1 * k1, + k2 * k2, + k3*k3);
166
167 Set::Scalar bilap = lap*lap;
168
169 eta_hat(m, n, p) =
170 (eta_hat(m, n, p) - L * lap * chempot_hat(m, n, p) * dt) /
171 (1.0 + L * gamma * bilap * dt);
172
173
174 eta_hat(m,n,p) *= scaling;
175 });
176 }
177
178 //
179 // Transform solution back to realspace
180 //
181 my_fft.backward(eta_hat_mf, *etanew_mf[lev]);
182}
183#else
184void
185CahnHilliard::AdvanceSpectral (int, Set::Scalar, Set::Scalar)
186{
187 Util::Abort(INFO,"Alamo must be compiled with fft");
188}
189#endif
190
191
192
193void
194CahnHilliard::Initialize (int lev)
195{
196 intermediate[lev]->setVal(0.0);
197 ic->Initialize(lev,etanew_mf);
198 if (method == "realspace")
199 ic->Initialize(lev,etaold_mf);
200}
201
202
203void
204CahnHilliard::TagCellsForRefinement (int lev, amrex::TagBoxArray& a_tags, Set::Scalar /*time*/, int /*ngrow*/)
205{
206 if (method == "spectral") return;
207
208 const Set::Scalar* DX = geom[lev].CellSize();
209 Set::Scalar dr = sqrt(AMREX_D_TERM(DX[0] * DX[0], +DX[1] * DX[1], +DX[2] * DX[2]));
210
211 for (amrex::MFIter mfi(*etanew_mf[lev], amrex::TilingIfNotGPU()); mfi.isValid(); ++mfi)
212 {
213 const amrex::Box& bx = mfi.tilebox();
214 amrex::Array4<char> const& tags = a_tags.array(mfi);
215 Set::Patch<const Set::Scalar> eta = (*etanew_mf[lev]).array(mfi);
216
217 amrex::ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k)
218 {
219 Set::Vector grad = Numeric::Gradient(eta, i, j, k, 0, DX);
220 if (grad.lpNorm<2>() * dr > refinement_threshold)
221 tags(i, j, k) = amrex::TagBox::SET;
222 });
223 }
224}
225
226
227}
#define INFO
Definition Util.H:20
Set each point to a random value.
Definition Random.H:20
void select_default(std::string name, PTRTYPE *&ic_eta, Args &&... args)
Definition ParmParse.H:720
int query_default(std::string name, T &value, T defaultvalue, std::string="", std::string="", int=-1)
Definition ParmParse.H:185
int query_validate(std::string name, int &value, std::vector< int > possibleintvals, std::string file="", std::string func="", int line=-1)
Definition ParmParse.H:195
CahnHilliard()
Basic constructor (don't use)
IC::IC< Set::Scalar > * ic
eta's bc object
Set::Scalar gamma
eta's ic object
Set::Scalar refinement_threshold
BC::BC< Set::Scalar > * bc
Intermediate field used for CH kinetics.
~CahnHilliard()
Destroy pointers defined in Parse.
static void Parse(CahnHilliard &value, IO::ParmParse &pp)
Scan input values and initialize fields.
Collection of numerical integrator objects.
Definition AllenCahn.H:41
AMREX_FORCE_INLINE Set::Scalar Laplacian(const amrex::Array4< const Set::Scalar > &f, const int &i, const int &j, const int &k, const int &m, const Set::Scalar dx[AMREX_SPACEDIM], std::array< StencilType, AMREX_SPACEDIM > &stencil=DefaultType)
Definition Stencil.H:546
AMREX_FORCE_INLINE Set::Vector Gradient(const amrex::Array4< const Set::Scalar > &f, const int &i, const int &j, const int &k, const int &m, const Set::Scalar dx[AMREX_SPACEDIM], std::array< StencilType, AMREX_SPACEDIM > stencil=DefaultType)
Definition Stencil.H:672
static const Set::Scalar Pi
Definition Set.H:286
amrex::Real Scalar
Definition Base.H:19
Eigen::Matrix< amrex::Real, AMREX_SPACEDIM, 1 > Vector
Definition Base.H:20
void Abort(const char *msg)
Definition Util.cpp:170
void Message(std::string file, std::string func, int line, Args const &... args)
Definition Util.H:141