936 lines
32 KiB
C++
936 lines
32 KiB
C++
/*
|
|
Copyright 2013--2018 James E. McClure, Virginia Polytechnic & State University
|
|
Copyright Equnior ASA
|
|
|
|
This file is part of the Open Porous Media project (OPM).
|
|
OPM is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
OPM is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
You should have received a copy of the GNU General Public License
|
|
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <stdio.h>
|
|
#include <math.h>
|
|
|
|
/***** pH equilibrium ******/
|
|
extern "C" void ScaLBL_D3Q7_AAodd_pH_ionization(int *neighborList, double *dist,
|
|
double *Den,
|
|
double *ElectricField,
|
|
double *Velocity, double Di,
|
|
double Vt, int pH_ion,
|
|
int start, int finish, int Np) {
|
|
int n;
|
|
double Ex, Ey, Ez; //electrical field
|
|
double ux, uy, uz;
|
|
double uEPx, uEPy, uEPz; //electrochemical induced velocity
|
|
double Ca, Cb;
|
|
double A0, A1, A2, A3, A4, A5, A6;
|
|
double B0, B1, B2, B3, B4, B5, B6;
|
|
double f0, f1, f2, f3, f4, f5, f6;
|
|
int nr1, nr2, nr3, nr4, nr5, nr6;
|
|
double rhoe, tmp;
|
|
// double factor = Di / (Vt *Vt* ionizationEnergy);
|
|
|
|
for (n = start; n < finish; n++) {
|
|
|
|
//Load data
|
|
//Ci = Den[n];
|
|
Ex = ElectricField[n + 0 * Np];
|
|
Ey = ElectricField[n + 1 * Np];
|
|
Ez = ElectricField[n + 2 * Np];
|
|
|
|
ux = Velocity[n + 0 * Np];
|
|
uy = Velocity[n + 1 * Np];
|
|
uz = Velocity[n + 2 * Np];
|
|
|
|
uEPx = Di / Vt * Ex;
|
|
uEPy = Di / Vt * Ey;
|
|
uEPz = Di / Vt * Ez;
|
|
|
|
// q=0
|
|
// q=1
|
|
nr1 = neighborList[n]; // neighbor 2 ( > 10Np => odd part of dist)
|
|
// q=2
|
|
nr2 = neighborList[n + Np]; // neighbor 1 ( < 10Np => even part of dist)
|
|
// q=3
|
|
nr3 = neighborList[n + 2 * Np]; // neighbor 4
|
|
// q=4
|
|
nr4 = neighborList[n + 3 * Np]; // neighbor 3
|
|
// q=5
|
|
nr5 = neighborList[n + 4 * Np];
|
|
// q=6
|
|
nr6 = neighborList[n + 5 * Np];
|
|
|
|
A0 = dist[pH_ion * 7 * Np + n];
|
|
A1 =
|
|
dist[pH_ion * 7 * Np + nr1]; // reading the A1 data into register Aq
|
|
A2 =
|
|
dist[pH_ion * 7 * Np + nr2]; // reading the A2 data into register Aq
|
|
A3 = dist[pH_ion * 7 * Np + nr3];
|
|
A4 = dist[pH_ion * 7 * Np + nr4];
|
|
A5 = dist[pH_ion * 7 * Np + nr5];
|
|
A6 = dist[pH_ion * 7 * Np + nr6];
|
|
|
|
/*
|
|
B0 = dist[hydroxide*7*Np + n];
|
|
B1 = dist[hydroxide*7*Np + nr1]; // reading the B1 data into register Bq
|
|
B2 = dist[hydroxide*7*Np + nr2]; // reading the B2 data into register Bq
|
|
B3 = dist[hydroxide*7*Np + nr3];
|
|
B4 = dist[hydroxide*7*Np + nr4];
|
|
B5 = dist[hydroxide*7*Np + nr5];
|
|
B6 = dist[hydroxide*7*Np + nr6];
|
|
*/
|
|
|
|
// charge density
|
|
rhoe = A0 + A1 + A2 + A3 + A4 + A5 + A6;
|
|
//rhoe = Ca - Cb;
|
|
// new equilibrium
|
|
tmp = sqrt(rhoe * rhoe + 4.04e-14);
|
|
Ca = rhoe + tmp;
|
|
Cb = Ca - rhoe;
|
|
|
|
Den[pH_ion * Np + n] = Ca - Cb;
|
|
|
|
// proton production
|
|
A1 = 0.125 * Ca * (1.0 + 4.0 * (ux + uEPx));
|
|
A2 = 0.125 * Ca * (1.0 - 4.0 * (ux + uEPx));
|
|
A3 = 0.125 * Ca * (1.0 + 4.0 * (uy) + uEPy);
|
|
A4 = 0.125 * Ca * (1.0 - 4.0 * (uy) + uEPy);
|
|
A5 = 0.125 * Ca * (1.0 + 4.0 * (uz) + uEPz);
|
|
A6 = 0.125 * Ca * (1.0 - 4.0 * (uz) + uEPz);
|
|
|
|
A0 = Ca - (A1 + A2 + A3 + A4 + A5 + A6);
|
|
|
|
// hydroxide ions created by water ionization (no net charge increase)
|
|
//Cb += (f1 + f2 + f3 + f4 + f5 + f6);
|
|
// use relative mass of hydroxide + momentum conservation
|
|
B1 = 0.125 * Cb * (1.0 + 4.0 * (ux - uEPx));
|
|
B2 = 0.125 * Cb * (1.0 - 4.0 * (ux - uEPx));
|
|
B3 = 0.125 * Cb * (1.0 + 4.0 * (uy - uEPy));
|
|
B4 = 0.125 * Cb * (1.0 - 4.0 * (uy - uEPy));
|
|
B5 = 0.125 * Cb * (1.0 + 4.0 * (uz - uEPz));
|
|
B6 = 0.125 * Cb * (1.0 - 4.0 * (uz - uEPz));
|
|
|
|
B0 = Cb - (B1 + B2 + B3 + B4 + B5 + B6);
|
|
|
|
B0 = Cb - (B1 + B2 + B3 + B4 + B5 + B6);
|
|
|
|
f0 = A0 - B0;
|
|
f1 = A1 - B1;
|
|
f2 = A2 - B2;
|
|
f3 = A3 - B3;
|
|
f4 = A4 - B4;
|
|
f5 = A5 - B5;
|
|
f6 = A6 - B6;
|
|
|
|
dist[pH_ion * 7 * Np + n] = f0;
|
|
dist[pH_ion * 7 * Np + nr2] = f1;
|
|
dist[pH_ion * 7 * Np + nr1] = f2;
|
|
dist[pH_ion * 7 * Np + nr4] = f3;
|
|
dist[pH_ion * 7 * Np + nr3] = f4;
|
|
dist[pH_ion * 7 * Np + nr6] = f5;
|
|
dist[pH_ion * 7 * Np + nr5] = f6;
|
|
/*
|
|
dist[pH_ion*7*Np + n] = f0;
|
|
dist[pH_ion*7*Np + nr1] = f1;
|
|
dist[pH_ion*7*Np + nr2] = f2;
|
|
dist[pH_ion*7*Np + nr3] = f3;
|
|
dist[pH_ion*7*Np + nr4] = f4;
|
|
dist[pH_ion*7*Np + nr5] = f5;
|
|
dist[pH_ion*7*Np + nr6] = f6;
|
|
*/
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_AAeven_pH_ionization(
|
|
double *dist, double *Den, double *ElectricField, double *Velocity,
|
|
double Di, double Vt, int pH_ion, int start, int finish, int Np) {
|
|
|
|
int n;
|
|
double Ex, Ey, Ez; //electrical field
|
|
double ux, uy, uz;
|
|
double uEPx, uEPy, uEPz; //electrochemical induced velocity
|
|
double Ca, Cb;
|
|
double A0, A1, A2, A3, A4, A5, A6;
|
|
double B0, B1, B2, B3, B4, B5, B6;
|
|
double f0, f1, f2, f3, f4, f5, f6;
|
|
double rhoe, tmp;
|
|
// double factor = Di / (Vt *Vt* ionizationEnergy);
|
|
|
|
for (n = start; n < finish; n++) {
|
|
//Load data
|
|
//Ci = Den[n];
|
|
Ex = ElectricField[n + 0 * Np];
|
|
Ey = ElectricField[n + 1 * Np];
|
|
Ez = ElectricField[n + 2 * Np];
|
|
|
|
ux = Velocity[n + 0 * Np];
|
|
uy = Velocity[n + 1 * Np];
|
|
uz = Velocity[n + 2 * Np];
|
|
|
|
uEPx = Di / Vt * Ex;
|
|
uEPy = Di / Vt * Ey;
|
|
uEPz = Di / Vt * Ez;
|
|
|
|
A0 = dist[pH_ion * 7 * Np + n];
|
|
A1 = dist[pH_ion * 7 * Np + 2 * Np + n];
|
|
A2 = dist[pH_ion * 7 * Np + 1 * Np + n];
|
|
A3 = dist[pH_ion * 7 * Np + 4 * Np + n];
|
|
A4 = dist[pH_ion * 7 * Np + 3 * Np + n];
|
|
A5 = dist[pH_ion * 7 * Np + 6 * Np + n];
|
|
A6 = dist[pH_ion * 7 * Np + 5 * Np + n];
|
|
|
|
// charge density
|
|
rhoe = A0 + A1 + A2 + A3 + A4 + A5 + A6;
|
|
//rhoe = Ca - Cb;
|
|
// new equilibrium
|
|
tmp = sqrt(rhoe * rhoe + 4.04e-14);
|
|
Ca = rhoe + tmp;
|
|
Cb = Ca - rhoe;
|
|
if (Ca < 0.0)
|
|
printf(
|
|
"Error in hydronium concentration, %f (charge density = %f) \n",
|
|
Ca, rhoe);
|
|
if (Cb < 0.0)
|
|
printf("Error in hydroxide concentration, %f \n", Cb);
|
|
|
|
Den[pH_ion * Np + n] = Ca - Cb;
|
|
|
|
// proton production
|
|
A1 = 0.125 * Ca * (1.0 + 4.0 * (ux + uEPx));
|
|
A2 = 0.125 * Ca * (1.0 - 4.0 * (ux + uEPx));
|
|
A3 = 0.125 * Ca * (1.0 + 4.0 * (uy) + uEPy);
|
|
A4 = 0.125 * Ca * (1.0 - 4.0 * (uy) + uEPy);
|
|
A5 = 0.125 * Ca * (1.0 + 4.0 * (uz) + uEPz);
|
|
A6 = 0.125 * Ca * (1.0 - 4.0 * (uz) + uEPz);
|
|
|
|
A0 = Ca - (A1 + A2 + A3 + A4 + A5 + A6);
|
|
|
|
// hydroxide ions created by water ionization (no net charge increase)
|
|
//Cb += (f1 + f2 + f3 + f4 + f5 + f6);
|
|
// use relative mass of hydroxide + momentum conservation
|
|
B1 = 0.125 * Cb * (1.0 + 4.0 * (ux - uEPx));
|
|
B2 = 0.125 * Cb * (1.0 - 4.0 * (ux - uEPx));
|
|
B3 = 0.125 * Cb * (1.0 + 4.0 * (uy - uEPy));
|
|
B4 = 0.125 * Cb * (1.0 - 4.0 * (uy - uEPy));
|
|
B5 = 0.125 * Cb * (1.0 + 4.0 * (uz - uEPz));
|
|
B6 = 0.125 * Cb * (1.0 - 4.0 * (uz - uEPz));
|
|
|
|
B0 = Cb - (B1 + B2 + B3 + B4 + B5 + B6);
|
|
|
|
f0 = A0 - B0;
|
|
f1 = A1 - B1;
|
|
f2 = A2 - B2;
|
|
f3 = A3 - B3;
|
|
f4 = A4 - B4;
|
|
f5 = A5 - B5;
|
|
f6 = A6 - B6;
|
|
|
|
if (Ez > 0.0 && n == start) {
|
|
printf("Ca = %.5g, Cb = %.5g \n", Ca, Cb);
|
|
printf(" charge density = %.5g \n", rhoe);
|
|
printf(" Ez = %.5g, A5 = %.5g, A6 = %.5g \n", Ez, f5, f6);
|
|
}
|
|
|
|
dist[pH_ion * 7 * Np + n] = f0;
|
|
dist[pH_ion * 7 * Np + 1 * Np + n] = f1;
|
|
dist[pH_ion * 7 * Np + 2 * Np + n] = f2;
|
|
dist[pH_ion * 7 * Np + 3 * Np + n] = f3;
|
|
dist[pH_ion * 7 * Np + 4 * Np + n] = f4;
|
|
dist[pH_ion * 7 * Np + 5 * Np + n] = f5;
|
|
dist[pH_ion * 7 * Np + 6 * Np + n] = f6;
|
|
/*
|
|
dist[pH_ion*7*Np +2 * Np + n] = f1;
|
|
dist[pH_ion*7*Np +1 * Np + n] = f2;
|
|
dist[pH_ion*7*Np +4 * Np + n] = f3;
|
|
dist[pH_ion*7*Np +3 * Np + n] = f4;
|
|
dist[pH_ion*7*Np +6 * Np + n] = f5;
|
|
dist[pH_ion*7*Np +5 * Np + n] = f6;
|
|
*/
|
|
}
|
|
}
|
|
/**** end of pH equlibrium model ********/
|
|
|
|
extern "C" void ScaLBL_D3Q7_Membrane_AssignLinkCoef(
|
|
int *membrane, int *Map, double *Distance, double *Psi, double *coef,
|
|
double Threshold, double MassFractionIn, double MassFractionOut,
|
|
double ThresholdMassFractionIn, double ThresholdMassFractionOut,
|
|
int memLinks, int Nx, int Ny, int Nz, int Np) {
|
|
|
|
int link, iq, ip, nq, np, nqm, npm;
|
|
double aq, ap, membranePotential;
|
|
//double dq, dp, dist, orientation;
|
|
/* Interior Links */
|
|
for (link = 0; link < memLinks; link++) {
|
|
|
|
// inside //outside
|
|
aq = MassFractionIn;
|
|
ap = MassFractionOut;
|
|
iq = membrane[2 * link];
|
|
ip = membrane[2 * link + 1];
|
|
nq = iq % Np;
|
|
np = ip % Np;
|
|
nqm = Map[nq];
|
|
npm = Map[np]; // strided layout
|
|
//dq = Distance[nqm]; dp = Distance[npm];
|
|
/* orientation for link to distance gradient*/
|
|
//orientation = 1.0/fabs(dq - dp);
|
|
|
|
/* membrane potential for this link */
|
|
membranePotential = Psi[nqm] - Psi[npm];
|
|
if (membranePotential > Threshold) {
|
|
aq = ThresholdMassFractionIn;
|
|
ap = ThresholdMassFractionOut;
|
|
}
|
|
|
|
/* Save the mass transfer coefficients */
|
|
//coef[2*link] = aq*orientation; coef[2*link+1] = ap*orientation;
|
|
coef[2 * link] = aq;
|
|
coef[2 * link + 1] = ap;
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_Membrane_AssignLinkCoef_halo(
|
|
const int Cqx, const int Cqy, int const Cqz, int *Map, double *Distance,
|
|
double *Psi, double Threshold, double MassFractionIn,
|
|
double MassFractionOut, double ThresholdMassFractionIn,
|
|
double ThresholdMassFractionOut, int *d3q7_recvlist, int *d3q7_linkList,
|
|
double *coef, int start, int nlinks, int count, const int N, const int Nx,
|
|
const int Ny, const int Nz) {
|
|
//....................................................................................
|
|
// Unack distribution from the recv buffer
|
|
// Distribution q matche Cqx, Cqy, Cqz
|
|
// swap rule means that the distributions in recvbuf are OPPOSITE of q
|
|
// dist may be even or odd distributions stored by stream layout
|
|
//....................................................................................
|
|
int n, idx, label, nqm, npm, i, j, k;
|
|
double distanceLocal; //, distanceNonlocal;
|
|
double psiLocal, psiNonlocal, membranePotential;
|
|
double ap, aq; // coefficient
|
|
|
|
for (idx = 0; idx < count; idx++) {
|
|
n = d3q7_recvlist[idx];
|
|
label = d3q7_linkList[idx];
|
|
ap = 1.0; // regular streaming rule
|
|
aq = 1.0;
|
|
if (label > 0 && !(n < 0)) {
|
|
nqm = Map[n];
|
|
distanceLocal = Distance[nqm];
|
|
psiLocal = Psi[nqm];
|
|
|
|
// Get the 3-D indices from the send process
|
|
k = nqm / (Nx * Ny);
|
|
j = (nqm - Nx * Ny * k) / Nx;
|
|
i = nqm - Nx * Ny * k - Nx * j;
|
|
// Streaming link the non-local distribution
|
|
i -= Cqx;
|
|
j -= Cqy;
|
|
k -= Cqz;
|
|
npm = k * Nx * Ny + j * Nx + i;
|
|
//distanceNonlocal = Distance[npm];
|
|
psiNonlocal = Psi[npm];
|
|
|
|
membranePotential = psiLocal - psiNonlocal;
|
|
aq = MassFractionIn;
|
|
ap = MassFractionOut;
|
|
|
|
/* link is inside membrane */
|
|
if (distanceLocal > 0.0) {
|
|
if (membranePotential < Threshold * (-1.0)) {
|
|
ap = MassFractionIn;
|
|
aq = MassFractionOut;
|
|
} else {
|
|
ap = ThresholdMassFractionIn;
|
|
aq = ThresholdMassFractionOut;
|
|
}
|
|
} else if (membranePotential > Threshold) {
|
|
aq = ThresholdMassFractionIn;
|
|
ap = ThresholdMassFractionOut;
|
|
}
|
|
}
|
|
coef[2 * idx] = aq;
|
|
coef[2 * idx + 1] = ap;
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_Membrane_Unpack(int q, int *d3q7_recvlist,
|
|
double *recvbuf, int count,
|
|
double *dist, int N, double *coef) {
|
|
//....................................................................................
|
|
// Unack distribution from the recv buffer
|
|
// Distribution q matche Cqx, Cqy, Cqz
|
|
// swap rule means that the distributions in recvbuf are OPPOSITE of q
|
|
// dist may be even or odd distributions stored by stream layout
|
|
//....................................................................................
|
|
int n, idx;
|
|
double fq, fp, fqq, ap, aq; // coefficient
|
|
/* First unpack the regular links */
|
|
for (idx = 0; idx < count; idx++) {
|
|
n = d3q7_recvlist[idx];
|
|
// update link based on mass transfer coefficients
|
|
if (!(n < 0)) {
|
|
aq = coef[2 * idx];
|
|
ap = coef[2 * idx + 1];
|
|
fq = dist[q * N + n];
|
|
fp = recvbuf[idx];
|
|
fqq = (1 - aq) * fq + ap * fp;
|
|
dist[q * N + n] = fqq;
|
|
}
|
|
//printf(" LINK: site=%i, index=%i \n", n, idx);
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_Membrane_IonTransport(int *membrane, double *coef,
|
|
double *dist, double *Den,
|
|
int memLinks, int Np) {
|
|
|
|
int link, iq, ip, nq, np;
|
|
double aq, ap, fq, fp, fqq, fpp, Cq, Cp;
|
|
for (link = 0; link < memLinks; link++) {
|
|
// inside //outside
|
|
aq = coef[2 * link];
|
|
ap = coef[2 * link + 1];
|
|
iq = membrane[2 * link];
|
|
ip = membrane[2 * link + 1];
|
|
nq = iq % Np;
|
|
np = ip % Np;
|
|
fq = dist[iq];
|
|
fp = dist[ip];
|
|
fqq = (1 - aq) * fq + ap * fp;
|
|
fpp = (1 - ap) * fp + aq * fq;
|
|
Cq = Den[nq];
|
|
Cp = Den[np];
|
|
Cq += fqq - fq;
|
|
Cp += fpp - fp;
|
|
Den[nq] = Cq;
|
|
Den[np] = Cp;
|
|
dist[iq] = fqq;
|
|
dist[ip] = fpp;
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_AAodd_IonConcentration(int *neighborList,
|
|
double *dist, double *Den,
|
|
int start, int finish,
|
|
int Np) {
|
|
int n, nread;
|
|
double fq, Ci;
|
|
for (n = start; n < finish; n++) {
|
|
|
|
// q=0
|
|
fq = dist[n];
|
|
Ci = fq;
|
|
|
|
// q=1
|
|
nread = neighborList[n];
|
|
fq = dist[nread];
|
|
Ci += fq;
|
|
|
|
// q=2
|
|
nread = neighborList[n + Np];
|
|
fq = dist[nread];
|
|
Ci += fq;
|
|
|
|
// q=3
|
|
nread = neighborList[n + 2 * Np];
|
|
fq = dist[nread];
|
|
Ci += fq;
|
|
|
|
// q=4
|
|
nread = neighborList[n + 3 * Np];
|
|
fq = dist[nread];
|
|
Ci += fq;
|
|
|
|
// q=5
|
|
nread = neighborList[n + 4 * Np];
|
|
fq = dist[nread];
|
|
Ci += fq;
|
|
|
|
// q=6
|
|
nread = neighborList[n + 5 * Np];
|
|
fq = dist[nread];
|
|
Ci += fq;
|
|
|
|
Den[n] = Ci;
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_AAeven_IonConcentration(double *dist, double *Den,
|
|
int start, int finish,
|
|
int Np) {
|
|
int n;
|
|
double fq, Ci;
|
|
for (n = start; n < finish; n++) {
|
|
|
|
// q=0
|
|
fq = dist[n];
|
|
Ci = fq;
|
|
|
|
// q=1
|
|
fq = dist[2 * Np + n];
|
|
Ci += fq;
|
|
|
|
// q=2
|
|
fq = dist[1 * Np + n];
|
|
Ci += fq;
|
|
|
|
// q=3
|
|
fq = dist[4 * Np + n];
|
|
Ci += fq;
|
|
|
|
// q=4
|
|
fq = dist[3 * Np + n];
|
|
Ci += fq;
|
|
|
|
// q=5
|
|
fq = dist[6 * Np + n];
|
|
Ci += fq;
|
|
|
|
// q=6
|
|
fq = dist[5 * Np + n];
|
|
Ci += fq;
|
|
|
|
Den[n] = Ci;
|
|
}
|
|
}
|
|
|
|
extern "C" void
|
|
ScaLBL_D3Q7_AAodd_Ion_v0(int *neighborList, double *dist, double *Den,
|
|
double *FluxDiffusive, double *FluxAdvective,
|
|
double *FluxElectrical, double *Velocity,
|
|
double *ElectricField, double Di, int zi, double rlx,
|
|
double Vt, int start, int finish, int Np) {
|
|
int n;
|
|
double Ci;
|
|
double ux, uy, uz;
|
|
double uEPx, uEPy, uEPz; //electrochemical induced velocity
|
|
double Ex, Ey, Ez; //electrical field
|
|
double flux_diffusive_x, flux_diffusive_y, flux_diffusive_z;
|
|
double f0, f1, f2, f3, f4, f5, f6;
|
|
//double X,Y,Z,factor_x, factor_y, factor_z;
|
|
int nr1, nr2, nr3, nr4, nr5, nr6;
|
|
|
|
for (n = start; n < finish; n++) {
|
|
|
|
//Load data
|
|
Ci = Den[n];
|
|
Ex = ElectricField[n + 0 * Np];
|
|
Ey = ElectricField[n + 1 * Np];
|
|
Ez = ElectricField[n + 2 * Np];
|
|
ux = Velocity[n + 0 * Np];
|
|
uy = Velocity[n + 1 * Np];
|
|
uz = Velocity[n + 2 * Np];
|
|
uEPx = zi * Di / Vt * Ex;
|
|
uEPy = zi * Di / Vt * Ey;
|
|
uEPz = zi * Di / Vt * Ez;
|
|
|
|
// q=0
|
|
f0 = dist[n];
|
|
// q=1
|
|
nr1 = neighborList[n]; // neighbor 2 ( > 10Np => odd part of dist)
|
|
f1 = dist[nr1]; // reading the f1 data into register fq
|
|
// q=2
|
|
nr2 = neighborList[n + Np]; // neighbor 1 ( < 10Np => even part of dist)
|
|
f2 = dist[nr2]; // reading the f2 data into register fq
|
|
// q=3
|
|
nr3 = neighborList[n + 2 * Np]; // neighbor 4
|
|
f3 = dist[nr3];
|
|
// q=4
|
|
nr4 = neighborList[n + 3 * Np]; // neighbor 3
|
|
f4 = dist[nr4];
|
|
// q=5
|
|
nr5 = neighborList[n + 4 * Np];
|
|
f5 = dist[nr5];
|
|
// q=6
|
|
nr6 = neighborList[n + 5 * Np];
|
|
f6 = dist[nr6];
|
|
|
|
// compute diffusive flux
|
|
//Ci = f0 + f1 + f2 + f3 + f4 + f5 + f6;
|
|
flux_diffusive_x = (1.0 - 0.5 * rlx) * ((f1 - f2) - ux * Ci);
|
|
flux_diffusive_y = (1.0 - 0.5 * rlx) * ((f3 - f4) - uy * Ci);
|
|
flux_diffusive_z = (1.0 - 0.5 * rlx) * ((f5 - f6) - uz * Ci);
|
|
FluxDiffusive[n + 0 * Np] = flux_diffusive_x;
|
|
FluxDiffusive[n + 1 * Np] = flux_diffusive_y;
|
|
FluxDiffusive[n + 2 * Np] = flux_diffusive_z;
|
|
FluxAdvective[n + 0 * Np] = ux * Ci;
|
|
FluxAdvective[n + 1 * Np] = uy * Ci;
|
|
FluxAdvective[n + 2 * Np] = uz * Ci;
|
|
FluxElectrical[n + 0 * Np] = uEPx * Ci;
|
|
FluxElectrical[n + 1 * Np] = uEPy * Ci;
|
|
FluxElectrical[n + 2 * Np] = uEPz * Ci;
|
|
|
|
//Den[n] = Ci;
|
|
|
|
/* use logistic function to prevent negative distributions*/
|
|
//X = 4.0 * (ux + uEPx);
|
|
//Y = 4.0 * (uy + uEPy);
|
|
//Z = 4.0 * (uz + uEPz);
|
|
//factor_x = X / sqrt(1 + X*X);
|
|
//factor_y = Y / sqrt(1 + Y*Y);
|
|
//factor_z = Z / sqrt(1 + Z*Z);
|
|
|
|
// q=0
|
|
dist[n] = f0 * (1.0 - rlx) + rlx * 0.25 * Ci;
|
|
|
|
// q = 1
|
|
dist[nr2] =
|
|
f1 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (ux + uEPx));
|
|
// f1 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + factor_x);
|
|
|
|
// q=2
|
|
dist[nr1] =
|
|
f2 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (ux + uEPx));
|
|
// f2 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - factor_x);
|
|
|
|
// q = 3
|
|
dist[nr4] =
|
|
f3 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (uy + uEPy));
|
|
// f3 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + factor_y );
|
|
|
|
// q = 4
|
|
dist[nr3] =
|
|
f4 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (uy + uEPy));
|
|
// f4 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - factor_y);
|
|
|
|
// q = 5
|
|
dist[nr6] =
|
|
f5 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (uz + uEPz));
|
|
// f5 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + factor_z);
|
|
|
|
// q = 6
|
|
dist[nr5] =
|
|
f6 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (uz + uEPz));
|
|
// f6 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - factor_z);
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_AAeven_Ion_v0(
|
|
double *dist, double *Den, double *FluxDiffusive, double *FluxAdvective,
|
|
double *FluxElectrical, double *Velocity, double *ElectricField, double Di,
|
|
int zi, double rlx, double Vt, int start, int finish, int Np) {
|
|
int n;
|
|
double Ci;
|
|
double ux, uy, uz;
|
|
double uEPx, uEPy, uEPz; //electrochemical induced velocity
|
|
double Ex, Ey, Ez; //electrical field
|
|
double flux_diffusive_x, flux_diffusive_y, flux_diffusive_z;
|
|
double f0, f1, f2, f3, f4, f5, f6;
|
|
|
|
for (n = start; n < finish; n++) {
|
|
|
|
//Load data
|
|
Ci = Den[n];
|
|
Ex = ElectricField[n + 0 * Np];
|
|
Ey = ElectricField[n + 1 * Np];
|
|
Ez = ElectricField[n + 2 * Np];
|
|
ux = Velocity[n + 0 * Np];
|
|
uy = Velocity[n + 1 * Np];
|
|
uz = Velocity[n + 2 * Np];
|
|
uEPx = zi * Di / Vt * Ex;
|
|
uEPy = zi * Di / Vt * Ey;
|
|
uEPz = zi * Di / Vt * Ez;
|
|
|
|
f0 = dist[n];
|
|
f1 = dist[2 * Np + n];
|
|
f2 = dist[1 * Np + n];
|
|
f3 = dist[4 * Np + n];
|
|
f4 = dist[3 * Np + n];
|
|
f5 = dist[6 * Np + n];
|
|
f6 = dist[5 * Np + n];
|
|
|
|
// compute diffusive flux
|
|
//Ci = f0 + f1 + f2 + f3 + f4 + f5 + f6;
|
|
flux_diffusive_x = (1.0 - 0.5 * rlx) * ((f1 - f2) - ux * Ci);
|
|
flux_diffusive_y = (1.0 - 0.5 * rlx) * ((f3 - f4) - uy * Ci);
|
|
flux_diffusive_z = (1.0 - 0.5 * rlx) * ((f5 - f6) - uz * Ci);
|
|
FluxDiffusive[n + 0 * Np] = flux_diffusive_x;
|
|
FluxDiffusive[n + 1 * Np] = flux_diffusive_y;
|
|
FluxDiffusive[n + 2 * Np] = flux_diffusive_z;
|
|
FluxAdvective[n + 0 * Np] = ux * Ci;
|
|
FluxAdvective[n + 1 * Np] = uy * Ci;
|
|
FluxAdvective[n + 2 * Np] = uz * Ci;
|
|
FluxElectrical[n + 0 * Np] = uEPx * Ci;
|
|
FluxElectrical[n + 1 * Np] = uEPy * Ci;
|
|
FluxElectrical[n + 2 * Np] = uEPz * Ci;
|
|
|
|
//Den[n] = Ci;
|
|
|
|
/* use logistic function to prevent negative distributions*/
|
|
//X = 4.0 * (ux + uEPx);
|
|
//Y = 4.0 * (uy + uEPy);
|
|
//Z = 4.0 * (uz + uEPz);
|
|
//factor_x = X / sqrt(1 + X*X);
|
|
//factor_y = Y / sqrt(1 + Y*Y);
|
|
//factor_z = Z / sqrt(1 + Z*Z);
|
|
|
|
// q=0
|
|
dist[n] = f0 * (1.0 - rlx) + rlx * 0.25 * Ci;
|
|
|
|
// q = 1
|
|
dist[1 * Np + n] =
|
|
f1 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (ux + uEPx));
|
|
// f1 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + factor_x);
|
|
|
|
// q=2
|
|
dist[2 * Np + n] =
|
|
f2 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (ux + uEPx));
|
|
// f2 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - factor_x);
|
|
|
|
// q = 3
|
|
dist[3 * Np + n] =
|
|
f3 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (uy + uEPy));
|
|
// f3 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + factor_y);
|
|
|
|
// q = 4
|
|
dist[4 * Np + n] =
|
|
f4 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (uy + uEPy));
|
|
// f4 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - factor_y);
|
|
|
|
// q = 5
|
|
dist[5 * Np + n] =
|
|
f5 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (uz + uEPz));
|
|
// f5 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + factor_z);
|
|
|
|
// q = 6
|
|
dist[6 * Np + n] =
|
|
f6 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (uz + uEPz));
|
|
// f6 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - factor_z);
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_AAodd_Ion(int *neighborList, double *dist,
|
|
double *Den, double *FluxDiffusive,
|
|
double *FluxAdvective,
|
|
double *FluxElectrical, double *Velocity,
|
|
double *ElectricField, double Di, int zi,
|
|
double rlx, double Vt, int start,
|
|
int finish, int Np) {
|
|
int n;
|
|
double Ci;
|
|
double ux, uy, uz;
|
|
double uEPx, uEPy, uEPz; //electrochemical induced velocity
|
|
double Ex, Ey, Ez; //electrical field
|
|
double flux_diffusive_x, flux_diffusive_y, flux_diffusive_z;
|
|
double f0, f1, f2, f3, f4, f5, f6;
|
|
//double X,Y,Z,factor_x, factor_y, factor_z;
|
|
int nr1, nr2, nr3, nr4, nr5, nr6;
|
|
|
|
for (n = start; n < finish; n++) {
|
|
|
|
//Load data
|
|
//Ci = Den[n];
|
|
Ex = ElectricField[n + 0 * Np];
|
|
Ey = ElectricField[n + 1 * Np];
|
|
Ez = ElectricField[n + 2 * Np];
|
|
ux = Velocity[n + 0 * Np];
|
|
uy = Velocity[n + 1 * Np];
|
|
uz = Velocity[n + 2 * Np];
|
|
uEPx = zi * Di / Vt * Ex;
|
|
uEPy = zi * Di / Vt * Ey;
|
|
uEPz = zi * Di / Vt * Ez;
|
|
|
|
// q=0
|
|
f0 = dist[n];
|
|
// q=1
|
|
nr1 = neighborList[n]; // neighbor 2 ( > 10Np => odd part of dist)
|
|
f1 = dist[nr1]; // reading the f1 data into register fq
|
|
// q=2
|
|
nr2 = neighborList[n + Np]; // neighbor 1 ( < 10Np => even part of dist)
|
|
f2 = dist[nr2]; // reading the f2 data into register fq
|
|
// q=3
|
|
nr3 = neighborList[n + 2 * Np]; // neighbor 4
|
|
f3 = dist[nr3];
|
|
// q=4
|
|
nr4 = neighborList[n + 3 * Np]; // neighbor 3
|
|
f4 = dist[nr4];
|
|
// q=5
|
|
nr5 = neighborList[n + 4 * Np];
|
|
f5 = dist[nr5];
|
|
// q=6
|
|
nr6 = neighborList[n + 5 * Np];
|
|
f6 = dist[nr6];
|
|
|
|
// compute diffusive flux
|
|
Ci = f0 + f1 + f2 + f3 + f4 + f5 + f6;
|
|
flux_diffusive_x = (1.0 - 0.5 * rlx) * ((f1 - f2) - ux * Ci);
|
|
flux_diffusive_y = (1.0 - 0.5 * rlx) * ((f3 - f4) - uy * Ci);
|
|
flux_diffusive_z = (1.0 - 0.5 * rlx) * ((f5 - f6) - uz * Ci);
|
|
FluxDiffusive[n + 0 * Np] = flux_diffusive_x;
|
|
FluxDiffusive[n + 1 * Np] = flux_diffusive_y;
|
|
FluxDiffusive[n + 2 * Np] = flux_diffusive_z;
|
|
FluxAdvective[n + 0 * Np] = ux * Ci;
|
|
FluxAdvective[n + 1 * Np] = uy * Ci;
|
|
FluxAdvective[n + 2 * Np] = uz * Ci;
|
|
FluxElectrical[n + 0 * Np] = uEPx * Ci;
|
|
FluxElectrical[n + 1 * Np] = uEPy * Ci;
|
|
FluxElectrical[n + 2 * Np] = uEPz * Ci;
|
|
|
|
Den[n] = Ci;
|
|
|
|
// q=0
|
|
dist[n] = f0 * (1.0 - rlx) + rlx * 0.25 * Ci;
|
|
|
|
// q = 1
|
|
dist[nr2] =
|
|
f1 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (ux + uEPx));
|
|
|
|
// q=2
|
|
dist[nr1] =
|
|
f2 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (ux + uEPx));
|
|
|
|
// q = 3
|
|
dist[nr4] =
|
|
f3 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (uy + uEPy));
|
|
|
|
// q = 4
|
|
dist[nr3] =
|
|
f4 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (uy + uEPy));
|
|
|
|
// q = 5
|
|
dist[nr6] =
|
|
f5 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (uz + uEPz));
|
|
|
|
// q = 6
|
|
dist[nr5] =
|
|
f6 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (uz + uEPz));
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_AAeven_Ion(
|
|
double *dist, double *Den, double *FluxDiffusive, double *FluxAdvective,
|
|
double *FluxElectrical, double *Velocity, double *ElectricField, double Di,
|
|
int zi, double rlx, double Vt, int start, int finish, int Np) {
|
|
int n;
|
|
double Ci;
|
|
double ux, uy, uz;
|
|
double uEPx, uEPy, uEPz; //electrochemical induced velocity
|
|
double Ex, Ey, Ez; //electrical field
|
|
double flux_diffusive_x, flux_diffusive_y, flux_diffusive_z;
|
|
double f0, f1, f2, f3, f4, f5, f6;
|
|
|
|
for (n = start; n < finish; n++) {
|
|
|
|
//Load data
|
|
//Ci = Den[n];
|
|
Ex = ElectricField[n + 0 * Np];
|
|
Ey = ElectricField[n + 1 * Np];
|
|
Ez = ElectricField[n + 2 * Np];
|
|
ux = Velocity[n + 0 * Np];
|
|
uy = Velocity[n + 1 * Np];
|
|
uz = Velocity[n + 2 * Np];
|
|
uEPx = zi * Di / Vt * Ex;
|
|
uEPy = zi * Di / Vt * Ey;
|
|
uEPz = zi * Di / Vt * Ez;
|
|
|
|
f0 = dist[n];
|
|
f1 = dist[2 * Np + n];
|
|
f2 = dist[1 * Np + n];
|
|
f3 = dist[4 * Np + n];
|
|
f4 = dist[3 * Np + n];
|
|
f5 = dist[6 * Np + n];
|
|
f6 = dist[5 * Np + n];
|
|
|
|
// compute diffusive flux
|
|
Ci = f0 + f1 + f2 + f3 + f4 + f5 + f6;
|
|
flux_diffusive_x = (1.0 - 0.5 * rlx) * ((f1 - f2) - ux * Ci);
|
|
flux_diffusive_y = (1.0 - 0.5 * rlx) * ((f3 - f4) - uy * Ci);
|
|
flux_diffusive_z = (1.0 - 0.5 * rlx) * ((f5 - f6) - uz * Ci);
|
|
FluxDiffusive[n + 0 * Np] = flux_diffusive_x;
|
|
FluxDiffusive[n + 1 * Np] = flux_diffusive_y;
|
|
FluxDiffusive[n + 2 * Np] = flux_diffusive_z;
|
|
FluxAdvective[n + 0 * Np] = ux * Ci;
|
|
FluxAdvective[n + 1 * Np] = uy * Ci;
|
|
FluxAdvective[n + 2 * Np] = uz * Ci;
|
|
FluxElectrical[n + 0 * Np] = uEPx * Ci;
|
|
FluxElectrical[n + 1 * Np] = uEPy * Ci;
|
|
FluxElectrical[n + 2 * Np] = uEPz * Ci;
|
|
|
|
Den[n] = Ci;
|
|
|
|
// q=0
|
|
dist[n] = f0 * (1.0 - rlx) + rlx * 0.25 * Ci;
|
|
|
|
// q = 1
|
|
dist[1 * Np + n] =
|
|
f1 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (ux + uEPx));
|
|
|
|
// q=2
|
|
dist[2 * Np + n] =
|
|
f2 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (ux + uEPx));
|
|
|
|
// q = 3
|
|
dist[3 * Np + n] =
|
|
f3 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (uy + uEPy));
|
|
|
|
// q = 4
|
|
dist[4 * Np + n] =
|
|
f4 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (uy + uEPy));
|
|
|
|
// q = 5
|
|
dist[5 * Np + n] =
|
|
f5 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 + 4.0 * (uz + uEPz));
|
|
|
|
// q = 6
|
|
dist[6 * Np + n] =
|
|
f6 * (1.0 - rlx) + rlx * 0.125 * Ci * (1.0 - 4.0 * (uz + uEPz));
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_Ion_Init(double *dist, double *Den, double DenInit,
|
|
int Np) {
|
|
int n;
|
|
for (n = 0; n < Np; n++) {
|
|
dist[0 * Np + n] = 0.25 * DenInit;
|
|
dist[1 * Np + n] = 0.125 * DenInit;
|
|
dist[2 * Np + n] = 0.125 * DenInit;
|
|
dist[3 * Np + n] = 0.125 * DenInit;
|
|
dist[4 * Np + n] = 0.125 * DenInit;
|
|
dist[5 * Np + n] = 0.125 * DenInit;
|
|
dist[6 * Np + n] = 0.125 * DenInit;
|
|
Den[n] = DenInit;
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_Ion_Init_FromFile(double *dist, double *Den,
|
|
int Np) {
|
|
int n;
|
|
double DenInit;
|
|
for (n = 0; n < Np; n++) {
|
|
DenInit = Den[n];
|
|
dist[0 * Np + n] = 0.25 * DenInit;
|
|
dist[1 * Np + n] = 0.125 * DenInit;
|
|
dist[2 * Np + n] = 0.125 * DenInit;
|
|
dist[3 * Np + n] = 0.125 * DenInit;
|
|
dist[4 * Np + n] = 0.125 * DenInit;
|
|
dist[5 * Np + n] = 0.125 * DenInit;
|
|
dist[6 * Np + n] = 0.125 * DenInit;
|
|
}
|
|
}
|
|
|
|
extern "C" void ScaLBL_D3Q7_Ion_ChargeDensity(double *Den,
|
|
double *ChargeDensity,
|
|
double IonValence,
|
|
int ion_component, int start,
|
|
int finish, int Np) {
|
|
|
|
int n;
|
|
double Ci; //ion concentration of species i
|
|
double CD; //charge density
|
|
double CD_tmp;
|
|
double F =
|
|
96485.0; //Faraday's constant; unit[C/mol]; F=e*Na, where Na is the Avogadro constant
|
|
|
|
for (n = start; n < finish; n++) {
|
|
Ci = Den[n + ion_component * Np];
|
|
CD = ChargeDensity[n];
|
|
CD_tmp = F * IonValence * Ci;
|
|
ChargeDensity[n] = CD * (ion_component > 0) + CD_tmp;
|
|
}
|
|
}
|