| 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): |