Introduction
Introduction Statistics Contact Development Disclaimer Help
tMerge pull request #8 from anders-dc/darcy - sphere - GPU-based 3D discrete el…
git clone git://src.adamsgaard.dk/sphere
Log
Files
Refs
LICENSE
---
commit 2dc04091730193f7b8df4263b0a00ea9f744c9c7
parent e6181dcce46e3632a3f4a18ab0aa4c5db4a008a1
Author: Anders Damsgaard <[email protected]>
Date: Wed, 5 Nov 2014 15:25:07 +0100
Merge pull request #8 from anders-dc/darcy
Darcy solver implemented
Diffstat:
M CMakeLists.txt | 4 +---
A output/cube-init.output00029.bin | 0
A output/cube-init.status.dat | 1 +
M python/capillary-cohesion.py | 2 +-
M python/collapse.py | 2 +-
M python/cube-init.py | 2 +-
A python/halfshear-darcy-starter.py | 69 ++++++++++++++++++++++++++++++
M python/segregation.py | 2 +-
M python/shear-results-strain.py | 4 ++--
M python/shear-results.py | 10 +++++-----
M python/shear-test.py | 2 +-
M python/shear2-init.py | 2 +-
M python/sphere.py | 806 +++++++++++++++++++++--------…
M src/CMakeLists.txt | 6 +++---
M src/constants.h | 2 +-
A src/darcy.cpp | 311 +++++++++++++++++++++++++++++…
A src/darcy.cuh | 1025 +++++++++++++++++++++++++++++…
M src/datatypes.h | 31 +++++++++++++++++++++++++++++…
M src/debug.h | 8 ++++----
M src/device.cu | 1588 +++++++++++++++++++----------…
M src/file_io.cpp | 337 +++++++++++++++++++++--------…
M src/navierstokes.cpp | 4 ++--
M src/navierstokes.cuh | 116 +++++++++++++++++------------…
M src/sphere.cpp | 69 +++++++++++++++++++++++++++--…
M src/sphere.h | 49 +++++++++++++++++++++++++++++…
M src/utility.cu | 6 +++++-
M tests/CMakeLists.txt | 12 ++++++++++++
A tests/cfd_tests_darcy.py | 151 +++++++++++++++++++++++++++++…
A tests/cfd_tests_darcy_particles.py | 165 +++++++++++++++++++++++++++++…
A tests/cfd_tests_neumann_darcy.py | 41 +++++++++++++++++++++++++++++…
A tests/fluid_particle_interaction_d… | 31 +++++++++++++++++++++++++++…
A tests/highlighttext.py | 51 +++++++++++++++++++++++++++++…
M tests/io_tests_fluid.py | 54 +++++++++++++++++++++++++++++…
M tests/pytestutils.py | 5 +++--
34 files changed, 3926 insertions(+), 1042 deletions(-)
---
diff --git a/CMakeLists.txt b/CMakeLists.txt
t@@ -30,9 +30,7 @@ enable_testing()
# Set build type = Debug
#set(CMAKE_BUILD_TYPE Debug)
-#if (CUDA_FOUND)
-# set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-g -G)
-#endif()
+#set(CUDA_NVCC_FLAGS ${CUDA_NVCC_FLAGS};-g -G)
# Set build type = Release
set(CMAKE_BUILD_TYPE Release)
diff --git a/output/cube-init.output00029.bin b/output/cube-init.output00029.bin
Binary files differ.
diff --git a/output/cube-init.status.dat b/output/cube-init.status.dat
t@@ -0,0 +1 @@
+5.8000e+00 9.6667e+01 29
diff --git a/python/capillary-cohesion.py b/python/capillary-cohesion.py
t@@ -27,7 +27,7 @@ sim.mu_s[0] = 0.0
sim.mu_d[0] = 0.0
sim.k_n[0] = 1.0e7
sim.k_t[0] = 1.0e7
-sim.generateRadii(psd='uni', radius_mean=1.0e-3, radius_variance=1.0e-4)
+sim.generateRadii(psd='uni', mean=1.0e-3, variance=1.0e-4)
sim.contactModel(1)
sim.initRandomGridPos([12, 12, 10000])
sim.initTemporal(5.0, file_dt=0.01, epsilon=0.07)
diff --git a/python/collapse.py b/python/collapse.py
t@@ -21,7 +21,7 @@ sim_id = 'collapse'
init = sphere.sim(np = np, nd = 3, nw = 0, sid = sim_id + '-init')
# Set radii
-init.generateRadii(radius_mean = 0.1)
+init.generateRadii(mean = 0.1)
# Use default params
init.defaultParams(
diff --git a/python/cube-init.py b/python/cube-init.py
t@@ -3,7 +3,7 @@ import sphere
init = sphere.sim('cube-init', np=1e2)
-init.generateRadii(psd='uni', radius_mean=0.01, radius_variance=0.002)
+init.generateRadii(psd='uni', mean=0.01, variance=0.002)
init.periodicBoundariesXY()
diff --git a/python/halfshear-darcy-starter.py b/python/halfshear-darcy-starter…
t@@ -0,0 +1,69 @@
+#!/usr/bin/env python
+import sphere
+import numpy
+import sys
+
+# launch with:
+# $ ipython halfshear-darcy-starter.py <device> <fluid> <c_phi> <k_c> <sigma_0…
+
+device = int(sys.argv[1])
+wet = int(sys.argv[2])
+c_phi = float(sys.argv[3])
+k_c = float(sys.argv[4])
+sigma0 = float(sys.argv[5])
+mu = float(sys.argv[6])
+
+if wet == 1:
+ fluid = True
+else:
+ fluid = False
+
+sim = sphere.sim('halfshear-sigma0=' + str(sigma0), fluid=False)
+print('Input: ' + sim.sid)
+sim.readlast()
+
+sim.fluid = fluid
+if fluid:
+ sim.id('halfshear-darcy-sigma0=' + str(sigma0) + '-k_c=' + str(k_c) + \
+ '-mu=' + str(mu) + '-shear')
+else:
+ sim.id('halfshear-sigma0=' + str(sigma0) + '-shear')
+
+sim.checkerboardColors(nx=6,ny=3,nz=6)
+sim.cleanup()
+sim.adjustUpperWall()
+sim.zeroKinematics()
+
+sim.shear(1.0/20.0)
+
+if fluid:
+ #sim.num[2] *= 2
+ sim.num[:] /= 2
+ #sim.L[2] *= 2.0
+ #sim.initFluid(mu = 1.787e-6, p = 600.0e3, cfd_solver = 1)
+ sim.initFluid(mu = 1.787e-6, p = 0.0, cfd_solver = 1)
+ sim.setFluidBottomNoFlow()
+ sim.setFluidTopFixedPressure()
+ #sim.setDEMstepsPerCFDstep(100)
+ sim.setMaxIterations(2e5)
+ sim.beta_f[0] = mu
+ sim.k_c[0] = k_c
+
+sim.initTemporal(total = 20.0, file_dt = 0.01, epsilon=0.07)
+sim.w_devs[0] = sigma0
+sim.w_m[0] = numpy.abs(sigma0*sim.L[0]*sim.L[1]/sim.g[2])
+sim.mu_s[0] = 0.5
+sim.mu_d[0] = 0.5
+sim.setDampingNormal(0.0)
+sim.setDampingTangential(0.0)
+
+# Fix lowermost particles
+#dz = sim.L[2]/sim.num[2]
+#I = numpy.nonzero(sim.x[:,2] < 1.5*dz)
+#sim.fixvel[I] = 1
+
+sim.run(dry=True)
+sim.run(device=device)
+#sim.writeVTKall()
+#sim.visualize('walls')
+#sim.visualize('fluid-pressure')
diff --git a/python/segregation.py b/python/segregation.py
t@@ -27,7 +27,7 @@ devslist = [120e3]
init = sphere.sim(np = np, nd = 3, nw = 0, sid = sim_id + '-init')
# Save radii
-init.generateRadii(radius_mean = 0.08)
+init.generateRadii(mean = 0.08)
# Use default params
init.defaultParams(gamma_n = 100.0, mu_s = 0.4, mu_d = 0.4)
diff --git a/python/shear-results-strain.py b/python/shear-results-strain.py
t@@ -14,8 +14,8 @@ import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator
sigma0 = 20000.0
-cvals = ['dry', 1.0, 0.1, 0.01]
-#cvals = ['dry', 1.0, 0.1]
+#cvals = ['dry', 1.0, 0.1, 0.01]
+cvals = ['dry', 1.0, 0.1]
#cvals = ['dry', 1.0]
#step = 1999
diff --git a/python/shear-results.py b/python/shear-results.py
t@@ -21,8 +21,8 @@ zflow = False
#sigma0_list = numpy.array([1.0e3, 2.0e3, 4.0e3, 10.0e3, 20.0e3, 40.0e3])
#sigma0 = 10.0e3
sigma0 = float(sys.argv[1])
-#cvals = [1.0, 0.1]
-cvals = [1.0, 0.1, 0.01]
+cvals = [1.0, 0.1]
+#cvals = [1.0, 0.1, 0.01]
#cvals = [1.0]
# return a smoothed version of in. The returned array is smaller than the
t@@ -139,9 +139,9 @@ for c in numpy.arange(1,len(cvals)+1):
#sid = 'shear-sigma0=' + str(sigma0) + '-c_phi=' + \
#str(c_phi) + '-c_v=' + str(c_v) + \
#'-hi_mu-lo_visc-hw'
- #sid = 'halfshear-sigma0=' + str(sigma0) + '-c=' + str(c_v) + '-shear'
- sid = 'halfshear-sigma0=' + str(sigma0) + '-c_v=' + str(c_v) +\
- '-c_a=0.0-velfac=1.0-shear'
+ sid = 'halfshear-sigma0=' + str(sigma0) + '-c=' + str(c_v) + '-shear'
+ #sid = 'halfshear-sigma0=' + str(sigma0) + '-c_v=' + str(c_v) +\
+ #'-c_a=0.0-velfac=1.0-shear'
if os.path.isfile('../output/' + sid + '.status.dat'):
sim = sphere.sim(sid, fluid=fluid)
diff --git a/python/shear-test.py b/python/shear-test.py
t@@ -26,7 +26,7 @@ devslist = [80e3, 10e3, 20e3, 40e3, 60e3, 120e3]
init = Spherebin(np = np, nd = 3, nw = 0, sid = sim_id + "-init")
# Save radii
-init.generateRadii(radius_mean = 0.02)
+init.generateRadii(mean = 0.02)
# Use default params
init.defaultParams(gamma_n = 100.0, mu_s = 0.6, mu_d = 0.6)
diff --git a/python/shear2-init.py b/python/shear2-init.py
t@@ -2,7 +2,7 @@
import sphere
sim = sphere.sim('init2', np=10000)
-sim.generateRadii(psd='uni', radius_mean=0.02, radius_variance=0.01)
+sim.generateRadii(psd='uni', mean=0.02, variance=0.01)
sim.initRandomGridPos([12, 12, 1000])
sim.initTemporal(10.0, file_dt=0.05, epsilon=0.07)
sim.gamma_n[0] = 1000.0
diff --git a/python/sphere.py b/python/sphere.py
t@@ -19,7 +19,7 @@ numpy.seterr(all='warn', over='raise')
# Sphere version number. This field should correspond to the value in
# `../src/constants.h`.
-VERSION=1.07
+VERSION=2.0
class sim:
'''
t@@ -40,9 +40,18 @@ class sim:
:type sid: str
:param fluid: Setup fluid simulation (default = False)
:type fluid: bool
+ :param cfd_solver: Fluid solver to use if fluid == True. 0: Navier-Stokes
+ (default), 1: Darcy.
+ :type cfd_solver: int
'''
- def __init__(self, sid = 'unnamed', np = 0, nd = 3, nw = 0, fluid = False):
+ def __init__(self,
+ sid = 'unnamed',
+ np = 0,
+ nd = 3,
+ nw = 0,
+ fluid = False,
+ cfd_solver = 0):
# Sphere version number
self.version = numpy.ones(1, dtype=numpy.float64)*VERSION
t@@ -272,6 +281,11 @@ class sim:
if self.fluid:
+ # Fluid solver type
+ # 0: Navier Stokes (fluid with inertia)
+ # 1: Stokes-Darcy (fluid without inertia)
+ self.cfd_solver = numpy.zeros(1, dtype=numpy.int32)
+
# Fluid dynamic viscosity [N/(m/s)]
self.mu = numpy.zeros(1, dtype=numpy.float64)
t@@ -311,40 +325,73 @@ class sim:
## Solver parameters
- # Smoothing parameter, should be in the range [0.0;1.0[.
- # 0.0 = no smoothing.
- self.gamma = numpy.array(0.0)
+ # Navier-Stokes
+ if self.cfd_solver[0] == 0:
- # Under-relaxation parameter, should be in the range ]0.0;1.0].
- # 1.0 = no under-relaxation
- self.theta = numpy.array(1.0)
+ # Smoothing parameter, should be in the range [0.0;1.0[.
+ # 0.0 = no smoothing.
+ self.gamma = numpy.array(0.0)
- # Velocity projection parameter, should be in the range [0.0;1.0]
- self.beta = numpy.array(0.0)
+ # Under-relaxation parameter, should be in the range ]0.0;1.0].
+ # 1.0 = no under-relaxation
+ self.theta = numpy.array(1.0)
- # Tolerance criteria for the normalized max. residual
- self.tolerance = numpy.array(1.0e-8)
+ # Velocity projection parameter, should be in the range
+ # [0.0;1.0]
+ self.beta = numpy.array(0.0)
- # The maximum number of iterations to perform per time step
- self.maxiter = numpy.array(1e4)
+ # Tolerance criteria for the normalized max. residual
+ self.tolerance = numpy.array(1.0e-3)
- # The number of DEM time steps to perform between CFD updates
- self.ndem = numpy.array(1)
+ # The maximum number of iterations to perform per time step
+ self.maxiter = numpy.array(1e4)
- # Porosity scaling factor
- self.c_phi = numpy.ones(1, dtype=numpy.float64)
+ # The number of DEM time steps to perform between CFD updates
+ self.ndem = numpy.array(1)
- # Fluid velocity scaling factor
- self.c_v = numpy.ones(1, dtype=numpy.float64)
+ # Porosity scaling factor
+ self.c_phi = numpy.ones(1, dtype=numpy.float64)
- # DEM-CFD time scaling factor
- self.dt_dem_fac = numpy.ones(1, dtype=numpy.float64)
+ # Fluid velocity scaling factor
+ self.c_v = numpy.ones(1, dtype=numpy.float64)
- ## Interaction forces
- self.f_d = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
- self.f_p = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
- self.f_v = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
- self.f_sum = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ # DEM-CFD time scaling factor
+ self.dt_dem_fac = numpy.ones(1, dtype=numpy.float64)
+
+ ## Interaction forces
+ self.f_d = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ self.f_p = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ self.f_v = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ self.f_sum = numpy.zeros((self.np, self.nd), dtype=numpy.float…
+
+ # Darcy
+ elif self.cfd_solver[0] == 1:
+
+ # Tolerance criteria for the normalized max. residual
+ self.tolerance = numpy.array(1.0e-3)
+
+ # The maximum number of iterations to perform per time step
+ self.maxiter = numpy.array(1e4)
+
+ # The number of DEM time steps to perform between CFD updates
+ self.ndem = numpy.array(1)
+
+ # Porosity scaling factor
+ self.c_phi = numpy.ones(1, dtype=numpy.float64)
+
+ # Interaction forces
+ self.f_p = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+
+ # Adiabatic fluid compressibility [1/Pa].
+ # Fluid bulk modulus = 1/self.beta_f
+ self.beta_f = numpy.ones(1, dtype=numpy.float64)*4.5e-10
+
+ # Hydraulic permeability prefactor [m*m]
+ self.k_c = numpy.ones(1, dtype=numpy.float64)*4.6e-10
+
+ else:
+ raise Exception('Value of cfd_solver not understood (' + \
+ str(self.cfd_solver[0]) + ')')
# Particle color marker
self.color = numpy.zeros(self.np, dtype=numpy.int32)
t@@ -546,7 +593,10 @@ class sim:
return 64
if self.fluid:
- if (self.mu != other.mu):
+ if (self.cfd_solver != other.cfd_solver):
+ print(91)
+ return 91
+ elif (self.mu != other.mu):
print(65)
return 65
elif ((self.v_f != other.v_f).any()):
t@@ -585,44 +635,69 @@ class sim:
elif (self.free_slip_top != other.free_slip_top):
print(77)
return 77
- elif (self.gamma != other.gamma):
- print(78)
- return 78
- elif (self.theta != other.theta):
- print(79)
- return 79
- elif (self.beta != other.beta):
- print(80)
- return 80
- elif (self.tolerance != other.tolerance):
- print(81)
- return 81
- elif (self.maxiter != other.maxiter):
- print(82)
- return 82
- elif (self.ndem != other.ndem):
- print(83)
- return 83
- elif (self.c_phi != other.c_phi):
- print(84)
- return(84)
- elif (self.c_v != other.c_v):
- print(85)
- elif (self.dt_dem_fac != other.dt_dem_fac):
- print(85)
- return(85)
- elif (self.f_d != other.f_d).any():
- print(86)
- return(86)
- elif (self.f_p != other.f_p).any():
- print(87)
- return(87)
- elif (self.f_v != other.f_v).any():
- print(88)
- return(88)
- elif (self.f_sum != other.f_sum).any():
- print(89)
- return(89)
+
+ if (self.cfd_solver == 0):
+ if (self.gamma != other.gamma):
+ print(78)
+ return 78
+ elif (self.theta != other.theta):
+ print(79)
+ return 79
+ elif (self.beta != other.beta):
+ print(80)
+ return 80
+ elif (self.tolerance != other.tolerance):
+ print(81)
+ return 81
+ elif (self.maxiter != other.maxiter):
+ print(82)
+ return 82
+ elif (self.ndem != other.ndem):
+ print(83)
+ return 83
+ elif (self.c_phi != other.c_phi):
+ print(84)
+ return(84)
+ elif (self.c_v != other.c_v):
+ print(85)
+ elif (self.dt_dem_fac != other.dt_dem_fac):
+ print(85)
+ return(85)
+ elif (self.f_d != other.f_d).any():
+ print(86)
+ return(86)
+ elif (self.f_p != other.f_p).any():
+ print(87)
+ return(87)
+ elif (self.f_v != other.f_v).any():
+ print(88)
+ return(88)
+ elif (self.f_sum != other.f_sum).any():
+ print(89)
+ return(89)
+
+ if (self.cfd_solver == 1):
+ if (self.tolerance != other.tolerance):
+ print(81)
+ return 81
+ elif (self.maxiter != other.maxiter):
+ print(82)
+ return 82
+ elif (self.ndem != other.ndem):
+ print(83)
+ return 83
+ elif (self.c_phi != other.c_phi):
+ print(84)
+ return(84)
+ elif (self.f_p != other.f_p).any():
+ print(86)
+ return(86)
+ elif (self.beta_f != other.beta_f):
+ print(87)
+ return(87)
+ elif (self.k_c != other.k_c):
+ print(88)
+ return(88)
if ((self.color != other.color)).any():
print(90)
t@@ -631,15 +706,31 @@ class sim:
# All equal
return 0
- def id(self, sid):
+ def id(self, sid=''):
'''
- Set the simulation id/name, which will be used to identify simulation
- files in the output folders.
+ Returns or sets the simulation id/name, which is used to identify
+ simulation files in the output folders.
- :param sid: The desired simulation id
+ :param sid: The desired simulation id. If left blank the current
+ simulation id will be returned.
:type sid: str
+ :returns: The current simulation id if no new value is set.
+ :return type: str
'''
- self.sid = sid
+ if sid == '':
+ return self.sid
+ else:
+ self.sid = sid
+
+ def idAppend(self, string):
+ '''
+ Append a string to the simulation id/name, which is used to identify
+ simulation files in the output folders.
+
+ :param string: The string to append to the simulation id (`self.sid`).
+ :type string: str
+ '''
+ self.sid += string
def addParticle(self,
x,
t@@ -852,7 +943,7 @@ class sim:
self.periodic = numpy.fromfile(fh, dtype=numpy.int32, count=1)
# Per-particle vectors
- for i in range(self.np):
+ for i in numpy.arange(self.np):
self.x[i,:] =\
numpy.fromfile(fh, dtype=numpy.float64, count=self.nd)
self.radius[i] =\
t@@ -865,7 +956,7 @@ class sim:
self.xyzsum = numpy.fromfile(fh, dtype=numpy.float64,\
count=self.np*2).reshape(self.np,2)
- for i in range(self.np):
+ for i in numpy.arange(self.np):
self.vel[i,:] =\
numpy.fromfile(fh, dtype=numpy.float64, count=self.nd)
self.fixvel[i] =\
t@@ -924,11 +1015,11 @@ class sim:
self.w_devs = numpy.empty(self.nw, dtype=numpy.float64)
self.wmode = numpy.fromfile(fh, dtype=numpy.int32, count=self.nw)
- for i in range(self.nw):
+ for i in numpy.arange(self.nw):
self.w_n[i,:] =\
numpy.fromfile(fh, dtype=numpy.float64, count=self.nd)
self.w_x[i] = numpy.fromfile(fh, dtype=numpy.float64, count=…
- for i in range(self.nw):
+ for i in numpy.arange(self.nw):
self.w_m[i] = numpy.fromfile(fh, dtype=numpy.float64, count=…
self.w_vel[i] = numpy.fromfile(fh, dtype=numpy.float64, count=…
self.w_force[i] =\
t@@ -946,7 +1037,7 @@ class sim:
self.sigma_b = numpy.fromfile(fh, dtype=numpy.float64, count=1)
self.tau_b = numpy.fromfile(fh, dtype=numpy.float64, count=1)
self.bonds = numpy.empty((self.nb0, 2), dtype=numpy.uint32)
- for i in range(self.nb0):
+ for i in numpy.arange(self.nb0):
self.bonds[i,0] = numpy.fromfile(fh, dtype=numpy.uint32,
count=1)
self.bonds[i,1] = numpy.fromfile(fh, dtype=numpy.uint32,
t@@ -963,6 +1054,13 @@ class sim:
self.nb0 = numpy.zeros(1, dtype=numpy.uint32)
if self.fluid:
+
+ if self.version >= 2.0:
+ self.cfd_solver = numpy.fromfile(fh, dtype=numpy.int32,
+ count=1)
+ else:
+ self.cfd_solver = numpy.zeros(1, dtype=numpy.int32)
+
self.mu = numpy.fromfile(fh, dtype=numpy.float64, count=1)
self.v_f = numpy.empty(
t@@ -978,9 +1076,9 @@ class sim:
numpy.empty((self.num[0],self.num[1],self.num[2]),
dtype=numpy.float64)
- for z in range(self.num[2]):
- for y in range(self.num[1]):
- for x in range(self.num[0]):
+ for z in numpy.arange(self.num[2]):
+ for y in numpy.arange(self.num[1]):
+ for x in numpy.arange(self.num[0]):
self.v_f[x,y,z,0] = \
numpy.fromfile(fh, dtype=numpy.float64,\
count=1)
t@@ -1000,7 +1098,7 @@ class sim:
numpy.fromfile(fh, dtype=numpy.float64,\
count=1)
- if (self.version >= 0.36):
+ if self.version >= 0.36:
self.rho_f =\
numpy.fromfile(fh, dtype=numpy.float64, count=1)
self.p_mod_A =\
t@@ -1019,65 +1117,93 @@ class sim:
self.free_slip_top =\
numpy.fromfile(fh, dtype=numpy.int32, count=1)
- self.gamma = numpy.fromfile(fh, dtype=numpy.float64, count=1)
- self.theta = numpy.fromfile(fh, dtype=numpy.float64, count=1)
- self.beta = numpy.fromfile(fh, dtype=numpy.float64, count=1)
- self.tolerance =\
- numpy.fromfile(fh, dtype=numpy.float64, count=1)
- self.maxiter = numpy.fromfile(fh, dtype=numpy.uint32, count=1)
- if self.version >= 1.01:
- self.ndem = numpy.fromfile(fh, dtype=numpy.uint32, count=1)
- else:
- self.ndem = 1
-
- if self.version >= 1.04:
- self.c_phi = \
+ if self.version >= 2.0 and self.cfd_solver == 0:
+ self.gamma = \
numpy.fromfile(fh, dtype=numpy.float64, count=1)
- self.c_v =\
- numpy.fromfile(fh, dtype=numpy.float64, count=1)
- if self.version == 1.06:
- self.c_a =\
- numpy.fromfile(fh, dtype=numpy.float64, count=…
- elif self.version >= 1.07:
- self.dt_dem_fac =\
- numpy.fromfile(fh, dtype=numpy.float64, count=…
+ self.theta = \
+ numpy.fromfile(fh, dtype=numpy.float64, count=1)
+ self.beta = \
+ numpy.fromfile(fh, dtype=numpy.float64, count=1)
+ self.tolerance =\
+ numpy.fromfile(fh, dtype=numpy.float64, count=1)
+ self.maxiter = \
+ numpy.fromfile(fh, dtype=numpy.uint32, count=1)
+ if self.version >= 1.01:
+ self.ndem = \
+ numpy.fromfile(fh, dtype=numpy.uint32, count=1)
else:
- self.c_a = numpy.ones(1, dtype=numpy.float64)
- else:
- self.c_phi = numpy.ones(1, dtype=numpy.float64)
- self.c_v = numpy.ones(1, dtype=numpy.float64)
+ self.ndem = 1
- if self.version >= 1.05:
- self.f_d = numpy.empty_like(self.x)
+ if self.version >= 1.04:
+ self.c_phi = \
+ numpy.fromfile(fh, dtype=numpy.float64, count=…
+ self.c_v =\
+ numpy.fromfile(fh, dtype=numpy.float64, count=1)
+ if self.version == 1.06:
+ self.c_a =\
+ numpy.fromfile(fh, \
+ dtype=numpy.float64, count=1)
+ elif self.version >= 1.07:
+ self.dt_dem_fac =\
+ numpy.fromfile(fh, \
+ dtype=numpy.float64, count=1)
+ else:
+ self.c_a = numpy.ones(1, dtype=numpy.float64)
+ else:
+ self.c_phi = numpy.ones(1, dtype=numpy.float64)
+ self.c_v = numpy.ones(1, dtype=numpy.float64)
+
+ if self.version >= 1.05:
+ self.f_d = numpy.empty_like(self.x)
+ self.f_p = numpy.empty_like(self.x)
+ self.f_v = numpy.empty_like(self.x)
+ self.f_sum = numpy.empty_like(self.x)
+
+ for i in numpy.arange(self.np[0]):
+ self.f_d[i,:] = \
+ numpy.fromfile(fh, dtype=numpy.float64,
+ count=self.nd)
+ for i in numpy.arange(self.np[0]):
+ self.f_p[i,:] = \
+ numpy.fromfile(fh, dtype=numpy.float64,
+ count=self.nd)
+ for i in numpy.arange(self.np[0]):
+ self.f_v[i,:] = \
+ numpy.fromfile(fh, dtype=numpy.float64,
+ count=self.nd)
+ for i in numpy.arange(self.np[0]):
+ self.f_sum[i,:] = \
+ numpy.fromfile(fh, dtype=numpy.float64,
+ count=self.nd)
+ else:
+ self.f_d = numpy.zeros((self.np, self.nd),
+ dtype=numpy.float64)
+ self.f_p = numpy.zeros((self.np, self.nd),
+ dtype=numpy.float64)
+ self.f_v = numpy.zeros((self.np, self.nd),
+ dtype=numpy.float64)
+ self.f_sum = numpy.zeros((self.np, self.nd),
+ dtype=numpy.float64)
+
+ elif self.version >= 2.0 and self.cfd_solver == 1:
+
+ self.tolerance = \
+ numpy.fromfile(fh, dtype=numpy.float64, count=1)
+ self.maxiter = \
+ numpy.fromfile(fh, dtype=numpy.uint32, count=1)
+ self.ndem = numpy.fromfile(fh, dtype=numpy.uint32, count=1)
+ self.c_phi = \
+ numpy.fromfile(fh, dtype=numpy.float64, count=1)
self.f_p = numpy.empty_like(self.x)
- self.f_v = numpy.empty_like(self.x)
- self.f_sum = numpy.empty_like(self.x)
-
- for i in range(self.np[0]):
- self.f_d[i,:] = \
- numpy.fromfile(fh, dtype=numpy.float64,
- count=self.nd)
- for i in range(self.np[0]):
+ for i in numpy.arange(self.np[0]):
self.f_p[i,:] = \
numpy.fromfile(fh, dtype=numpy.float64,
count=self.nd)
- for i in range(self.np[0]):
- self.f_v[i,:] = \
- numpy.fromfile(fh, dtype=numpy.float64,
- count=self.nd)
- for i in range(self.np[0]):
- self.f_sum[i,:] = \
- numpy.fromfile(fh, dtype=numpy.float64,
- count=self.nd)
- else:
- self.f_d = numpy.zeros((self.np, self.nd),
- dtype=numpy.float64)
- self.f_p = numpy.zeros((self.np, self.nd),
- dtype=numpy.float64)
- self.f_v = numpy.zeros((self.np, self.nd),
- dtype=numpy.float64)
- self.f_sum = numpy.zeros((self.np, self.nd),
- dtype=numpy.float64)
+ self.beta_f = \
+ numpy.fromfile(fh, dtype=numpy.float64, count=1)
+
+ self.k_c = \
+ numpy.fromfile(fh, dtype=numpy.float64, count=1)
if (self.version >= 1.02):
self.color =\
t@@ -1131,14 +1257,14 @@ class sim:
fh.write(self.periodic.astype(numpy.uint32))
# Per-particle vectors
- for i in range(self.np):
+ for i in numpy.arange(self.np):
fh.write(self.x[i,:].astype(numpy.float64))
fh.write(self.radius[i].astype(numpy.float64))
if (self.np[0] > 0):
fh.write(self.xyzsum.astype(numpy.float64))
- for i in range(self.np):
+ for i in numpy.arange(self.np):
fh.write(self.vel[i,:].astype(numpy.float64))
fh.write(self.fixvel[i].astype(numpy.float64))
t@@ -1177,13 +1303,13 @@ class sim:
fh.write(self.V_b.astype(numpy.float64))
fh.write(self.nw.astype(numpy.uint32))
- for i in range(self.nw):
+ for i in numpy.arange(self.nw):
fh.write(self.wmode[i].astype(numpy.int32))
- for i in range(self.nw):
+ for i in numpy.arange(self.nw):
fh.write(self.w_n[i,:].astype(numpy.float64))
fh.write(self.w_x[i].astype(numpy.float64))
- for i in range(self.nw):
+ for i in numpy.arange(self.nw):
fh.write(self.w_m[i].astype(numpy.float64))
fh.write(self.w_vel[i].astype(numpy.float64))
fh.write(self.w_force[i].astype(numpy.float64))
t@@ -1195,7 +1321,7 @@ class sim:
fh.write(self.nb0.astype(numpy.uint32))
fh.write(self.sigma_b.astype(numpy.float64))
fh.write(self.tau_b.astype(numpy.float64))
- for i in range(self.nb0):
+ for i in numpy.arange(self.nb0):
fh.write(self.bonds[i,0].astype(numpy.uint32))
fh.write(self.bonds[i,1].astype(numpy.uint32))
fh.write(self.bonds_delta_n.astype(numpy.float64))
t@@ -1204,10 +1330,12 @@ class sim:
fh.write(self.bonds_omega_t.astype(numpy.float64))
if self.fluid:
+
+ fh.write(self.cfd_solver.astype(numpy.int32))
fh.write(self.mu.astype(numpy.float64))
- for z in range(self.num[2]):
- for y in range(self.num[1]):
- for x in range(self.num[0]):
+ for z in numpy.arange(self.num[2]):
+ for y in numpy.arange(self.num[1]):
+ for x in numpy.arange(self.num[0]):
fh.write(self.v_f[x,y,z,0].astype(numpy.float64))
fh.write(self.v_f[x,y,z,1].astype(numpy.float64))
fh.write(self.v_f[x,y,z,2].astype(numpy.float64))
t@@ -1225,25 +1353,44 @@ class sim:
fh.write(self.free_slip_bot.astype(numpy.int32))
fh.write(self.free_slip_top.astype(numpy.int32))
- fh.write(self.gamma.astype(numpy.float64))
- fh.write(self.theta.astype(numpy.float64))
- fh.write(self.beta.astype(numpy.float64))
- fh.write(self.tolerance.astype(numpy.float64))
- fh.write(self.maxiter.astype(numpy.uint32))
- fh.write(self.ndem.astype(numpy.uint32))
-
- fh.write(self.c_phi.astype(numpy.float64))
- fh.write(self.c_v.astype(numpy.float64))
- fh.write(self.dt_dem_fac.astype(numpy.float64))
-
- for i in numpy.arange(self.np):
- fh.write(self.f_d[i,:].astype(numpy.float64))
- for i in numpy.arange(self.np):
- fh.write(self.f_p[i,:].astype(numpy.float64))
- for i in numpy.arange(self.np):
- fh.write(self.f_v[i,:].astype(numpy.float64))
- for i in numpy.arange(self.np):
- fh.write(self.f_sum[i,:].astype(numpy.float64))
+ # Navier Stokes
+ if self.cfd_solver[0] == 0:
+ fh.write(self.gamma.astype(numpy.float64))
+ fh.write(self.theta.astype(numpy.float64))
+ fh.write(self.beta.astype(numpy.float64))
+ fh.write(self.tolerance.astype(numpy.float64))
+ fh.write(self.maxiter.astype(numpy.uint32))
+ fh.write(self.ndem.astype(numpy.uint32))
+
+ fh.write(self.c_phi.astype(numpy.float64))
+ fh.write(self.c_v.astype(numpy.float64))
+ fh.write(self.dt_dem_fac.astype(numpy.float64))
+
+ for i in numpy.arange(self.np):
+ fh.write(self.f_d[i,:].astype(numpy.float64))
+ for i in numpy.arange(self.np):
+ fh.write(self.f_p[i,:].astype(numpy.float64))
+ for i in numpy.arange(self.np):
+ fh.write(self.f_v[i,:].astype(numpy.float64))
+ for i in numpy.arange(self.np):
+ fh.write(self.f_sum[i,:].astype(numpy.float64))
+
+ # Darcy
+ elif self.cfd_solver[0] == 1:
+
+ fh.write(self.tolerance.astype(numpy.float64))
+ fh.write(self.maxiter.astype(numpy.uint32))
+ fh.write(self.ndem.astype(numpy.uint32))
+ fh.write(self.c_phi.astype(numpy.float64))
+ for i in numpy.arange(self.np):
+ fh.write(self.f_p[i,:].astype(numpy.float64))
+ fh.write(self.beta_f.astype(numpy.float64))
+ fh.write(self.k_c.astype(numpy.float64))
+
+ else:
+ raise Exception('Value of cfd_solver not understood (' + \
+ str(self.cfd_solver[0]) + ')')
+
fh.write(self.color.astype(numpy.int32))
t@@ -1385,7 +1532,7 @@ class sim:
+ 'NumberOfComponents="3" format="ascii">\n')
fh.write(' ')
for i in range(self.np):
- fh.write('%f %f %f' % (self.x[i,0], self.x[i,1], self.x[i,2]))
+ fh.write('%f %f %f ' % (self.x[i,0], self.x[i,1], self.x[i,2]))
fh.write('\n')
fh.write(' </DataArray>\n')
fh.write(' </Points>\n')
t@@ -1423,27 +1570,30 @@ class sim:
fh.write(' </DataArray>\n')
if self.fluid:
- # Fluid interaction force
- fh.write(' <DataArray type="Float32" '
- + 'Name="Fluid force total" '
- + 'NumberOfComponents="3" format="ascii">\n')
- fh.write(' ')
- for i in range(self.np):
- fh.write('%f %f %f ' % \
- (self.f_sum[i,0], self.f_sum[i,1], self.f_sum[i,2]…
- fh.write('\n')
- fh.write(' </DataArray>\n')
- # Fluid drag force
- fh.write(' <DataArray type="Float32" '
- + 'Name="Fluid drag force" '
- + 'NumberOfComponents="3" format="ascii">\n')
- fh.write(' ')
- for i in range(self.np):
- fh.write('%f %f %f ' % \
- (self.f_d[i,0], self.f_d[i,1], self.f_d[i,2]))
- fh.write('\n')
- fh.write(' </DataArray>\n')
+ if self.cfd_solver == 0: # Navier Stokes
+ # Fluid interaction force
+ fh.write(' <DataArray type="Float32" '
+ + 'Name="Fluid force total" '
+ + 'NumberOfComponents="3" format="ascii">\n')
+ fh.write(' ')
+ for i in range(self.np):
+ fh.write('%f %f %f ' % \
+ (self.f_sum[i,0], self.f_sum[i,1], \
+ self.f_sum[i,2]))
+ fh.write('\n')
+ fh.write(' </DataArray>\n')
+
+ # Fluid drag force
+ fh.write(' <DataArray type="Float32" '
+ + 'Name="Fluid drag force" '
+ + 'NumberOfComponents="3" format="ascii">\n')
+ fh.write(' ')
+ for i in range(self.np):
+ fh.write('%f %f %f ' % \
+ (self.f_d[i,0], self.f_d[i,1], self.f_d[i,2]))
+ fh.write('\n')
+ fh.write(' </DataArray>\n')
# Fluid pressure force
fh.write(' <DataArray type="Float32" '
t@@ -1456,16 +1606,17 @@ class sim:
fh.write('\n')
fh.write(' </DataArray>\n')
- # Fluid viscous force
- fh.write(' <DataArray type="Float32" '
- + 'Name="Fluid viscous force" '
- + 'NumberOfComponents="3" format="ascii">\n')
- fh.write(' ')
- for i in range(self.np):
- fh.write('%f %f %f ' % \
- (self.f_v[i,0], self.f_v[i,1], self.f_v[i,2]))
- fh.write('\n')
- fh.write(' </DataArray>\n')
+ if self.cfd_solver == 0: # Navier Stokes
+ # Fluid viscous force
+ fh.write(' <DataArray type="Float32" '
+ + 'Name="Fluid viscous force" '
+ + 'NumberOfComponents="3" format="ascii">\n')
+ fh.write(' ')
+ for i in range(self.np):
+ fh.write('%f %f %f ' % \
+ (self.f_v[i,0], self.f_v[i,1], self.f_v[i,2]))
+ fh.write('\n')
+ fh.write(' </DataArray>\n')
# fixvel
fh.write(' <DataArray type="Float32" Name="FixedVel" '
t@@ -1709,6 +1860,17 @@ class sim:
else:
Re.SetNumberOfTuples(grid.GetNumberOfPoints())
+ # Find permeabilities if the Darcy solver is used
+ if self.cfd_solver[0] == 1:
+ self.findPermeabilities()
+ k = vtk.vtkDoubleArray()
+ k.SetName("Permeability [m*m]")
+ k.SetNumberOfComponents(1)
+ if cell_centered:
+ k.SetNumberOfTuples(grid.GetNumberOfCells())
+ else:
+ k.SetNumberOfTuples(grid.GetNumberOfPoints())
+
# insert values
for z in range(self.num[2]):
for y in range(self.num[1]):
t@@ -1719,6 +1881,8 @@ class sim:
poros.SetValue(idx, self.phi[x,y,z])
dporos.SetValue(idx, self.dphi[x,y,z])
Re.SetValue(idx, self.Re[x,y,z])
+ if self.cfd_solver[0] == 1:
+ k.SetValue(idx, self.k[x,y,z])
# add pres array to grid
if cell_centered:
t@@ -1727,12 +1891,16 @@ class sim:
grid.GetCellData().AddArray(poros)
grid.GetCellData().AddArray(dporos)
grid.GetCellData().AddArray(Re)
+ if self.cfd_solver[0] == 1:
+ grid.GetCellData().AddArray(k)
else:
grid.GetPointData().AddArray(pres)
grid.GetPointData().AddArray(vel)
grid.GetPointData().AddArray(poros)
grid.GetPointData().AddArray(dporos)
grid.GetPointData().AddArray(Re)
+ if self.cfd_solver[0] == 1:
+ grid.GetPointData().AddArray(k)
# write VTK XML image data file
writer = vtk.vtkXMLImageDataWriter()
t@@ -1804,9 +1972,9 @@ class sim:
self.readbin(fn, verbose)
def generateRadii(self, psd = 'logn',
- radius_mean = 440e-6,
- radius_variance = 8.8e-9,
- histogram = True):
+ mean = 440e-6,
+ variance = 8.8e-9,
+ histogram = False):
'''
Draw random particle radii from a selected probability distribution.
The larger the variance of radii is, the slower the computations will
t@@ -1820,26 +1988,29 @@ class sim:
``logn``, which is a log-normal probability distribution, suitable
for approximating well-sorted, coarse sediments. The other possible
value is ``uni``, which is a uniform distribution from
- ``radius_mean-radius_variance`` to ``radius_mean+radius_variance``.
+ ``mean - variance`` to ``mean + variance``.
:type psd: str
- :param radius_mean: The mean radius [m] (default = 440e-6 m)
- :type radius_mean: float
- :param radius_variance: The variance in the probability distribution
+ :param mean: The mean radius [m] (default = 440e-6 m)
+ :type mean: float
+ :param variance: The variance in the probability distribution
[m].
- :type radius_variance: float
+ :type variance: float
See also: :func:`generateBimodalRadii()`.
'''
if psd == 'logn': # Log-normal probability distribution
mu = math.log(\
- (radius_mean**2)/math.sqrt(radius_variance+radius_mean**2))
- sigma = math.sqrt(math.log(radius_variance/(radius_mean**2)+1))
+ (mean**2)/math.sqrt(variance+mean**2))
+ sigma = math.sqrt(math.log(variance/(mean**2)+1))
self.radius = numpy.random.lognormal(mu, sigma, self.np)
- if psd == 'uni': # Uniform distribution
- radius_min = radius_mean - radius_variance
- radius_max = radius_mean + radius_variance
+ elif psd == 'uni': # Uniform distribution
+ radius_min = mean - variance
+ radius_max = mean + variance
self.radius = numpy.random.uniform(radius_min, radius_max, self.np)
+ else:
+ raise Exception('Particle size distribution type not understood ('
+ + str(psd) + '). Valid values are \'uni\' or \'logn\'')
# Show radii as histogram
if histogram:
t@@ -2560,7 +2731,7 @@ class sim:
self.mu_ws[0] = 0.0
self.mu_wd[0] = 0.0
- def largestFluidTimeStep(self, safety=0.01):
+ def largestFluidTimeStep(self, safety=0.5):
'''
Finds and returns the largest time step in the fluid phase by von
Neumann and Courant-Friedrichs-Lewy analysis given the current
t@@ -2579,28 +2750,107 @@ class sim:
:return type: float
'''
- dx_min = numpy.min(self.L/self.num)
- dt_min_von_neumann = 0.5*dx_min**2/self.mu[0]
+ if self.fluid:
- # Normalized velocities
- v_norm = numpy.empty(self.num[0]*self.num[1]*self.num[2])
- idx = 0
- for x in numpy.arange(self.num[0]):
- for y in numpy.arange(self.num[1]):
- for z in numpy.arange(self.num[2]):
- v_norm[idx] = numpy.sqrt(self.v_f[x,y,z,:].dot(\
- self.v_f[x,y,z,:]))
- idx += 1
+ # Navier-Stokes
+ if self.cfd_solver[0] == 0:
+ dx_min = numpy.min(self.L/self.num)
+ dt_min_von_neumann = 0.5*dx_min**2/self.mu[0]
- # Advection term. This term has to be reevaluated during the
- # computations, as the fluid velocity changes.
- v_max = numpy.amax(v_norm)
- if v_max == 0:
- v_max = 1.0e-7
+ # Normalized velocities
+ v_norm = numpy.empty(self.num[0]*self.num[1]*self.num[2])
+ idx = 0
+ for x in numpy.arange(self.num[0]):
+ for y in numpy.arange(self.num[1]):
+ for z in numpy.arange(self.num[2]):
+ v_norm[idx] = numpy.sqrt(self.v_f[x,y,z,:].dot(\
+ self.v_f[x,y,z,:]))
+ idx += 1
+
+ # Advection term. This term has to be reevaluated during the
+ # computations, as the fluid velocity changes.
+ v_max = numpy.amax(v_norm)
+ if v_max == 0:
+ v_max = 1.0e-7
+
+ dt_min_cfl = dx_min/v_max
+
+ return numpy.min([dt_min_von_neumann, dt_min_cfl])*safety
+
+ # Darcy
+ elif self.cfd_solver[0] == 1:
+
+ # Determine on the base of the diffusivity coefficient
+ # components
+ self.cellSize()
+ self.hydraulicPermeability()
+ alpha_max = numpy.max(self.k/(self.beta_f*0.9*self.mu))
+ return safety * 1.0/(2.0*alpha_max)*1.0/(
+ 1.0/(self.dx[0]**2) + \
+ 1.0/(self.dx[1]**2) + \
+ 1.0/(self.dx[2]**2))
+
+ '''
+ # Determine value on the base of the hydraulic conductivity
+ g = numpy.max(numpy.abs(self.g))
+
+ # Bulk modulus of fluid
+ K = 1.0/self.beta_f[0]
+
+ self.hydraulicDiffusivity()
+ self.cellSize()
+
+ return safety * 1.0/(2.0*self.D)*1.0/( \
+ 1.0/(self.dx[0]**2) + \
+ 1.0/(self.dx[1]**2) + \
+ 1.0/(self.dx[2]**2))
+ '''
- dt_min_cfl = dx_min/v_max
+ def cellSize(self):
+ '''
+ Calculate the particle sorting (and fluid) cell dimensions.
+ These values are stored in `self.dx` and are NOT returned.
+ '''
+ self.dx = self.L/self.num
+
+ def hydraulicConductivity(self):
+ '''
+ Determine the hydraulic conductivity (K) [m/s] from the permeability
+ prefactor. This value is stored in `self.K_c`. This function only works
+ for the Darcy solver (`self.cfd_solver == 1`)
+ '''
+ if self.cfd_solver[0] == 1:
+ self.K_c = self.k_c*self.rho_f*g/self.mu
+ else:
+ raise Exception('This function only works for the Darcy solver')
+
+ def hydraulicPermeability(self, phi_min = 0.1, phi_max = 0.9):
+ '''
+ Determine the hydraulic permeability (k) [m*m] from the Kozeny-Carman
+ relationship, using the permeability prefactor (`self.k_c`), and the
+ range of valid porosities set in `src/darcy.cuh`, by default in the
+ range 0.1 to 0.9.
+
+ This function is only valid for the Darcy solver (`self.cfd_solver ==
+ 1`).
+ '''
+ if self.cfd_solver[0] == 1:
+ self.findPermeabilities()
+ else:
+ raise Exception('This function only works for the Darcy solver')
- return numpy.min([dt_min_von_neumann, dt_min_cfl])*safety
+ def hydraulicDiffusivity(self):
+ '''
+ Determine the hydraulic diffusivity (D) [m*m/s]. The result is stored …
+ `self.D`. This function only works for the Darcy solver
+ (`self.cfd_solver[0] == 1`)
+ '''
+ if self.cfd_solver[0] == 1:
+ self.hydraulicConductivity()
+ phi_bar = numpy.mean(self.phi)
+ alpha = self.K_c/(self.rho_f*g*(self.k_n[0] + phi_bar*K))
+ else:
+ raise Exception('This function only works for the Darcy solver')
def initTemporal(self, total,
current = 0.0,
t@@ -2707,7 +2957,7 @@ class sim:
self.initFluid()
def initFluid(self, mu = 8.9e-4, rho = 1.0e3, p = 1.0,
- hydrostatic = True):
+ hydrostatic = False, cfd_solver = 0):
'''
Initialize the fluid arrays and the fluid viscosity. The default value
of ``mu`` equals the dynamic viscosity of water at 25 degrees Celcius.
t@@ -2725,6 +2975,9 @@ class sim:
created if a gravitational acceleration along :math:`z` previously
has been specified
:type hydrostatic: bool
+ :param cfd_solver: Solver to use for the computational fluid dynamics.
+ Accepted values: 0 (Navier Stokes, default) and 1 (Darcy).
+ :type cfd_solver: int
'''
self.fluid = True
self.mu = numpy.ones(1, dtype=numpy.float64) * mu
t@@ -2771,21 +3024,41 @@ class sim:
self.free_slip_bot = numpy.ones(1, dtype=numpy.int32)
self.free_slip_top = numpy.ones(1, dtype=numpy.int32)
- self.gamma = numpy.array(0.0)
- self.theta = numpy.array(1.0)
- self.beta = numpy.array(0.0)
- self.tolerance = numpy.array(1.0e-8)
- self.maxiter = numpy.array(1e4)
- self.ndem = numpy.array(1)
+ # Fluid solver type
+ # 0: Navier Stokes (fluid with inertia)
+ # 1: Stokes-Darcy (fluid without inertia)
+ self.cfd_solver = numpy.ones(1)*cfd_solver
+
+ if self.cfd_solver[0] == 0:
+ self.gamma = numpy.array(0.0)
+ self.theta = numpy.array(1.0)
+ self.beta = numpy.array(0.0)
+ self.tolerance = numpy.array(1.0e-3)
+ self.maxiter = numpy.array(1e4)
+ self.ndem = numpy.array(1)
+
+ self.c_phi = numpy.ones(1, dtype=numpy.float64)
+ self.c_v = numpy.ones(1, dtype=numpy.float64)
+ self.dt_dem_fac = numpy.ones(1, dtype=numpy.float64)
+
+ self.f_d = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ self.f_p = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ self.f_v = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ self.f_sum = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
- self.c_phi = numpy.ones(1, dtype=numpy.float64)
- self.c_v = numpy.ones(1, dtype=numpy.float64)
- self.dt_dem_fac = numpy.ones(1, dtype=numpy.float64)
+ elif self.cfd_solver[0] == 1:
+ self.tolerance = numpy.array(1.0e-3)
+ self.maxiter = numpy.array(1e4)
+ self.ndem = numpy.array(1)
+ self.c_phi = numpy.ones(1, dtype=numpy.float64)
+ self.f_d = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ self.beta_f = numpy.ones(1, dtype=numpy.float64)*4.5e-10
+ self.f_p = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ self.k_c = numpy.ones(1, dtype=numpy.float64)*4.6e-10
- self.f_d = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
- self.f_p = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
- self.f_v = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
- self.f_sum = numpy.zeros((self.np, self.nd), dtype=numpy.float64)
+ else:
+ raise Exception('Value of cfd_solver not understood (' + \
+ str(self.cfd_solver[0]) + ')')
def setFluidBottomNoFlow(self):
'''
t@@ -2847,6 +3120,18 @@ class sim:
'''
self.bc_top[0] = 0
+ def findPermeabilities(self):
+ '''
+ Calculates the hydrological permeabilities from the Kozeny-Carman
+ relationship. These values are only relevant when the Darcy solver is
+ used (`self.cfd_solver = 1`). The permeability pre-factor `self.k_c`
+ and the assemblage porosities must be set beforehand. The former values
+ are set if a file from the `output/` folder is read using
+ `self.readbin`.
+ '''
+ phi = numpy.clip(self.phi, 0.1, 0.9)
+ self.k = self.k_c * phi**3/(1.0 - phi**2)
+
def defaultParams(self,
mu_s = 0.5,
mu_d = 0.5,
t@@ -2960,6 +3245,26 @@ class sim:
# Debonding distance
self.db[0] = (1.0 + theta/2.0) * self.V_b**(1.0/3.0)
+ def setStiffnessNormal(self, k_n):
+ '''
+ Set the elastic stiffness (`k_n`) in the normal direction of the
+ contact.
+
+ :param k_n: The elastic stiffness coefficient [N/m]
+ :type k_n: float
+ '''
+ self.k_n[0] = k_n
+
+ def setStiffnessTangential(self, k_t):
+ '''
+ Set the elastic stiffness (`k_t`) in the tangential direction of the
+ contact.
+
+ :param k_t: The elastic stiffness coefficient [N/m]
+ :type k_t: float
+ '''
+ self.k_t[0] = k_t
+
def setDampingNormal(self, gamma, over_damping=False):
'''
Set the dampening coefficient (gamma) in the normal direction of the
t@@ -3324,18 +3629,27 @@ class sim:
def bulkPorosity(self):
'''
- Calculates the bulk porosity
+ Calculates the bulk porosity in the smallest axis-parallel cube.
:returns: The bulk porosity, in [0:1]
:return type: float
'''
- if (self.nw == 0):
- V_total = self.L[0] * self.L[1] * self.L[2]
- elif (self.nw == 1):
- V_total = self.L[0] * self.L[1] * self.w_x[0]
- if (V_total <= 0.0):
- raise Exception("Could not determine total volume")
+ min_x = numpy.min(self.x[:,0] - self.radius)
+ min_y = numpy.min(self.x[:,1] - self.radius)
+ min_z = numpy.min(self.x[:,2] - self.radius)
+ max_x = numpy.max(self.x[:,0] + self.radius)
+ max_y = numpy.max(self.x[:,1] + self.radius)
+ max_z = numpy.max(self.x[:,2] + self.radius)
+
+ #if (self.nw == 0):
+ #V_total = self.L[0] * self.L[1] * self.L[2]
+ #elif (self.nw == 1):
+ #V_total = self.L[0] * self.L[1] * self.w_x[0]
+ #if (V_total <= 0.0):
+ #raise Exception("Could not determine total volume")
+
+ V_total = (max_x - min_x)*(max_y - min_y)*(max_z - min_z)
# Find the volume of solids
V_solid = numpy.sum(V_sphere(self.radius))
t@@ -4677,7 +4991,7 @@ class sim:
plt.ylabel('Jacobi iterations')
plt.plot(conv[:,0], conv[:,1])
plt.grid()
- plt.savefig('../output/' + self.sid + '-conv.' + graphics_format)
+ plt.savefig(self.sid + '-conv.' + graphics_format)
plt.clf()
plt.close(fig)
t@@ -4814,7 +5128,7 @@ class sim:
the required value of the maximum normalized residual for the fluid
solver.
- The default and recommended value is 1.0e-8.
+ The default and recommended value is 1.0e-3.
:param tolerance: The tolerance criteria for the maximal normalized
residual
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
t@@ -23,13 +23,13 @@ ENDIF (GPU_GENERATION EQUAL 1)
# Rule to build executable program
CUDA_ADD_EXECUTABLE(../sphere
main.cpp file_io.cpp sphere.cpp device.cu utility.cu utility.cpp
- navierstokes.cpp)
+ navierstokes.cpp darcy.cpp)
CUDA_ADD_EXECUTABLE(../porosity
porosity.cpp file_io.cpp sphere.cpp device.cu utility.cu utility.cpp
- navierstokes.cpp)
+ navierstokes.cpp darcy.cpp)
CUDA_ADD_EXECUTABLE(../forcechains
forcechains.cpp file_io.cpp sphere.cpp device.cu utility.cu utility.cpp
- navierstokes.cpp)
+ navierstokes.cpp darcy.cpp)
#ADD_EXECUTABLE(unittests boost-unit-tests.cpp sphere.cpp)
#TARGET_LINK_LIBRARIES(unittests
diff --git a/src/constants.h b/src/constants.h
t@@ -16,7 +16,7 @@ const Float PI = 3.14159265358979;
const unsigned int ND = 3;
// Define source code version
-const double VERSION = 1.07;
+const double VERSION = 2.00;
// Max. number of contacts per particle
//const int NC = 16;
diff --git a/src/darcy.cpp b/src/darcy.cpp
t@@ -0,0 +1,311 @@
+#include <iostream>
+#include <cstdio>
+#include <cstdlib>
+#include <string>
+#include <vector>
+
+#include "typedefs.h"
+#include "datatypes.h"
+#include "constants.h"
+#include "sphere.h"
+#include "utility.h"
+
+// 1: Enable color output in array printing functions, 0: Disable
+const int color_output = 0;
+
+// Initialize memory
+void DEM::initDarcyMem()
+{
+ // Number of cells
+ darcy.nx = grid.num[0];
+ darcy.ny = grid.num[1];
+ darcy.nz = grid.num[2];
+ unsigned int ncells = darcyCells();
+ //unsigned int ncells_st = darcyCellsVelocity();
+
+ darcy.p = new Float[ncells]; // hydraulic pressure
+ darcy.v = new Float3[ncells]; // hydraulic velocity
+ darcy.phi = new Float[ncells]; // porosity
+ darcy.dphi = new Float[ncells]; // porosity change
+ darcy.norm = new Float[ncells]; // normalized residual of epsilon
+ darcy.f_p = new Float4[np]; // pressure force on particles
+ darcy.k = new Float[ncells]; // hydraulic pressure
+}
+
+unsigned int DEM::darcyCells()
+{
+ //return darcy.nx*darcy.ny*darcy.nz; // without ghost nodes
+ return (darcy.nx+2)*(darcy.ny+2)*(darcy.nz+2); // with ghost nodes
+}
+
+// Returns the number of velocity nodes in a congruent padded grid. There are
+// velocity nodes between the boundary points and the pressure ghost nodes, but
+// not on the outer side of the ghost nodes
+unsigned int DEM::darcyCellsVelocity()
+{
+ // Congruent padding for velocity grids. See "Cohen and Molemaker 'A fast
+ // double precision CFD code using CUDA'" for details
+ //return (darcy.nx+1)*(darcy.ny+1)*(darcy.nz+1); // without ghost nodes
+ return (darcy.nx+3)*(darcy.ny+3)*(darcy.nz+3); // with ghost nodes
+}
+
+// Free memory
+void DEM::freeDarcyMem()
+{
+ delete[] darcy.p;
+ delete[] darcy.v;
+ delete[] darcy.phi;
+ delete[] darcy.dphi;
+ delete[] darcy.norm;
+ delete[] darcy.f_p;
+ delete[] darcy.k;
+}
+
+// 3D index to 1D index
+unsigned int DEM::d_idx(
+ const int x,
+ const int y,
+ const int z)
+{
+ // without ghost nodes
+ //return x + d.nx*y + d.nx*d.ny*z;
+
+ // with ghost nodes
+ // the ghost nodes are placed at x,y,z = -1 and WIDTH
+ return (x+1) + (darcy.nx+2)*(y+1) + (darcy.nx+2)*(darcy.ny+2)*(z+1);
+}
+
+// 3D index to 1D index of cell-face velocity nodes. The cell-face velocities
+// are placed at x = [0;nx], y = [0;ny], z = [0;nz].
+// The coordinate x,y,z corresponds to the lowest corner of cell(x,y,z).
+unsigned int DEM::d_vidx(
+ const int x,
+ const int y,
+ const int z)
+{
+ //return x + (darcy.nx+1)*y + (darcy.nx+1)*(darcy.ny+1)*z; // without ghos…
+ return (x+1) + (darcy.nx+3)*(y+1) + (darcy.nx+3)*(darcy.ny+3)*(z+1); // wi…
+}
+
+Float DEM::largestDarcyPermeability()
+{
+ Float k_max = 0.0;
+ for (unsigned int z=0; z<grid.num[2]; z++)
+ for (unsigned int y=0; y<grid.num[1]; y++)
+ for (unsigned int x=0; x<grid.num[0]; x++)
+ if (darcy.k[d_idx(x,y,z)] > k_max)
+ k_max = darcy.k[d_idx(x,y,z)];
+ return k_max;
+}
+
+Float DEM::smallestDarcyPorosity()
+{
+ Float phi_min = 10.0;
+ for (unsigned int z=0; z<grid.num[2]; z++)
+ for (unsigned int y=0; y<grid.num[1]; y++)
+ for (unsigned int x=0; x<grid.num[0]; x++)
+ if (darcy.phi[d_idx(x,y,z)] < phi_min)
+ phi_min = darcy.phi[d_idx(x,y,z)];
+ return phi_min;
+}
+
+// Determine if the FTCS (forward time, central space) solution of the Navier
+// Stokes equations is unstable
+void DEM::checkDarcyStability()
+{
+ // Cell dimensions
+ const Float dx = grid.L[0]/grid.num[0];
+ const Float dy = grid.L[1]/grid.num[1];
+ const Float dz = grid.L[2]/grid.num[2];
+
+ const Float alpha_max = largestDarcyPermeability()
+ /(darcy.beta_f*smallestDarcyPorosity()*darcy.mu);
+
+ // Check the diffusion term using von Neumann stability analysis
+ //if (darcy.mu*time.dt/(dmin*dmin) > 0.5) {
+ if (time.dt >= 1.0/(2.0*alpha_max) *
+ 1.0/(1.0/(dx*dx) + 1.0/(dy*dy) + 1.0/(dz*dz))) {
+ std::cerr << "Error: The time step is too large to ensure stability in…
+ "the diffusive term of the fluid momentum equation.\n"
+ "Increase the viscosity, decrease the time step, and/or increase "
+ "the fluid grid cell size." << std::endl;
+ //exit(1);
+ }
+}
+
+// Print array values to file stream (stdout, stderr, other file)
+void DEM::printDarcyArray(FILE* stream, Float* arr)
+{
+ int x, y, z;
+
+ // show ghost nodes
+ for (z = darcy.nz; z >= -1; z--) { // top to bottom
+
+ fprintf(stream, "z = %d\n", z);
+
+ for (y=-1; y<=darcy.ny; y++) {
+ for (x=-1; x<=darcy.nx; x++) {
+
+ if (x > -1 && x < darcy.nx &&
+ y > -1 && y < darcy.ny &&
+ z > -1 && z < darcy.nz) {
+ fprintf(stream, "%f\t", arr[d_idx(x,y,z)]);
+ } else { // ghost node
+ if (color_output) {
+ fprintf(stream, "\x1b[30;1m%f\x1b[0m\t",
+ arr[d_idx(x,y,z)]);
+ } else {
+ fprintf(stream, "%f\t", arr[d_idx(x,y,z)]);
+ }
+ }
+ }
+ fprintf(stream, "\n");
+ }
+ fprintf(stream, "\n");
+ }
+}
+
+// Overload printDarcyArray to add optional description
+void DEM::printDarcyArray(FILE* stream, Float* arr, std::string desc)
+{
+ std::cout << "\n" << desc << ":\n";
+ printDarcyArray(stream, arr);
+}
+
+// Print array values to file stream (stdout, stderr, other file)
+void DEM::printDarcyArray(FILE* stream, Float3* arr)
+{
+ int x, y, z;
+ for (z=0; z<darcy.nz; z++) {
+ for (y=0; y<darcy.ny; y++) {
+ for (x=0; x<darcy.nx; x++) {
+ fprintf(stream, "%f,%f,%f\t",
+ arr[d_idx(x,y,z)].x,
+ arr[d_idx(x,y,z)].y,
+ arr[d_idx(x,y,z)].z);
+ }
+ fprintf(stream, "\n");
+ }
+ fprintf(stream, "\n");
+ }
+}
+
+// Overload printDarcyArray to add optional description
+void DEM::printDarcyArray(FILE* stream, Float3* arr, std::string desc)
+{
+ std::cout << "\n" << desc << ":\n";
+ printDarcyArray(stream, arr);
+}
+
+// Returns the average value of the normalized residuals
+double DEM::avgNormResDarcy()
+{
+ double norm_res_sum, norm_res;
+
+ // do not consider the values of the ghost nodes
+ for (int z=0; z<grid.num[2]; ++z) {
+ for (int y=0; y<grid.num[1]; ++y) {
+ for (int x=0; x<grid.num[0]; ++x) {
+ norm_res = static_cast<double>(darcy.norm[d_idx(x,y,z)]);
+ if (norm_res != norm_res) {
+ std::cerr << "\nError: normalized residual is NaN ("
+ << norm_res << ") in cell "
+ << x << "," << y << "," << z << std::endl;
+ std::cerr << "\tt = " << time.current << ", iter = "
+ << int(time.current/time.dt) << std::endl;
+ std::cerr << "This often happens if the system has become "
+ "unstable." << std::endl;
+ exit(1);
+ }
+ norm_res_sum += norm_res;
+ }
+ }
+ }
+ return norm_res_sum/(grid.num[0]*grid.num[1]*grid.num[2]);
+}
+
+
+// Returns the average value of the normalized residuals
+double DEM::maxNormResDarcy()
+{
+ double max_norm_res = -1.0e9; // initialized to a small number
+ double norm_res;
+
+ // do not consider the values of the ghost nodes
+ for (int z=0; z<grid.num[2]; ++z) {
+ for (int y=0; y<grid.num[1]; ++y) {
+ for (int x=0; x<grid.num[0]; ++x) {
+ norm_res = fabs(static_cast<double>(darcy.norm[d_idx(x,y,z)]));
+ if (norm_res != norm_res) {
+ std::cerr << "\nError: normalized residual is NaN ("
+ << norm_res << ") in cell "
+ << x << "," << y << "," << z << std::endl;
+ std::cerr << "\tt = " << time.current << ", iter = "
+ << int(time.current/time.dt) << std::endl;
+ std::cerr << "This often happens if the system has become "
+ "unstable." << std::endl;
+ exit(1);
+ }
+ if (norm_res > max_norm_res)
+ max_norm_res = norm_res;
+ }
+ }
+ }
+ return max_norm_res;
+}
+
+// Initialize fluid parameters
+void DEM::initDarcy()
+{
+ // Cell size
+ darcy.dx = grid.L[0]/darcy.nx;
+ darcy.dy = grid.L[1]/darcy.ny;
+ darcy.dz = grid.L[2]/darcy.nz;
+
+ if (verbose == 1) {
+ std::cout << " - Fluid grid dimensions: "
+ << darcy.nx << "*"
+ << darcy.ny << "*"
+ << darcy.nz << std::endl;
+ std::cout << " - Fluid grid cell size: "
+ << darcy.dx << "*"
+ << darcy.dy << "*"
+ << darcy.dz << std::endl;
+ }
+}
+
+// Write values in scalar field to file
+void DEM::writeDarcyArray(Float* array, const char* filename)
+{
+ FILE* file;
+ if ((file = fopen(filename,"w"))) {
+ printDarcyArray(file, array);
+ fclose(file);
+ } else {
+ fprintf(stderr, "Error, could not open %s.\n", filename);
+ }
+}
+
+// Write values in vector field to file
+void DEM::writeDarcyArray(Float3* array, const char* filename)
+{
+ FILE* file;
+ if ((file = fopen(filename,"w"))) {
+ printDarcyArray(file, array);
+ fclose(file);
+ } else {
+ fprintf(stderr, "Error, could not open %s.\n", filename);
+ }
+}
+
+
+// Print final heads and free memory
+void DEM::endDarcy()
+{
+ // Write arrays to stdout/text files for debugging
+ //writeDarcyArray(darcy.phi, "ns_phi.txt");
+
+ freeDarcyMem();
+}
+
+// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/src/darcy.cuh b/src/darcy.cuh
t@@ -0,0 +1,1025 @@
+// darcy.cuh
+// CUDA implementation of Darcy porous flow
+
+#include <iostream>
+#include <cuda.h>
+//#include <cutil_math.h>
+#include <helper_math.h>
+
+#include "vector_arithmetic.h" // for arbitrary precision vectors
+#include "sphere.h"
+#include "datatypes.h"
+#include "utility.h"
+#include "constants.cuh"
+#include "debug.h"
+
+// Initialize memory
+void DEM::initDarcyMemDev(void)
+{
+ // size of scalar field
+ unsigned int memSizeF = sizeof(Float)*darcyCells();
+
+ // size of cell-face arrays in staggered grid discretization
+ //unsigned int memSizeFface = sizeof(Float)*darcyCellsVelocity();
+
+ cudaMalloc((void**)&dev_darcy_dpdt, memSizeF); // Backwards Euler gradient
+ cudaMalloc((void**)&dev_darcy_p_old, memSizeF); // old pressure
+ cudaMalloc((void**)&dev_darcy_p, memSizeF); // hydraulic pressure
+ cudaMalloc((void**)&dev_darcy_p_new, memSizeF); // updated pressure
+ cudaMalloc((void**)&dev_darcy_v, memSizeF*3); // cell hydraulic velocity
+ //cudaMalloc((void**)&dev_darcy_vp_avg, memSizeF*3); // avg. particle velo…
+ //cudaMalloc((void**)&dev_darcy_d_avg, memSizeF); // avg. particle diameter
+ cudaMalloc((void**)&dev_darcy_phi, memSizeF); // cell porosity
+ cudaMalloc((void**)&dev_darcy_dphi, memSizeF); // cell porosity change
+ cudaMalloc((void**)&dev_darcy_norm, memSizeF); // normalized residual
+ cudaMalloc((void**)&dev_darcy_f_p, sizeof(Float4)*np); // pressure force
+ cudaMalloc((void**)&dev_darcy_k, memSizeF); // hydraulic permeabili…
+ cudaMalloc((void**)&dev_darcy_grad_k, memSizeF*3); // grad(permeability)
+ //cudaMalloc((void**)&dev_darcy_div_v_p, memSizeF3); // divergence(v_p)
+
+ checkForCudaErrors("End of initDarcyMemDev");
+}
+
+// Free memory
+void DEM::freeDarcyMemDev()
+{
+ cudaFree(dev_darcy_dpdt);
+ cudaFree(dev_darcy_p_old);
+ cudaFree(dev_darcy_p);
+ cudaFree(dev_darcy_p_new);
+ cudaFree(dev_darcy_v);
+ //cudaFree(dev_darcy_vp_avg);
+ //cudaFree(dev_darcy_d_avg);
+ cudaFree(dev_darcy_phi);
+ cudaFree(dev_darcy_dphi);
+ cudaFree(dev_darcy_norm);
+ cudaFree(dev_darcy_f_p);
+ cudaFree(dev_darcy_k);
+ cudaFree(dev_darcy_grad_k);
+ //cudaFree(dev_darcy_div_v_p);
+}
+
+// Transfer to device
+void DEM::transferDarcyToGlobalDeviceMemory(int statusmsg)
+{
+ checkForCudaErrors("Before attempting cudaMemcpy in "
+ "transferDarcyToGlobalDeviceMemory");
+
+ //if (verbose == 1 && statusmsg == 1)
+ //std::cout << " Transfering fluid data to the device: ";
+
+ // memory size for a scalar field
+ unsigned int memSizeF = sizeof(Float)*darcyCells();
+
+ //writeNSarray(ns.p, "ns.p.txt");
+
+ cudaMemcpy(dev_darcy_p, darcy.p, memSizeF, cudaMemcpyHostToDevice);
+ checkForCudaErrors("transferDarcytoGlobalDeviceMemory after first "
+ "cudaMemcpy");
+ cudaMemcpy(dev_darcy_v, darcy.v, memSizeF*3, cudaMemcpyHostToDevice);
+ cudaMemcpy(dev_darcy_phi, darcy.phi, memSizeF, cudaMemcpyHostToDevice);
+ cudaMemcpy(dev_darcy_dphi, darcy.dphi, memSizeF, cudaMemcpyHostToDevice);
+ cudaMemcpy(dev_darcy_f_p, darcy.f_p, sizeof(Float4)*np,
+ cudaMemcpyHostToDevice);
+
+ checkForCudaErrors("End of transferDarcyToGlobalDeviceMemory");
+ //if (verbose == 1 && statusmsg == 1)
+ //std::cout << "Done" << std::endl;
+}
+
+// Transfer from device
+void DEM::transferDarcyFromGlobalDeviceMemory(int statusmsg)
+{
+ if (verbose == 1 && statusmsg == 1)
+ std::cout << " Transfering fluid data from the device: ";
+
+ // memory size for a scalar field
+ unsigned int memSizeF = sizeof(Float)*darcyCells();
+
+ cudaMemcpy(darcy.p, dev_darcy_p, memSizeF, cudaMemcpyDeviceToHost);
+ checkForCudaErrors("In transferDarcyFromGlobalDeviceMemory, dev_darcy_p", …
+ cudaMemcpy(darcy.v, dev_darcy_v, memSizeF*3, cudaMemcpyDeviceToHost);
+ cudaMemcpy(darcy.phi, dev_darcy_phi, memSizeF, cudaMemcpyDeviceToHost);
+ cudaMemcpy(darcy.dphi, dev_darcy_dphi, memSizeF, cudaMemcpyDeviceToHost);
+ cudaMemcpy(darcy.f_p, dev_darcy_f_p, sizeof(Float4)*np,
+ cudaMemcpyDeviceToHost);
+ cudaMemcpy(darcy.k, dev_darcy_k, memSizeF, cudaMemcpyDeviceToHost);
+
+ checkForCudaErrors("End of transferDarcyFromGlobalDeviceMemory", 0);
+ if (verbose == 1 && statusmsg == 1)
+ std::cout << "Done" << std::endl;
+}
+
+// Transfer the normalized residuals from device to host
+void DEM::transferDarcyNormFromGlobalDeviceMemory()
+{
+ cudaMemcpy(darcy.norm, dev_darcy_norm, sizeof(Float)*darcyCells(),
+ cudaMemcpyDeviceToHost);
+ checkForCudaErrors("End of transferDarcyNormFromGlobalDeviceMemory");
+}
+
+// Transfer the pressures from device to host
+void DEM::transferDarcyPressuresFromGlobalDeviceMemory()
+{
+ cudaMemcpy(darcy.p, dev_darcy_p, sizeof(Float)*darcyCells(),
+ cudaMemcpyDeviceToHost);
+ checkForCudaErrors("End of transferDarcyNormFromGlobalDeviceMemory");
+}
+
+// Get linear index from 3D grid position
+__inline__ __device__ unsigned int d_idx(
+ const int x, const int y, const int z)
+{
+ // without ghost nodes
+ //return x + dev_grid.num[0]*y + dev_grid.num[0]*dev_grid.num[1]*z;
+
+ // with ghost nodes
+ // the ghost nodes are placed at x,y,z = -1 and WIDTH
+ return (x+1) + (devC_grid.num[0]+2)*(y+1) +
+ (devC_grid.num[0]+2)*(devC_grid.num[1]+2)*(z+1);
+}
+
+// Get linear index of velocity node from 3D grid position in staggered grid
+__inline__ __device__ unsigned int d_vidx(
+ const int x, const int y, const int z)
+{
+ // without ghost nodes
+ //return x + (devC_grid.num[0]+1)*y
+ //+ (devC_grid.num[0]+1)*(devC_grid.num[1]+1)*z;
+
+ // with ghost nodes
+ // the ghost nodes are placed at x,y,z = -1 and WIDTH+1
+ return (x+1) + (devC_grid.num[0]+3)*(y+1)
+ + (devC_grid.num[0]+3)*(devC_grid.num[1]+3)*(z+1);
+}
+
+// The normalized residuals are given an initial value of 0, since the values …
+// the Dirichlet boundaries aren't written during the iterations.
+__global__ void setDarcyNormZero(
+ Float* __restrict__ dev_darcy_norm)
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // check that we are not outside the fluid grid
+ if (x < devC_grid.num[0] && y < devC_grid.num[1] && z < devC_grid.num[2]) {
+ __syncthreads();
+ dev_darcy_norm[d_idx(x,y,z)] = 0.0;
+ }
+}
+
+// Update a field in the ghost nodes from their parent cell values. The edge
+// (diagonal) cells are not written since they are not read. Launch this kernel
+// for all cells in the grid using
+// setDarcyGhostNodes<datatype><<<.. , ..>>>( .. );
+ template<typename T>
+__global__ void setDarcyGhostNodes(
+ T* __restrict__ dev_scalarfield,
+ const int bc_bot,
+ const int bc_top)
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // Grid dimensions
+ const unsigned int nx = devC_grid.num[0];
+ const unsigned int ny = devC_grid.num[1];
+ const unsigned int nz = devC_grid.num[2];
+
+ // check that we are not outside the fluid grid
+ if (x < nx && y < ny && z < nz) {
+
+ const T val = dev_scalarfield[d_idx(x,y,z)];
+
+ // x
+ if (x == 0)
+ dev_scalarfield[idx(nx,y,z)] = val;
+ if (x == nx-1)
+ dev_scalarfield[idx(-1,y,z)] = val;
+
+ // y
+ if (y == 0)
+ dev_scalarfield[idx(x,ny,z)] = val;
+ if (y == ny-1)
+ dev_scalarfield[idx(x,-1,z)] = val;
+
+ // z
+ if (z == 0 && bc_bot == 0)
+ dev_scalarfield[idx(x,y,-1)] = val; // Dirichlet
+ if (z == 0 && bc_bot == 1)
+ dev_scalarfield[idx(x,y,-1)] = val; // Neumann
+ if (z == 0 && bc_bot == 2)
+ dev_scalarfield[idx(x,y,nz)] = val; // Periodic -z
+
+ if (z == nz-1 && bc_top == 0)
+ dev_scalarfield[idx(x,y,nz)] = val; // Dirichlet
+ if (z == nz-2 && bc_top == 1)
+ dev_scalarfield[idx(x,y,nz)] = val; // Neumann
+ if (z == nz-1 && bc_top == 2)
+ dev_scalarfield[idx(x,y,-1)] = val; // Periodic +z
+ }
+}
+
+// Find the porosity in each cell on the base of a sphere, centered at the cell
+// center.
+__global__ void findDarcyPorosities(
+ const unsigned int* __restrict__ dev_cellStart, // in
+ const unsigned int* __restrict__ dev_cellEnd, // in
+ const Float4* __restrict__ dev_x_sorted, // in
+ const unsigned int iteration, // in
+ const unsigned int np, // in
+ const Float c_phi, // in
+ Float* __restrict__ dev_darcy_phi, // in + out
+ Float* __restrict__ dev_darcy_dphi) // out
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // Grid dimensions
+ const unsigned int nx = devC_grid.num[0];
+ const unsigned int ny = devC_grid.num[1];
+ const unsigned int nz = devC_grid.num[2];
+
+ // Cell dimensions
+ const Float dx = devC_grid.L[0]/nx;
+ const Float dy = devC_grid.L[1]/ny;
+ const Float dz = devC_grid.L[2]/nz;
+
+ // Cell sphere radius
+ //const Float R = fmin(dx, fmin(dy,dz)) * 0.5; // diameter = cell width
+ const Float R = fmin(dx, fmin(dy,dz)); // diameter = 2*cell width
+ const Float cell_volume = 4.0/3.0*M_PI*R*R*R;
+
+ Float void_volume = cell_volume;
+ Float4 xr; // particle pos. and radius
+
+ // check that we are not outside the fluid grid
+ if (x < nx && y < ny && z < nz) {
+
+ if (np > 0) {
+
+ // Cell sphere center position
+ const Float3 X = MAKE_FLOAT3(
+ x*dx + 0.5*dx,
+ y*dy + 0.5*dy,
+ z*dz + 0.5*dz);
+
+ Float d, r;
+ Float phi = 1.00;
+ //Float4 v;
+ unsigned int n = 0;
+
+ //Float3 v_avg = MAKE_FLOAT3(0.0, 0.0, 0.0);
+ //Float d_avg = 0.0;
+
+ // Read old porosity
+ __syncthreads();
+ Float phi_0 = dev_darcy_phi[d_idx(x,y,z)];
+
+ // The cell 3d index
+ const int3 gridPos = make_int3((int)x,(int)y,(int)z);
+
+ // The neighbor cell 3d index
+ int3 targetCell;
+
+ // The distance modifier for particles across periodic boundaries
+ Float3 dist, distmod;
+
+ unsigned int cellID, startIdx, endIdx, i;
+
+ // Iterate over 27 neighbor cells, R = cell width
+ /*for (int z_dim=-1; z_dim<2; ++z_dim) // z-axis
+ for (int y_dim=-1; y_dim<2; ++y_dim) // y-axis
+ for (int x_dim=-1; x_dim<2; ++x_dim) // x-axis*/
+
+ // Iterate over 27 neighbor cells, R = 2*cell width
+ for (int z_dim=-2; z_dim<3; ++z_dim) { // z-axis
+ for (int y_dim=-2; y_dim<3; ++y_dim) { // y-axis
+ for (int x_dim=-2; x_dim<3; ++x_dim) { // x-axis
+
+ // Index of neighbor cell this iteration is looking at
+ targetCell = gridPos + make_int3(x_dim, y_dim, z_dim);
+
+ // Get distance modifier for interparticle
+ // vector, if it crosses a periodic boundary
+ distmod = MAKE_FLOAT3(0.0, 0.0, 0.0);
+ if (findDistMod(&targetCell, &distmod) != -1) {
+
+ // Calculate linear cell ID
+ cellID = targetCell.x
+ + targetCell.y * devC_grid.num[0]
+ + (devC_grid.num[0] * devC_grid.num[1])
+ * targetCell.z;
+
+ // Lowest particle index in cell
+ __syncthreads();
+ startIdx = dev_cellStart[cellID];
+
+ // Make sure cell is not empty
+ if (startIdx != 0xffffffff) {
+
+ // Highest particle index in cell
+ __syncthreads();
+ endIdx = dev_cellEnd[cellID];
+
+ // Iterate over cell particles
+ for (i=startIdx; i<endIdx; ++i) {
+
+ // Read particle position and radius
+ __syncthreads();
+ xr = dev_x_sorted[i];
+ //v = dev_vel_sorted[i];
+ r = xr.w;
+
+ // Find center distance
+ dist = MAKE_FLOAT3(
+ X.x - xr.x,
+ X.y - xr.y,
+ X.z - xr.z);
+ dist += distmod;
+ d = length(dist);
+
+ // Lens shaped intersection
+ if ((R - r) < d && d < (R + r)) {
+ void_volume -=
+ 1.0/(12.0*d) * (
+ M_PI*(R + r - d)*(R + r - …
+ *(d*d + 2.0*d*r - 3.0*r*r
+ + 2.0*d*R + 6.0*r*R
+ - 3.0*R*R) );
+ //v_avg += MAKE_FLOAT3(v.x, v.y, v.z);
+ //d_avg += r+r;
+ n++;
+ }
+
+ // Particle fully contained in cell sphere
+ if (d <= R - r) {
+ void_volume -= 4.0/3.0*M_PI*r*r*r;
+ //v_avg += MAKE_FLOAT3(v.x, v.y, v.z);
+ //d_avg += r+r;
+ n++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //if (phi < 0.999) {
+ //v_avg /= n;
+ //d_avg /= n;
+ //}
+
+ // Make sure that the porosity is in the interval [0.0;1.0]
+ phi = fmin(0.99, fmax(0.01, void_volume/cell_volume));
+ //phi = void_volume/cell_volume;
+
+ Float dphi = phi - phi_0;
+ if (iteration == 0)
+ dphi = 0.0;
+
+ // report values to stdout for debugging
+ //printf("%d,%d,%d\tphi = %f dphi = %f\n", x,y,z, phi, dphi);
+ //printf("%d,%d,%d\tphi = %f dphi = %f v_avg = %f,%f,%f d_avg = %f…
+ // x,y,z, phi, dphi, v_avg.x, v_avg.y, v_avg.z, d_avg);
+
+ // Save porosity and porosity change
+ __syncthreads();
+ //phi = 0.5; dphi = 0.0; // disable porosity effects
+ const unsigned int cellidx = d_idx(x,y,z);
+ dev_darcy_phi[cellidx] = phi*c_phi;
+ dev_darcy_dphi[cellidx] = dphi*c_phi;
+ //dev_darcy_vp_avg[cellidx] = v_avg;
+ //dev_darcy_d_avg[cellidx] = d_avg;
+
+#ifdef CHECK_FLUID_FINITE
+ (void)checkFiniteFloat("phi", x, y, z, phi);
+ (void)checkFiniteFloat("dphi", x, y, z, dphi);
+ //(void)checkFiniteFloat3("v_avg", x, y, z, v_avg);
+ //(void)checkFiniteFloat("d_avg", x, y, z, d_avg);
+#endif
+ } else {
+
+ __syncthreads();
+ const unsigned int cellidx = d_idx(x,y,z);
+
+ //Float phi = 0.5;
+ //Float dphi = 0.0;
+ //if (iteration == 20 && x == nx/2 && y == ny/2 && z == nz/2) {
+ //phi = 0.4;
+ //dphi = 0.1;
+ //}
+ //dev_darcy_phi[cellidx] = phi;
+ //dev_darcy_dphi[cellidx] = dphi;
+ dev_darcy_phi[cellidx] = 0.999;
+ dev_darcy_dphi[cellidx] = 0.0;
+
+ //dev_darcy_vp_avg[cellidx] = MAKE_FLOAT3(0.0, 0.0, 0.0);
+ //dev_darcy_d_avg[cellidx] = 0.0;
+ }
+ }
+}
+
+// Find the particle velocity divergence at the cell center from the average
+// particle velocities on the cell faces
+__global__ void findDarcyParticleVelocityDivergence(
+ const Float* __restrict__ dev_darcy_v_p_x, // in
+ const Float* __restrict__ dev_darcy_v_p_y, // in
+ const Float* __restrict__ dev_darcy_v_p_z, // in
+ Float* __restrict__ dev_darcy_div_v_p) // out
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // Grid dimensions
+ const unsigned int nx = devC_grid.num[0];
+ const unsigned int ny = devC_grid.num[1];
+ const unsigned int nz = devC_grid.num[2];
+
+ if (x < nx && y < ny && z < nz) {
+
+ // read values
+ __syncthreads();
+ Float v_p_xn = dev_darcy_v_p_x[d_vidx(x,y,z)];
+ Float v_p_xp = dev_darcy_v_p_x[d_vidx(x+1,y,z)];
+ Float v_p_yn = dev_darcy_v_p_y[d_vidx(x,y,z)];
+ Float v_p_yp = dev_darcy_v_p_y[d_vidx(x,y+1,z)];
+ Float v_p_zn = dev_darcy_v_p_z[d_vidx(x,y,z)];
+ Float v_p_zp = dev_darcy_v_p_z[d_vidx(x,y,z+1)];
+
+ // cell dimensions
+ const Float dx = devC_grid.L[0]/nx;
+ const Float dy = devC_grid.L[1]/ny;
+ const Float dz = devC_grid.L[2]/nz;
+
+ // calculate the divergence using first order central finite differenc…
+ const Float div_v_p =
+ (v_p_xp - v_p_xn)/dx +
+ (v_p_yp - v_p_yn)/dy +
+ (v_p_zp - v_p_zn)/dz;
+
+ __syncthreads();
+ dev_darcy_div_v_p[d_idx(x,y,z)] = div_v_p;
+
+#ifdef CHECK_FLUID_FINITE
+ checkFiniteFloat("div_v_p", x, y, z, div_v_p);
+#endif
+ }
+}
+
+// Find particle-fluid interaction force as outlined by Zhou et al. 2010, and
+// originally by Gidaspow 1992. All terms other than the pressure force are
+// neglected. The buoyancy force is included.
+__global__ void findDarcyPressureForce(
+ const Float4* __restrict__ dev_x, // in
+ const Float* __restrict__ dev_darcy_p, // in
+ const Float* __restrict__ dev_darcy_phi, // in
+ Float4* __restrict__ dev_force, // out
+ Float4* __restrict__ dev_darcy_f_p) // out
+{
+ unsigned int i = threadIdx.x + blockIdx.x*blockDim.x; // Particle index
+
+ if (i < devC_np) {
+
+ // read particle information
+ __syncthreads();
+ const Float4 x = dev_x[i];
+
+ // determine fluid cell containing the particle
+ const unsigned int i_x =
+ floor((x.x - devC_grid.origo[0])/(devC_grid.L[0]/devC_grid.num[0])…
+ const unsigned int i_y =
+ floor((x.y - devC_grid.origo[1])/(devC_grid.L[1]/devC_grid.num[1])…
+ const unsigned int i_z =
+ floor((x.z - devC_grid.origo[2])/(devC_grid.L[2]/devC_grid.num[2])…
+ const unsigned int cellidx = d_idx(i_x, i_y, i_z);
+
+ // determine cell dimensions
+ const Float dx = devC_grid.L[0]/devC_grid.num[0];
+ const Float dy = devC_grid.L[1]/devC_grid.num[1];
+ const Float dz = devC_grid.L[2]/devC_grid.num[2];
+
+ // read fluid information
+ __syncthreads();
+ const Float phi = dev_darcy_phi[cellidx];
+ const Float p_xn = dev_darcy_p[d_idx(i_x-1,i_y,i_z)];
+ //const Float p = dev_darcy_p[cellidx];
+ const Float p_xp = dev_darcy_p[d_idx(i_x+1,i_y,i_z)];
+ const Float p_yn = dev_darcy_p[d_idx(i_x,i_y-1,i_z)];
+ const Float p_yp = dev_darcy_p[d_idx(i_x,i_y+1,i_z)];
+ const Float p_zn = dev_darcy_p[d_idx(i_x,i_y,i_z-1)];
+ const Float p_zp = dev_darcy_p[d_idx(i_x,i_y,i_z+1)];
+
+ // find particle volume (radius in x.w)
+ const Float V = 4.0/3.0*M_PI*x.w*x.w*x.w;
+
+ // determine pressure gradient from first order central difference
+ const Float3 grad_p = MAKE_FLOAT3(
+ (p_xp - p_xn)/(dx + dx),
+ (p_yp - p_yn)/(dy + dy),
+ (p_zp - p_zn)/(dz + dz));
+
+ // find pressure gradient force plus buoyancy force.
+ // buoyancy force = weight of displaced fluid
+ // f_b = -rho_f*V*g
+ const Float3 f_p = -1.0*grad_p*V/(1.0 - phi);
+ //- devC_params.rho_f*V*MAKE_FLOAT3(
+ //devC_params.g[0],
+ //devC_params.g[1],
+ //devC_params.g[2]);
+
+ /*printf("%d,%d,%d findPF:\n"
+ "\tphi = %f\n"
+ "\tp = %f\n"
+ "\tgrad_p = % f, % f, % f\n"
+ "\tf_p = % f, % f, % f\n",
+ i_x, i_y, i_z,
+ phi, p,
+ grad_p.x, grad_p.y, grad_p.z,
+ f_p.x, f_p.y, f_p.z);*/
+
+#ifdef CHECK_FLUID_FINITE
+ checkFiniteFloat3("f_p", i_x, i_y, i_z, f_p);
+#endif
+ // save force
+ __syncthreads();
+ dev_force[i] += MAKE_FLOAT4(f_p.x, f_p.y, f_p.z, 0.0);
+ dev_darcy_f_p[i] = MAKE_FLOAT4(f_p.x, f_p.y, f_p.z, 0.0);
+ }
+}
+
+// Set the pressure at the top boundary to new_pressure
+__global__ void setDarcyTopPressure(
+ const Float new_pressure, Float* __restrict__ dev_darcy_p)
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // check that the thread is located at the top boundary
+ if (x < devC_grid.num[0] &&
+ y < devC_grid.num[1] &&
+ z == devC_grid.num[2]-1) {
+
+ const unsigned int cellidx = idx(x,y,z);
+
+ // Write the new pressure the top boundary cells
+ __syncthreads();
+ dev_darcy_p[cellidx] = new_pressure;
+ }
+}
+
+// Set the pressure at the top wall to new_pressure
+__global__ void setDarcyTopWallPressure(
+ const Float new_pressure,
+ const unsigned int wall0_iz,
+ Float* __restrict__ dev_darcy_p)
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // check that the thread is located at the top boundary
+ if (x < devC_grid.num[0] &&
+ y < devC_grid.num[1] &&
+ z == wall0_iz) {
+
+ const unsigned int cellidx = idx(x,y,z);
+
+ // Write the new pressure the top boundary cells
+ __syncthreads();
+ dev_darcy_p[cellidx] = new_pressure;
+ }
+}
+
+
+// Find the cell permeabilities from the Kozeny-Carman equation
+__global__ void findDarcyPermeabilities(
+ const Float k_c, // in
+ const Float* __restrict__ dev_darcy_phi, // in
+ Float* __restrict__ dev_darcy_k) // out
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // Grid dimensions
+ const unsigned int nx = devC_grid.num[0];
+ const unsigned int ny = devC_grid.num[1];
+ const unsigned int nz = devC_grid.num[2];
+
+ if (x < nx && y < ny && z < nz) {
+
+ // 1D thread index
+ const unsigned int cellidx = d_idx(x,y,z);
+
+ __syncthreads();
+ Float phi = dev_darcy_phi[cellidx];
+
+ // avoid division by zero
+ if (phi > 0.9999)
+ phi = 0.9999;
+
+ Float k = k_c*pow(phi,3)/pow(1.0 - phi, 2);
+
+ /*printf("%d,%d,%d findK:\n"
+ "\tphi = %f\n"
+ "\tk = %e\n",
+ x, y, z,
+ phi, k);*/
+
+ // limit permeability [m*m]
+ // K_gravel = 3.0e-2 m/s => k_gravel = 2.7e-9 m*m
+ k = fmin(2.7e-9, k);
+
+ __syncthreads();
+ dev_darcy_k[cellidx] = k;
+
+#ifdef CHECK_FLUID_FINITE
+ checkFiniteFloat("k", x, y, z, k);
+#endif
+ }
+}
+
+// Find the spatial gradients of the permeability. To be used in the pressure
+// diffusion term in updateDarcySolution.
+__global__ void findDarcyPermeabilityGradients(
+ const Float* __restrict__ dev_darcy_k, // in
+ Float3* __restrict__ dev_darcy_grad_k) // out
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // Grid dimensions
+ const unsigned int nx = devC_grid.num[0];
+ const unsigned int ny = devC_grid.num[1];
+ const unsigned int nz = devC_grid.num[2];
+
+ // Cell size
+ const Float dx = devC_grid.L[0]/nx;
+ const Float dy = devC_grid.L[1]/ny;
+ const Float dz = devC_grid.L[2]/nz;
+
+ if (x < nx && y < ny && z < nz) {
+
+ // 1D thread index
+ const unsigned int cellidx = d_idx(x,y,z);
+
+ // read values
+ __syncthreads();
+ const Float k_xn = dev_darcy_k[d_idx(x-1,y,z)];
+ const Float k_xp = dev_darcy_k[d_idx(x+1,y,z)];
+ const Float k_yn = dev_darcy_k[d_idx(x,y-1,z)];
+ const Float k_yp = dev_darcy_k[d_idx(x,y+1,z)];
+ const Float k_zn = dev_darcy_k[d_idx(x,y,z-1)];
+ const Float k_zp = dev_darcy_k[d_idx(x,y,z+1)];
+
+ // gradient approximated by first-order central difference
+ const Float3 grad_k = MAKE_FLOAT3(
+ (k_xp - k_xn)/(dx+dx),
+ (k_yp - k_yn)/(dy+dy),
+ (k_zp - k_zn)/(dz+dz));
+
+ // write result
+ __syncthreads();
+ dev_darcy_grad_k[cellidx] = grad_k;
+
+ /*printf("%d,%d,%d findK:\n"
+ "\tk_x = %e, %e\n"
+ "\tk_y = %e, %e\n"
+ "\tk_z = %e, %e\n"
+ "\tgrad(k) = %e, %e, %e\n",
+ x, y, z,
+ k_xn, k_xp,
+ k_yn, k_yp,
+ k_zn, k_zp,
+ grad_k.x, grad_k.y, grad_k.z);*/
+
+#ifdef CHECK_FLUID_FINITE
+ checkFiniteFloat3("grad_k", x, y, z, grad_k);
+#endif
+ }
+}
+
+// Find the temporal gradient in pressure using the backwards Euler method
+__global__ void findDarcyPressureChange(
+ const Float* __restrict__ dev_darcy_p_old,
+ const Float* __restrict__ dev_darcy_p,
+ const unsigned int iter,
+ Float* __restrict__ dev_darcy_dpdt)
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ if (x < devC_grid.num[0] && y < devC_grid.num[1] && z < devC_grid.num[2]) {
+
+ // 1D thread index
+ const unsigned int cellidx = d_idx(x,y,z);
+
+ // read values
+ __syncthreads();
+ const Float p_old = dev_darcy_p_old[cellidx];
+ const Float p = dev_darcy_p[cellidx];
+
+ Float dpdt = (p - p_old)/devC_dt;
+
+ // Ignore the large initial pressure gradients caused by solver "warm
+ // up" towards hydrostatic pressure distribution
+ if (iter < 2)
+ dpdt = 0.0;
+
+ // write result
+ __syncthreads();
+ dev_darcy_dpdt[cellidx] = dpdt;
+
+ /*printf("%d,%d,%d\n"
+ "\tp_old = %e\n"
+ "\tp = %e\n"
+ "\tdt = %e\n"
+ "\tdpdt = %e\n",
+ x,y,z,
+ p_old, p,
+ devC_dt, dpdt);*/
+
+#ifdef CHECK_FLUID_FINITE
+ checkFiniteFloat("dpdt", x, y, z, dpdt);
+#endif
+ }
+}
+
+// A single jacobi iteration where the pressure values are updated to
+// dev_darcy_p_new.
+// bc = 0: Dirichlet, 1: Neumann
+__global__ void updateDarcySolution(
+ const Float* __restrict__ dev_darcy_p_old, // in
+ //const Float* __restrict__ dev_darcy_dpdt, // in
+ const Float* __restrict__ dev_darcy_p, // in
+ const Float* __restrict__ dev_darcy_k, // in
+ const Float* __restrict__ dev_darcy_phi, // in
+ const Float* __restrict__ dev_darcy_dphi, // in
+ const Float3* __restrict__ dev_darcy_grad_k, // in
+ const Float beta_f, // in
+ const Float mu, // in
+ const int bc_bot, // in
+ const int bc_top, // in
+ const unsigned int ndem, // in
+ const unsigned int wall0_iz, // in
+ Float* __restrict__ dev_darcy_p_new, // out
+ Float* __restrict__ dev_darcy_norm) // out
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // Grid dimensions
+ const unsigned int nx = devC_grid.num[0];
+ const unsigned int ny = devC_grid.num[1];
+ const unsigned int nz = devC_grid.num[2];
+
+ // Cell size
+ const Float dx = devC_grid.L[0]/nx;
+ const Float dy = devC_grid.L[1]/ny;
+ const Float dz = devC_grid.L[2]/nz;
+
+ if (x < nx && y < ny && z < nz) {
+
+ // 1D thread index
+ const unsigned int cellidx = d_idx(x,y,z);
+
+ // read values
+ __syncthreads();
+ const Float k = dev_darcy_k[cellidx];
+ const Float3 grad_k = dev_darcy_grad_k[cellidx];
+ const Float phi = dev_darcy_phi[cellidx];
+ const Float dphi = dev_darcy_dphi[cellidx];
+
+ //const Float dpdt = dev_darcy_dpdt[cellidx];
+
+ const Float p_old = dev_darcy_p_old[cellidx];
+
+ const Float p_xn = dev_darcy_p[d_idx(x-1,y,z)];
+ const Float p = dev_darcy_p[cellidx];
+ const Float p_xp = dev_darcy_p[d_idx(x+1,y,z)];
+ const Float p_yn = dev_darcy_p[d_idx(x,y-1,z)];
+ const Float p_yp = dev_darcy_p[d_idx(x,y+1,z)];
+ Float p_zn = dev_darcy_p[d_idx(x,y,z-1)];
+ Float p_zp = dev_darcy_p[d_idx(x,y,z+1)];
+
+ // gradient approximated by first-order central difference
+ const Float3 grad_p = MAKE_FLOAT3(
+ (p_xp - p_xn)/(dx+dx),
+ (p_yp - p_yn)/(dy+dy),
+ (p_zp - p_zn)/(dz+dz));
+
+ const Float laplace_p =
+ (p_xp - (p+p) + p_xn)/(dx*dx) +
+ (p_yp - (p+p) + p_yn)/(dy*dy) +
+ (p_zp - (p+p) + p_zn)/(dz*dz);
+
+ // find forcing function value
+ /*const Float f_transient = beta_f*phi*mu/k*dpdt;
+ const Float f_forcing = mu/((1.0 - phi)*k)*dphi/devC_dt;
+ const Float f_diff = -1.0*dot(grad_p, grad_k)/k;
+ const Float f = f_transient + f_forcing + f_diff;*/
+
+ //const Float div_v_p = dev_darcy_div_v_p[cellidx];
+
+ // Neumann BCs
+ if (z == 0 && bc_bot == 1)
+ p_zn = p;
+ if (z == nz-1 && bc_top == 1)
+ p_zp = p;
+
+ // New value of epsilon in 3D update, derived by rearranging the
+ // 3d discrete finite difference Laplacian
+ /*const Float dxdx = dx*dx;
+ const Float dydy = dy*dy;
+ const Float dzdz = dz*dz;
+ Float p_new
+ = (-dxdx*dydy*dzdz*f
+ + dydy*dzdz*(p_xn + p_xp)
+ + dxdx*dzdz*(p_yn + p_yp)
+ + dxdx*dydy*(p_zn + p_zp))
+ /(2.0*(dxdx*dydy + dxdx*dzdz + dydy*dzdz));*/
+
+ Float p_new = p_old
+ + devC_dt/(beta_f*phi*mu)*(k*laplace_p + dot(grad_k, grad_p))
+ - dphi/(beta_f*phi*(1.0 - phi));
+
+ // Dirichlet BC at dynamic top wall. wall0_iz will be larger than the
+ // grid if the wall isn't dynamic
+ if (z == wall0_iz)
+ p_new = p;
+
+ // Neumann BC at dynamic top wall
+ //if (z == wall0_iz + 1)
+ //p_new = p_zn + dp_dz;
+
+ // Dirichlet BCs
+ if ((z == 0 && bc_bot == 0) ||
+ (z == nz-1 && bc_top == 0) ||
+ (z == wall0_iz))
+ p_new = p;
+
+ // normalized residual, avoid division by zero
+ //const Float res_norm = (p_new - p)*(p_new - p)/(p_new*p_new + 1.0e-1…
+ const Float res_norm = (p_new - p)/(p + 1.0e-16);
+
+#ifdef REPORT_FORCING_TERMS
+ printf("\n%d,%d,%d updateDarcySolution\n"
+ "dpdt = %e\n"
+ "p = %e\n"
+ "p_new = %e\n"
+ "f = %e\n"
+ "f_transient = %e\n"
+ "f_forcing = %e\n"
+ "f_diff = %e\n"
+ "res_norm = %e\n",
+ x,y,z,
+ dpdt,
+ p, p_new,
+ f,
+ f_transient, f_forcing, f_diff,
+ res_norm);
+#endif
+
+ // save new pressure and the residual
+ __syncthreads();
+ dev_darcy_p_new[cellidx] = p_new;
+ dev_darcy_norm[cellidx] = res_norm;
+
+ /*printf("%d,%d,%d\tp = % f\tp_new = % f\tres_norm = % f\n",
+ x,y,z,
+ p,
+ p_new,
+ res_norm);*/
+
+#ifdef CHECK_FLUID_FINITE
+ checkFiniteFloat("p_new", x, y, z, p_new);
+ checkFiniteFloat("res_norm", x, y, z, res_norm);
+#endif
+ }
+}
+
+__global__ void findNewPressure(
+ const Float* __restrict__ dev_darcy_dp, // in
+ Float* __restrict__ dev_darcy_p) // in+out
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // Grid dimensions
+ const unsigned int nx = devC_grid.num[0];
+ const unsigned int ny = devC_grid.num[1];
+ const unsigned int nz = devC_grid.num[2];
+
+ // Check that we are not outside the fluid grid
+ if (x < nx && y < ny && z < nz) {
+
+ const unsigned int cellidx = d_idx(x,y,z);
+
+ const Float dp = dev_darcy_dp[cellidx];
+
+ // save new pressure
+ __syncthreads();
+ dev_darcy_p[cellidx] += dp;
+
+ /*printf("%d,%d,%d\tp = % f\tp_new = % f\tres_norm = % f\n",
+ x,y,z,
+ p,
+ p_new,
+ res_norm);*/
+
+#ifdef CHECK_FLUID_FINITE
+ checkFiniteFloat("dp", x, y, z, dp);
+#endif
+ }
+}
+
+// Find cell velocities
+__global__ void findDarcyVelocities(
+ const Float* __restrict__ dev_darcy_p, // in
+ const Float* __restrict__ dev_darcy_phi, // in
+ const Float* __restrict__ dev_darcy_k, // in
+ const Float mu, // in
+ Float3* __restrict__ dev_darcy_v) // out
+{
+ // 3D thread index
+ const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
+ const unsigned int y = blockDim.y * blockIdx.y + threadIdx.y;
+ const unsigned int z = blockDim.z * blockIdx.z + threadIdx.z;
+
+ // Grid dimensions
+ const unsigned int nx = devC_grid.num[0];
+ const unsigned int ny = devC_grid.num[1];
+ const unsigned int nz = devC_grid.num[2];
+
+ // Cell size
+ const Float dx = devC_grid.L[0]/nx;
+ const Float dy = devC_grid.L[1]/ny;
+ const Float dz = devC_grid.L[2]/nz;
+
+ // Check that we are not outside the fluid grid
+ if (x < nx && y < ny && z < nz) {
+
+ const unsigned int cellidx = d_idx(x,y,z);
+
+ __syncthreads();
+ const Float p_xn = dev_darcy_p[d_idx(x-1,y,z)];
+ const Float p_xp = dev_darcy_p[d_idx(x+1,y,z)];
+ const Float p_yn = dev_darcy_p[d_idx(x,y-1,z)];
+ const Float p_yp = dev_darcy_p[d_idx(x,y+1,z)];
+ const Float p_zn = dev_darcy_p[d_idx(x,y,z-1)];
+ const Float p_zp = dev_darcy_p[d_idx(x,y,z+1)];
+
+ const Float k = dev_darcy_k[cellidx];
+ const Float phi = dev_darcy_phi[cellidx];
+
+ // approximate pressure gradient with first order central differences
+ const Float3 grad_p = MAKE_FLOAT3(
+ (p_xp - p_xn)/(dx + dx),
+ (p_yp - p_yn)/(dy + dy),
+ (p_zp - p_zn)/(dz + dz));
+
+ // Flux [m/s]: q = -k/nu * dH
+ // Pore velocity [m/s]: v = q/n
+
+ // calculate flux
+ //const Float3 q = -k/mu*grad_p;
+
+ // calculate velocity
+ //const Float3 v = q/phi;
+ const Float3 v = (-k/mu * grad_p)/phi;
+
+ // Save velocity
+ __syncthreads();
+ dev_darcy_v[cellidx] = v;
+ }
+}
+
+// Print final heads and free memory
+void DEM::endDarcyDev()
+{
+ freeDarcyMemDev();
+}
+
+// vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
diff --git a/src/datatypes.h b/src/datatypes.h
t@@ -96,8 +96,6 @@ struct Params {
Float tau_b; // Bond shear strength
Float devs_A; // Amplitude of modulations in normal stress
Float devs_f; // Frequency of modulations in normal stress
- Float mu; // Fluid dynamic viscosity
- Float rho_f; // Fluid density
};
// Structure containing wall parameters
t@@ -146,6 +144,35 @@ struct NavierStokes {
Float4* f_p; // Pressure force on particles
Float4* f_v; // Viscous force on particles
Float4* f_sum; // Viscous force on particles
+ Float mu; // Fluid dynamic viscosity
+ Float rho_f; // Fluid density
+};
+
+struct Darcy {
+ int nx, ny, nz; // Number of cells in each dimension
+ Float dx, dy, dz; // Cell length in each dim
+ Float* p; // Cell hydraulic pressures
+ Float3* v; // Cell fluid velocity
+ Float* k; // Cell hydraulic permeability
+ Float* phi; // Cell porosity
+ Float* dphi; // Cell porosity change
+ Float* norm; // Normalized residual of epsilon updates
+ Float p_mod_A; // Pressure modulation amplitude at top
+ Float p_mod_f; // Pressure modulation frequency at top
+ Float p_mod_phi; // Pressure modulation phase at top
+ int bc_bot; // 0: Dirichlet, 1: Neumann
+ int bc_top; // 0: Dirichlet, 1: Neumann
+ int free_slip_bot; // 0: no, 1: yes
+ int free_slip_top; // 0: no, 1: yes
+ Float tolerance; // Solver parameter: Max residual tolerance
+ unsigned int maxiter; // Solver parameter: Max iterations to perform
+ unsigned int ndem; // Solver parameter: DEM time steps per CFD step
+ Float c_phi; // Porosity scaling coefficient
+ Float4* f_p; // Pressure force on particles
+ Float beta_f; // Adiabatic fluid compressibility
+ Float k_c; // Permeability prefactor in Kozeny-Carman eq.
+ Float mu; // Fluid dynamic viscosity
+ Float rho_f; // Fluid density
};
// Image structure
diff --git a/src/debug.h b/src/debug.h
t@@ -20,7 +20,7 @@ const unsigned int nijacnorm = 10;
// 0: False, 1: True
const int write_res_log = 0;
-// Report epsilon values during Jacobi iterations to stdout
+// Report pressure (epsilon) values during Jacobi iterations to stdout
//#define REPORT_EPSILON
//#define REPORT_MORE_EPSILON
t@@ -30,15 +30,15 @@ const int write_res_log = 0;
const int write_conv_log = 1;
// The interval between iteration number reporting in 'output/<sid>-conv.log'
-//const int conv_log_interval = 10;
-const int conv_log_interval = 4;
+const int conv_log_interval = 10;
+//const int conv_log_interval = 4;
//const int conv_log_interval = 1;
// Enable drag force and particle fluid coupling
#define CFD_DEM_COUPLING
// Check for nan/inf values in fluid solver kernels
-#define CHECK_NS_FINITE
+#define CHECK_FLUID_FINITE
// Enable reporting of velocity prediction components to stdout
//#define REPORT_V_P_COMPONENTS
diff --git a/src/device.cu b/src/device.cu
t@@ -24,6 +24,7 @@
#include "integration.cuh"
#include "raytracer.cuh"
#include "navierstokes.cuh"
+#include "darcy.cuh"
// Returns the number of cores per streaming multiprocessor, which is
// a function of the device compute capability
t@@ -170,40 +171,65 @@ __global__ void checkConstantValues(int* dev_equal,
// Compare values between global- and constant
// memory structures
- if (dev_grid->origo[0] != devC_grid.origo[0] ||
- dev_grid->origo[1] != devC_grid.origo[1] ||
- dev_grid->origo[2] != devC_grid.origo[2] ||
- dev_grid->L[0] != devC_grid.L[0] ||
- dev_grid->L[1] != devC_grid.L[1] ||
- dev_grid->L[2] != devC_grid.L[2] ||
- dev_grid->num[0] != devC_grid.num[0] ||
- dev_grid->num[1] != devC_grid.num[1] ||
- dev_grid->num[2] != devC_grid.num[2] ||
- dev_grid->periodic != devC_grid.periodic)
- *dev_equal = 1; // Not ok
-
- else if (dev_params->g[0] != devC_params.g[0] ||
- dev_params->g[1] != devC_params.g[1] ||
- dev_params->g[2] != devC_params.g[2] ||
- dev_params->k_n != devC_params.k_n ||
- dev_params->k_t != devC_params.k_t ||
- dev_params->k_r != devC_params.k_r ||
- dev_params->gamma_n != devC_params.gamma_n ||
- dev_params->gamma_t != devC_params.gamma_t ||
- dev_params->gamma_r != devC_params.gamma_r ||
- dev_params->mu_s != devC_params.mu_s ||
- dev_params->mu_d != devC_params.mu_d ||
- dev_params->mu_r != devC_params.mu_r ||
- dev_params->rho != devC_params.rho ||
- dev_params->contactmodel != devC_params.contactmodel ||
- dev_params->kappa != devC_params.kappa ||
- dev_params->db != devC_params.db ||
- dev_params->V_b != devC_params.V_b ||
- dev_params->lambda_bar != devC_params.lambda_bar ||
- dev_params->nb0 != devC_params.nb0 ||
- dev_params->mu != devC_params.mu ||
- dev_params->rho_f != devC_params.rho_f)
+ if (dev_grid->origo[0] != devC_grid.origo[0])
+ *dev_equal = 1;
+ if (dev_grid->origo[1] != devC_grid.origo[1])
*dev_equal = 2; // Not ok
+ if (dev_grid->origo[2] != devC_grid.origo[2])
+ *dev_equal = 3; // Not ok
+ if (dev_grid->L[0] != devC_grid.L[0])
+ *dev_equal = 4; // Not ok
+ if (dev_grid->L[1] != devC_grid.L[1])
+ *dev_equal = 5; // Not ok
+ if (dev_grid->L[2] != devC_grid.L[2])
+ *dev_equal = 6; // Not ok
+ if (dev_grid->num[0] != devC_grid.num[0])
+ *dev_equal = 7; // Not ok
+ if (dev_grid->num[1] != devC_grid.num[1])
+ *dev_equal = 8; // Not ok
+ if (dev_grid->num[2] != devC_grid.num[2])
+ *dev_equal = 9; // Not ok
+ if (dev_grid->periodic != devC_grid.periodic)
+ *dev_equal = 10; // Not ok
+
+ if (dev_params->g[0] != devC_params.g[0])
+ *dev_equal = 11; // Not ok
+ if (dev_params->g[1] != devC_params.g[1])
+ *dev_equal = 12; // Not ok
+ if (dev_params->g[2] != devC_params.g[2])
+ *dev_equal = 13; // Not ok
+ if (dev_params->k_n != devC_params.k_n)
+ *dev_equal = 14; // Not ok
+ if (dev_params->k_t != devC_params.k_t)
+ *dev_equal = 15; // Not ok
+ if (dev_params->k_r != devC_params.k_r)
+ *dev_equal = 16; // Not ok
+ if (dev_params->gamma_n != devC_params.gamma_n)
+ *dev_equal = 17; // Not ok
+ if (dev_params->gamma_t != devC_params.gamma_t)
+ *dev_equal = 18; // Not ok
+ if (dev_params->gamma_r != devC_params.gamma_r)
+ *dev_equal = 19; // Not ok
+ if (dev_params->mu_s != devC_params.mu_s)
+ *dev_equal = 20; // Not ok
+ if (dev_params->mu_d != devC_params.mu_d)
+ *dev_equal = 21; // Not ok
+ if (dev_params->mu_r != devC_params.mu_r)
+ *dev_equal = 22; // Not ok
+ if (dev_params->rho != devC_params.rho)
+ *dev_equal = 23; // Not ok
+ if (dev_params->contactmodel != devC_params.contactmodel)
+ *dev_equal = 24; // Not ok
+ if (dev_params->kappa != devC_params.kappa)
+ *dev_equal = 25; // Not ok
+ if (dev_params->db != devC_params.db)
+ *dev_equal = 26; // Not ok
+ if (dev_params->V_b != devC_params.V_b)
+ *dev_equal = 27; // Not ok
+ if (dev_params->lambda_bar != devC_params.lambda_bar)
+ *dev_equal = 28; // Not ok
+ if (dev_params->nb0 != devC_params.nb0)
+ *dev_equal = 29; // Not ok
}
// Copy the constant data components to device memory,
t@@ -524,9 +550,12 @@ __host__ void DEM::freeGlobalDeviceMemory()
cudaFree(dev_walls_acc);
// Fluid arrays
- if (navierstokes == 1) {
+ if (fluid == 1 && cfd_solver == 0) {
freeNSmemDev();
}
+ if (fluid == 1 && cfd_solver == 1) {
+ freeDarcyMemDev();
+ }
//checkForCudaErrors("During cudaFree calls");
t@@ -604,11 +633,15 @@ __host__ void DEM::transferToGlobalDeviceMemory(int stat…
sizeof(Float4)*walls.nw, cudaMemcpyHostToDevice);
// Fluid arrays
- if (navierstokes == 1) {
- transferNStoGlobalDeviceMemory(1);
- } else if (navierstokes != 0) {
- std::cerr << "Error: navierstokes value not understood ("
- << navierstokes << ")" << std::endl;
+ if (fluid == 1) {
+ if (cfd_solver == 0) {
+ transferNStoGlobalDeviceMemory(1);
+ } else if (cfd_solver == 1) {
+ transferDarcyToGlobalDeviceMemory(1);
+ } else {
+ std::cerr << "Error: cfd_solver value not understood ("
+ << cfd_solver << ")" << std::endl;
+ }
}
checkForCudaErrors("End of transferToGlobalDeviceMemory");
t@@ -680,9 +713,13 @@ __host__ void DEM::transferFromGlobalDeviceMemory()
sizeof(Float4)*walls.nw, cudaMemcpyDeviceToHost);
// Fluid arrays
- if (navierstokes == 1) {
+ if (fluid == 1 && cfd_solver == 0) {
transferNSfromGlobalDeviceMemory(0);
}
+ else if (fluid == 1 && cfd_solver == 1) {
+ transferDarcyFromGlobalDeviceMemory(0);
+ checkDarcyStability();
+ }
//checkForCudaErrors("End of transferFromGlobalDeviceMemory");
}
t@@ -733,7 +770,7 @@ __host__ void DEM::startTime()
iDivUp(grid.num[0], dimBlockFluid.x),
iDivUp(grid.num[1], dimBlockFluid.y),
iDivUp(grid.num[2], dimBlockFluid.z));
- if (dimGridFluid.z > 64 && navierstokes == 1) {
+ if (dimGridFluid.z > 64 && fluid == 1) {
cerr << "Error: dimGridFluid.z > 64" << endl;
exit(1);
}
t@@ -744,7 +781,7 @@ __host__ void DEM::startTime()
iDivUp(grid.num[0]+1, dimBlockFluidFace.x),
iDivUp(grid.num[1]+1, dimBlockFluidFace.y),
iDivUp(grid.num[2]+1, dimBlockFluidFace.z));
- if (dimGridFluidFace.z > 64 && navierstokes == 1) {
+ if (dimGridFluidFace.z > 64 && fluid == 1) {
cerr << "Error: dimGridFluidFace.z > 64" << endl;
exit(1);
}
t@@ -766,7 +803,7 @@ __host__ void DEM::startTime()
<< dimBlock.x << "*" << dimBlock.y << "*" << dimBlock.z << "\n"
<< " - Shared memory required per block: " << smemSize << " bytes"
<< endl;
- if (navierstokes == 1) {
+ if (fluid == 1) {
cout << " - Blocks per fluid grid: "
<< dimGridFluid.x << "*" << dimGridFluid.y << "*" <<
dimGridFluid.z << "\n"
t@@ -832,6 +869,17 @@ __host__ void DEM::startTime()
double t_jacobiIterationNS = 0.0;
double t_updateNSvelocityPressure = 0.0;
+ double t_findDarcyPorosities = 0.0;
+ double t_setDarcyGhostNodes = 0.0;
+ double t_findDarcyPressureForce = 0.0;
+ double t_setDarcyTopPressure = 0.0;
+ double t_findDarcyPermeabilities = 0.0;
+ double t_findDarcyPermeabilityGradients = 0.0;
+ //double t_findDarcyPressureChange = 0.0;
+ double t_updateDarcySolution = 0.0;
+ double t_copyValues = 0.0;
+ double t_findDarcyVelocities = 0.0;
+
if (PROFILING == 1) {
cudaEventCreate(&kernel_tic);
cudaEventCreate(&kernel_toc);
t@@ -844,7 +892,11 @@ __host__ void DEM::startTime()
// Index of dynamic top wall (if it exists)
unsigned int wall0_iz = 10000000;
// weight of fluid between two cells in z direction
- const Float dp_dz = fabs(params.rho_f*params.g[2]*grid.L[2]/grid.num[2]);
+ Float dp_dz;
+ if (cfd_solver == 0)
+ dp_dz = fabs(ns.rho_f*params.g[2]*grid.L[2]/grid.num[2]);
+ else if (cfd_solver == 1)
+ dp_dz = fabs(darcy.rho_f*params.g[2]*grid.L[2]/grid.num[2]);
//std::cout << "dp_dz = " << dp_dz << std::endl;
// Write a log file of the number of iterations it took before
t@@ -1018,163 +1070,170 @@ __host__ void DEM::startTime()
}
}
- // Solve Navier Stokes flow through the grid
- if (navierstokes == 1) {
- checkForCudaErrorsIter("Before findPorositiesDev", iter);
- // Find cell porosities, average particle velocities, and average
- // particle diameters. These are needed for predicting the fluid
- // velocities
- if (PROFILING == 1)
- startTimer(&kernel_tic);
- findPorositiesVelocitiesDiametersSpherical
- //findPorositiesVelocitiesDiametersSphericalGradient
- <<<dimGridFluid, dimBlockFluid>>>(
- dev_cellStart,
- dev_cellEnd,
- dev_x_sorted,
- dev_vel_sorted,
- dev_ns_phi,
- dev_ns_dphi,
- dev_ns_vp_avg,
- dev_ns_d_avg,
- iter,
- np,
- ns.c_phi);
- cudaThreadSynchronize();
- if (PROFILING == 1)
- stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
- &t_findPorositiesDev);
- checkForCudaErrorsIter("Post findPorositiesDev", iter);
+ // Solve fluid flow through the grid
+ if (fluid == 1) {
-#ifdef CFD_DEM_COUPLING
- /*if (params.nu <= 0.0) {
- std::cerr << "Error! The fluid needs a positive viscosity "
- "value in order to simulate particle-fluid interaction."
- << std::endl;
- exit(1);
- }*/
- if (iter == 0) {
- // set cell center ghost nodes
- setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_v, ns.bc_bot, ns.bc_top);
+ // Navier-Stokes solution
+ if (cfd_solver == 0) {
- // find cell face velocities
- interpolateCenterToFace
- <<<dimGridFluidFace, dimBlockFluidFace>>>(
- dev_ns_v,
- dev_ns_v_x,
- dev_ns_v_y,
- dev_ns_v_z);
+ checkForCudaErrorsIter("Before findPorositiesDev", iter);
+ // Find cell porosities, average particle velocities, and aver…
+ // particle diameters. These are needed for predicting the flu…
+ // velocities
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findPorositiesVelocitiesDiametersSpherical
+ //findPorositiesVelocitiesDiametersSphericalGradient
+ <<<dimGridFluid, dimBlockFluid>>>(
+ dev_cellStart,
+ dev_cellEnd,
+ dev_x_sorted,
+ dev_vel_sorted,
+ dev_ns_phi,
+ dev_ns_dphi,
+ dev_ns_vp_avg,
+ dev_ns_d_avg,
+ iter,
+ np,
+ ns.c_phi);
cudaThreadSynchronize();
- checkForCudaErrors("Post interpolateCenterToFace");
- }
-
- setNSghostNodesFace<Float>
- <<<dimGridFluidFace, dimBlockFluidFace>>>(
- dev_ns_v_x,
- dev_ns_v_y,
- dev_ns_v_z,
- ns.bc_bot,
- ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSghostNodesFace", iter);
-
- findFaceDivTau<<<dimGridFluidFace, dimBlockFluidFace>>>(
- dev_ns_v_x,
- dev_ns_v_y,
- dev_ns_v_z,
- dev_ns_div_tau_x,
- dev_ns_div_tau_y,
- dev_ns_div_tau_z);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post findFaceDivTau", iter);
-
- setNSghostNodesFace<Float>
- <<<dimGridFluidFace, dimBlockFluid>>>(
- dev_ns_div_tau_x,
- dev_ns_div_tau_y,
- dev_ns_div_tau_z,
- ns.bc_bot,
- ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSghostNodes(dev_ns_div_tau)",
- iter);
-
- setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_p, ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSghostNodes(dev_ns_p)", iter);
-
- setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_phi, ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSghostNodes(dev_ns_p)", iter);
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_findPorositiesDev);
+ checkForCudaErrorsIter("Post findPorositiesDev", iter);
+#ifdef CFD_DEM_COUPLING
+ /*if (params.nu <= 0.0) {
+ std::cerr << "Error! The fluid needs a positive viscosity "
+ "value in order to simulate particle-fluid interaction."
+ << std::endl;
+ exit(1);
+ }*/
+ if (iter == 0) {
+ // set cell center ghost nodes
+ setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_v, ns.bc_bot, ns.bc_top);
+
+ // find cell face velocities
+ interpolateCenterToFace
+ <<<dimGridFluidFace, dimBlockFluidFace>>>(
+ dev_ns_v,
+ dev_ns_v_x,
+ dev_ns_v_y,
+ dev_ns_v_z);
+ cudaThreadSynchronize();
+ checkForCudaErrors("Post interpolateCenterToFace");
+ }
- if (np > 0) {
+ setNSghostNodesFace<Float>
+ <<<dimGridFluidFace, dimBlockFluidFace>>>(
+ dev_ns_v_x,
+ dev_ns_v_y,
+ dev_ns_v_z,
+ ns.bc_bot,
+ ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSghostNodesFace", iter);
- // Per particle, find the fluid-particle interaction force f_pf
- // and apply it to the particle
- findInteractionForce<<<dimGrid, dimBlock>>>(
- dev_x,
- dev_vel,
- dev_ns_phi,
- dev_ns_p,
+ findFaceDivTau<<<dimGridFluidFace, dimBlockFluidFace>>>(
dev_ns_v_x,
dev_ns_v_y,
dev_ns_v_z,
+ ns.mu,
dev_ns_div_tau_x,
dev_ns_div_tau_y,
- dev_ns_div_tau_z,
- //ns.c_v,
- dev_ns_f_pf,
- dev_force,
- dev_ns_f_d,
- dev_ns_f_p,
- dev_ns_f_v,
- dev_ns_f_sum);
+ dev_ns_div_tau_z);
cudaThreadSynchronize();
- checkForCudaErrorsIter("Post findInteractionForce", iter);
+ checkForCudaErrorsIter("Post findFaceDivTau", iter);
+
+ setNSghostNodesFace<Float>
+ <<<dimGridFluidFace, dimBlockFluid>>>(
+ dev_ns_div_tau_x,
+ dev_ns_div_tau_y,
+ dev_ns_div_tau_z,
+ ns.bc_bot,
+ ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSghostNodes(dev_ns_div_tau)",
+ iter);
setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
dev_ns_p, ns.bc_bot, ns.bc_top);
cudaThreadSynchronize();
checkForCudaErrorsIter("Post setNSghostNodes(dev_ns_p)", iter);
- // Apply fluid-particle interaction force to the fluid
- applyInteractionForceToFluid<<<dimGridFluid, dimBlockFluid>>>(
- dev_gridParticleIndex,
- dev_cellStart,
- dev_cellEnd,
- dev_ns_f_pf,
- dev_ns_F_pf);
- //dev_ns_F_pf_x,
- //dev_ns_F_pf_y,
- //dev_ns_F_pf_z);
+ setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_phi, ns.bc_bot, ns.bc_top);
cudaThreadSynchronize();
- checkForCudaErrorsIter("Post applyInteractionForceToFluid",
- iter);
+ checkForCudaErrorsIter("Post setNSghostNodes(dev_ns_p)", iter);
- setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_F_pf, ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSghostNodes(F_pf)", iter);
- }
+
+ if (np > 0) {
+
+ // Per particle, find the fluid-particle interaction force…
+ // and apply it to the particle
+ findInteractionForce<<<dimGrid, dimBlock>>>(
+ dev_x,
+ dev_vel,
+ dev_ns_phi,
+ dev_ns_p,
+ dev_ns_v_x,
+ dev_ns_v_y,
+ dev_ns_v_z,
+ dev_ns_div_tau_x,
+ dev_ns_div_tau_y,
+ dev_ns_div_tau_z,
+ //ns.c_v,
+ ns.mu,
+ ns.rho_f,
+ dev_ns_f_pf,
+ dev_force,
+ dev_ns_f_d,
+ dev_ns_f_p,
+ dev_ns_f_v,
+ dev_ns_f_sum);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post findInteractionForce", iter);
+
+ setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_p, ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSghostNodes(dev_ns_p)", i…
+
+ // Apply fluid-particle interaction force to the fluid
+ applyInteractionForceToFluid<<<dimGridFluid, dimBlockFluid…
+ dev_gridParticleIndex,
+ dev_cellStart,
+ dev_cellEnd,
+ dev_ns_f_pf,
+ dev_ns_F_pf);
+ //dev_ns_F_pf_x,
+ //dev_ns_F_pf_y,
+ //dev_ns_F_pf_z);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post applyInteractionForceToFluid",
+ iter);
+
+ setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_F_pf, ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSghostNodes(F_pf)", iter);
+ }
#endif
- if ((iter % ns.ndem) == 0) {
- // Initial guess for the top epsilon values. These may be
- // changed in setUpperPressureNS
- // TODO: Check if this should only be set when top bc=Dirichlet
- Float pressure = ns.p[idx(0,0,ns.nz-1)];
- Float pressure_new = pressure; // Dirichlet
- Float epsilon_value = pressure_new - ns.beta*pressure;
- setNSepsilonTop<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- dev_ns_epsilon_new,
- epsilon_value);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSepsilonTop", iter);
+ if ((iter % ns.ndem) == 0) {
+ // Initial guess for the top epsilon values. These may be
+ // changed in setUpperPressureNS
+ // TODO: Check if this should only be set when top bc=Diri…
+ Float pressure = ns.p[idx(0,0,ns.nz-1)];
+ Float pressure_new = pressure; // Dirichlet
+ Float epsilon_value = pressure_new - ns.beta*pressure;
+ setNSepsilonTop<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon,
+ dev_ns_epsilon_new,
+ epsilon_value);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSepsilonTop", iter);
#if defined(REPORT_EPSILON) || defined(REPORT_V_P_COMPONENTS) || defined(REPOR…
std::cout
t@@ -1182,503 +1241,811 @@ __host__ void DEM::startTime()
<< std::endl;
#endif
- // find cell containing top wall
- if (walls.nw > 0 && walls.wmode[0] == 1) {
- wall0_iz = walls.nx->w/(grid.L[2]/grid.num[2]);
- setNSepsilonAtTopWall<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- dev_ns_epsilon_new,
- wall0_iz,
- epsilon_value,
- dp_dz);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSepsilonAtTopWall", iter);
+ // find cell containing top wall
+ if (walls.nw > 0 && walls.wmode[0] == 1) {
+ wall0_iz = walls.nx->w/(grid.L[2]/grid.num[2]);
+ setNSepsilonAtTopWall<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon,
+ dev_ns_epsilon_new,
+ wall0_iz,
+ epsilon_value,
+ dp_dz);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSepsilonAtTopWall", i…
#ifdef REPORT_EPSILON
- std::cout
- << "\n###### EPSILON setNSepsilonAtTopWall "
- << "######" << std::endl;
- transferNSepsilonFromGlobalDeviceMemory();
- printNSarray(stdout, ns.epsilon, "epsilon");
+ std::cout
+ << "\n###### EPSILON setNSepsilonAtTopWall "
+ << "######" << std::endl;
+ transferNSepsilonFromGlobalDeviceMemory();
+ printNSarray(stdout, ns.epsilon, "epsilon");
#endif
- }
+ }
- // Modulate the pressures at the upper boundary cells
- if ((ns.p_mod_A > 1.0e-5 || ns.p_mod_A < -1.0e-5) &&
- ns.p_mod_f > 1.0e-7) {
- // original pressure
- Float new_pressure = ns.p[idx(0,0,ns.nz-1)]
- + ns.p_mod_A*sin(2.0*M_PI*ns.p_mod_f*time.current
- + ns.p_mod_phi);
- setUpperPressureNS<<<dimGridFluid, dimBlockFluid>>>(
+ // Modulate the pressures at the upper boundary cells
+ if ((ns.p_mod_A > 1.0e-5 || ns.p_mod_A < -1.0e-5) &&
+ ns.p_mod_f > 1.0e-7) {
+ // original pressure
+ Float new_pressure = ns.p[idx(0,0,ns.nz-1)]
+ + ns.p_mod_A*sin(2.0*M_PI*ns.p_mod_f*time.current
+ + ns.p_mod_phi);
+ setUpperPressureNS<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_p,
+ dev_ns_epsilon,
+ dev_ns_epsilon_new,
+ ns.beta,
+ new_pressure);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setUpperPressureNS", iter…
+
+#ifdef REPORT_MORE_EPSILON
+ std::cout
+ << "\n@@@@@@ TIME STEP " << iter << " @@@@@@"
+ << "\n###### EPSILON AFTER setUpperPressureNS "
+ << "######" << std::endl;
+ transferNSepsilonFromGlobalDeviceMemory();
+ printNSarray(stdout, ns.epsilon, "epsilon");
+#endif
+ }
+
+ // Set the values of the ghost nodes in the grid
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+
+ setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_p, ns.bc_bot, ns.bc_top);
+
+ //setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
+ //dev_ns_v, ns.bc_bot, ns.bc_top);
+
+ setNSghostNodesFace<Float>
+ <<<dimGridFluidFace, dimBlockFluidFace>>>(
+ dev_ns_v_p_x,
+ dev_ns_v_p_y,
+ dev_ns_v_p_z,
+ ns.bc_bot, ns.bc_top);
+
+ setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_phi, ns.bc_bot, ns.bc_top);
+
+ setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_dphi, ns.bc_bot, ns.bc_top);
+
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_setNSghostNodesDev);
+ checkForCudaErrorsIter("Post setNSghostNodesDev", iter);
+ /*std::cout << "\n###### EPSILON AFTER setNSghostNodesDev …
+ << std::endl;
+ transferNSepsilonFromGlobalDeviceMemory();
+ printNSarray(stdout, ns.epsilon, "epsilon");*/
+
+ // interpolate velocities to cell centers which makes velo…
+ // prediction easier
+ interpolateFaceToCenter<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_v_x,
+ dev_ns_v_y,
+ dev_ns_v_z,
+ dev_ns_v);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post interpolateFaceToCenter", ite…
+
+ // Set cell-center velocity ghost nodes
+ setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_v, ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSghostNodes(v)", iter);
+
+ // Find the divergence of phi*vi*v, needed for predicting …
+ // fluid velocities
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findNSdivphiviv<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_phi,
+ dev_ns_v,
+ dev_ns_div_phi_vi_v);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_findNSdivphiviv);
+ checkForCudaErrorsIter("Post findNSdivphiviv", iter);
+
+ // Set cell-center ghost nodes
+ setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_div_phi_vi_v, ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSghostNodes(div_phi_vi_v)…
+ iter);
+
+ // Predict the fluid velocities on the base of the old pre…
+ // field and ignoring the incompressibility constraint
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findPredNSvelocities<<<dimGridFluidFace, dimBlockFluidFace…
dev_ns_p,
- dev_ns_epsilon,
- dev_ns_epsilon_new,
+ dev_ns_v_x,
+ dev_ns_v_y,
+ dev_ns_v_z,
+ dev_ns_phi,
+ dev_ns_dphi,
+ dev_ns_div_tau_x,
+ dev_ns_div_tau_y,
+ dev_ns_div_tau_z,
+ dev_ns_div_phi_vi_v,
+ ns.bc_bot,
+ ns.bc_top,
ns.beta,
- new_pressure);
+ dev_ns_F_pf,
+ ns.ndem,
+ wall0_iz,
+ ns.c_v,
+ ns.mu,
+ ns.rho_f,
+ dev_ns_v_p_x,
+ dev_ns_v_p_y,
+ dev_ns_v_p_z);
cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setUpperPressureNS", iter);
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_findPredNSvelocities);
+ checkForCudaErrorsIter("Post findPredNSvelocities", iter);
+
+ setNSghostNodesFace<Float>
+ <<<dimGridFluidFace, dimBlockFluidFace>>>(
+ dev_ns_v_p_x,
+ dev_ns_v_p_y,
+ dev_ns_v_p_z,
+ ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter(
+ "Post setNSghostNodesFace(dev_ns_v_p)", iter);
+
+ interpolateFaceToCenter<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_v_p_x,
+ dev_ns_v_p_y,
+ dev_ns_v_p_z,
+ dev_ns_v_p);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post interpolateFaceToCenter", ite…
+
+
+ // In the first iteration of the sphere program, we'll nee…
+ // manually estimate the values of epsilon. In the subsequ…
+ // iterations, the previous values are used.
+ if (iter == 0) {
+
+ // Define the first estimate of the values of epsilon.
+ // The initial guess depends on the value of ns.beta.
+ Float pressure = ns.p[idx(2,2,2)];
+ Float pressure_new = pressure; // Guess p_current = p_…
+ Float epsilon_value = pressure_new - ns.beta*pressure;
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ setNSepsilonInterior<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon, epsilon_value);
+ cudaThreadSynchronize();
+
+ setNSnormZero<<<dimGridFluid, dimBlockFluid>>>(dev_ns_…
+ cudaThreadSynchronize();
+
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapse…
+ &t_setNSepsilon);
+ checkForCudaErrorsIter("Post setNSepsilonInterior", it…
#ifdef REPORT_MORE_EPSILON
- std::cout
+ std::cout
+ << "\n###### EPSILON AFTER setNSepsilonInterior "
+ << "######" << std::endl;
+ transferNSepsilonFromGlobalDeviceMemory();
+ printNSarray(stdout, ns.epsilon, "epsilon");
+#endif
+
+ // Set the epsilon values at the lower boundary
+ pressure = ns.p[idx(0,0,0)];
+ pressure_new = pressure; // Guess p_current = p_new
+ epsilon_value = pressure_new - ns.beta*pressure;
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ setNSepsilonBottom<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon,
+ dev_ns_epsilon_new,
+ epsilon_value);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapse…
+ &t_setNSdirichlet);
+ checkForCudaErrorsIter("Post setNSepsilonBottom", iter…
+
+#ifdef REPORT_MORE_EPSILON
+ std::cout
+ << "\n###### EPSILON AFTER setNSepsilonBottom "
+ << "######" << std::endl;
+ transferNSepsilonFromGlobalDeviceMemory();
+ printNSarray(stdout, ns.epsilon, "epsilon");
+#endif
+
+ /*setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid…
+ dev_ns_epsilon);
+ cudaThreadSynchronize();
+ checkForCudaErrors("Post setNSghostNodesFloat(dev_ns…
+ iter);*/
+ setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>…
+ dev_ns_epsilon,
+ ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSghostNodesEpsilon(1)…
+ iter);
+
+#ifdef REPORT_MORE_EPSILON
+ std::cout <<
+ "\n###### EPSILON AFTER setNSghostNodes(epsilon) "
+ << "######" << std::endl;
+ transferNSepsilonFromGlobalDeviceMemory();
+ printNSarray(stdout, ns.epsilon, "epsilon");
+#endif
+ }
+
+ // Solve the system of epsilon using a Jacobi iterative so…
+ // The average normalized residual is initialized to a lar…
+ // value.
+ //double avg_norm_res;
+ double max_norm_res;
+
+ // Write a log file of the normalized residuals during the…
+ // iterations
+ std::ofstream reslog;
+ if (write_res_log == 1)
+ reslog.open("max_res_norm.dat");
+
+ // transfer normalized residuals from GPU to CPU
+#ifdef REPORT_MORE_EPSILON
+ std::cout << "\n###### BEFORE FIRST JACOBI ITERATION #####…
<< "\n@@@@@@ TIME STEP " << iter << " @@@@@@"
- << "\n###### EPSILON AFTER setUpperPressureNS "
- << "######" << std::endl;
+ << std::endl;
transferNSepsilonFromGlobalDeviceMemory();
printNSarray(stdout, ns.epsilon, "epsilon");
#endif
- }
- // Set the values of the ghost nodes in the grid
- if (PROFILING == 1)
- startTimer(&kernel_tic);
+ for (unsigned int nijac = 0; nijac<ns.maxiter; ++nijac) {
- setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_p, ns.bc_bot, ns.bc_top);
+ // Only grad(epsilon) changes during the Jacobi iterat…
+ // The remaining terms of the forcing function are only
+ // calculated during the first iteration.
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findNSforcing<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon,
+ dev_ns_phi,
+ dev_ns_dphi,
+ dev_ns_v_p,
+ dev_ns_v_p_x,
+ dev_ns_v_p_y,
+ dev_ns_v_p_z,
+ nijac,
+ ns.ndem,
+ ns.c_v,
+ ns.rho_f,
+ dev_ns_f1,
+ dev_ns_f2,
+ dev_ns_f);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapse…
+ &t_findNSforcing);
+ checkForCudaErrorsIter("Post findNSforcing", iter);
+ /*setNSghostNodesForcing<<<dimGridFluid, dimBlockFluid…
+ dev_ns_f1,
+ dev_ns_f2,
+ dev_ns_f,
+ nijac);
+ cudaThreadSynchronize();
+ checkForCudaErrors("Post setNSghostNodesForcing", it…
+
+ setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>…
+ dev_ns_epsilon,
+ ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSghostNodesEpsilon(2)…
+ iter);
- //setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
- //dev_ns_v, ns.bc_bot, ns.bc_top);
+#ifdef REPORT_EPSILON
+ std::cout << "\n###### JACOBI ITERATION "
+ << nijac
+ << " after setNSghostNodes(epsilon,2) ######"
+ << std::endl;
+ transferNSepsilonFromGlobalDeviceMemory();
+ printNSarray(stdout, ns.epsilon, "epsilon");
+#endif
- setNSghostNodesFace<Float>
- <<<dimGridFluidFace, dimBlockFluidFace>>>(
- dev_ns_v_p_x,
- dev_ns_v_p_y,
- dev_ns_v_p_z,
- ns.bc_bot, ns.bc_top);
+ // Perform a single Jacobi iteration
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ jacobiIterationNS<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon,
+ dev_ns_epsilon_new,
+ dev_ns_norm,
+ dev_ns_f,
+ ns.bc_bot,
+ ns.bc_top,
+ ns.theta,
+ wall0_iz,
+ dp_dz);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapse…
+ &t_jacobiIterationNS);
+ checkForCudaErrorsIter("Post jacobiIterationNS", iter);
+
+ // set Dirichlet and Neumann BC at cells containing to…
+ /*if (walls.nw > 0 && walls.wmode[0] == 1) {
+ setNSepsilonAtTopWall<<<dimGridFluid, dimBlockFluid>…
+ dev_ns_epsilon,
+ dev_ns_epsilon_new,
+ wall0_iz,
+ epsilon_value,
+ dp_dz);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setNSepsilonAtTopWall",
+ iter);
+ }*/
+
+ // Copy new values to current values
+ copyValues<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon_new,
+ dev_ns_epsilon);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter
+ ("Post copyValues (epsilon_new->epsilon)", iter);
- setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_phi, ns.bc_bot, ns.bc_top);
+#ifdef REPORT_EPSILON
+ std::cout << "\n###### JACOBI ITERATION "
+ << nijac << " after jacobiIterationNS ######"
+ << std::endl;
+ transferNSepsilonFromGlobalDeviceMemory();
+ printNSarray(stdout, ns.epsilon, "epsilon");
+#endif
- setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_dphi, ns.bc_bot, ns.bc_top);
+ if (nijac % nijacnorm == 0) {
- cudaThreadSynchronize();
- if (PROFILING == 1)
- stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
- &t_setNSghostNodesDev);
- checkForCudaErrorsIter("Post setNSghostNodesDev", iter);
- /*std::cout << "\n###### EPSILON AFTER setNSghostNodesDev ####…
- << std::endl;
- transferNSepsilonFromGlobalDeviceMemory();
- printNSarray(stdout, ns.epsilon, "epsilon");*/
+ // Read the normalized residuals from the device
+ transferNSnormFromGlobalDeviceMemory();
- // interpolate velocities to cell centers which makes velocity
- // prediction easier
- interpolateFaceToCenter<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_v_x,
- dev_ns_v_y,
- dev_ns_v_z,
- dev_ns_v);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post interpolateFaceToCenter", iter);
+ // Write the normalized residuals to the terminal
+ //printNSarray(stdout, ns.norm, "norm");
- // Set cell-center velocity ghost nodes
- setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_v, ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSghostNodes(v)", iter);
-
- // Find the divergence of phi*vi*v, needed for predicting the
- // fluid velocities
- if (PROFILING == 1)
- startTimer(&kernel_tic);
- findNSdivphiviv<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_phi,
- dev_ns_v,
- dev_ns_div_phi_vi_v);
- cudaThreadSynchronize();
- if (PROFILING == 1)
- stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
- &t_findNSdivphiviv);
- checkForCudaErrorsIter("Post findNSdivphiviv", iter);
+ // Find the maximum value of the normalized residu…
+ max_norm_res = maxNormResNS();
- // Set cell-center ghost nodes
- setNSghostNodes<Float3><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_div_phi_vi_v, ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSghostNodes(div_phi_vi_v)",
- iter);
+ // Write the Jacobi iteration number and maximum v…
+ // of the normalized residual to the log file
+ if (write_res_log == 1)
+ reslog << nijac << '\t' << max_norm_res
+ << std::endl;
+ }
- // Predict the fluid velocities on the base of the old pressure
- // field and ignoring the incompressibility constraint
- if (PROFILING == 1)
- startTimer(&kernel_tic);
- findPredNSvelocities<<<dimGridFluidFace, dimBlockFluidFace>>>(
- dev_ns_p,
- dev_ns_v_x,
- dev_ns_v_y,
- dev_ns_v_z,
- dev_ns_phi,
- dev_ns_dphi,
- dev_ns_div_tau_x,
- dev_ns_div_tau_y,
- dev_ns_div_tau_z,
- dev_ns_div_phi_vi_v,
- ns.bc_bot,
- ns.bc_top,
- ns.beta,
- dev_ns_F_pf,
- ns.ndem,
- wall0_iz,
- ns.c_v,
- dev_ns_v_p_x,
- dev_ns_v_p_y,
- dev_ns_v_p_z);
- cudaThreadSynchronize();
- if (PROFILING == 1)
- stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
- &t_findPredNSvelocities);
- checkForCudaErrorsIter("Post findPredNSvelocities", iter);
+ if (max_norm_res < ns.tolerance) {
- setNSghostNodesFace<Float>
- <<<dimGridFluidFace, dimBlockFluidFace>>>(
- dev_ns_v_p_x,
- dev_ns_v_p_y,
- dev_ns_v_p_z,
- ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter(
- "Post setNSghostNodesFace(dev_ns_v_p)", iter);
+ if (write_conv_log == 1 && iter % conv_log_interva…
+ convlog << iter+1 << '\t' << nijac << std::end…
- interpolateFaceToCenter<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_v_p_x,
- dev_ns_v_p_y,
- dev_ns_v_p_z,
- dev_ns_v_p);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post interpolateFaceToCenter", iter);
+ setNSghostNodes<Float>
+ <<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon,
+ ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter
+ ("Post setNSghostNodesEpsilon(4)", iter);
+ // Apply smoothing if requested
+ if (ns.gamma > 0.0) {
+
+ smoothing<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon,
+ ns.gamma,
+ ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post smoothing", iter);
+
+ setNSghostNodes<Float>
+ <<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon,
+ ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter
+ ("Post setNSghostNodesEpsilon(4)", iter);
+ }
- // In the first iteration of the sphere program, we'll need to
- // manually estimate the values of epsilon. In the subsequent
- // iterations, the previous values are used.
- if (iter == 0) {
+#ifdef REPORT_EPSILON
+ std::cout << "\n###### JACOBI ITERATION "
+ << nijac << " after smoothing ######"
+ << std::endl;
+ transferNSepsilonFromGlobalDeviceMemory();
+ printNSarray(stdout, ns.epsilon, "epsilon");
+#endif
- // Define the first estimate of the values of epsilon.
- // The initial guess depends on the value of ns.beta.
- Float pressure = ns.p[idx(2,2,2)];
- Float pressure_new = pressure; // Guess p_current = p_new
- Float epsilon_value = pressure_new - ns.beta*pressure;
+ break; // solution has converged, exit Jacobi loop
+ }
+
+ if (nijac >= ns.maxiter-1) {
+
+ if (write_conv_log == 1)
+ convlog << iter+1 << '\t' << nijac << std::end…
+
+ std::cerr << "\nIteration " << iter << ", time "
+ << iter*time.dt << " s: "
+ "Error, the epsilon solution in the fluid "
+ "calculations did not converge. Try increasing…
+ "value of 'ns.maxiter' (" << ns.maxiter
+ << ") or increase 'ns.tolerance' ("
+ << ns.tolerance << ")." << std::endl;
+ }
+ //break; // end after Jacobi first iteration
+ } // end Jacobi iteration loop
+
+ if (write_res_log == 1)
+ reslog.close();
+
+ // Find the new pressures and velocities
if (PROFILING == 1)
startTimer(&kernel_tic);
- setNSepsilonInterior<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon, epsilon_value);
- cudaThreadSynchronize();
- setNSnormZero<<<dimGridFluid, dimBlockFluid>>>(dev_ns_norm…
+ updateNSpressure<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_epsilon,
+ ns.beta,
+ dev_ns_p);
cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post updateNSpressure", iter);
+ updateNSvelocity<<<dimGridFluidFace, dimBlockFluidFace>>>(
+ dev_ns_v_p_x,
+ dev_ns_v_p_y,
+ dev_ns_v_p_z,
+ dev_ns_phi,
+ dev_ns_epsilon,
+ ns.beta,
+ ns.bc_bot,
+ ns.bc_top,
+ ns.ndem,
+ ns.c_v,
+ ns.rho_f,
+ wall0_iz,
+ iter,
+ dev_ns_v_x,
+ dev_ns_v_y,
+ dev_ns_v_z);
+ cudaThreadSynchronize();
if (PROFILING == 1)
stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
- &t_setNSepsilon);
- checkForCudaErrorsIter("Post setNSepsilonInterior", iter);
+ &t_updateNSvelocityPressure);
+ checkForCudaErrorsIter("Post updateNSvelocity", iter);
+
+ setNSghostNodesFace<Float>
+ <<<dimGridFluidFace, dimBlockFluidFace>>>(
+ dev_ns_v_p_x,
+ dev_ns_v_p_y,
+ dev_ns_v_p_z,
+ ns.bc_bot, ns.bc_top);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter(
+ "Post setNSghostNodesFace(dev_ns_v)", iter);
+
+ interpolateFaceToCenter<<<dimGridFluid, dimBlockFluid>>>(
+ dev_ns_v_x,
+ dev_ns_v_y,
+ dev_ns_v_z,
+ dev_ns_v);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post interpolateFaceToCenter", ite…
+ } // end iter % ns.dem == 0
+ } // end cfd_solver == 0
-#ifdef REPORT_MORE_EPSILON
+ // Darcy solution
+ else if (cfd_solver == 1) {
+
+#if defined(REPORT_EPSILON) || defined(REPORT_FORCING_TERMS)
std::cout
- << "\n###### EPSILON AFTER setNSepsilonInterior "
- << "######" << std::endl;
- transferNSepsilonFromGlobalDeviceMemory();
- printNSarray(stdout, ns.epsilon, "epsilon");
+ << "\n\n@@@@@@ TIME STEP " << iter << " @@@"
+ << std::endl;
#endif
- // Set the epsilon values at the lower boundary
- pressure = ns.p[idx(0,0,0)];
- pressure_new = pressure; // Guess p_current = p_new
- epsilon_value = pressure_new - ns.beta*pressure;
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findDarcyPorosities<<<dimGridFluid, dimBlockFluid>>>(
+ dev_cellStart,
+ dev_cellEnd,
+ dev_x_sorted,
+ iter,
+ np,
+ darcy.c_phi,
+ dev_darcy_phi,
+ dev_darcy_dphi);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_findDarcyPorosities);
+ checkForCudaErrorsIter("Post findDarcyPorosities", iter);
+
+ if (np > 0) {
+
if (PROFILING == 1)
startTimer(&kernel_tic);
- setNSepsilonBottom<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- dev_ns_epsilon_new,
- epsilon_value);
+ setDarcyGhostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_darcy_p, darcy.bc_bot, darcy.bc_top);
cudaThreadSynchronize();
if (PROFILING == 1)
stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
- &t_setNSdirichlet);
- checkForCudaErrorsIter("Post setNSepsilonBottom", iter);
-
-#ifdef REPORT_MORE_EPSILON
- std::cout
- << "\n###### EPSILON AFTER setNSepsilonBottom "
- << "######" << std::endl;
- transferNSepsilonFromGlobalDeviceMemory();
- printNSarray(stdout, ns.epsilon, "epsilon");
-#endif
+ &t_setDarcyGhostNodes);
+ checkForCudaErrorsIter("Post setDarcyGhostNodes("
+ "dev_darcy_p) before findDarcyPressureForce", iter…
- /*setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon);
- cudaThreadSynchronize();
- checkForCudaErrors("Post setNSghostNodesFloat(dev_ns_eps…
- iter);*/
- setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- ns.bc_bot, ns.bc_top);
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findDarcyPressureForce<<<dimGrid, dimBlock>>>(
+ dev_x,
+ dev_darcy_p,
+ dev_darcy_phi,
+ dev_force,
+ dev_darcy_f_p);
cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSghostNodesEpsilon(1)",
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_findDarcyPressureForce);
+ checkForCudaErrorsIter("Post findDarcyPressureForce",
iter);
+ }
-#ifdef REPORT_MORE_EPSILON
- std::cout <<
- "\n###### EPSILON AFTER setNSghostNodes(epsilon) "
- << "######" << std::endl;
- transferNSepsilonFromGlobalDeviceMemory();
- printNSarray(stdout, ns.epsilon, "epsilon");
-#endif
+ // Modulate the pressures at the upper boundary cells
+ if ((darcy.p_mod_A > 1.0e-5 || darcy.p_mod_A < -1.0e-5) &&
+ darcy.p_mod_f > 1.0e-7) {
+ // original pressure
+ Float new_pressure = darcy.p[d_idx(0,0,darcy.nz-1)] //orig…
+ + darcy.p_mod_A*sin(2.0*M_PI*darcy.p_mod_f*time.current
+ + darcy.p_mod_phi);
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ setDarcyTopPressure<<<dimGridFluid, dimBlockFluid>>>(
+ new_pressure,
+ dev_darcy_p);
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_setDarcyTopPressure);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setUpperPressureNS", iter);
+ }
+
+ if (walls.nw > 0 && walls.wmode[0] == 1) {
+ wall0_iz = walls.nx->w/(grid.L[2]/grid.num[2]);
+ /*setDarcyTopWallPressure<<<dimGridFluid, dimBlockFluid>>>(
+ new_pressure,
+ wall0_iz,
+ dev_darcy_p);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setDarcyTopWallPressure",
+ iter);*/
+ }
+
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findDarcyPermeabilities<<<dimGridFluid, dimBlockFluid>>>(
+ darcy.k_c, dev_darcy_phi, dev_darcy_k);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_findDarcyPermeabilities);
+ checkForCudaErrorsIter("Post findDarcyPermeabilities",
+ iter);
+
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ setDarcyGhostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_darcy_k, darcy.bc_bot, darcy.bc_top);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_setDarcyGhostNodes);
+ checkForCudaErrorsIter("Post setDarcyGhostNodes(dev_darcy_k)",
+ iter);
+
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findDarcyPermeabilityGradients<<<dimGridFluid, dimBlockFluid>>…
+ dev_darcy_k, dev_darcy_grad_k);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_findDarcyPermeabilityGradients);
+ checkForCudaErrorsIter("Post findDarcyPermeabilityGradients",
+ iter);
+
+ if (iter == 0) {
+ setDarcyNormZero<<<dimGridFluid, dimBlockFluid>>>(
+ dev_darcy_norm);
+ cudaThreadSynchronize();
+ checkForCudaErrorsIter("Post setDarcyNormZero", iter);
+
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ copyValues<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_darcy_p,
+ dev_darcy_p_old);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_copyValues);
+ checkForCudaErrorsIter("Post copyValues(p -> p_old)",
+ iter);
}
+ /*if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findDarcyPressureChange<<<dimGridFluid, dimBlockFluid>>>(
+ dev_darcy_p_old,
+ dev_darcy_p,
+ iter,
+ dev_darcy_dpdt);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_findDarcyPressureChange);
+ checkForCudaErrorsIter("Post findDarcyPressureChange", iter);*/
+
// Solve the system of epsilon using a Jacobi iterative solver.
// The average normalized residual is initialized to a large
// value.
//double avg_norm_res;
double max_norm_res;
- // Write a log file of the normalized residuals during the Jac…
- // iterations
+ // Write a log file of the normalized residuals during the
+ // Jacobi iterations
std::ofstream reslog;
if (write_res_log == 1)
reslog.open("max_res_norm.dat");
- // transfer normalized residuals from GPU to CPU
-#ifdef REPORT_MORE_EPSILON
- std::cout << "\n###### BEFORE FIRST JACOBI ITERATION ######"
- << "\n@@@@@@ TIME STEP " << iter << " @@@@@@"
- << std::endl;
- transferNSepsilonFromGlobalDeviceMemory();
- printNSarray(stdout, ns.epsilon, "epsilon");
-#endif
+ for (unsigned int nijac = 0; nijac<darcy.maxiter; ++nijac) {
- for (unsigned int nijac = 0; nijac<ns.maxiter; ++nijac) {
-
- //printf("### Jacobi iteration %d\n", nijac);
+ if (nijac == 0) {
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ copyValues<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_darcy_p,
+ dev_darcy_p_old);
+ cudaThreadSynchronize();
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapse…
+ &t_copyValues);
+ checkForCudaErrorsIter("Post copyValues(p -> p_old)",
+ iter);
+ }
- // Only grad(epsilon) changes during the Jacobi iterations.
- // The remaining terms of the forcing function are only
- // calculated during the first iteration.
if (PROFILING == 1)
startTimer(&kernel_tic);
- findNSforcing<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- dev_ns_phi,
- dev_ns_dphi,
- dev_ns_v_p,
- dev_ns_v_p_x,
- dev_ns_v_p_y,
- dev_ns_v_p_z,
- nijac,
- ns.ndem,
- ns.c_v,
- dev_ns_f1,
- dev_ns_f2,
- dev_ns_f);
+ setDarcyGhostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
+ dev_darcy_p, darcy.bc_bot, darcy.bc_top);
cudaThreadSynchronize();
if (PROFILING == 1)
stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
- &t_findNSforcing);
- checkForCudaErrorsIter("Post findNSforcing", iter);
- /*setNSghostNodesForcing<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_f1,
- dev_ns_f2,
- dev_ns_f,
- nijac);
- cudaThreadSynchronize();
- checkForCudaErrors("Post setNSghostNodesForcing", iter);…
-
- setNSghostNodes<Float><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSghostNodesEpsilon(2)",
- iter);
-
-#ifdef REPORT_EPSILON
- std::cout << "\n###### JACOBI ITERATION "
- << nijac
- << " after setNSghostNodes(epsilon,2) ######"
- << std::endl;
- transferNSepsilonFromGlobalDeviceMemory();
- printNSarray(stdout, ns.epsilon, "epsilon");
-#endif
+ &t_setDarcyGhostNodes);
+ checkForCudaErrorsIter("Post setDarcyGhostNodes("
+ "dev_darcy_p) in Jacobi loop", iter);
- // Perform a single Jacobi iteration
if (PROFILING == 1)
startTimer(&kernel_tic);
- jacobiIterationNS<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- dev_ns_epsilon_new,
- dev_ns_norm,
- dev_ns_f,
- ns.bc_bot,
- ns.bc_top,
- ns.theta,
+ updateDarcySolution<<<dimGridFluid, dimBlockFluid>>>(
+ dev_darcy_p_old,
+ //dev_darcy_dpdt,
+ dev_darcy_p,
+ dev_darcy_k,
+ dev_darcy_phi,
+ dev_darcy_dphi,
+ dev_darcy_grad_k,
+ darcy.beta_f,
+ darcy.mu,
+ darcy.bc_bot,
+ darcy.bc_top,
+ darcy.ndem,
wall0_iz,
- dp_dz);
+ dev_darcy_p_new,
+ dev_darcy_norm);
cudaThreadSynchronize();
if (PROFILING == 1)
stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
- &t_jacobiIterationNS);
- checkForCudaErrorsIter("Post jacobiIterationNS", iter);
-
- // set Dirichlet and Neumann BC at cells containing top wa…
- /*if (walls.nw > 0 && walls.wmode[0] == 1) {
- setNSepsilonAtTopWall<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- dev_ns_epsilon_new,
- wall0_iz,
- epsilon_value,
- dp_dz);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post setNSepsilonAtTopWall",
- iter);
- }*/
+ &t_updateDarcySolution);
+ checkForCudaErrorsIter("Post updateDarcySolution", iter);
// Copy new values to current values
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
copyValues<Float><<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon_new,
- dev_ns_epsilon);
+ dev_darcy_p_new,
+ dev_darcy_p);
cudaThreadSynchronize();
- checkForCudaErrorsIter
- ("Post copyValues (epsilon_new->epsilon)", iter);
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_copyValues);
+ checkForCudaErrorsIter("Post copyValues(p_new -> p)", iter…
#ifdef REPORT_EPSILON
std::cout << "\n###### JACOBI ITERATION "
- << nijac << " after jacobiIterationNS ######"
- << std::endl;
- transferNSepsilonFromGlobalDeviceMemory();
- printNSarray(stdout, ns.epsilon, "epsilon");
+ << nijac << " after copyValues ######" << std::endl;
+ transferDarcyPressuresFromGlobalDeviceMemory();
+ printDarcyArray(stdout, darcy.p, "p");
#endif
if (nijac % nijacnorm == 0) {
-
// Read the normalized residuals from the device
- transferNSnormFromGlobalDeviceMemory();
+ transferDarcyNormFromGlobalDeviceMemory();
// Write the normalized residuals to the terminal
- //printNSarray(stdout, ns.norm, "norm");
+ //printDarcyArray(stdout, darcy.norm, "norm");
// Find the maximum value of the normalized residuals
- max_norm_res = maxNormResNS();
+ max_norm_res = maxNormResDarcy();
// Write the Jacobi iteration number and maximum value
// of the normalized residual to the log file
if (write_res_log == 1)
reslog << nijac << '\t' << max_norm_res
<< std::endl;
- }
- if (max_norm_res < ns.tolerance) {
+ if (max_norm_res <= darcy.tolerance) {
+ if (write_conv_log == 1
+ && iter % conv_log_interval == 0)
+ convlog << iter+1 << '\t' << nijac << std::end…
- if (write_conv_log == 1 && iter % conv_log_interval ==…
- convlog << iter << '\t' << nijac << std::endl;
-
- setNSghostNodes<Float>
- <<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter
- ("Post setNSghostNodesEpsilon(4)", iter);
-
- // Apply smoothing if requested
- if (ns.gamma > 0.0) {
-
- smoothing<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- ns.gamma,
- ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post smoothing", iter);
-
- setNSghostNodes<Float>
- <<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter
- ("Post setNSghostNodesEpsilon(4)", iter);
+ break; // solution has converged, exit Jacobi loop
}
-
-#ifdef REPORT_EPSILON
- std::cout << "\n###### JACOBI ITERATION "
- << nijac << " after smoothing ######"
- << std::endl;
- transferNSepsilonFromGlobalDeviceMemory();
- printNSarray(stdout, ns.epsilon, "epsilon");
-#endif
-
- break; // solution has converged, exit Jacobi loop
}
- if (nijac >= ns.maxiter-1) {
+ if (nijac == darcy.maxiter-1) {
if (write_conv_log == 1)
- convlog << iter << '\t' << nijac << std::endl;
+ convlog << iter+1 << '\t' << nijac << std::endl;
std::cerr << "\nIteration " << iter << ", time "
<< iter*time.dt << " s: "
- "Error, the epsilon solution in the fluid "
- "calculations did not converge. Try increasing the…
- "value of 'ns.maxiter' (" << ns.maxiter
- << ") or increase 'ns.tolerance' ("
- << ns.tolerance << ")." << std::endl;
+ "Error, the pressure solution in the fluid "
+ "calculations did not converge. Try increasing "
+ "the value of 'darcy.maxiter' ("
+ << darcy.maxiter
+ << ") or increase 'darcy.tolerance' ("
+ << darcy.tolerance << ")." << std::endl;
}
- //break; // end after Jacobi first iteration
- } // end Jacobi iteration loop
- if (write_res_log == 1)
- reslog.close();
+ if (write_res_log == 1)
+ reslog.close();
+
+ //break; // end after first iteration
+ }
- // Find the new pressures and velocities
if (PROFILING == 1)
startTimer(&kernel_tic);
-
- updateNSpressure<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_epsilon,
- ns.beta,
- dev_ns_p);
- cudaThreadSynchronize();
- checkForCudaErrorsIter("Post updateNSpressure", iter);
-
- updateNSvelocity<<<dimGridFluidFace, dimBlockFluidFace>>>(
- dev_ns_v_p_x,
- dev_ns_v_p_y,
- dev_ns_v_p_z,
- dev_ns_phi,
- dev_ns_epsilon,
- ns.beta,
- ns.bc_bot,
- ns.bc_top,
- ns.ndem,
- ns.c_v,
- wall0_iz,
- iter,
- dev_ns_v_x,
- dev_ns_v_y,
- dev_ns_v_z);
+ setDarcyGhostNodes<Float> <<<dimGridFluid, dimBlockFluid>>>
+ (dev_darcy_p, darcy.bc_bot, darcy.bc_top);
cudaThreadSynchronize();
if (PROFILING == 1)
stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
- &t_updateNSvelocityPressure);
- checkForCudaErrorsIter("Post updateNSvelocity", iter);
-
- setNSghostNodesFace<Float>
- <<<dimGridFluidFace, dimBlockFluidFace>>>(
- dev_ns_v_p_x,
- dev_ns_v_p_y,
- dev_ns_v_p_z,
- ns.bc_bot, ns.bc_top);
- cudaThreadSynchronize();
- checkForCudaErrorsIter(
- "Post setNSghostNodesFace(dev_ns_v)", iter);
+ &t_setDarcyGhostNodes);
+ checkForCudaErrorsIter("Post setDarcyGhostNodes("
+ "dev_darcy_p) after Jacobi loop", iter);
- interpolateFaceToCenter<<<dimGridFluid, dimBlockFluid>>>(
- dev_ns_v_x,
- dev_ns_v_y,
- dev_ns_v_z,
- dev_ns_v);
+ if (PROFILING == 1)
+ startTimer(&kernel_tic);
+ findDarcyVelocities<<<dimGridFluid, dimBlockFluid>>>(
+ dev_darcy_p,
+ dev_darcy_phi,
+ dev_darcy_k,
+ darcy.mu,
+ dev_darcy_v);
cudaThreadSynchronize();
- checkForCudaErrorsIter("Post interpolateFaceToCenter", iter);
- } // end iter % ns.dem == 0
- } // end navierstokes == 1
+ if (PROFILING == 1)
+ stopTimer(&kernel_tic, &kernel_toc, &kernel_elapsed,
+ &t_findDarcyVelocities);
+ checkForCudaErrorsIter("Post findDarcyVelocities", iter);
+ }
+ }
+ //break; // end after first iteration
if (np > 0) {
// Update particle kinematics
t@@ -1777,7 +2144,7 @@ __host__ void DEM::startTime()
checkForCudaErrorsIter("Beginning of file output section", iter);
// v_x, v_y, v_z -> v
- if (navierstokes == 1) {
+ if (fluid == 1 && cfd_solver == 0) {
interpolateFaceToCenter<<<dimGridFluid, dimBlockFluid>>>(
dev_ns_v_x,
dev_ns_v_y,
t@@ -1797,7 +2164,7 @@ __host__ void DEM::startTime()
cudaThreadSynchronize();
// Check the numerical stability of the NS solver
- if (navierstokes == 1)
+ if (fluid == 1 && cfd_solver == 0)
checkNSstability();
// Write binary output file
t@@ -1812,7 +2179,7 @@ __host__ void DEM::startTime()
printNSarray(stdout, ns.epsilon, "epsilon");*/
// Write fluid arrays
- /*if (navierstokes == 1) {
+ /*if (fluid == 1 && cfd_solver == 0) {
sprintf(file,"output/%s.ns_phi.output%05d.bin", sid.c_str(),
time.step_count);
writeNSarray(ns.phi, file);
t@@ -1904,7 +2271,12 @@ __host__ void DEM::startTime()
t_findNSstressTensor +
t_findNSdivphiviv + t_findNSdivtau + t_findPredNSvelocities +
t_setNSepsilon + t_setNSdirichlet + t_setNSghostNodesDev +
- t_findNSforcing + t_jacobiIterationNS + t_updateNSvelocityPressure;
+ t_findNSforcing + t_jacobiIterationNS + t_updateNSvelocityPressure…
+ t_findDarcyPorosities + t_setDarcyGhostNodes +
+ t_findDarcyPressureForce + t_setDarcyTopPressure +
+ t_findDarcyPermeabilities + t_findDarcyPermeabilityGradients +
+ //t_findDarcyPressureChange +
+ t_updateDarcySolution + t_copyValues + t_findDarcyVelocities;
cout << "\nKernel profiling statistics:\n"
<< " - calcParticleCellID:\t\t" << t_calcParticleCellID/1000.0
t@@ -1931,34 +2303,67 @@ __host__ void DEM::startTime()
<< "\t(" << 100.0*t_summation/t_sum << " %)\n"
<< " - integrateWalls:\t\t" << t_integrateWalls/1000.0 << " s"
<< "\t(" << 100.0*t_integrateWalls/t_sum << " %)\n";
- if (navierstokes == 1) {
+ if (fluid == 1 && cfd_solver == 0) {
cout << " - findPorositiesDev:\t\t" << t_findPorositiesDev/1000.0
- << " s" << "\t(" << 100.0*t_findPorositiesDev/t_sum << " %)\n"
- << " - findNSstressTensor:\t\t" << t_findNSstressTensor/1000.0
- << " s" << "\t(" << 100.0*t_findNSstressTensor/t_sum << " %)\n"
- << " - findNSdivphiviv:\t\t" << t_findNSdivphiviv/1000.0
- << " s" << "\t(" << 100.0*t_findNSdivphiviv/t_sum << " %)\n"
- << " - findNSdivtau:\t\t" << t_findNSdivtau/1000.0
- << " s" << "\t(" << 100.0*t_findNSdivtau/t_sum << " %)\n"
- << " - findPredNSvelocities:\t" << t_findPredNSvelocities/1000.0
- << " s" << "\t(" << 100.0*t_findPredNSvelocities/t_sum << " %)\n"
- << " - setNSepsilon:\t\t" << t_setNSepsilon/1000.0
- << " s" << "\t(" << 100.0*t_setNSepsilon/t_sum << " %)\n"
- << " - setNSdirichlet:\t\t" << t_setNSdirichlet/1000.0
- << " s" << "\t(" << 100.0*t_setNSdirichlet/t_sum << " %)\n"
- << " - setNSghostNodesDev:\t\t" << t_setNSghostNodesDev/1000.0
- << " s" << "\t(" << 100.0*t_setNSghostNodesDev/t_sum << " %)\n"
- << " - findNSforcing:\t\t" << t_findNSforcing/1000.0 << " s"
- << "\t(" << 100.0*t_findNSforcing/t_sum << " %)\n"
- << " - jacobiIterationNS:\t\t" << t_jacobiIterationNS/1000.0 << "…
- << "\t(" << 100.0*t_jacobiIterationNS/t_sum << " %)\n"
- << " - updateNSvelocityPressure:\t"
- << t_updateNSvelocityPressure/1000.0 << " s"
- << "\t(" << 100.0*t_updateNSvelocityPressure/t_sum << " %)\n";
+ << " s" << "\t(" << 100.0*t_findPorositiesDev/t_sum << " %)\n"
+ << " - findNSstressTensor:\t\t" << t_findNSstressTensor/1000.0
+ << " s" << "\t(" << 100.0*t_findNSstressTensor/t_sum << " %)\n"
+ << " - findNSdivphiviv:\t\t" << t_findNSdivphiviv/1000.0
+ << " s" << "\t(" << 100.0*t_findNSdivphiviv/t_sum << " %)\n"
+ << " - findNSdivtau:\t\t" << t_findNSdivtau/1000.0
+ << " s" << "\t(" << 100.0*t_findNSdivtau/t_sum << " %)\n"
+ << " - findPredNSvelocities:\t" <<
+ t_findPredNSvelocities/1000.0 << " s" << "\t(" <<
+ 100.0*t_findPredNSvelocities/t_sum << " %)\n"
+ << " - setNSepsilon:\t\t" << t_setNSepsilon/1000.0
+ << " s" << "\t(" << 100.0*t_setNSepsilon/t_sum << " %)\n"
+ << " - setNSdirichlet:\t\t" << t_setNSdirichlet/1000.0
+ << " s" << "\t(" << 100.0*t_setNSdirichlet/t_sum << " %)\n"
+ << " - setNSghostNodesDev:\t\t" << t_setNSghostNodesDev/1000.0
+ << " s" << "\t(" << 100.0*t_setNSghostNodesDev/t_sum << " %)\n"
+ << " - findNSforcing:\t\t" << t_findNSforcing/1000.0 << " s"
+ << "\t(" << 100.0*t_findNSforcing/t_sum << " %)\n"
+ << " - jacobiIterationNS:\t\t" << t_jacobiIterationNS/1000.0
+ << " s"
+ << "\t(" << 100.0*t_jacobiIterationNS/t_sum << " %)\n"
+ << " - updateNSvelocityPressure:\t"
+ << t_updateNSvelocityPressure/1000.0 << " s"
+ << "\t(" << 100.0*t_updateNSvelocityPressure/t_sum << " %)\n";
+ } else if (fluid == 1 && cfd_solver == 1) {
+ cout << " - findDarcyPorosities:\t" <<
+ t_findDarcyPorosities/1000.0 << " s" << "\t(" <<
+ 100.0*t_findDarcyPorosities/t_sum << " %)\n"
+ << " - setDarcyGhostNodes:\t\t" <<
+ t_setDarcyGhostNodes/1000.0 << " s" << "\t(" <<
+ 100.0*t_setDarcyGhostNodes/t_sum << " %)\n"
+ << " - findDarcyPressureForce:\t" <<
+ t_findDarcyPressureForce/1000.0 << " s" << "\t(" <<
+ 100.0*t_findDarcyPressureForce/t_sum << " %)\n"
+ << " - setDarcyTopPressure:\t" <<
+ t_setDarcyTopPressure/1000.0 << " s" << "\t(" <<
+ 100.0*t_setDarcyTopPressure/t_sum << " %)\n"
+ << " - findDarcyPermeabilities:\t" <<
+ t_findDarcyPermeabilities/1000.0 << " s" << "\t(" <<
+ 100.0*t_findDarcyPermeabilities/t_sum << " %)\n"
+ << " - findDarcyPermeabilityGrads:\t" <<
+ t_findDarcyPermeabilityGradients/1000.0 << " s" << "\t(" <<
+ 100.0*t_findDarcyPermeabilityGradients/t_sum << " %)\n"
+ //<< " - findDarcyPressureChange:\t" <<
+ //t_findDarcyPressureChange/1000.0 << " s" << "\t(" <<
+ //100.0*t_findDarcyPressureChange/t_sum << " %)\n"
+ << " - updateDarcySolution:\t" <<
+ t_updateDarcySolution/1000.0 << " s" << "\t(" <<
+ 100.0*t_updateDarcySolution/t_sum << " %)\n"
+ << " - copyValues:\t\t\t" <<
+ t_copyValues/1000.0 << " s" << "\t(" <<
+ 100.0*t_copyValues/t_sum << " %)\n"
+ << " - findDarcyVelocities:\t" <<
+ t_findDarcyVelocities/1000.0 << " s" << "\t(" <<
+ 100.0*t_findDarcyVelocities/t_sum << " %)" << std::endl;
}
}
- // Free GPU device memory
+ // Free GPU device memory
freeGlobalDeviceMemory();
checkForCudaErrorsIter("After freeGlobalDeviceMemory()", iter);
t@@ -1967,8 +2372,11 @@ __host__ void DEM::startTime()
delete[] k.distmod;
delete[] k.delta_t;
- if (navierstokes == 1) {
- endNS();
+ if (fluid == 1) {
+ if (cfd_solver == 0)
+ endNS();
+ else if (cfd_solver == 1)
+ endDarcy();
}
cudaDeviceReset();
diff --git a/src/file_io.cpp b/src/file_io.cpp
t@@ -254,73 +254,135 @@ void DEM::readbin(const char *target)
if (verbose == 1)
cout << "Done\n";
- if (navierstokes == 1) { // Navier Stokes flow
+ // Simulate fluid
+ if (fluid == 1) {
- initNSmem();
+ ifs.read(as_bytes(cfd_solver), sizeof(int));
- ifs.read(as_bytes(params.mu), sizeof(params.mu));
+ if (cfd_solver < 0 || cfd_solver > 1) {
+ std::cerr << "Value of cfd_solver not understood ("
+ << cfd_solver << ")" << std::endl;
+ exit(1);
+ }
+
+ if (cfd_solver == 0) { // Navier Stokes flow
+
+ initNSmem();
+
+ ifs.read(as_bytes(ns.mu), sizeof(Float));
- if (verbose == 1)
- cout << " - Reading fluid values:\t\t\t ";
+ if (verbose == 1)
+ cout << " - Reading fluid values:\t\t\t ";
- for (z = 0; z<grid.num[2]; ++z) {
- for (y = 0; y<grid.num[1]; ++y) {
- for (x = 0; x<grid.num[0]; ++x) {
- i = idx(x,y,z);
- ifs.read(as_bytes(ns.v[i].x), sizeof(Float));
- ifs.read(as_bytes(ns.v[i].y), sizeof(Float));
- ifs.read(as_bytes(ns.v[i].z), sizeof(Float));
- ifs.read(as_bytes(ns.p[i]), sizeof(Float));
- ifs.read(as_bytes(ns.phi[i]), sizeof(Float));
- ifs.read(as_bytes(ns.dphi[i]), sizeof(Float));
+ for (z = 0; z<grid.num[2]; ++z) {
+ for (y = 0; y<grid.num[1]; ++y) {
+ for (x = 0; x<grid.num[0]; ++x) {
+ i = idx(x,y,z);
+ ifs.read(as_bytes(ns.v[i].x), sizeof(Float));
+ ifs.read(as_bytes(ns.v[i].y), sizeof(Float));
+ ifs.read(as_bytes(ns.v[i].z), sizeof(Float));
+ ifs.read(as_bytes(ns.p[i]), sizeof(Float));
+ ifs.read(as_bytes(ns.phi[i]), sizeof(Float));
+ ifs.read(as_bytes(ns.dphi[i]), sizeof(Float));
+ }
}
}
- }
- ifs.read(as_bytes(params.rho_f), sizeof(Float));
- ifs.read(as_bytes(ns.p_mod_A), sizeof(Float));
- ifs.read(as_bytes(ns.p_mod_f), sizeof(Float));
- ifs.read(as_bytes(ns.p_mod_phi), sizeof(Float));
+ ifs.read(as_bytes(ns.rho_f), sizeof(Float));
+ ifs.read(as_bytes(ns.p_mod_A), sizeof(Float));
+ ifs.read(as_bytes(ns.p_mod_f), sizeof(Float));
+ ifs.read(as_bytes(ns.p_mod_phi), sizeof(Float));
- ifs.read(as_bytes(ns.bc_bot), sizeof(int));
- ifs.read(as_bytes(ns.bc_top), sizeof(int));
- ifs.read(as_bytes(ns.free_slip_bot), sizeof(int));
- ifs.read(as_bytes(ns.free_slip_top), sizeof(int));
+ ifs.read(as_bytes(ns.bc_bot), sizeof(int));
+ ifs.read(as_bytes(ns.bc_top), sizeof(int));
+ ifs.read(as_bytes(ns.free_slip_bot), sizeof(int));
+ ifs.read(as_bytes(ns.free_slip_top), sizeof(int));
- ifs.read(as_bytes(ns.gamma), sizeof(Float));
- ifs.read(as_bytes(ns.theta), sizeof(Float));
- ifs.read(as_bytes(ns.beta), sizeof(Float));
- ifs.read(as_bytes(ns.tolerance), sizeof(Float));
- ifs.read(as_bytes(ns.maxiter), sizeof(unsigned int));
- ifs.read(as_bytes(ns.ndem), sizeof(unsigned int));
+ ifs.read(as_bytes(ns.gamma), sizeof(Float));
+ ifs.read(as_bytes(ns.theta), sizeof(Float));
+ ifs.read(as_bytes(ns.beta), sizeof(Float));
+ ifs.read(as_bytes(ns.tolerance), sizeof(Float));
+ ifs.read(as_bytes(ns.maxiter), sizeof(unsigned int));
+ ifs.read(as_bytes(ns.ndem), sizeof(unsigned int));
- ifs.read(as_bytes(ns.c_phi), sizeof(Float));
- ifs.read(as_bytes(ns.c_v), sizeof(Float));
- ifs.read(as_bytes(ns.dt_dem_fac), sizeof(Float));
+ ifs.read(as_bytes(ns.c_phi), sizeof(Float));
+ ifs.read(as_bytes(ns.c_v), sizeof(Float));
+ ifs.read(as_bytes(ns.dt_dem_fac), sizeof(Float));
- for (i = 0; i<np; ++i) {
- ifs.read(as_bytes(ns.f_d[i].x), sizeof(Float));
- ifs.read(as_bytes(ns.f_d[i].y), sizeof(Float));
- ifs.read(as_bytes(ns.f_d[i].z), sizeof(Float));
- }
- for (i = 0; i<np; ++i) {
- ifs.read(as_bytes(ns.f_p[i].x), sizeof(Float));
- ifs.read(as_bytes(ns.f_p[i].y), sizeof(Float));
- ifs.read(as_bytes(ns.f_p[i].z), sizeof(Float));
- }
- for (i = 0; i<np; ++i) {
- ifs.read(as_bytes(ns.f_v[i].x), sizeof(Float));
- ifs.read(as_bytes(ns.f_v[i].y), sizeof(Float));
- ifs.read(as_bytes(ns.f_v[i].z), sizeof(Float));
- }
- for (i = 0; i<np; ++i) {
- ifs.read(as_bytes(ns.f_sum[i].x), sizeof(Float));
- ifs.read(as_bytes(ns.f_sum[i].y), sizeof(Float));
- ifs.read(as_bytes(ns.f_sum[i].z), sizeof(Float));
- }
+ for (i = 0; i<np; ++i) {
+ ifs.read(as_bytes(ns.f_d[i].x), sizeof(Float));
+ ifs.read(as_bytes(ns.f_d[i].y), sizeof(Float));
+ ifs.read(as_bytes(ns.f_d[i].z), sizeof(Float));
+ }
+ for (i = 0; i<np; ++i) {
+ ifs.read(as_bytes(ns.f_p[i].x), sizeof(Float));
+ ifs.read(as_bytes(ns.f_p[i].y), sizeof(Float));
+ ifs.read(as_bytes(ns.f_p[i].z), sizeof(Float));
+ }
+ for (i = 0; i<np; ++i) {
+ ifs.read(as_bytes(ns.f_v[i].x), sizeof(Float));
+ ifs.read(as_bytes(ns.f_v[i].y), sizeof(Float));
+ ifs.read(as_bytes(ns.f_v[i].z), sizeof(Float));
+ }
+ for (i = 0; i<np; ++i) {
+ ifs.read(as_bytes(ns.f_sum[i].x), sizeof(Float));
+ ifs.read(as_bytes(ns.f_sum[i].y), sizeof(Float));
+ ifs.read(as_bytes(ns.f_sum[i].z), sizeof(Float));
+ }
+
+ if (verbose == 1)
+ cout << "Done" << std::endl;
- if (verbose == 1)
- cout << "Done" << std::endl;
+ } else if (cfd_solver == 1) { // Darcy flow
+
+ initDarcyMem();
+
+ ifs.read(as_bytes(darcy.mu), sizeof(Float));
+
+ if (verbose == 1)
+ cout << " - Reading fluid values:\t\t\t ";
+
+ for (z = 0; z<darcy.nz; ++z) {
+ for (y = 0; y<darcy.ny; ++y) {
+ for (x = 0; x<darcy.nx; ++x) {
+ i = d_idx(x,y,z);
+ ifs.read(as_bytes(darcy.v[i].x), sizeof(Float));
+ ifs.read(as_bytes(darcy.v[i].y), sizeof(Float));
+ ifs.read(as_bytes(darcy.v[i].z), sizeof(Float));
+ ifs.read(as_bytes(darcy.p[i]), sizeof(Float));
+ ifs.read(as_bytes(darcy.phi[i]), sizeof(Float));
+ ifs.read(as_bytes(darcy.dphi[i]), sizeof(Float));
+ }
+ }
+ }
+
+ ifs.read(as_bytes(darcy.rho_f), sizeof(Float));
+ ifs.read(as_bytes(darcy.p_mod_A), sizeof(Float));
+ ifs.read(as_bytes(darcy.p_mod_f), sizeof(Float));
+ ifs.read(as_bytes(darcy.p_mod_phi), sizeof(Float));
+
+ ifs.read(as_bytes(darcy.bc_bot), sizeof(int));
+ ifs.read(as_bytes(darcy.bc_top), sizeof(int));
+ ifs.read(as_bytes(darcy.free_slip_bot), sizeof(int));
+ ifs.read(as_bytes(darcy.free_slip_top), sizeof(int));
+
+ ifs.read(as_bytes(darcy.tolerance), sizeof(Float));
+ ifs.read(as_bytes(darcy.maxiter), sizeof(unsigned int));
+ ifs.read(as_bytes(darcy.ndem), sizeof(unsigned int));
+ ifs.read(as_bytes(darcy.c_phi), sizeof(Float));
+
+ for (i = 0; i<np; ++i) {
+ ifs.read(as_bytes(darcy.f_p[i].x), sizeof(Float));
+ ifs.read(as_bytes(darcy.f_p[i].y), sizeof(Float));
+ ifs.read(as_bytes(darcy.f_p[i].z), sizeof(Float));
+ }
+
+ ifs.read(as_bytes(darcy.beta_f), sizeof(Float));
+ ifs.read(as_bytes(darcy.k_c), sizeof(Float));
+
+ if (verbose == 1)
+ cout << "Done" << std::endl;
+ }
}
for (i = 0; i<np; ++i)
t@@ -484,73 +546,128 @@ void DEM::writebin(const char *target)
ofs.write(as_bytes(k.bonds_omega[i].z), sizeof(Float));
}
- if (navierstokes == 1) { // Navier Stokes flow
+ if (fluid == 1) {
- ofs.write(as_bytes(params.mu), sizeof(params.mu));
+ ofs.write(as_bytes(cfd_solver), sizeof(int));
- int x, y, z;
- for (z=0; z<ns.nz; z++) {
- for (y=0; y<ns.ny; y++) {
- for (x=0; x<ns.nx; x++) {
- i = idx(x,y,z);
+ if (cfd_solver == 0) { // Navier Stokes flow
+
+ ofs.write(as_bytes(ns.mu), sizeof(Float));
+
+ int x, y, z;
+ for (z=0; z<ns.nz; z++) {
+ for (y=0; y<ns.ny; y++) {
+ for (x=0; x<ns.nx; x++) {
+ i = idx(x,y,z);
- // Interpolated cell-center velocities
- ofs.write(as_bytes(ns.v[i].x), sizeof(Float));
- ofs.write(as_bytes(ns.v[i].y), sizeof(Float));
- ofs.write(as_bytes(ns.v[i].z), sizeof(Float));
+ // Interpolated cell-center velocities
+ ofs.write(as_bytes(ns.v[i].x), sizeof(Float));
+ ofs.write(as_bytes(ns.v[i].y), sizeof(Float));
+ ofs.write(as_bytes(ns.v[i].z), sizeof(Float));
- // Cell-face velocities
- //ofs.write(as_bytes(ns.v_x[vidx(x,y,z)]), sizeof(Floa…
- //ofs.write(as_bytes(ns.v_y[vidx(x,y,z)]), sizeof(Floa…
- //ofs.write(as_bytes(ns.v_z[vidx(x,y,z)]), sizeof(Floa…
+ // Cell-face velocities
+ //ofs.write(as_bytes(ns.v_x[vidx(x,y,z)]), sizeof(…
+ //ofs.write(as_bytes(ns.v_y[vidx(x,y,z)]), sizeof(…
+ //ofs.write(as_bytes(ns.v_z[vidx(x,y,z)]), sizeof(…
- ofs.write(as_bytes(ns.p[i]), sizeof(Float));
- ofs.write(as_bytes(ns.phi[i]), sizeof(Float));
- ofs.write(as_bytes(ns.dphi[i]), sizeof(Float));
+ ofs.write(as_bytes(ns.p[i]), sizeof(Float));
+ ofs.write(as_bytes(ns.phi[i]), sizeof(Float));
+ ofs.write(as_bytes(ns.dphi[i]), sizeof(Float));
+ }
}
}
- }
- ofs.write(as_bytes(params.rho_f), sizeof(Float));
- ofs.write(as_bytes(ns.p_mod_A), sizeof(Float));
- ofs.write(as_bytes(ns.p_mod_f), sizeof(Float));
- ofs.write(as_bytes(ns.p_mod_phi), sizeof(Float));
+ ofs.write(as_bytes(ns.rho_f), sizeof(Float));
+ ofs.write(as_bytes(ns.p_mod_A), sizeof(Float));
+ ofs.write(as_bytes(ns.p_mod_f), sizeof(Float));
+ ofs.write(as_bytes(ns.p_mod_phi), sizeof(Float));
+
+ ofs.write(as_bytes(ns.bc_bot), sizeof(int));
+ ofs.write(as_bytes(ns.bc_top), sizeof(int));
+ ofs.write(as_bytes(ns.free_slip_bot), sizeof(int));
+ ofs.write(as_bytes(ns.free_slip_top), sizeof(int));
+
+ ofs.write(as_bytes(ns.gamma), sizeof(Float));
+ ofs.write(as_bytes(ns.theta), sizeof(Float));
+ ofs.write(as_bytes(ns.beta), sizeof(Float));
+ ofs.write(as_bytes(ns.tolerance), sizeof(Float));
+ ofs.write(as_bytes(ns.maxiter), sizeof(unsigned int));
+ ofs.write(as_bytes(ns.ndem), sizeof(unsigned int));
+
+ ofs.write(as_bytes(ns.c_phi), sizeof(Float));
+ ofs.write(as_bytes(ns.c_v), sizeof(Float));
+ ofs.write(as_bytes(ns.dt_dem_fac), sizeof(Float));
+
+ for (i = 0; i<np; ++i) {
+ ofs.write(as_bytes(ns.f_d[i].x), sizeof(Float));
+ ofs.write(as_bytes(ns.f_d[i].y), sizeof(Float));
+ ofs.write(as_bytes(ns.f_d[i].z), sizeof(Float));
+ }
+ for (i = 0; i<np; ++i) {
+ ofs.write(as_bytes(ns.f_p[i].x), sizeof(Float));
+ ofs.write(as_bytes(ns.f_p[i].y), sizeof(Float));
+ ofs.write(as_bytes(ns.f_p[i].z), sizeof(Float));
+ }
+ for (i = 0; i<np; ++i) {
+ ofs.write(as_bytes(ns.f_v[i].x), sizeof(Float));
+ ofs.write(as_bytes(ns.f_v[i].y), sizeof(Float));
+ ofs.write(as_bytes(ns.f_v[i].z), sizeof(Float));
+ }
+ for (i = 0; i<np; ++i) {
+ ofs.write(as_bytes(ns.f_sum[i].x), sizeof(Float));
+ ofs.write(as_bytes(ns.f_sum[i].y), sizeof(Float));
+ ofs.write(as_bytes(ns.f_sum[i].z), sizeof(Float));
+ }
+
+ } else if (cfd_solver == 1) { // Darcy flow
- ofs.write(as_bytes(ns.bc_bot), sizeof(int));
- ofs.write(as_bytes(ns.bc_top), sizeof(int));
- ofs.write(as_bytes(ns.free_slip_bot), sizeof(int));
- ofs.write(as_bytes(ns.free_slip_top), sizeof(int));
+ ofs.write(as_bytes(darcy.mu), sizeof(Float));
- ofs.write(as_bytes(ns.gamma), sizeof(Float));
- ofs.write(as_bytes(ns.theta), sizeof(Float));
- ofs.write(as_bytes(ns.beta), sizeof(Float));
- ofs.write(as_bytes(ns.tolerance), sizeof(Float));
- ofs.write(as_bytes(ns.maxiter), sizeof(unsigned int));
- ofs.write(as_bytes(ns.ndem), sizeof(unsigned int));
+ int x, y, z;
+ for (z=0; z<darcy.nz; z++) {
+ for (y=0; y<darcy.ny; y++) {
+ for (x=0; x<darcy.nx; x++) {
+ i = d_idx(x,y,z);
- ofs.write(as_bytes(ns.c_phi), sizeof(Float));
- ofs.write(as_bytes(ns.c_v), sizeof(Float));
- ofs.write(as_bytes(ns.dt_dem_fac), sizeof(Float));
+ // Interpolated cell-center velocities
+ ofs.write(as_bytes(darcy.v[i].x), sizeof(Float));
+ ofs.write(as_bytes(darcy.v[i].y), sizeof(Float));
+ ofs.write(as_bytes(darcy.v[i].z), sizeof(Float));
- for (i = 0; i<np; ++i) {
- ofs.write(as_bytes(ns.f_d[i].x), sizeof(Float));
- ofs.write(as_bytes(ns.f_d[i].y), sizeof(Float));
- ofs.write(as_bytes(ns.f_d[i].z), sizeof(Float));
- }
- for (i = 0; i<np; ++i) {
- ofs.write(as_bytes(ns.f_p[i].x), sizeof(Float));
- ofs.write(as_bytes(ns.f_p[i].y), sizeof(Float));
- ofs.write(as_bytes(ns.f_p[i].z), sizeof(Float));
- }
- for (i = 0; i<np; ++i) {
- ofs.write(as_bytes(ns.f_v[i].x), sizeof(Float));
- ofs.write(as_bytes(ns.f_v[i].y), sizeof(Float));
- ofs.write(as_bytes(ns.f_v[i].z), sizeof(Float));
- }
- for (i = 0; i<np; ++i) {
- ofs.write(as_bytes(ns.f_sum[i].x), sizeof(Float));
- ofs.write(as_bytes(ns.f_sum[i].y), sizeof(Float));
- ofs.write(as_bytes(ns.f_sum[i].z), sizeof(Float));
+ // Cell-face velocities
+ //ofs.write(as_bytes(darcy.v_x[vidx(x,y,z)]), size…
+ //ofs.write(as_bytes(darcy.v_y[vidx(x,y,z)]), size…
+ //ofs.write(as_bytes(darcy.v_z[vidx(x,y,z)]), size…
+
+ ofs.write(as_bytes(darcy.p[i]), sizeof(Float));
+ ofs.write(as_bytes(darcy.phi[i]), sizeof(Float));
+ ofs.write(as_bytes(darcy.dphi[i]), sizeof(Float));
+ }
+ }
+ }
+
+ ofs.write(as_bytes(darcy.rho_f), sizeof(Float));
+ ofs.write(as_bytes(darcy.p_mod_A), sizeof(Float));
+ ofs.write(as_bytes(darcy.p_mod_f), sizeof(Float));
+ ofs.write(as_bytes(darcy.p_mod_phi), sizeof(Float));
+
+ ofs.write(as_bytes(darcy.bc_bot), sizeof(int));
+ ofs.write(as_bytes(darcy.bc_top), sizeof(int));
+ ofs.write(as_bytes(darcy.free_slip_bot), sizeof(int));
+ ofs.write(as_bytes(darcy.free_slip_top), sizeof(int));
+
+ ofs.write(as_bytes(darcy.tolerance), sizeof(Float));
+ ofs.write(as_bytes(darcy.maxiter), sizeof(unsigned int));
+ ofs.write(as_bytes(darcy.ndem), sizeof(unsigned int));
+ ofs.write(as_bytes(darcy.c_phi), sizeof(Float));
+
+ for (i = 0; i<np; ++i) {
+ ofs.write(as_bytes(darcy.f_p[i].x), sizeof(Float));
+ ofs.write(as_bytes(darcy.f_p[i].y), sizeof(Float));
+ ofs.write(as_bytes(darcy.f_p[i].z), sizeof(Float));
+ }
+ ofs.write(as_bytes(darcy.beta_f), sizeof(Float));
+ ofs.write(as_bytes(darcy.k_c), sizeof(Float));
}
}
diff --git a/src/navierstokes.cpp b/src/navierstokes.cpp
t@@ -122,7 +122,7 @@ void DEM::checkNSstability()
const Float dmin = fmin(dx, fmin(dy, dz));
// Check the diffusion term using von Neumann stability analysis
- if (params.mu*time.dt/(dmin*dmin) > 0.5) {
+ if (ns.mu*time.dt/(dmin*dmin) > 0.5) {
std::cerr << "Error: The time step is too large to ensure stability in…
"the diffusive term of the fluid momentum equation.\n"
"Decrease the viscosity, decrease the time step, and/or increase "
t@@ -279,7 +279,7 @@ double DEM::maxNormResNS()
for (int z=0; z<grid.num[2]; ++z) {
for (int y=0; y<grid.num[1]; ++y) {
for (int x=0; x<grid.num[0]; ++x) {
- norm_res = static_cast<double>(ns.norm[idx(x,y,z)]);
+ norm_res = fabs(static_cast<double>(ns.norm[idx(x,y,z)]));
if (norm_res != norm_res) {
std::cerr << "\nError: normalized residual is NaN ("
<< norm_res << ") in cell "
diff --git a/src/navierstokes.cuh b/src/navierstokes.cuh
t@@ -1309,7 +1309,7 @@ __global__ void findPorositiesVelocitiesDiametersSpheric…
dev_ns_vp_avg[cellidx] = v_avg;
dev_ns_d_avg[cellidx] = d_avg;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat("phi", x, y, z, phi);
(void)checkFiniteFloat("dphi", x, y, z, dphi);
(void)checkFiniteFloat3("v_avg", x, y, z, v_avg);
t@@ -1526,7 +1526,7 @@ __global__ void findPorositiesVelocitiesDiametersSpheric…
dev_ns_vp_avg[cellidx] = v_avg;
dev_ns_d_avg[cellidx] = d_avg;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat("phi", x, y, z, phi);
(void)checkFiniteFloat("dphi", x, y, z, dphi);
(void)checkFiniteFloat3("v_avg", x, y, z, v_avg);
t@@ -1578,7 +1578,7 @@ __global__ void setUpperPressureNS(
dev_ns_epsilon_new[cellidx] = epsilon;
dev_ns_p[cellidx] = new_pressure;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat("epsilon", x, y, z, epsilon);
(void)checkFiniteFloat("new_pressure", x, y, z, new_pressure);
#endif
t@@ -1715,7 +1715,7 @@ __device__ Float3 divergence_tensor(
(t_yz_yp - t_yz_yn)/dy +
(t_zz_zp - t_zz_zn)/dz);
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat3("div_tensor", x, y, z, div_tensor);
#endif
return div_tensor;
t@@ -1755,7 +1755,7 @@ __global__ void findNSgradientsDev(
__syncthreads();
dev_vectorfield[cellidx] = grad;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat3("grad", x, y, z, grad);
#endif
}
t@@ -1799,7 +1799,7 @@ __global__ void findvvOuterProdNS(
dev_ns_v_prod[cellidx6+4] = v.y*v.z;
dev_ns_v_prod[cellidx6+5] = v.z*v.z;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat("v_prod[0]", x, y, z, v.x*v.x);
(void)checkFiniteFloat("v_prod[1]", x, y, z, v.x*v.y);
(void)checkFiniteFloat("v_prod[2]", x, y, z, v.x*v.z);
t@@ -1815,6 +1815,7 @@ __global__ void findvvOuterProdNS(
// values in 3D.
__global__ void findNSstressTensor(
const Float3* __restrict__ dev_ns_v, // in
+ const Float mu, // in
Float* __restrict__ dev_ns_tau) // out
{
// 3D thread index
t@@ -1860,17 +1861,17 @@ __global__ void findNSstressTensor(
const Float3 zn = dev_ns_v[idx(x,y,z-1)];
// The diagonal stress tensor components
- const Float tau_xx = 2.0*devC_params.mu*(xp.x - xn.x)/(2.0*dx);
- const Float tau_yy = 2.0*devC_params.mu*(yp.y - yn.y)/(2.0*dy);
- const Float tau_zz = 2.0*devC_params.mu*(zp.z - zn.z)/(2.0*dz);
+ const Float tau_xx = 2.0*mu*(xp.x - xn.x)/(2.0*dx);
+ const Float tau_yy = 2.0*mu*(yp.y - yn.y)/(2.0*dy);
+ const Float tau_zz = 2.0*mu*(zp.z - zn.z)/(2.0*dz);
// The off-diagonal stress tensor components
const Float tau_xy =
- devC_params.mu*((yp.x - yn.x)/(2.0*dy) + (xp.y - xn.y)/(2.0*dx));
+ mu*((yp.x - yn.x)/(2.0*dy) + (xp.y - xn.y)/(2.0*dx));
const Float tau_xz =
- devC_params.mu*((zp.x - zn.x)/(2.0*dz) + (xp.z - xn.z)/(2.0*dx));
+ mu*((zp.x - zn.x)/(2.0*dz) + (xp.z - xn.z)/(2.0*dx));
const Float tau_yz =
- devC_params.mu*((zp.y - zn.y)/(2.0*dz) + (yp.z - yn.z)/(2.0*dy));
+ mu*((zp.y - zn.y)/(2.0*dz) + (yp.z - yn.z)/(2.0*dy));
/*
if (x == 0 && y == 0 && z == 0)
t@@ -1892,7 +1893,7 @@ __global__ void findNSstressTensor(
dev_ns_tau[cellidx6+4] = tau_yz;
dev_ns_tau[cellidx6+5] = tau_zz;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat("tau_xx", x, y, z, tau_xx);
(void)checkFiniteFloat("tau_xy", x, y, z, tau_xy);
(void)checkFiniteFloat("tau_xz", x, y, z, tau_xz);
t@@ -2036,7 +2037,7 @@ __global__ void findNSdivphiviv(
//printf("div(phi*v*v) [%d,%d,%d] = %f, %f, %f\n", x,y,z,
//div_phi_vi_v.x, div_phi_vi_v.y, div_phi_vi_v.z);
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat3("div_phi_vi_v", x, y, z, div_phi_vi_v);
#endif
}
t@@ -2175,7 +2176,7 @@ __global__ void findNSdivphitau(
__syncthreads();
dev_ns_div_phi_tau[cellidx] = div_phi_tau;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat3("div_phi_tau", x, y, z, div_phi_tau);
#endif
}
t@@ -2263,7 +2264,7 @@ __global__ void findNSdivphivv(
__syncthreads();
dev_ns_div_phi_v_v[cellidx] = div;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat3("div_phi_v_v", x, y, z, div);
#endif
}
t@@ -2290,6 +2291,8 @@ __global__ void findPredNSvelocities(
const unsigned int ndem, // in
const unsigned int wall0_iz, // in
const Float c_v, // in
+ const Float mu, // in
+ const Float rho_f, // in
Float* __restrict__ dev_ns_v_p_x, // out
Float* __restrict__ dev_ns_v_p_y, // out
Float* __restrict__ dev_ns_v_p_z) // out
t@@ -2326,7 +2329,7 @@ __global__ void findPredNSvelocities(
//printf("v in v* [%d,%d,%d] = %f, %f, %f\n", x,y,z, v.x, v.y, v.z);
Float3 div_tau = MAKE_FLOAT3(0.0, 0.0, 0.0);
- if (devC_params.mu > 0.0) {
+ if (mu > 0.0) {
div_tau = MAKE_FLOAT3(
dev_ns_div_tau_x[fidx],
dev_ns_div_tau_y[fidx],
t@@ -2362,7 +2365,7 @@ __global__ void findPredNSvelocities(
// The particle-fluid interaction force should only be incoorporated if
// there is a fluid viscosity
Float3 f_i_c, f_i_xn, f_i_yn, f_i_zn;
- if (devC_params.mu > 0.0 && devC_np > 0) {
+ if (mu > 0.0 && devC_np > 0) {
f_i_c = dev_ns_F_pf[cellidx];
f_i_xn = dev_ns_F_pf[idx(x-1,y,z)];
f_i_yn = dev_ns_F_pf[idx(x,y-1,z)];
t@@ -2379,7 +2382,6 @@ __global__ void findPredNSvelocities(
amean(f_i_c.z, f_i_zn.z));
const Float dt = ndem*devC_dt;
- const Float rho = devC_params.rho_f;
// The pressure gradient is not needed in Chorin's projection method
// (ns.beta=0), so only has to be looked up in pressure-dependant
t@@ -2396,10 +2398,10 @@ __global__ void findPredNSvelocities(
(p - p_yn)/dy,
(p - p_zn)/dz);
#ifdef SET_1
- pressure_term = -beta*dt/(rho*phi)*grad_p;
+ pressure_term = -beta*dt/(rho_f*phi)*grad_p;
#endif
#ifdef SET_2
- pressure_term = -beta*dt/rho*grad_p;
+ pressure_term = -beta*dt/rho_f*grad_p;
#endif
}
t@@ -2409,16 +2411,16 @@ __global__ void findPredNSvelocities(
amean(div_phi_vi_v_zn.x, div_phi_vi_v_c.z));
// Determine the terms of the predicted velocity change
- const Float3 interaction_term = -dt/(rho*phi)*f_i;
+ const Float3 interaction_term = -dt/(rho_f*phi)*f_i;
const Float3 gravity_term = MAKE_FLOAT3(
devC_params.g[0], devC_params.g[1], devC_params.g[2])*dt;
const Float3 advection_term = -1.0*div_phi_vi_v*dt/phi;
const Float3 porosity_term = -1.0*v*dphi/phi;
#ifdef SET_1
- const Float3 diffusion_term = dt/(rho*phi)*div_tau;
+ const Float3 diffusion_term = dt/(rho_f*phi)*div_tau;
#endif
#ifdef SET_2
- const Float3 diffusion_term = dt/rho*div_tau;
+ const Float3 diffusion_term = dt/rho_f*div_tau;
#endif
// Predict new velocity and add scaling parameters
t@@ -2481,7 +2483,7 @@ __global__ void findPredNSvelocities(
dev_ns_v_p_y[fidx] = v_p.y;
dev_ns_v_p_z[fidx] = v_p.z;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat3("v_p", x, y, z, v_p);
#endif
}
t@@ -2503,6 +2505,7 @@ __global__ void findNSforcing(
const unsigned int nijac, // in
const unsigned int ndem, // in
const Float c_v, // in
+ const Float rho_f, // in
Float* __restrict__ dev_ns_f1, // out
Float3* __restrict__ dev_ns_f2, // out
Float* __restrict__ dev_ns_f) // out
t@@ -2554,14 +2557,14 @@ __global__ void findNSforcing(
// Find forcing function terms
#ifdef SET_1
- const Float t1 = devC_params.rho_f*phi*div_v_p/(c_v*dt);
- const Float t2 = devC_params.rho_f*dot(grad_phi, v_p)/(c_v*dt);
- const Float t4 = devC_params.rho_f*dphi/(dt*dt*c_v);
+ const Float t1 = rho_f*phi*div_v_p/(c_v*dt);
+ const Float t2 = rho_f*dot(grad_phi, v_p)/(c_v*dt);
+ const Float t4 = rho_f*dphi/(dt*dt*c_v);
#endif
#ifdef SET_2
- const Float t1 = devC_params.rho_f*div_v_p/(c_v*dt);
- const Float t2 = devC_params.rho_f*dot(grad_phi, v_p)/(c_v*dt*phi);
- const Float t4 = devC_params.rho_f*dphi/(dt*dt*phi*c_v);
+ const Float t1 = rho_f*div_v_p/(c_v*dt);
+ const Float t2 = rho_f*dot(grad_phi, v_p)/(c_v*dt*phi);
+ const Float t4 = rho_f*dphi/(dt*dt*phi*c_v);
#endif
f1 = t1 + t2 + t4;
f2 = grad_phi/phi; // t3/grad(epsilon)
t@@ -2603,7 +2606,7 @@ __global__ void findNSforcing(
__syncthreads();
dev_ns_f[cellidx] = f;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat("f", x, y, z, f);
#endif
}
t@@ -2666,7 +2669,7 @@ __global__ void smoothing(
" e_zn = %f, e_zp = %f\n", x,y,z, e_xn, e_xp,
e_yn, e_yp, e_zn, e_zp);*/
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat("e_smooth", x, y, z, e_smooth);
#endif
}
t@@ -2775,7 +2778,7 @@ __global__ void jacobiIterationNS(
dev_ns_epsilon_new[cellidx] = e_relax;
dev_ns_norm[cellidx] = res_norm;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
(void)checkFiniteFloat("e_new", x, y, z, e_new);
(void)checkFiniteFloat("e_relax", x, y, z, e_relax);
//(void)checkFiniteFloat("res_norm", x, y, z, res_norm);
t@@ -2861,12 +2864,13 @@ __global__ void findNormalizedResiduals(
// Find the normalized residual value. A small value is added to the
// denominator to avoid a divide by zero.
- const Float res_norm = (e_new - e)*(e_new - e)/(e_new*e_new + 1.0e-16);
+ //const Float res_norm = (e_new - e)*(e_new - e)/(e_new*e_new + 1.0e-1…
+ const Float res_norm = (e_new - e)/(e + 1.0e-16);
__syncthreads();
dev_ns_norm[cellidx] = res_norm;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
checkFiniteFloat("res_norm", x, y, z, res_norm);
#endif
}
t@@ -2902,7 +2906,7 @@ __global__ void updateNSpressure(
__syncthreads();
dev_ns_p[cellidx] = p;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
checkFiniteFloat("p", x, y, z, p);
#endif
}
t@@ -2919,6 +2923,7 @@ __global__ void updateNSvelocity(
const int bc_top, // in
const unsigned int ndem, // in
const Float c_v, // in
+ const Float rho_f, // in
const unsigned int wall0_iz, // in
const unsigned int iter, // in
Float* __restrict__ dev_ns_v_x, // out
t@@ -2978,10 +2983,10 @@ __global__ void updateNSvelocity(
// Find new velocity
Float3 v = v_p
#ifdef SET_1
- - c_v*ndem*devC_dt/(phi*devC_params.rho_f)*grad_epsilon;
+ - c_v*ndem*devC_dt/(phi*rho_f)*grad_epsilon;
#endif
#ifdef SET_2
- - c_v*ndem*devC_dt/devC_params.rho_f*grad_epsilon;
+ - c_v*ndem*devC_dt/rho_f*grad_epsilon;
#endif
if ((z == 0 && bc_bot == 1) || (z > nz-1 && bc_top == 1))
t@@ -3043,7 +3048,7 @@ __global__ void updateNSvelocity(
dev_ns_v_y[cellidx] = v.y;
dev_ns_v_z[cellidx] = v.z;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
checkFiniteFloat3("v", x, y, z, v);
#endif
}
t@@ -3112,7 +3117,7 @@ __global__ void findAvgParticleVelocityDiameter(
dev_ns_vp_avg[cellidx] = v_avg;
dev_ns_d_avg[cellidx] = d_avg;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
checkFiniteFloat3("v_avg", x, y, z, v_avg);
checkFiniteFloat("d_avg", x, y, z, d_avg);
#endif
t@@ -3144,6 +3149,8 @@ __global__ void findInteractionForce(
const Float* __restrict__ dev_ns_div_tau_x,// in
const Float* __restrict__ dev_ns_div_tau_y,// in
const Float* __restrict__ dev_ns_div_tau_z,// in
+ const Float mu, // in
+ const Float rho_f, // in
//const Float c_v, // in
Float3* __restrict__ dev_ns_f_pf, // out
Float4* __restrict__ dev_force, // out
t@@ -3209,7 +3216,7 @@ __global__ void findInteractionForce(
const Float v_rel_length = length(v_rel);
const Float V_p = dx*dy*dz - phi*dx*dy*dz;
- const Float Re = devC_params.rho_f*d*phi*v_rel_length/devC_params.mu;
+ const Float Re = rho_f*d*phi*v_rel_length/mu;
Float Cd = pow(0.63 + 4.8/pow(Re, 0.5), 2.0);
Float chi = 3.7 - 0.65*exp(-pow(1.5 - log10(Re), 2.0)/2.0);
t@@ -3219,7 +3226,7 @@ __global__ void findInteractionForce(
}
// Drag force
- const Float3 f_d = 0.125*Cd*devC_params.rho_f*M_PI*d*d*phi*phi
+ const Float3 f_d = 0.125*Cd*rho_f*M_PI*d*d*phi*phi
*v_rel_length*v_rel*pow(phi, -chi);
// Pressure gradient force
t@@ -3233,7 +3240,7 @@ __global__ void findInteractionForce(
__syncthreads();
const Float3 f_pf = f_d + f_p + f_v;
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
/*
printf("\nfindInteractionForce %d [%d,%d,%d]\n"
"\tV_p = %f Re=%f Cd=%f chi=%f\n"
t@@ -3325,7 +3332,7 @@ __global__ void applyInteractionForceToFluid(
const Float3 F_pf = fi/(dx*dy*dz);
-#ifdef CHECK_NS_FINITE
+#ifdef CHECK_FLUID_FINITE
checkFiniteFloat3("F_pf", x, y, z, F_pf);
#endif
//printf("F_pf [%d,%d,%d] = %f,%f,%f\n", x,y,z, F_pf.x, F_pf.y, F_pf.z…
t@@ -3418,12 +3425,13 @@ __global__ void interpolateFaceToCenter(
// Warning: The grid-corner values will be invalid, along with the non-normal
// components of the ghost nodes
__global__ void findFaceDivTau(
- const Float* __restrict__ dev_ns_v_x,
- const Float* __restrict__ dev_ns_v_y,
- const Float* __restrict__ dev_ns_v_z,
- Float* __restrict__ dev_ns_div_tau_x,
- Float* __restrict__ dev_ns_div_tau_y,
- Float* __restrict__ dev_ns_div_tau_z)
+ const Float* __restrict__ dev_ns_v_x, // in
+ const Float* __restrict__ dev_ns_v_y, // in
+ const Float* __restrict__ dev_ns_v_z, // in
+ const Float mu, // in
+ Float* __restrict__ dev_ns_div_tau_x, // out
+ Float* __restrict__ dev_ns_div_tau_y, // out
+ Float* __restrict__ dev_ns_div_tau_z) // out
{
// 3D thread index
const unsigned int x = blockDim.x * blockIdx.x + threadIdx.x;
t@@ -3472,17 +3480,17 @@ __global__ void findFaceDivTau(
const Float v_z_zp = dev_ns_v_z[vidx(x,y,z+1)];
const Float div_tau_x =
- devC_params.mu*(
+ mu*(
(v_x_xp - 2.0*v_x + v_x_xn)/(dx*dx) +
(v_x_yp - 2.0*v_x + v_x_yn)/(dy*dy) +
(v_x_zp - 2.0*v_x + v_x_zn)/(dz*dz));
const Float div_tau_y =
- devC_params.mu*(
+ mu*(
(v_y_xp - 2.0*v_y + v_y_xn)/(dx*dx) +
(v_y_yp - 2.0*v_y + v_y_yn)/(dy*dy) +
(v_y_zp - 2.0*v_y + v_y_zn)/(dz*dz));
const Float div_tau_z =
- devC_params.mu*(
+ mu*(
(v_z_xp - 2.0*v_z + v_z_xn)/(dx*dx) +
(v_z_yp - 2.0*v_z + v_z_yn)/(dy*dy) +
(v_z_zp - 2.0*v_z + v_z_zn)/(dz*dz));
diff --git a/src/sphere.cpp b/src/sphere.cpp
t@@ -21,7 +21,7 @@ DEM::DEM(const std::string inputbin,
const int transferConstMem,
const int fluidFlow,
const int device)
-: verbose(verbosity), navierstokes(fluidFlow), device(device)
+: verbose(verbosity), fluid(fluidFlow), device(device)
{
using std::cout;
using std::cerr;
t@@ -50,8 +50,16 @@ DEM::DEM(const std::string inputbin,
if (dry == 1)
exit(0);
- if (navierstokes == 1) {
- initNS();
+ if (fluid == 1) {
+ if (cfd_solver == 0)
+ initNS();
+ else if (cfd_solver == 1)
+ initDarcy();
+ else {
+ std::cerr << "DEM::DEM Error: Value of cfd_solver not understood ("
+ << cfd_solver << ")" << std::endl;
+ exit(1);
+ }
}
if (initCuda == 1) {
t@@ -64,8 +72,17 @@ DEM::DEM(const std::string inputbin,
transferToConstantDeviceMemory();
}
- if (navierstokes == 1) {
- initNSmemDev();
+ if (fluid == 1) {
+ if (cfd_solver == 0)
+ initNSmemDev();
+ else if (cfd_solver == 1)
+ initDarcyMemDev();
+ else {
+ std::cerr
+ << "DEM::DEM Error: Value of cfd_solver not understood ("
+ << cfd_solver << ")" << std::endl;
+ exit(1);
+ }
}
// Allocate device memory for particle variables,
t@@ -224,8 +241,8 @@ void DEM::checkValues(void)
checkIfNaN(x, "position", i);
checkIfNaN(vel, "velocity", i);
- checkIfNaN(angpos, "angular position", i);
- checkIfNaN(angvel, "angular velocity", i);
+ //checkIfNaN(angpos, "angular position", i);
+ //checkIfNaN(angvel, "angular velocity", i);
// Check that all particles are inside of the grid
if (x.x < grid.origo[0] ||
t@@ -281,6 +298,44 @@ void DEM::checkValues(void)
cerr << "Error: rho = " << params.rho << " kg/m3" << endl;
exit(1);
}
+
+ if (fluid == 1) {
+
+ // Navier-Stokes tests
+ if (cfd_solver == 0) {
+ if (ns.rho_f <= 0.0) {
+ cerr << "Error: rho = " << params.rho << " kg/m3" << endl;
+ exit(1);
+ }
+ }
+
+ // Darcy tests
+ else if (cfd_solver == 1) {
+ if (darcy.rho_f <= 0.0) {
+ cerr << "Error: rho_f = " << darcy.rho_f << " kg/m3" << endl;
+ exit(1);
+ }
+
+ if (darcy.mu <= 0.0) {
+ cerr << "Error: mu = " << darcy.mu << " Pa s" << endl;
+ exit(1);
+ }
+
+ if (darcy.beta_f <= 0.0) {
+ cerr << "Error: beta_f = " << darcy.beta_f << " 1/Pa" << endl;
+ exit(1);
+ }
+
+ if (darcy.k_c <= 0.0) {
+ cerr << "Error: k_c = " << darcy.k_c << " m*m" << endl;
+ exit(1);
+ }
+ } else {
+ cerr << "Solver type value not understood (cfd_solver = "
+ << cfd_solver << endl;
+ exit(1);
+ }
+ }
}
diff --git a/src/sphere.h b/src/sphere.h
t@@ -173,7 +173,8 @@ class DEM {
Float4 *dev_v_rho; // Device equivalent
//// Porous flow
- int navierstokes; // 0: no, 1: yes
+ int fluid; // 0: no, 1: yes
+ int cfd_solver; // 0: Navier Stokes, 1: Darcy
// Navier Stokes values, host
NavierStokes ns;
t@@ -262,7 +263,7 @@ class DEM {
unsigned int idx(const int x, const int y, const int z); // pres. nodes
unsigned int vidx(const int x, const int y, const int z); // vel. nodes
- // Initialize Darcy values and arrays
+ // Initialize Navier Stokes values and arrays
void initNS();
// Clean up Navier Stokes arrays
t@@ -289,6 +290,50 @@ class DEM {
void transferNSepsilonFromGlobalDeviceMemory();
void transferNSepsilonNewFromGlobalDeviceMemory();
+ // Darcy values, host
+ Darcy darcy;
+
+ // Darcy values, device
+ Float* dev_darcy_p_old; // Previous cell hydraulic pressure
+ Float* dev_darcy_dpdt; // Previous cell hydraulic pressure
+ Float* dev_darcy_p; // Cell hydraulic pressure
+ Float* dev_darcy_p_new; // Updated cell hydraulic pressure
+ Float3* dev_darcy_v; // Cell fluid velocity
+ Float* dev_darcy_phi; // Cell porosity
+ Float* dev_darcy_dphi; // Cell porosity change
+ Float* dev_darcy_norm; // Normalized residual of epsilon values
+ Float4* dev_darcy_f_p; // Pressure gradient force on particles
+ Float* dev_darcy_k; // Cell hydraulic permeability
+ Float3* dev_darcy_grad_k; // Spatial gradient of permeability
+
+ // Darcy functions
+ void initDarcyMem();
+ Float largestDarcyPermeability();
+ Float smallestDarcyPorosity();
+ void initDarcyMemDev();
+ unsigned int darcyCells();
+ unsigned int darcyCellsVelocity();
+ void transferDarcyToGlobalDeviceMemory(int statusmsg);
+ void transferDarcyFromGlobalDeviceMemory(int statusmsg);
+ void transferDarcyNormFromGlobalDeviceMemory();
+ void transferDarcyPressuresFromGlobalDeviceMemory();
+ void freeDarcyMem();
+ void freeDarcyMemDev();
+ unsigned int d_idx(const int x, const int y, const int z);
+ unsigned int d_vidx(const int x, const int y, const int z);
+ void checkDarcyStability();
+ void printDarcyArray(FILE* stream, Float* arr);
+ void printDarcyArray(FILE* stream, Float* arr, std::string desc);
+ void printDarcyArray(FILE* stream, Float3* arr);
+ void printDarcyArray(FILE* stream, Float3* arr, std::string desc);
+ double avgNormResDarcy();
+ double maxNormResDarcy();
+ void initDarcy();
+ void writeDarcyArray(Float* arr, const char* filename);
+ void writeDarcyArray(Float3* arr, const char* filename);
+ void endDarcy();
+ void endDarcyDev();
+
public:
// Values and functions accessible from the outside
diff --git a/src/utility.cu b/src/utility.cu
t@@ -15,10 +15,14 @@ void DEM::diagnostics()
checkValues();
// Clean up memory before exiting
- if (navierstokes == 1) {
+ if (fluid == 1 && cfd_solver == 0) {
freeNSmemDev();
freeNSmem();
}
+ if (fluid == 1 && cfd_solver == 1) {
+ freeDarcyMemDev();
+ freeDarcyMem();
+ }
freeGlobalDeviceMemory();
// CPU memory freed upon object destruction
}
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
t@@ -32,3 +32,15 @@ add_test(cfd_tests_neumann-c_v=0.1 ${PYTHON_EXECUTABLE}
add_test(fluid_particle_interaction ${PYTHON_EXECUTABLE}
${CMAKE_CURRENT_BINARY_DIR}/fluid_particle_interaction.py)
+
+add_test(cfd_tests_darcy ${PYTHON_EXECUTABLE}
+ ${CMAKE_CURRENT_BINARY_DIR}/cfd_tests_darcy.py)
+
+add_test(cfd_tests_neumann_darcy ${PYTHON_EXECUTABLE}
+ ${CMAKE_CURRENT_BINARY_DIR}/cfd_tests_neumann_darcy.py)
+
+add_test(fluid_particle_interaction_darcy ${PYTHON_EXECUTABLE}
+ ${CMAKE_CURRENT_BINARY_DIR}/fluid_particle_interaction_darcy.py)
+
+add_test(cfd_tests_darcy_particles ${PYTHON_EXECUTABLE}
+ ${CMAKE_CURRENT_BINARY_DIR}/cfd_tests_darcy_particles.py)
diff --git a/tests/cfd_tests_darcy.py b/tests/cfd_tests_darcy.py
t@@ -0,0 +1,151 @@
+#!/usr/bin/env python
+from pytestutils import *
+
+import sphere
+import sys
+import numpy
+import matplotlib.pyplot as plt
+
+print("### CFD tests - Dirichlet BCs ###")
+
+# Iteration and conservation of mass test
+# No gravity, no pressure gradients => no flow
+orig = sphere.sim(np = 0, nd = 3, nw = 0, sid = "cfdtest", fluid = True)
+cleanup(orig)
+orig.defaultParams()
+#orig.defineWorldBoundaries([1.0,1.0,1.0], dx=0.1)
+orig.defineWorldBoundaries([0.4,0.3,0.4], dx=0.1)
+orig.initFluid(cfd_solver = 1)
+#orig.initFluid(mu = 8.9e-4)
+orig.initTemporal(total = 0.2, file_dt = 0.01, dt = 1.0e-7)
+#orig.g[2] = -10.0
+orig.time_file_dt = orig.time_dt*0.99
+orig.time_total = orig.time_dt*10
+#orig.run(dry=True)
+orig.run(verbose=False)
+#orig.run(verbose=True)
+py = sphere.sim(sid = orig.sid, fluid = True)
+
+ones = numpy.ones((orig.num))
+py.readlast(verbose = False)
+compareNumpyArrays(ones, py.p_f, "Conservation of pressure:")
+
+# Convergence rate (1/3)
+it = numpy.loadtxt("../output/" + orig.sid + "-conv.log")
+compare(it[:,1].sum(), 0.0, "Convergence rate (1/3):\t")
+
+# Fluid flow should be very small
+if ((numpy.abs(py.v_f[:,:,:,:]) < 1.0e-6).all()):
+ print("Flow field:\t\t" + passed())
+else:
+ print("Flow field:\t\t" + failed())
+ print(numpy.min(py.v_f))
+ print(numpy.mean(py.v_f))
+ print(numpy.max(py.v_f))
+ raise Exception("Failed")
+
+
+# Add pressure gradient
+# This test passes with BETA=0.0 and tolerance=1.0e-9
+orig.p_f[:,:,-1] = 1.1
+#orig.setTolerance(1.0e-8)
+orig.cleanup()
+#orig.time_file_dt = orig.time_dt*0.99
+#orig.time_total = orig.time_dt*1
+orig.run(verbose=False)
+#orig.run(verbose=True)
+py.readlast(verbose = False)
+ideal_grad_p_z = numpy.linspace(orig.p_f[0,0,0], orig.p_f[0,0,-1], orig.num[2])
+#orig.writeVTKall()
+compareNumpyArraysClose(numpy.zeros((1,orig.num[2])),\
+ ideal_grad_p_z - py.p_f[0,0,:],\
+ "Pressure gradient:\t", tolerance=1.0e-1)
+ #"Pressure gradient:\t", tolerance=1.0e-2)
+
+# Fluid flow direction, opposite of gradient (i.e. towards -z)
+if ((py.v_f[:,:,:,2] < 0.0).all() and (py.v_f[:,:,:,0:1] < 1.0e-7).all()):
+ print("Flow field:\t\t" + passed())
+else:
+ print("Flow field:\t\t" + failed())
+ raise Exception("Failed")
+
+# Convergence rate (2/3)
+it = numpy.loadtxt("../output/" + orig.sid + "-conv.log")
+if ((it[0:6,1] < 1000).all() and (it[6:,1] < 20).all()):
+ print("Convergence rate (2/3):\t" + passed())
+else:
+ print("Convergence rate (2/3):\t" + failed())
+#'''
+
+# Long test
+'''
+#orig.p_f[:,:,-1] = 1.1
+orig.time_total[0] = 0.1
+orig.time_file_dt[0] = orig.time_total[0]/10.0
+orig.run(verbose=False)
+py.readlast(verbose = False)
+ideal_grad_p_z = numpy.linspace(orig.p_f[0,0,0], orig.p_f[0,0,-1], orig.num[2])
+#py.writeVTKall()
+compareNumpyArraysClose(numpy.zeros((1,orig.num[2])),\
+ ideal_grad_p_z - py.p_f[0,0,:],\
+ "Pressure gradient (long test):", tolerance=1.0e-2)
+
+# Fluid flow direction, opposite of gradient (i.e. towards -z)
+if ((py.v_f[:,:,:,2] < 0.0).all() and (py.v_f[:,:,:,0:1] < 1.0e-7).all()):
+ print("Flow field:\t\t" + passed())
+else:
+ print("Flow field:\t\t" + failed())
+
+# Convergence rate (3/3)
+# This test passes with BETA=0.0 and tolerance=1.0e-9
+it = numpy.loadtxt("../output/" + orig.sid + "-conv.log")
+if (it[0,1] < 700 and it[1,1] < 250 and (it[2:,1] < 20).all()):
+ print("Convergence rate (3/3):\t" + passed())
+else:
+ print("Convergence rate (3/3):\t" + failed())
+'''
+
+'''
+# Slow pressure modulation test
+orig.cleanup()
+orig.time_total[0] = 1.0e-1
+orig.time_file_dt[0] = 0.101*orig.time_total[0]
+orig.setFluidPressureModulation(A=1.0, f=1.0/orig.time_total[0])
+#orig.plotPrescribedFluidPressures()
+orig.run(verbose=False)
+#py.readlast()
+#py.plotConvergence()
+#py.plotFluidDiffAdvPresZ()
+#py.writeVTKall()
+for it in range(1,py.status()): # gradient should be smooth in all output files
+ py.readstep(it, verbose=False)
+ ideal_grad_p_z =\
+ numpy.linspace(py.p_f[0,0,0], py.p_f[0,0,-1], py.num[2])
+ compareNumpyArraysClose(numpy.zeros((1,py.num[2])),\
+ ideal_grad_p_z - py.p_f[0,0,:],\
+ 'Slow pressure modulation (' +
+ str(it+1) + '/' + str(py.status()) + '):', tolerance=1.0e-1)
+'''
+
+#'''
+# Fast pressure modulation test
+orig.time_total[0] = 1.0e-2
+orig.time_file_dt[0] = 0.101*orig.time_total[0]
+orig.setFluidPressureModulation(A=1.0, f=1.0/orig.time_total[0])
+#orig.plotPrescribedFluidPressures()
+orig.run(verbose=False)
+#py.plotConvergence()
+#py.plotFluidDiffAdvPresZ()
+#py.writeVTKall()
+for it in range(1,py.status()+1): # gradient should be smooth in all output fi…
+ py.readstep(it, verbose=False)
+ #py.plotFluidDiffAdvPresZ()
+ ideal_grad_p_z =\
+ numpy.linspace(py.p_f[0,0,0], py.p_f[0,0,-1], py.num[2])
+ compareNumpyArraysClose(numpy.zeros((1,py.num[2])),\
+ ideal_grad_p_z - py.p_f[0,0,:],\
+ 'Fast pressure modulation (' +
+ str(it) + '/' + str(py.status()) + '):', tolerance=5.0e-1)
+#'''
+
+cleanup(orig)
diff --git a/tests/cfd_tests_darcy_particles.py b/tests/cfd_tests_darcy_particl…
t@@ -0,0 +1,165 @@
+#!/usr/bin/env python
+from pytestutils import *
+import sphere
+import numpy
+
+#'''
+print("### Steady state, no gravity, no forcing, Dirichlet+Dirichlet BCs")
+orig = sphere.sim('darcy_particles', np = 1000)
+orig.cleanup()
+#orig.generateRadii(histogram=False, psd='uni', radius_mean=5.0e-4, radius_var…
+orig.defaultParams()
+orig.generateRadii(psd='uni', mean=5.0e-2, variance=5.0e-5)
+orig.initRandomGridPos([20, 20, 200])
+orig.initTemporal(total=0.005, file_dt=0.001)
+orig.initFluid(cfd_solver=1)
+#orig.p_f[5,3,2] *= 1.5
+#orig.k_c[0] = 4.6e-15
+orig.k_c[0] = 4.6e-10
+#orig.g[2] = -10.0
+orig.setStiffnessNormal(36.4e9)
+orig.setStiffnessTangential(36.4e9/3.0)
+orig.run(verbose=False)
+#orig.writeVTKall()
+py = sphere.sim(sid = orig.sid, fluid = True)
+py.readlast(verbose=False)
+
+ones = numpy.ones((orig.num))
+py.readlast(verbose = False)
+compareNumpyArrays(ones, py.p_f, "Conservation of pressure:")
+
+# Fluid flow should be very small
+if ((numpy.abs(py.v_f[:,:,:,:]) < 1.0e-6).all()):
+ print("Flow field:\t\t" + passed())
+else:
+ print("Flow field:\t\t" + failed())
+ print(numpy.min(py.v_f))
+ print(numpy.mean(py.v_f))
+ print(numpy.max(py.v_f))
+ raise Exception("Failed")
+
+
+
+print("### Steady state, no gravity, no forcing, Neumann+Dirichlet BCs")
+orig = sphere.sim('darcy_particles', np = 1000)
+orig.cleanup()
+#orig.generateRadii(histogram=False, psd='uni', radius_mean=5.0e-4, radius_var…
+orig.defaultParams()
+orig.generateRadii(psd='uni', mean=5.0e-2, variance=5.0e-5)
+orig.initRandomGridPos([20, 20, 200])
+orig.initTemporal(total=0.005, file_dt=0.001)
+orig.initFluid(cfd_solver=1)
+#orig.p_f[5,3,2] *= 1.5
+#orig.k_c[0] = 4.6e-15
+orig.k_c[0] = 4.6e-10
+orig.setFluidBottomNoFlow()
+#orig.g[2] = -10.0
+orig.setStiffnessNormal(36.4e9)
+orig.setStiffnessTangential(36.4e9/3.0)
+orig.run(verbose=False)
+#orig.writeVTKall()
+py = sphere.sim(sid = orig.sid, fluid = True)
+py.readlast(verbose=False)
+
+ones = numpy.ones((orig.num))
+py.readlast(verbose = False)
+compareNumpyArrays(ones, py.p_f, "Conservation of pressure:")
+
+# Fluid flow should be very small
+if ((numpy.abs(py.v_f[:,:,:,:]) < 1.0e-6).all()):
+ print("Flow field:\t\t" + passed())
+else:
+ print("Flow field:\t\t" + failed())
+ print(numpy.min(py.v_f))
+ print(numpy.mean(py.v_f))
+ print(numpy.max(py.v_f))
+ raise Exception("Failed")
+
+
+
+print("### Steady state, no gravity, no forcing, Neumann+Neumann BCs")
+orig = sphere.sim('darcy_particles', np = 1000)
+orig.cleanup()
+#orig.generateRadii(histogram=False, psd='uni', radius_mean=5.0e-4, radius_var…
+orig.defaultParams()
+orig.generateRadii(psd='uni', mean=5.0e-2, variance=5.0e-5)
+orig.initRandomGridPos([20, 20, 200])
+orig.initTemporal(total=0.005, file_dt=0.001)
+orig.initFluid(cfd_solver=1)
+#orig.p_f[5,3,2] *= 1.5
+#orig.k_c[0] = 4.6e-15
+orig.k_c[0] = 4.6e-10
+orig.setFluidBottomNoFlow()
+orig.setFluidTopNoFlow()
+#orig.g[2] = -10.0
+orig.setStiffnessNormal(36.4e9)
+orig.setStiffnessTangential(36.4e9/3.0)
+orig.run(verbose=False)
+#orig.writeVTKall()
+py = sphere.sim(sid = orig.sid, fluid = True)
+py.readlast(verbose=False)
+
+ones = numpy.ones((orig.num))
+py.readlast(verbose = False)
+compareNumpyArrays(ones, py.p_f, "Conservation of pressure:")
+
+# Fluid flow should be very small
+if ((numpy.abs(py.v_f[:,:,:,:]) < 1.0e-6).all()):
+ print("Flow field:\t\t" + passed())
+else:
+ print("Flow field:\t\t" + failed())
+ print(numpy.min(py.v_f))
+ print(numpy.mean(py.v_f))
+ print(numpy.max(py.v_f))
+ raise Exception("Failed")
+#'''
+
+
+print("### Fluidization test: Transient, gravity, Dirichlet+Dirichlet BCs")
+#orig = sphere.sim('diffusivity-relax', fluid=False)
+orig = sphere.sim('cube-init', fluid=False)
+orig.readlast(verbose=False)
+orig.num[2] /= 2
+orig.L[2] /= 2.0
+orig.id('darcy_fluidization')
+orig.cleanup()
+orig.initTemporal(total=0.005, file_dt=0.001)
+orig.initFluid(cfd_solver=1)
+orig.g[2] = -10.0
+#orig.k_c[0] = numpy.mean(orig.radius)**2/540.0
+
+mean_porosity = orig.bulkPorosity()
+fluidize_pressure = numpy.abs((orig.rho - orig.rho_f) \
+ *(1.0 - mean_porosity)*numpy.abs(orig.g[2]))
+
+fluid_pressure_gradient = numpy.array([0.9, 2.0])
+
+for i in numpy.arange(fluid_pressure_gradient.size):
+
+ orig.id('fluidization-' + str(fluid_pressure_gradient[i]))
+ # set pressure gradient
+ dpdz = fluid_pressure_gradient[i] * fluidize_pressure
+ dp = dpdz * orig.L[2]
+ base_p = 0.0
+ orig.p_f[:,:,0] = base_p + dp # high pressure at bottom
+ orig.p_f[:,:,-1] = base_p # low pressure at top
+
+ orig.run(verbose=False)
+ orig.writeVTKall()
+ py = sphere.sim(sid = orig.sid, fluid = True)
+ py.readlast(verbose=False)
+
+ """print('Mean particle velocity: '
+ + str(numpy.mean(py.vel[:,0])) + ', '
+ + str(numpy.mean(py.vel[:,1])) + ', '
+ + str(numpy.mean(py.vel[:,2])) + ' m/s')"""
+
+ z_vel_threshold = 0.001
+ if fluid_pressure_gradient[i] < 1.0:
+ test(numpy.mean(py.vel[:,2]) < z_vel_threshold,
+ 'Fluidization (' + str(fluid_pressure_gradient[i]) + '):\t')
+ elif fluid_pressure_gradient[i] > 1.0:
+ test(numpy.mean(py.vel[:,2]) > z_vel_threshold,
+ 'Fluidization (' + str(fluid_pressure_gradient[i]) + '):\t')
+
+
diff --git a/tests/cfd_tests_neumann_darcy.py b/tests/cfd_tests_neumann_darcy.py
t@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+from pytestutils import *
+
+import sphere
+import sys
+import numpy
+import matplotlib.pyplot as plt
+
+print('### CFD tests - Dirichlet/Neumann BCs ###')
+
+print('''# Neumann bottom, Dirichlet top BC.
+# No gravity, no pressure gradients => no flow''')
+
+orig = sphere.sim("neumann", fluid = True)
+cleanup(orig)
+orig.defaultParams(mu_s = 0.4, mu_d = 0.4)
+orig.defineWorldBoundaries([0.4, 0.4, 1], dx = 0.1)
+orig.initFluid(cfd_solver = 1)
+orig.initTemporal(total = 0.05, file_dt = 0.005, dt = 1.0e-4)
+py = sphere.sim(sid = orig.sid, fluid = True)
+orig.bc_bot[0] = 1 # No-flow BC at bottom (Neumann)
+#orig.run(dry=True)
+orig.run(verbose=False)
+#orig.writeVTKall()
+py.readlast(verbose = False)
+ones = numpy.ones((orig.num))
+py.readlast(verbose = False)
+compareNumpyArraysClose(ones, py.p_f, "Conservation of pressure:",
+ tolerance = 1.0e-5)
+
+# Fluid flow along z should be very small
+if ((numpy.abs(py.v_f[:,:,:,:]) < 1.0e-6).all()):
+ print("Flow field:\t\t" + passed())
+else:
+ print("Flow field:\t\t" + failed())
+ print(numpy.min(py.v_f))
+ print(numpy.mean(py.v_f))
+ print(numpy.max(py.v_f))
+ raise Exception("Failed")
+
+orig.cleanup()
diff --git a/tests/fluid_particle_interaction_darcy.py b/tests/fluid_particle_i…
t@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+import sphere
+from pytestutils import *
+
+sim = sphere.sim('fluid_particle_interaction', fluid=True)
+sim.cleanup()
+
+sim.defineWorldBoundaries([1.0, 1.0, 1.0], dx = 0.1)
+sim.initFluid(cfd_solver = 1)
+
+
+# No gravity, pressure gradient enforced by Dirichlet boundaries.
+# The particle should be sucked towards the low pressure
+print('# Test 1: Test pressure gradient force')
+sim.p_f[:,:,0] = 1.0
+sim.p_f[:,:,-1] = 1.1
+sim.addParticle([0.5, 0.5, 0.5], 0.01)
+sim.initTemporal(total=0.001, file_dt=0.0001)
+#sim.time_file_dt[0] = sim.time_dt[0]
+#sim.time_total[0] = sim.time_dt[0]
+
+#sim.run(verbose=False)
+sim.run()
+#sim.run(dry=True)
+#sim.run(cudamemcheck=True)
+#sim.writeVTKall()
+
+sim.readlast()
+test(sim.vel[0,2] < 0.0, 'Particle velocity:')
+
+sim.cleanup()
diff --git a/tests/highlighttext.py b/tests/highlighttext.py
t@@ -0,0 +1,51 @@
+#!/usr/bin/env python
+# ANSI color coded text if the terminal supports it. No external requirements.
+# Inspired by
+# http://korbinin.blogspot.dk/2012/10/color-text-output-from-python.html
+
+import sys
+
+def highlight(string, fg, bold=False):
+ '''
+ Return `string` with ANSI color codes.
+
+ :param string: String to colorize.
+ :type string: str
+ :param fg: Foreground text color. Possible values: 'g', 'green', 'r', 're…
+ 'y', 'yellow', 'b', 'blue', 'm' or 'magenta'
+ :type fg: str
+ :param bold: Bold text
+ :type bold: bool
+
+ :returns: ANSI formatted string, can be `print()`'ed directly.
+ :return type: str
+ '''
+
+ attr = []
+ if sys.stdout.isatty():
+
+ if fg == 'g' or fg == 'green':
+ attr.append('32')
+
+ elif fg == 'r' or fg == 'red':
+ attr.append('31')
+
+ elif fg == 'y' or fg == 'yellow':
+ attr.append('33')
+
+ elif fg == 'b' or fg == 'blue':
+ attr.append('34')
+
+ elif fg == 'm' or fg == 'magenta':
+ attr.append('35')
+
+ else:
+ raise Exception('Error: Foreground color `fg` value not understood…
+
+ if bold:
+ attr.append('1')
+
+ return '\x1b[%sm%s\x1b[0m' % (';'.join(attr), string)
+
+ else:
+ return string
diff --git a/tests/io_tests_fluid.py b/tests/io_tests_fluid.py
t@@ -3,10 +3,11 @@ from pytestutils import *
import sphere
#### Input/output tests ####
-print("### Fluid input/output tests ###")
+print("### Fluid input/output tests - Navier Stokes CFD solver ###")
# Generate data in python
orig = sphere.sim(np=100, sid="test-initgrid-fluid", fluid=True)
+orig.cleanup()
orig.generateRadii(histogram=False, radius_mean=1.0)
orig.defaultParams()
orig.initRandomGridPos()
t@@ -22,7 +23,56 @@ py.readbin("../input/" + orig.sid + ".bin", verbose=False)
compare(orig, py, "Python IO:")
# Test C++ IO routines
-orig.run()
+orig.run(verbose=False)
+#orig.run(dry=True)
+#orig.run(verbose=True, hideinputfile=False, cudamemcheck=True)
+cpp = sphere.sim(fluid=True)
+cpp.readbin("../output/" + orig.sid + ".output00000.bin", verbose=False)
+compare(orig, cpp, "C++ IO: ")
+
+# Test CUDA IO routines
+cuda = sphere.sim(fluid=True)
+cuda.readbin("../output/" + orig.sid + ".output00001.bin", verbose=False)
+cuda.time_current = orig.time_current
+cuda.time_step_count = orig.time_step_count
+compareNumpyArraysClose(orig.v_f, cuda.v_f, "cuda.v_f:", tolerance=1e-5)
+cuda.v_f = orig.v_f
+#compareNumpyArraysClose(orig.p_f, cuda.p_f, "cuda.p_f:", tolerance=0.1)
+cuda.p_f = orig.p_f
+if numpy.allclose(orig.x, cuda.x, 0.01):
+ cuda.x = orig.x # ignore small changes
+if numpy.max(numpy.abs(cuda.vel - orig.vel)) < 1.0e-5:
+ cuda.vel = orig.vel # ignore small changes
+ cuda.xyzsum = orig.xyzsum
+ cuda.force = orig.force
+compare(orig, cuda, "CUDA IO: ")
+
+
+
+#### Input/output tests ####
+print("### Fluid input/output tests - Darcy CFD solver ###")
+
+# Generate data in python
+orig = sphere.sim(np=100, sid="test-initgrid-fluid", fluid=True)
+orig.cleanup()
+orig.generateRadii(histogram=False, radius_mean=1.0)
+orig.defaultParams()
+orig.initRandomGridPos()
+
+orig.initFluid(cfd_solver = 1)
+orig.setMaxIterations(10)
+orig.initTemporal(current=0.0, total=0.0)
+orig.time_total=2.0*orig.time_dt
+orig.time_file_dt = orig.time_dt
+orig.writebin(verbose=False)
+
+# Test Python IO routines
+py = sphere.sim(fluid=True)
+py.readbin("../input/" + orig.sid + ".bin", verbose=False)
+compare(orig, py, "Python IO:")
+
+# Test C++ IO routines
+orig.run(verbose=False)
#orig.run(dry=True)
#orig.run(verbose=True, hideinputfile=False, cudamemcheck=True)
cpp = sphere.sim(fluid=True)
diff --git a/tests/pytestutils.py b/tests/pytestutils.py
t@@ -1,14 +1,15 @@
#!/usr/bin/env python
from sphere import *
+from highlighttext import highlight
import subprocess
import sys
def passed():
- return "\tPassed"
+ return "\t" + highlight("Passed", "green")
def failed():
- return "\tFailed"
+ return "\t" + highlight("Failed", "red", True)
def test(statement, string):
if (statement == True):
You are viewing proxied material from mx1.adamsgaard.dk. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.