Skip to content

Correction of velocity calculation in the lbpm_permeability_simulator #104

@Ricardoleite

Description

@Ricardoleite

There are two issues in the fucntion "ScaLBL_D3Q19_Momentum(double *dist, double *vel, int Np) ", which is dedicated to calculating velocity array used to estimate the absolute permeability. I list and explain them below:

  • The velocity is currently computed as $V_{\alpha}=\sum_{i}f_{i}c_{\alpha,i}$ (not correct) instead of $V_{\alpha}=\sum_{i}f_{i}c_{\alpha,i}/\rho$ (Correct), of coarse, if we consider a first-order discretization of space-time in the presence of an external force that drving the flow. However, it is well known in the LBM literature that problems with an external force term require a second-order discretization of space–time. In this case, the correct formulation becomes: $V_{\alpha}=\sum_{i}f_{i}c_{\alpha,i}/\rho + \delta_{t}F_{\alpha}/2$.

  • As the code is currently structured, the analysis routine is performed after the AA-even time step, when the distribution functions are in a post-collisional state and not yet underwent streaming . To clarify, consider the D2Q9 lattice to illustrate odd and even steps (I am following the odd and even convention presented by LBPM). In the Lattice Boltzmann Method, the macroscopic moments should be computed is after the streaming step. Thus, in LBPM velocity is calculated after the even time step, when the distributions are still post-collisional. This is problematic because, in the presence of an external force, the first-order moment is not a conserved quantity. In other words, pre-collisional and post-collisional moments differ. With the current code structure these can be fixed by using the post-collisional distribution functions to compute the pre-collisional velocity after the even time step.

$$V_{\alpha} = \sum_{i} f_{i}^{*} c_{\alpha,i} / \rho - \delta_{t}F_{\alpha}/2 $$

where $f_{i}^{*}$ is post-collision distribution function.

Image

BCC (Benchmark)

The goal of this correction is to improve accuracy and reduce the artificial dependence of permeability on viscosity, as discussed by Pan et al. (2006) (https://doi.org/10.1016/j.compfluid.2005.03.008).

The figure below compares results before and after applying the correction for a body-centered cubic (BCC) array. The BCC geometry follows the parameters in Pan et al. (2006). The analytical solution used for comparison is given below.

Image

BCC analytical solution

Click to expand code
import warnings
warnings.filterwarnings("ignore", category=UserWarning, module='matplotlib')
import numpy as np
import matplotlib.pyplot as plt

#Coefficients up to the order 25
alpha_s = np.array([1.0,1.575834,2.483254,3.233022,4.022864,4.650320,5.281412,
                    5.826374,6.258376,6.544504,6.878396,7.190839,7.268068,
                    7.304025,7.301217,7.2364410,7.298014,7.369847,7.109497,
                    6.228418,5.235796,4.476874,3.541982,2.939353,3.935484])
a=11.77/32.0 #Dimensionless Ratio
a0=11.77 #Dimensional Ratio
chi=( (64.0*a**(3.))/(np.sqrt(3.0)*3.0*(1.0)**(3.0)) )**(1./3.) #Ratio between solid volume and max volume of solid
#-------------Dimensionless Drag Force Calculation-----------------------------
d=0.0
for i in range (0,len(alpha_s)):
    d=d+alpha_s[i]*chi**(i)
#-------------------------------------------------------------------------------
ks=1.0/(d*6.0*np.pi*a) #Dimensionless Permeability
print("--------------------------------------------------------------------------------")
print("d=",d, "        Dimensionless Drag Force")
print("k=",ks, "     Dimensionless Permeability")
print("chi=",chi, "     Ratio between solid volume and max volume of solid")
print("--------------------------------------------------------------------------------")

Code to generate the BCC Geometry

Click to expand code
import numpy as np
import matplotlib.pylab as plt
cx = 32
cy = 32
cz = 32
Rr=11.77
D=np.ones((cx,cy,cz),dtype="uint8")*1
for i in range(0,cx):
    for j in range (0, cy):
        for k in range (0,cz):
            dist = np.sqrt((i+0.5-cx/2)*(i+0.5-cx/2) + (j+0.5-cy/2)*(j+0.5-cy/2) + (k+0.5-cz/2)*(k+0.5-cz/2))
            if (dist < Rr) :
                D[i,j,k] = 0
            dist = np.sqrt((i+0.5-cx)*(i+0.5-cx) + (j+0.5)*(j+0.5) + (k+0.5)*(k+0.5))
            if (dist < Rr) :
                D[i,j,k] = 0
            dist = np.sqrt((i+0.5)*(i+0.5) + (j+0.5-cy)*(j+0.5-cy) + (k+0.5)*(k+0.5))
            if (dist < Rr) :
                D[i,j,k] = 0
            dist = np.sqrt((i+0.5)*(i+0.5) + (j+0.5)*(j+0.5) + (k+0.5-cz)*(k+0.5-cz))
            if (dist < Rr) :
                D[i,j,k] = 0
            dist = np.sqrt((i+0.5)*(i+0.5) + (j+0.5)*(j+0.5) + (k+0.5)*(k+0.5))
            if (dist < Rr) :
                D[i,j,k] = 0
            dist = np.sqrt((i+0.5)*(i+0.5) + (j+0.5-cy)*(j+0.5-cy) + (k+0.5-cz)*(k+0.5-cz))
            if (dist < Rr) :
                D[i,j,k] = 0
            dist = np.sqrt((i+0.5-cx)*(i+0.5-cx) + (j+0.5)*(j+0.5) + (k+0.5-cz)*(k+0.5-cz))
            if (dist < Rr) :
                D[i,j,k] = 0
            dist = np.sqrt((i+0.5-cx)*(i+0.5-cx) + (j+0.5-cy)*(j+0.5-cy) + (k+0.5)*(k+0.5))
            if (dist < Rr) :
                D[i,j,k] = 0
            dist = np.sqrt((i+0.5-cx)*(i+0.5-cx) + (j+0.5-cy)*(j+0.5-cy) + (k+0.5-cz)*(k+0.5-cz))
            if (dist < Rr) :
                D[i,j,k] = 0

D.tofile("bcc-%d.raw"% (cx)) # Array save in a file .raw 

BCC .db file

Click to expand code
MRT {
   tau = 0.54
   F = 0.0, 0.0, 0.000001
   timestepMax = 6000000
   tolerance = 0.000001
}
Domain {
   Filename = "../../bcc-32.raw"
   ReadType = "8bit"
   nproc = 1, 1, 1
   N = 32, 32, 32
   n = 32, 32, 32
   voxel_length = 1.0
   ReadValues = 0, 1, 2
   WriteValues = 0, 1, 2
   BC = 0
}
Visualization {
   write_silo = true     // write SILO databases with assigned variables
   save_8bit_raw = true  // write labeled 8-bit binary files with phase assignments
   save_phase_field = true  // save phase field within SILO database
   save_pressure = true    // save pressure field within SILO database
   save_velocity = true    // save velocity field within SILO database
}

LV60A (3D Digital Rock)

Applying the same correction to the LV60A sandpack (https://figshare.com/articles/dataset/LV60A_sandpack/1153795/2
) yields the same outcome: a much weaker (closer to negligible) dependence of permeability on viscosity.

Image

LV60A .db file

Click to expand code
MRT {
   tau = 0.56
   F = 0.0, 0.0, 0.000001
   timestepMax = 6000000
   tolerance = 0.000001
}
Domain {
   Filename = "../../lv60a.raw"
   ReadType = "8bit"
   nproc = 1, 1, 1
   N = 450, 450, 450
   n = 450, 450, 450
   voxel_length = 10.002
   ReadValues = 0, 1, 2
   WriteValues = 0, 1, 2
   BC = 0
}
Visualization {
   write_silo = true     // write SILO databases with assigned variables
   save_8bit_raw = true  // write labeled 8-bit binary files with phase assignments
   save_phase_field = true  // save phase field within SILO database
   save_pressure = true    // save pressure field within SILO database
   save_velocity = true    // save velocity field within SILO database
}
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions