OpenLB 1.8.1
Loading...
Searching...
No Matches
phaseFieldCoupling.h
Go to the documentation of this file.
1/* This file is part of the OpenLB library
2 *
3 * Copyright (C) 2024 Tim Bingert, Michael Rennick
4 * E-mail contact: info@openlb.net
5 * The most recent release of OpenLB can be downloaded at
6 * <http://www.openlb.net/>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public
19 * License along with this program; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22*/
23
24#ifndef PHASE_FIELD_COUPLING_H
25#define PHASE_FIELD_COUPLING_H
26
27#include "core/operator.h"
28
29namespace olb {
30
31namespace stage {
32 struct ChemPotCalc { };
33 struct InitOutlet { };
34 struct PhiLimiter { };
35}
36
37// =========================================================================//
38// ==================Allen-Cahn + signed distance function==================//
39// =========================================================================//
40
41struct initialPsi {
44
45 int getPriority() const {
46 return 1;
47 }
48
49 template <typename CELL, typename PARAMETERS>
50 void apply(CELL& cell, PARAMETERS& parameters) any_platform
51 {
52 using V = typename CELL::value_t;
53 auto w = parameters.template get<descriptors::INTERFACE_WIDTH>();
54 V phi = cell.template getFieldComponent<descriptors::STATISTIC>(0);
55 V psi = 0;
56 if (phi > (0.99)) {
57 psi += -4.595120;
58 }
59 else if (phi < (0.01)) {
60 psi += 4.595120;
61 }
62 else {
63 psi += util::log(1/phi-1);
64 }
65 psi *= -w/4.;
66 cell.template setField<descriptors::SCALAR>(psi/util::sqrt(psi*psi+1.));
67 cell.template setField<descriptors::PSI>(psi);
68 cell.template setField<descriptors::PSI0>(psi);
69 }
70
71};
72
76
77 int getPriority() const {
78 return 0;
79 }
80
81 template <typename CELL, typename PARAMETERS>
82 void apply(CELL& cell, PARAMETERS& parameters) any_platform
83 {
84 using V = typename CELL::value_t;
85 using DESCRIPTOR = typename CELL::descriptor_t;
86
87 auto psi = cell.template getField<descriptors::PSI>();
88 auto psi0 = cell.template getField<descriptors::PSI0>();
89 auto epsilon = parameters.template get<descriptors::EPSILON>();
91 V normGradPsi = 1.;
92 if (util::fabs(psi) <= epsilon) {
93 V a = psi - cell.neighbor({-1,0}).template getField<descriptors::PSI>();
94 V b = cell.neighbor({1,0}).template getField<descriptors::PSI>() - psi;
95 V c = psi - cell.neighbor({0,-1}).template getField<descriptors::PSI>();
96 V d = cell.neighbor({0,1}).template getField<descriptors::PSI>() - psi;
97 V gradX, gradY;
98 if (psi0 > 0) {
99 if (a<0) a = 0;
100 if (b>0) b = 0;
101 if (c<0) c = 0;
102 if (d>0) d = 0;
103 gradX = a;
104 if (b*b>a*a) gradX = b;
105 gradY = c;
106 if (d*d>c*c) gradY = d;
107 normGradPsi = util::sqrt(gradX*gradX+gradY*gradY);
108 }
109 else if (psi0 < 0) {
110 if (a>0) a = 0;
111 if (b<0) b = 0;
112 if (c>0) c = 0;
113 if (d<0) d = 0;
114 gradX = a;
115 if (b*b>a*a) gradX = b;
116 gradY = c;
117 if (d*d>c*c) gradY = d;
118 normGradPsi = util::sqrt(gradX*gradX+gradY*gradY);
119 }
120 else {}
121 cell.template setField<descriptors::NORMGRADPSI>(normGradPsi);
122 } else {
123 cell.template setField<descriptors::NORMGRADPSI>(normGradPsi);
124 }
125 }
126};
127
128template<typename T, typename DESCRIPTOR, int xNormal, int yNormal>
132
133 int getPriority() const {
134 return 0;
135 }
136
137 template <typename CELL, typename PARAMETERS>
138 void apply(CELL& cell, PARAMETERS& parameters) any_platform
139 {
140 auto psi = cell.template getField<descriptors::PSI>();
141 auto psi0 = cell.template getField<descriptors::PSI0>();
142 auto epsilon = parameters.template get<descriptors::EPSILON>();
143 Vector<T,DESCRIPTOR::d> gradPsi{};
144 T normGradPsi = 1.;
145 if (util::fabs(psi) <= epsilon) {
146 T a = psi - cell.neighbor({-1,0}).template getField<descriptors::PSI>();
147 T b = cell.neighbor({1,0}).template getField<descriptors::PSI>() - psi;
148 T c = psi - cell.neighbor({0,-1}).template getField<descriptors::PSI>();
149 T d = cell.neighbor({0,1}).template getField<descriptors::PSI>() - psi;
150 if (xNormal == 1) b = a;
151 else if (xNormal == -1) a = b;
152 if (yNormal == 1) d = c;
153 else if (yNormal == -1) c = d;
154 T gradX, gradY;
155 if (psi0 > 0) {
156 if (a<0) a = 0;
157 if (b>0) b = 0;
158 if (c<0) c = 0;
159 if (d>0) d = 0;
160 gradX = a;
161 if (b*b>a*a) gradX = b;
162 gradY = c;
163 if (d*d>c*c) gradY = d;
164 normGradPsi = util::sqrt(gradX*gradX+gradY*gradY);
165 }
166 else if (psi0 < 0) {
167 if (a>0) a = 0;
168 if (b<0) b = 0;
169 if (c>0) c = 0;
170 if (d<0) d = 0;
171 gradX = a;
172 if (b*b>a*a) gradX = b;
173 gradY = c;
174 if (d*d>c*c) gradY = d;
175 normGradPsi = util::sqrt(gradX*gradX+gradY*gradY);
176 }
177 else {}
178 cell.template setField<descriptors::NORMGRADPSI>(normGradPsi);
179 } else {
180 cell.template setField<descriptors::NORMGRADPSI>(normGradPsi);
181 }
182 }
183};
184
185struct psiEvolve {
187 struct DELTAT : public descriptors::FIELD_BASE<1> { };
189
190 int getPriority() const {
191 return 1;
192 }
193
194 template <typename CELL, typename PARAMETERS>
195 void apply(CELL& cell, PARAMETERS& parameters) any_platform
196 {
197 using V = typename CELL::value_t;
198 auto dt = parameters.template get<DELTAT>();
199 auto epsilon = parameters.template get<descriptors::EPSILON>();
200 auto s = cell.template getField<descriptors::SCALAR>();
201 auto psi = cell.template getField<descriptors::PSI>();
202 V psi_new = psi;
203 if (util::fabs(psi) >= epsilon) cell.template setField<descriptors::PSI>(psi_new);
204 else {
205 auto normGradPsi = cell.template getField<descriptors::NORMGRADPSI>();
206 psi_new = psi-dt*s*(normGradPsi-1.);
207 cell.template setField<descriptors::PSI>(psi_new);
208 }
209 }
210};
211
215
216 int getPriority() const {
217 return 0;
218 }
219
220 template <typename CELL, typename PARAMETERS>
221 void apply(CELL& cell, PARAMETERS& parameters) any_platform
222 {
223 using V = typename CELL::value_t;
224 using DESCRIPTOR = typename CELL::descriptor_t;
225 V w = parameters.template get<descriptors::INTERFACE_WIDTH>();
226 V psi = cell.template getField<descriptors::PSI>();
227 auto phi = cell.template getField<descriptors::STATISTIC>();
228 if (fabs(psi) >= 1.5*w) {
229 if (phi[0] > 0.5 && phi[0] < 0.995) {
230 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
231 cell[iPop] += descriptors::t<V,DESCRIPTOR>(iPop) * (1-phi[0]);
232 }
233 } else if (phi[0] < 0.5 && phi[0] > 0.005) {
234 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
235 cell[iPop] += descriptors::t<V,DESCRIPTOR>(iPop) * (0-phi[0]);
236 }
237 }
238 phi[0] = cell.computeRho();
239 cell.template setField<descriptors::STATISTIC>(phi);
240 }
241 }
242};
243
247
248 int getPriority() const {
249 return 0;
250 }
251
252 template <typename CELL, typename PARAMETERS>
253 void apply(CELL& cell, PARAMETERS& parameters) any_platform
254 {
255 using V = typename CELL::value_t;
256 V phi = cell.template getFieldComponent<descriptors::STATISTIC>(0);
257 auto epsilon = parameters.template get<descriptors::EPSILON>();
258
259 V psi = cell.template getField<descriptors::PSI>();
260 V interfaceIndicator = 0;
261 if (util::fabs(psi) < epsilon) interfaceIndicator = 1;
262 V top = (1.-interfaceIndicator)*phi*(phi-1.)*(phi-0.5);
263 V bottom = (1.-interfaceIndicator)*(1.-phi)*phi;
264
265 cell.template setField<descriptors::TOP>(top);
266 cell.template setField<descriptors::BOTTOM>(bottom);
267 }
268};
269
272 struct SIGMA : public descriptors::FIELD_BASE<1> { };
273 struct W : public descriptors::FIELD_BASE<1> { };
274 struct TAUS : public descriptors::FIELD_BASE<3> { };
275 struct RHOS : public descriptors::FIELD_BASE<2> { };
276 struct NONLOCALITY : public descriptors::FIELD_BASE<1> { };
278
279 int getPriority() const {
280 return 0;
281 }
282
283 template <typename CELL, typename PARAMETERS>
284 void apply(CELL& cells, PARAMETERS& parameters) any_platform
285 {
286 using V = typename CELL::template value_t<names::NavierStokes>::value_t;
287 using DESCRIPTOR = typename CELL::template value_t<names::NavierStokes>::descriptor_t;
288
289 auto& cellNS = cells.template get<names::NavierStokes>();
290 auto& cellAC = cells.template get<names::Component1>();
291
292 V phi = cellAC.template getFieldComponent<descriptors::STATISTIC>(0);
293 Vector<V,DESCRIPTOR::d> gradPhi{};
294 V laplacePhi = 0;
295 //TODO: use lattice gradient schemes here from Cahn-Hilliard implementation
296 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
297 const V phi_i = cellAC.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getFieldComponent<descriptors::STATISTIC>(0);
299 laplacePhi += 2*(phi_i - phi) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
300 }
301
302 auto scale = cellNS.template getField<descriptors::SCALAR>();
303 auto sigma = parameters.template get<SIGMA>()*(0.99*scale+0.01);
304 auto w = parameters.template get<W>();
305 auto rho_v = parameters.template get<RHOS>()[0];
306 auto rho_l = parameters.template get<RHOS>()[1];
307 V rho = rho_v + (rho_l-rho_v)*phi;
308 auto tau_v = parameters.template get<TAUS>()[0];
309 auto tau_l = parameters.template get<TAUS>()[1];
310 V tau = (tau_v + (tau_l-tau_v)*phi);//*(-9.*scale+10.);
311 auto gamma = parameters.template get<NONLOCALITY>();
312 auto tau_mobil = parameters.template get<TAUS>()[2];
313 V M = (tau_mobil-0.5)/descriptors::invCs2<V,DESCRIPTOR>();
314
315 // Computation and storage of forces
316 Vector<V,DESCRIPTOR::d> forceNS{};
317 V u[DESCRIPTOR::d] {};
318 //cellNS.computeU(u);
319 V k = 1.5*sigma*w;
320 V beta = 12*sigma/w;
321 V mu = 4*beta*phi*(phi-1.)*(phi-0.5)-k*laplacePhi;
322 forceNS += mu*gradPhi;
323 auto externalForce = cellNS.template getField<descriptors::EXTERNAL_FORCE>();
324 cellNS.template setField<descriptors::FORCE>(externalForce + forceNS/rho);
325 cellNS.template setField<descriptors::NABLARHO>((rho_l-rho_v)*gradPhi);
326 cellNS.template setField<descriptors::TAU_EFF>(tau);
327 cellNS.template setField<descriptors::RHO>(rho);
328 cellNS.computeU(u);
329
330 V psi = cellAC.template getField<descriptors::PSI>();
331 V interfaceIndicator = 0.;
332 if (util::fabs(psi) < 3.*w) interfaceIndicator = 1;
333 Vector<V,DESCRIPTOR::d> forceAC{};
334 Vector<V,DESCRIPTOR::d> old_phiU{};
337 V gradPhiSqr = 0;
338 for (int iD=0; iD < DESCRIPTOR::d; ++iD) {
339 gradPhiSqr += gradPhi[iD]*gradPhi[iD];
340 phiU[iD] = phi*u[iD];
341 }
342 if (gradPhiSqr >= 1e-28) {
343 n += gradPhi/util::sqrt(gradPhiSqr);
344 }
345 old_phiU = cellAC.template getField<descriptors::OLD_PHIU>();
346 cellAC.template setField<descriptors::OLD_PHIU>(phiU);
347 V lambda = 4*phi*(1.-phi)/w;
348 V D_N = 4*beta/k*(interfaceIndicator-1.)*(phi*(phi-1.)*(phi-0.5)-gamma*(1.-phi)*phi);
349 V source_old = cellAC.template getField<descriptors::SOURCE_OLD>();
350 cellAC.template setField<descriptors::SOURCE_OLD>(M*D_N);
351 forceAC += (phiU - old_phiU) + interfaceIndicator*lambda*n/descriptors::invCs2<V,DESCRIPTOR>();
352 cellAC.template setField<descriptors::FORCE>(forceAC);
353 V source = 1.5*M*D_N-0.5*source_old;
354 cellAC.template setField<descriptors::SOURCE>(source);
355 cellAC.template setField<descriptors::VELOCITY>(u);
356 }
357};
358
361
362 int getPriority() const {
363 return 0;
364 }
365
366 template <typename CELL>
367 void apply(CELL& cells) any_platform
368 {
369 using V = typename CELL::template value_t<names::NavierStokes>::value_t;
370 using DESCRIPTOR = typename CELL::template value_t<names::NavierStokes>::descriptor_t;
371
372 auto& cellNS = cells.template get<names::NavierStokes>();
373 auto& cellAC = cells.template get<names::Component1>();
374
375 // Computation and storage of forces
376 V u[DESCRIPTOR::d] {};
377 cellNS.computeU(u);
378 cellAC.template setField<descriptors::VELOCITY>(u);
379 }
380};
381
384 struct SIGMA : public descriptors::FIELD_BASE<1> { };
385 struct W : public descriptors::FIELD_BASE<1> { };
386 struct NORMAL : public descriptors::FIELD_BASE<2> { };
388
389 int getPriority() const {
390 return 0;
391 }
392
393 template <typename CELL, typename PARAMETERS>
394 void apply(CELL& cells, PARAMETERS& parameters) any_platform
395 {
396 using V = typename CELL::template value_t<names::NavierStokes>::value_t;
397 using DESCRIPTOR = typename CELL::template value_t<names::NavierStokes>::descriptor_t;
398
399 auto& cellNS = cells.template get<names::NavierStokes>();
400 auto& cellAC = cells.template get<names::Component1>();
401
402 auto w = parameters.template get<W>();
403 auto sigma = parameters.template get<SIGMA>();
404 Vector<int, DESCRIPTOR::d> normal = parameters.template get<NORMAL>();
405 auto rho = cellNS.template getField<descriptors::RHO>();
406 auto nablaRho = cellNS.template getField<descriptors::NABLARHO>();
407
408 V phi = cellAC.template getFieldComponent<descriptors::STATISTIC>(0);
409 auto cellAC_n1 = cellAC.neighbor({-normal[0],-normal[1]});
410 auto cellNS_n1 = cellNS.neighbor({-normal[0],-normal[1]});
411 V phi_n1 = cellAC_n1.template getFieldComponent<descriptors::STATISTIC>(0);
412 Vector<V,DESCRIPTOR::d> gradPhi{};
413 V laplacePhi = 0;
414
415 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
416 const V phi_i = cellAC.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getFieldComponent<descriptors::STATISTIC>(0);
418 laplacePhi += 2*(phi_i - phi) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
419 }
420 V laplacePhi_n1 = 0;
421 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
422 const V phi_i_n1 = cellAC_n1.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getFieldComponent<descriptors::STATISTIC>(0);
423 laplacePhi_n1 += 2*(phi_i_n1 - phi_n1) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
424 }
425
426 // Computation of thermodynamic pressure and update populations
427 V k = 1.5*sigma*w;
428 V beta = 12*sigma/w;
429 V mu = 4*beta*phi*(phi-1.)*(phi-0.5)-k*laplacePhi;
430 V mu_n1 = 4*beta*phi_n1*(phi_n1-1.)*(phi_n1-0.5)-k*laplacePhi_n1;
431
432 V u[DESCRIPTOR::d] {};
433 //cellAC_n1.computeU(u);
434 V rhoU = u[0]*nablaRho[0]+u[1]*nablaRho[1];
435 V p_n1 = cellNS_n1.computeRho();
436 V p_n2 = cellNS.neighbor({-2*normal[0],-2*normal[1]}).computeRho();
437 V p_old = cellNS.computeRho();
438 V p_out = (p_n1 + (mu+mu_n1)/2*(phi-phi_n1));//0.8*(0.25*sigma*curv*(2*phi-1)*((2*phi-1)*(2*phi-1)-3)+0.5*sigma*curv);
439 //V p_star = p_out;
440 if (phi >= 0.95) {
441 p_out = 0;
442 }
443 //V p_star = p_out-3./10.*rhoU;
444 cellNS.defineRho(p_out);
445 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
446 cellNS[iPop] += descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>() * (p_out-p_old);
447 }
448 }
449};
450
454
455 int getPriority() const {
456 return 0;
457 }
458
459 template <typename CELL, typename PARAMETERS>
460 void apply(CELL& cell, PARAMETERS& parameters) any_platform
461 {
462 using V = typename CELL::value_t;
463 using DESCRIPTOR = typename CELL::descriptor_t;
464
465 V phi = cell.template getFieldComponent<descriptors::STATISTIC>(0);
466 Vector<V,DESCRIPTOR::d> gradPhi{};
467 V laplacePhi = 0;
468
469 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
470 const V phi_i = cell.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getFieldComponent<descriptors::STATISTIC>(0);
472 laplacePhi += 2*(phi_i - phi) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
473 }
474 auto w = parameters.template get<descriptors::INTERFACE_WIDTH>();
475
476 // Computation and storage of forces
477 Vector<V,DESCRIPTOR::d> forceAC{};
478 Vector<V,DESCRIPTOR::d> old_phiU{};
481 V u[DESCRIPTOR::d] {};
482 cell.computeU(u);
483 V gradPhiSqr = 0;
484 for (int iD=0; iD < DESCRIPTOR::d; ++iD) {
485 gradPhiSqr += gradPhi[iD]*gradPhi[iD];
486 phiU[iD] = phi*u[iD];
487 }
488 if (gradPhiSqr >= 1e-28) {
489 n += gradPhi/util::sqrt(gradPhiSqr);
490 }
491
492 old_phiU = cell.template getField<descriptors::OLD_PHIU>();
493 cell.template setField<descriptors::OLD_PHIU>(phiU);
494 V lambda = 4*phi*(1.-phi)/w;
495 forceAC += (phiU - old_phiU) + lambda*n/descriptors::invCs2<V,DESCRIPTOR>();
496 cell.template setField<descriptors::FORCE>(forceAC);
497 }
498};
499
502 struct SIGMA : public descriptors::FIELD_BASE<1> { };
503 struct W : public descriptors::FIELD_BASE<1> { };
504 struct TAUS : public descriptors::FIELD_BASE<2> { };
505 struct RHOS : public descriptors::FIELD_BASE<2> { };
506 struct SWITCH : public descriptors::FIELD_BASE<1> { };
508
509 int getPriority() const {
510 return 0;
511 }
512
513 template <typename CELL, typename PARAMETERS>
514 void apply(CELL& cells, PARAMETERS& parameters) any_platform
515 {
516 using V = typename CELL::template value_t<names::NavierStokes>::value_t;
517 using DESCRIPTOR = typename CELL::template value_t<names::NavierStokes>::descriptor_t;
518
519 auto& cellNS = cells.template get<names::NavierStokes>();
520 auto& cellAC = cells.template get<names::Component1>();
521
522 V phi = cellAC.template getFieldComponent<descriptors::STATISTIC>(0);
523 Vector<V,DESCRIPTOR::d> gradPhi{};
524 V laplacePhi = 0;
525 //TODO: use lattice gradient schemes here from Cahn-Hilliard implementation
526 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
527 const V phi_i = cellAC.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getFieldComponent<descriptors::STATISTIC>(0);
529 gradPhi += phi_i * descriptors::c<DESCRIPTOR>(iPop) * tcs2;
530 laplacePhi += 2*(phi_i - phi) * tcs2;
531 }
532
533 auto scale = cellNS.template getField<descriptors::SCALAR>();
534 auto sigma = parameters.template get<SIGMA>()*scale;
535 auto w = parameters.template get<W>();
536 auto rho_v = parameters.template get<RHOS>()[0];
537 auto rho_l = parameters.template get<RHOS>()[1];
538 V rho = rho_v + (rho_l-rho_v)*phi;
539 auto tau_v = parameters.template get<TAUS>()[0];
540 auto tau_l = parameters.template get<TAUS>()[1];
541 V tau = (tau_v + (tau_l-tau_v)*phi)*scale + (1-scale)*5.;
542
543 // Computation and storage of forces
544 Vector<V,DESCRIPTOR::d> forceNS{};
545 V u[DESCRIPTOR::d] {};
546 V k = 1.5*sigma*w;
547 V beta = 12*sigma/w;
548 V mu = 4*beta*phi*(phi-1.)*(phi-0.5)-k*laplacePhi;
549 forceNS += mu*gradPhi;
550 auto externalForce = cellNS.template getField<descriptors::EXTERNAL_FORCE>();
551 cellNS.template setField<descriptors::FORCE>(externalForce + forceNS/rho);
552 cellNS.template setField<descriptors::NABLARHO>((rho_l-rho_v)*gradPhi);
553 cellNS.template setField<descriptors::TAU_EFF>(tau);
554 cellNS.template setField<descriptors::RHO>(rho);
555 cellNS.computeU(u);
556
557 Vector<V,DESCRIPTOR::d> forceAC{};
558 Vector<V,DESCRIPTOR::d> old_phiU{};
561 auto velo_switch = parameters.template get<SWITCH>();
562 V gradPhiSqr = 0;
563 for (int iD=0; iD < DESCRIPTOR::d; ++iD) {
564 gradPhiSqr += gradPhi[iD]*gradPhi[iD];
565 u[iD] *= velo_switch;
566 phiU[iD] = phi*u[iD];
567 }
568 if (gradPhiSqr >= 1e-28) {
569 n += gradPhi/util::sqrt(gradPhiSqr);
570 }
571 old_phiU = cellAC.template getField<descriptors::OLD_PHIU>();
572 cellAC.template setField<descriptors::OLD_PHIU>(phiU);
573 V lambda = 4*phi*(1.-phi)/w;
574 forceAC += (phiU - old_phiU) + lambda*n/descriptors::invCs2<V,DESCRIPTOR>();
575 cellAC.template setField<descriptors::FORCE>(forceAC);
576 cellAC.template setField<descriptors::VELOCITY>(u);
577 }
578};
579
582
583 int getPriority() const {
584 return 0;
585 }
586
587 template <typename CELL>
588 void apply(CELL& cell) any_platform
589 {
590 auto statistic = cell.template getField<descriptors::STATISTIC>();
591 statistic[0] = cell.computeRho();
592 cell.template setField<descriptors::STATISTIC>(statistic);
593 cell.template setField<descriptors::PHIWETTING>(statistic[0]);
594 }
595};
596
599 struct TAUS : public descriptors::FIELD_BASE<2> { };
600 struct RHOS : public descriptors::FIELD_BASE<2> { };
602
603 int getPriority() const {
604 return 0;
605 }
606
607 template <typename CELL, typename PARAMETERS>
608 void apply(CELL& cells, PARAMETERS& parameters) any_platform
609 {
610 using V = typename CELL::template value_t<names::NavierStokes>::value_t;
611 using DESCRIPTOR = typename CELL::template value_t<names::NavierStokes>::descriptor_t;
612
613 auto& cellNS = cells.template get<names::NavierStokes>();
614 auto& cellCH = cells.template get<names::Component1>();
615
616 V phi = cellCH.template getFieldComponent<descriptors::STATISTIC>(0);
617 V mu = cellCH.template getField<descriptors::CHEM_POTENTIAL>();
618 Vector<V,DESCRIPTOR::d> gradPhi{};
620 V laplacePhi = 0;
621 //TODO: use lattice gradient schemes here from Cahn-Hilliard implementation
622 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
623 const V phi_i = cellCH.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getFieldComponent<descriptors::STATISTIC>(0);
624 const V mu_i = cellCH.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getField<descriptors::CHEM_POTENTIAL>();
625 //const V phiMu_i = phi_i*mu_i;
626 //gradPhi += phi_i * descriptors::c<DESCRIPTOR>(iPop) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
627 //gradMu += mu_i * descriptors::c<DESCRIPTOR>(iPop) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
628 if(int(cellCH.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getField<descriptors::BOUNDARY>())) gradMu += mu * descriptors::c<DESCRIPTOR>(iPop) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
630 if(int(cellCH.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getField<descriptors::BOUNDARY>())) gradPhi += phi * descriptors::c<DESCRIPTOR>(iPop) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
632 laplacePhi += 2*(phi_i - phi) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
633 }
634
635 auto rho_v = parameters.template get<RHOS>()[0];
636 auto rho_l = parameters.template get<RHOS>()[1];
637 V rho = rho_v + (rho_l-rho_v)*phi;
638 auto tau_v = parameters.template get<TAUS>()[0];
639 auto tau_l = parameters.template get<TAUS>()[1];
640 V tau = tau_v + (tau_l-tau_v)*phi;
641
642 // Computation and storage of forces
643 Vector<V,DESCRIPTOR::d> forceNS{};
644 V u[DESCRIPTOR::d] {};
645 forceNS += -phi*gradMu;
646 //V mu = cellCH.template getField<descriptors::CHEM_POTENTIAL>();
647 //forceNS += mu*gradPhi;
648 auto externalBlockForce = cellNS.template getField<descriptors::EXTERNAL_FORCE>();
649 cellNS.template setField<descriptors::FORCE>(externalBlockForce + forceNS/rho);
650 cellNS.template setField<descriptors::NABLARHO>((rho_l-rho_v)*gradPhi);
651 cellNS.template setField<descriptors::TAU_EFF>(tau);
652 cellNS.template setField<descriptors::RHO>(rho);
653
654 V source{};
655 cellNS.computeU(u);
656 for (int iD=0; iD < DESCRIPTOR::d; ++iD) {
657 source += gradPhi[iD]*u[iD];
658 }
659 V source_old = cellCH.template getField<descriptors::SOURCE_OLD>();
660 cellCH.template setField<descriptors::SOURCE>(1.5*source-0.5*source_old);
661 cellCH.template setField<descriptors::SOURCE_OLD>(source);
662 cellCH.template setField<descriptors::VELOCITY>(u);
663 }
664};
665
669
670 int getPriority() const {
671 return 0;
672 }
673
674 template <typename CELL, typename PARAMETERS>
675 void apply(CELL& cell, PARAMETERS& parameters) any_platform
676 {
677 using V = typename CELL::value_t;
678 using DESCRIPTOR = typename CELL::descriptor_t;
679
680 V phi = cell.template getFieldComponent<descriptors::STATISTIC>(0);
681 V laplacePhi = 0;
682 //TODO: use lattice gradient schemes here from Cahn-Hilliard implementation
683 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
684 const V phi_i = cell.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getField<descriptors::PHIWETTING>();
685 laplacePhi += 2*(phi_i - phi) * descriptors::t<V,DESCRIPTOR>(iPop) * descriptors::invCs2<V,DESCRIPTOR>();
686 }
687
688 auto sigma = parameters.template get<descriptors::SCALAR>();
689 auto w = parameters.template get<descriptors::INTERFACE_WIDTH>();
690
691 // Computation and storage of chemical potential
692 V k = 1.5*sigma*w;
693 V beta = 12*sigma/w;
694 V mu = 4*beta*phi*(phi-1.)*(phi-0.5)+0.25*(phi<0)*phi-k*laplacePhi;
695 cell.template setField<descriptors::CHEM_POTENTIAL>(mu);
696 }
697};
698
699template<typename T, typename DESCRIPTOR, int xNormal, int yNormal>
703
704 int getPriority() const {
705 return 1;
706 }
707
708 template <typename CELL, typename PARAMETERS>
709 void apply(CELL& cell, PARAMETERS& parameters) any_platform
710 {
711 auto theta = parameters.template get<descriptors::THETA>();
712 auto w = parameters.template get<descriptors::INTERFACE_WIDTH>();
713
714 auto phi_n = cell.template getField<descriptors::STATISTIC>();
715 phi_n[0] = cell.neighbor({-xNormal,-yNormal}).computeRho();
716 //auto phi_w = phi_n[0] + 5.*4./w * cos(theta) *phi_n[0]*(1-phi_n[0])*phi_n[0]*(1-phi_n[0]);
717 auto phi_w = phi_n[0] + 4./w * cos(theta) *phi_n[0]*(1-phi_n[0]);
718 //auto phi_w = phi_n[0] + 0.55662613315165*5.*4./w * cos(theta) *((0.2+phi_n[0])*(1.2-phi_n[0])*(0.2+phi_n[0])*(1.2-phi_n[0])*(0.2+phi_n[0])*(1.2-phi_n[0])-0.0138824);
719 cell.template setField<descriptors::PHIWETTING>(phi_w);
720
721 auto cp_n = cell.template getField<descriptors::CHEM_POTENTIAL>();
722 cp_n = cell.neighbor({-xNormal,-yNormal}).template getField<descriptors::CHEM_POTENTIAL>();
723 cell.template setField<descriptors::STATISTIC>(phi_n);
724 cell.template setField<descriptors::CHEM_POTENTIAL>(cp_n);
725 }
726};
727
728template<typename T, typename DESCRIPTOR, int xNormal, int yNormal, int zNormal>
732
733 int getPriority() const {
734 return 1;
735 }
736
737 template <typename CELL, typename PARAMETERS>
738 void apply(CELL& cell, PARAMETERS& parameters) any_platform
739 {
740 auto theta = parameters.template get<descriptors::THETA>();
741 auto w = parameters.template get<descriptors::INTERFACE_WIDTH>();
742
743 auto phi_n = cell.template getField<descriptors::STATISTIC>();
744 phi_n[0] = cell.neighbor({-xNormal,-yNormal,-zNormal}).computeRho();
745 //auto phi_w = phi_n[0] + 5.*4./w * cos(theta) *phi_n[0]*(1-phi_n[0])*phi_n[0]*(1-phi_n[0]);
746 auto phi_w = phi_n[0] + 4./w * cos(theta) *phi_n[0]*(1-phi_n[0]);
747 //auto phi_w = phi_n[0] + 0.55662613315165*5.*4./w * cos(theta) *((0.2+phi_n[0])*(1.2-phi_n[0])*(0.2+phi_n[0])*(1.2-phi_n[0])*(0.2+phi_n[0])*(1.2-phi_n[0])-0.0138824);
748 cell.template setField<descriptors::PHIWETTING>(phi_w);
749
750 auto cp_n = cell.template getField<descriptors::CHEM_POTENTIAL>();
751 cp_n = cell.neighbor({-xNormal,-yNormal,-zNormal}).template getField<descriptors::CHEM_POTENTIAL>();
752 cell.template setField<descriptors::STATISTIC>(phi_n);
753 cell.template setField<descriptors::CHEM_POTENTIAL>(cp_n);
754 }
755};
756
757template<typename T, typename DESCRIPTOR, int xNormal, int yNormal>
761
762 int getPriority() const {
763 return 1;
764 }
765
766 template <typename CELL, typename PARAMETERS>
767 void apply(CELL& cell, PARAMETERS& parameters) any_platform
768 {
769 auto theta = parameters.template get<descriptors::THETA>();
770 Vector<int,DESCRIPTOR::d> tangent{yNormal*(-1),xNormal*1};
771 Vector<int,DESCRIPTOR::d> opp_tang{tangent[0]*(-1),tangent[1]*(-1)};
772
773 auto phi_1 = cell.neighbor({-xNormal,-yNormal}).template getFieldComponent<descriptors::STATISTIC>(0);
774 auto phi_1r = cell.neighbor({-xNormal,-yNormal}).neighbor(tangent).template getFieldComponent<descriptors::STATISTIC>(0);
775 auto phi_1l = cell.neighbor({-xNormal,-yNormal}).neighbor(opp_tang).template getFieldComponent<descriptors::STATISTIC>(0);
776 auto phi_2r = cell.neighbor({-2*xNormal,-2*yNormal}).neighbor(tangent).template getFieldComponent<descriptors::STATISTIC>(0);
777 auto phi_2l = cell.neighbor({-2*xNormal,-2*yNormal}).neighbor(opp_tang).template getFieldComponent<descriptors::STATISTIC>(0);
778
779 T dphi_1 = ( phi_1r - phi_1l ) / 2.;
780 T dphi_2 = ( phi_2r - phi_2l ) / 2.;
781 T tau_x_dphi = 1.5*dphi_1 - 0.5*dphi_2;
782
783 auto phi = cell.template getField<descriptors::STATISTIC>();
784 phi[0] = phi_1 + tan( M_PI/2. - theta ) * abs(tau_x_dphi);
785 cell.template setField<descriptors::STATISTIC>(phi);
786 }
787};
788
789template<typename T, typename DESCRIPTOR>
793
794 int getPriority() const {
795 return 1;
796 }
797
798 template <typename CELL, typename PARAMETERS>
799 void apply(CELL& cell, PARAMETERS& parameters) any_platform
800 {
801 auto phi = cell.template getField<descriptors::STATISTIC>();
802 phi[0] = 0;
803 T weightSum = 0;
804 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
805 if(cell.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getField<descriptors::BOUNDARY>() == 1.) {
806 phi[0] += cell.neighbor(descriptors::c<DESCRIPTOR>(iPop)).template getFieldComponent<descriptors::STATISTIC>(0) * descriptors::t<T,DESCRIPTOR>(iPop);
807 weightSum += descriptors::t<T,DESCRIPTOR>(iPop);
808 }
809 }
810 phi[0] = phi[0]/weightSum;
811 cell.template setField<descriptors::STATISTIC>(phi);
812 }
813};
814
815template<typename T, typename DESCRIPTOR, int xNormal, int yNormal>
819
820 int getPriority() const {
821 return 1;
822 }
823
824 template <typename CELL, typename PARAMETERS>
825 void apply(CELL& cell, PARAMETERS& parameters) any_platform
826 {
827 auto phi_s = cell.template getField<descriptors::STATISTIC>();
828 auto phi_b = cell.neighbor({-xNormal,-yNormal}).template getFieldComponent<descriptors::STATISTIC>(0);
829 if (phi_b >= 0.995) {
830 phi_s[0] = 1.;
831 }
832 else if (phi_b <= 0.005) {
833 phi_s[0] = 0.;
834 }
835 else {
836 auto theta = cell.template getField<descriptors::THETA>();
837 auto w = parameters.template get<descriptors::INTERFACE_WIDTH>();
838 T z_z0 = w/2.*util::atanh(2.*phi_b-1.);
839 T cx = util::cos(-theta)*xNormal-util::sin(-theta)*yNormal;
840 T cy = util::sin(-theta)*xNormal+util::cos(-theta)*yNormal;
842 Vector<T,DESCRIPTOR::d> n{T(xNormal),T(yNormal)};
843 c = util::normalize(c);
844 T d = c[0]*n[0]+c[1]*n[1];
845 phi_s[0] = 0.5*(1+util::tanh(2.*(z_z0+d)/w));
846 }
847 cell.template setField<descriptors::STATISTIC>(phi_s);
848 }
849};
850
851template<int xNormal, int yNormal>
854
855 int getPriority() const {
856 return 0;
857 }
858
859 template <typename CELL>
860 void apply(CELL& cell) any_platform
861 {
862 using T = typename CELL::value_t;
863 using DESCRIPTOR = typename CELL::descriptor_t;
864 T phi, u[DESCRIPTOR::d];
865 auto outlet_cell = cell.template getField<descriptors::CONV_POPS>();
866 cell.computeRhoU(phi, u);
867 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
868 outlet_cell[iPop] = equilibrium<DESCRIPTOR>::firstOrder(iPop, phi, u);
869 }
870 cell.template setField<descriptors::CONV_POPS>(outlet_cell);
871 auto phiGhost = cell.neighbor({xNormal,yNormal}).template getField<descriptors::STATISTIC>();
872 phiGhost[0] = phi;
873 cell.neighbor({xNormal,yNormal}).template setField<descriptors::STATISTIC>(phiGhost);
874 }
875};
876
879
880 int getPriority() const {
881 return 0;
882 }
883
884 template <typename CELL>
885 void apply(CELL& cell) any_platform
886 {
887 using DESCRIPTOR = typename CELL::descriptor_t;
888 //T p, u[DESCRIPTOR::d];
889 auto outlet_cell = cell.template getField<descriptors::CONV_POPS>();
890 //cell.computeRhoU(p, u);
891 //auto rho = cell.template getField<descriptors::RHO>();
892 for (int iPop=0; iPop < DESCRIPTOR::q; ++iPop) {
893 outlet_cell[iPop] = cell[iPop];
894 }
895 cell.template setField<descriptors::CONV_POPS>(outlet_cell);
896 }
897};
898
899};
900
901#endif
#define M_PI
Plain old scalar vector.
constexpr T invCs2() any_platform
Definition functions.h:107
constexpr T t(unsigned iPop, tag::CUM) any_platform
Definition cum.h:108
constexpr int c(unsigned iPop, unsigned iDim) any_platform
Definition functions.h:83
Expr sqrt(Expr x)
Definition expr.cpp:225
ADf< T, DIM > log(const ADf< T, DIM > &a)
Definition aDiff.h:475
ADf< T, DIM > sin(const ADf< T, DIM > &a)
Definition aDiff.h:569
Vector< T, D > normalize(const Vector< T, D > &a)
Expr fabs(Expr x)
Definition expr.cpp:230
ADf< T, DIM > tanh(const ADf< T, DIM > &a)
Definition aDiff.h:663
ADf< T, DIM > atanh(const ADf< T, DIM > &a)
Definition aDiff.h:689
ADf< T, DIM > cos(const ADf< T, DIM > &a)
Definition aDiff.h:578
Top level namespace for all of OpenLB.
std::enable_if_t< std::is_arithmetic< T >::type::value, T > abs(T x) any_platform
Definition util.h:464
OperatorScope
Block-wide operator application scopes.
@ PerCell
Per-cell application, i.e. OPERATOR::apply is passed a CELL concept implementation.
@ PerCellWithParameters
Per-cell application with parameters, i.e. OPERATOR::apply is passed a CELL concept implementation an...
#define any_platform
Define preprocessor macros for device-side functions, constant storage.
Definition platform.h:77
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
void apply(CELL &cells, PARAMETERS &parameters) any_platform
void apply(CELL &cells, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
void apply(CELL &cell, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
void apply(CELL &cell, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
void apply(CELL &cells, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
void apply(CELL &cell) any_platform
static constexpr OperatorScope scope
void apply(CELL &cell) any_platform
static constexpr OperatorScope scope
static constexpr OperatorScope scope
void apply(CELL &cell) any_platform
static constexpr OperatorScope scope
void apply(CELL &cells) any_platform
void apply(CELL &cells, PARAMETERS &parameters) any_platform
void apply(CELL &cell, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
Base of a field whose size is defined by [C_0,C_1,C_2]^T * [1,D,Q].
Definition fields.h:52
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
static V firstOrder(int iPop, const RHO &rho, const U &u) any_platform
Computation of equilibrium distribution, first order in u.
Definition lbm.h:37
static constexpr OperatorScope scope
int getPriority() const
void apply(CELL &cell, PARAMETERS &parameters) any_platform
Plain wrapper for list of types.
Definition meta.h:276
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
void apply(CELL &cell, PARAMETERS &parameters) any_platform
static constexpr OperatorScope scope
void apply(CELL &cell, PARAMETERS &parameters) any_platform
int getPriority() const
static constexpr OperatorScope scope