Two phase LBM with basic averaging

This commit is contained in:
James McClure 2013-10-08 22:29:21 -04:00
parent 1e8e27d530
commit 066b84acb2
25 changed files with 12580 additions and 27 deletions

2
.gitignore vendored
View File

@ -1,6 +1,8 @@
*~
*.o
*.o*
*.e*
*.dat
hybrid
bin
lib

View File

@ -1,21 +1,39 @@
CUDA_FLAGS=-arch sm_20
CUDA_LIB=/opt/apps/cuda/5.0.35/lib64
CUDA_FLAGS=-arch sm_35
bin/Color-WIA:gpu/lb2_Color_wia_mpi.o lib/libcuColor.a lib/libcuD3Q19.a lib/libcuD3Q7.a lib/libcuExtras.a
mkdir -p bin
CC -O3 -o bin/Color-WIA gpu/lb2_Color_wia_mpi.o -lcuColor -lcuD3Q19 -lcuD3Q7 -lcuExtras -Llib -Iinclude
bin/Color-WIA-CBUB:gpu/lb2_Color_wia_mpi_cbub.o lib/libcuColor.a lib/libcuD3Q19.a lib/libcuD3Q7.a lib/libcuExtras.a
mkdir -p bin
CC -O3 -D CBUB -o bin/Color-WIA-CBUB gpu/lb2_Color_wia_mpi_cbub.o -lcuColor -lcuD3Q19 -lcuD3Q7 -lcuExtras -Llib -Iinclude
bin/ColorLBM:gpu/lb2_Color_mpi.cpp lib/libcuColor.a lib/libcuD3Q19.a lib/libcuD3Q7.a lib/libcuExtras.a
mkdir -p bin
mpicxx -O3 -o bin/ColorLBM gpu/lb2_Color_mpi.cpp -lcuColor -lcuD3Q19 -lcuD3Q7 -lcuExtras -Llib
bin/gpu-Color:gpu/lb2_Color.cpp lib/libcuColor.a lib/libcuD3Q19.a lib/libcuD3Q7.a lib/libcuExtras.a
mkdir -p bin
g++ -O3 -o bin/gpu-Color gpu/lb2_Color.cpp -lcudart -lcuColor -lcuD3Q19 -lcuD3Q7 -lcuExtras -Llib -L$(CUDA_LIB)
CC -O3 -o bin/ColorLBM gpu/lb2_Color_mpi.cpp -lcuColor -lcuD3Q19 -lcuD3Q7 -lcuExtras -Llib
#bin/gpuMRT:gpu/lb1_MRT.cu lib/libcuMRT.a lib/libcuD3Q19.a
# mkdir -p bin
# nvcc -O3 -o bin/gpuMRT $(CUDA_FLAGS) gpu/lb1_MRT.cu -lcuMRT -lcuD3Q19 -Llib
bin/gpuColor:gpu/lb2_Color.cu lib/libcuColor.a lib/libcuD3Q19.a lib/libcuExtras.a lib/libcuD3Q7.a
mkdir -p bin
nvcc -o bin/gpuColor $(CUDA_FLAGS) gpu/lb2_Color.cu -lcuColor -lcuD3Q19 -lcuD3Q7 -lcuExtras -Llib
#bin/gpuColor:gpu/lb2_Color.cu lib/libcuColor.a lib/libcuD3Q19.a
# mkdir -p bin
# nvcc -o bin/gpuColor $(CUDA_FLAGS) gpu/lb2_Color.cu -lcuColor -lcuD3Q19 -Llib
gpu/lb2_Color_wia_mpi.o:gpu/lb2_Color_wia_mpi.cpp
CC -c -o gpu/lb2_Color_wia_mpi.o gpu/lb2_Color_wia_mpi.cpp -Iinclude
gpu/lb2_Color_wia_mpi_cbub.o:gpu/lb2_Color_wia_mpi.cpp
CC -c -DCBUB -o gpu/lb2_Color_wia_mpi_cbub.o gpu/lb2_Color_wia_mpi.cpp -Iinclude
#pmmc/pmmc.o:pmmc/pmmc.cpp
# CC -c -o pmmc/pmmc.o pmmc/pmmc.cpp -Iinclude
#include/Array.o:pmmc/Array.cpp
# CC -c -o include/Array.o include/Array.cpp -Iinclude
lib/libcuExtras.a: gpu/CudaExtras.cu
mkdir -p lib
@ -38,5 +56,6 @@ lib/libcuColor.a: gpu/Color.cu
nvcc -lib $(CUDA_FLAGS) gpu/Color.cu -o lib/libcuColor.a
clean:
rm gpu/*.o
rm bin/*
rm lib/*
rm lib/*

View File

@ -144,6 +144,97 @@ inline void AssignLocalSolidID(char *ID, int nspheres, double *List_cx, double *
}
}
inline void SignedDistance(double *Distance, int nspheres, double *List_cx, double *List_cy, double *List_cz, double *List_rad,
double Lx, double Ly, double Lz, int Nx, int Ny, int Nz,
int iproc, int jproc, int kproc, int nprocx, int nprocy, int nprocz)
{
// Use sphere lists to determine which nodes are in porespace
// Write out binary file for nodes
int N = Nx*Ny*Nz; // Domain size, including the halo
double hx,hy,hz;
double x,y,z;
double cx,cy,cz,r;
int imin,imax,jmin,jmax,kmin,kmax;
int p,i,j,k,n;
//............................................
double min_x,min_y,min_z;
double distance;
//............................................
// Lattice spacing for the entire domain
// It should generally be true that hx=hy=hz
// Otherwise, you will end up with ellipsoids
hx = Lx/((Nx-2)*nprocx-1);
hy = Ly/((Ny-2)*nprocy-1);
hz = Lz/((Nz-2)*nprocz-1);
//............................................
// Get maximum and minimum for this domain
// Halo is included !
min_x = double(iproc*(Nx-2)-1)*hx;
min_y = double(jproc*(Ny-2)-1)*hy;
min_z = double(kproc*(Nz-2)-1)*hz;
//............................................
//............................................
// Pre-initialize Distance
for (n=0;n<N;n++){
Distance[n]=100.0;
}
//............................................
//............................................
// .........Loop over the spheres.............
for (p=0;p<nspheres;p++){
// Get the sphere from the list, map to local min
cx = List_cx[p] - min_x;
cy = List_cy[p] - min_y;
cz = List_cz[p] - min_z;
r = List_rad[p];
// Check if
// Range for this sphere in global indexing
imin = int ((cx-r)/hx);
imax = int ((cx+r)/hx)+2;
jmin = int ((cy-r)/hy);
jmax = int ((cy+r)/hy)+2;
kmin = int ((cz-r)/hz);
kmax = int ((cz+r)/hz)+2;
// Obviously we have to do something at the edges
if (imin<0) imin = 0;
if (imin>Nx) imin = Nx;
if (imax<0) imax = 0;
if (imax>Nx) imax = Nx;
if (jmin<0) jmin = 0;
if (jmin>Ny) jmin = Ny;
if (jmax<0) jmax = 0;
if (jmax>Ny) jmax = Ny;
if (kmin<0) kmin = 0;
if (kmin>Nz) kmin = Nz;
if (kmax<0) kmax = 0;
if (kmax>Nz) kmax = Nz;
// Loop over the domain for this sphere (may be null)
for (i=imin;i<imax;i++){
for (j=jmin;j<jmax;j++){
for (k=kmin;k<kmax;k++){
// x,y,z is distance in physical units
x = i*hx;
y = j*hy;
z = k*hz;
// if inside sphere, set to zero
// get the position in the list
n = k*Nx*Ny+j*Nx+i;
// Compute the distance
distance = sqrt((cx-x)*(cx-x)+(cy-y)*(cy-y)+(cz-z)*(cz-z)) - r;
// Assign the minimum distance
if (distance < Distance[n]) Distance[n] = distance;
}
}
}
}
// Map the distance to lattice units
for (n=0; n<N; n++) Distance[n] = Distance[n]/hx;
}
inline void GenerateResidual(char *ID, int Nx, int Ny, int Nz, double Saturation)
{
//.......................................................................
@ -242,3 +333,13 @@ inline void WriteLocalSolidID(char *FILENAME, char *ID, int N)
File.close();
}
inline void WriteLocalSolidDistance(char *FILENAME, double *Distance, int N)
{
double value;
ofstream File(FILENAME,ios::binary);
for (int n=0; n<N; n++){
value = Distance[n];
File.write((char*) &value, sizeof(value));
}
File.close();
}

View File

@ -1,4 +1,5 @@
136315
8.0 8.0 8.0
192 192 192
10 10 10
2 2 2
82 82 82
399
1.0 1.0 1.0

View File

@ -1,4 +1,5 @@
136315
8.0 8.0 8.0
192 192 192
20 20 20
2 2 2
80 80 80
399
1.0 1.0 1.0

BIN
domain/ReadDomain Executable file

Binary file not shown.

106
domain/ReadDomain.cpp Normal file
View File

@ -0,0 +1,106 @@
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include "Domain.h"
int main(int argc, char **argv)
{
//.......................................................................
// Variable declaration
//.......................................................................
int i,j,k,n,N;
int Nx,Ny,Nz;
int nspheres;
double Lx,Ly,Lz;
// parallel domain size (# of sub-domains)
int nprocx,nprocy,nprocz;
// int iproc,jproc,kproc;
//.......................................................................
//.......................................................................
// Reading the input file
//.......................................................................
ifstream domain("Domain.in");
domain >> nprocx;
domain >> nprocy;
domain >> nprocz;
domain >> Nx;
domain >> Ny;
domain >> Nz;
domain >> nspheres;
domain >> Lx;
domain >> Ly;
domain >> Lz;
//.......................................................................
//.......................................................................
printf("********************************************************\n");
printf("Sub-domain size = %i x %i x %i\n",Nz,Nz,Nz);
printf("Parallel domain size = %i x %i x %i\n",nprocx,nprocy,nprocz);
printf("Number of spheres = %i \n", nspheres);
printf("Domain Length (x) = %f \n", Lx);
printf("Domain Length (y) = %f \n", Ly);
printf("Domain Length (z) = %f \n", Lz);
printf("********************************************************\n");
//.......................................................................
N = Nx*Ny*Nz;
printf("Read input media... \n");
char *id;
id = new char[N];
double *SignDist;
SignDist = new double[N];
//.......................................................................
// Read from a sphere packing
//.......................................................................
double *cx,*cy,*cz,*r;
cx = new double[nspheres];
cy = new double[nspheres];
cz = new double[nspheres];
r = new double[nspheres];
//.......................................................................
printf("Reading the sphere packing \n");
ReadSpherePacking(nspheres,cx,cy,cz,r);
//.......................................................................
//.......................................................................
// Write out the files
//.......................................................................
int rank;
char LocalRankString[8];
char LocalRankFilename[40];
for (k=0; k<nprocz; k++){
for (j=0; j<nprocy; j++){
for (i=0; i<nprocx; i++){
//.......................................................................
rank = k*nprocx*nprocy + j*nprocx + i;
//.......................................................................
sprintf(LocalRankString,"%05d",rank);
sprintf(LocalRankFilename,"%s%s","ID.",LocalRankString);
//.......................................................................
// printf("Assigning the local phase ID \n");
SignedDistance(SignDist,nspheres,cx,cy,cz,r,Lx,Ly,Lz,Nx,Ny,Nz,
i,j,k,nprocx,nprocy,nprocz);
for (n=0; n<N; n++){
if (SignDist[n] < 0.0) id[n] = 0;
else id[n] = 1;
}
//.......................................................................
// printf("Generating residual NWP \n");
GenerateResidual(id,Nx,Ny,Nz,0.3);
//.......................................................................
WriteLocalSolidID(LocalRankFilename, id, N);
//.......................................................................
sprintf(LocalRankFilename,"%s%s","SignDist.",LocalRankString);
WriteLocalSolidDistance(LocalRankFilename, SignDist, N);
//.......................................................................
printf("Finished rank = %i \n",rank);
}
}
}
//.......................................................................
}

View File

@ -22,16 +22,17 @@ int main(int argc, char **argv)
// Reading the input file
//.......................................................................
ifstream domain("Domain.in");
domain >> nprocx;
domain >> nprocy;
domain >> nprocz;
domain >> Nx;
domain >> Ny;
domain >> Nz;
domain >> nspheres;
domain >> Lx;
domain >> Ly;
domain >> Lz;
domain >> Nx;
domain >> Ny;
domain >> Nz;
domain >> nprocx;
domain >> nprocy;
domain >> nprocz;
//.......................................................................
printf("********************************************************\n");
printf("Sub-domain size = %i x %i x %i\n",Nz,Nz,Nz);

View File

@ -0,0 +1,8 @@
ID
160 32 128
1.0
1.0e-2 0.95 0.1 0.9
0.7
0.0 0.0 0.0
0 1.0 1.0
1000 1000 1e-5

View File

@ -0,0 +1,4 @@
1 1 1
100 100 100
229
1.0 1.0 1.0

View File

@ -0,0 +1,18 @@
#!/bin/bash
#PBS -A GEO019
#PBS -N ConstrainedBubble
#PBS -j oe
#PBS -l walltime=2:00:00,nodes=1
#PBS -l gres=widow2%widow3
#cd /tmp/work/$USER
date
cd $PBS_O_WORKDIR
#echo "PBS_O_WORKDIR: `echo $PBS_O_WORKDIR`"
source $MODULESHOME/init/bash
module swap cray-mpich2 cray-mpich2/5.6.3
export LD_LIBRARY_PATH=${CRAY_LD_LIBRARY_PATH}:${LD_LIBRARY_PATH}
export MPICH_RDMA_ENABLED_CUDA=1
aprun -n 1 -N 1 ~/LBPM-WIA/bin/Color-WIA-CBUB

View File

@ -644,8 +644,10 @@ __global__ void DensityStreamD3Q7(char *ID, double *Den, double *Copy, double *P
//....Instantiate the density distributions
// Generate Equilibrium Distributions and stream
// Stationary value - distribution 0
Den[2*n] += 0.3333333333333333*na;
Den[2*n+1] += 0.3333333333333333*nb;
// Den[2*n] += 0.3333333333333333*na;
// Den[2*n+1] += 0.3333333333333333*nb;
atomicAdd(&Den[2*n], 0.3333333333333333*na);
atomicAdd(&Den[2*n+1], 0.3333333333333333*nb);
// Non-Stationary equilibrium distributions
feq[0] = 0.1111111111111111*(1+3*ux);
feq[1] = 0.1111111111111111*(1-3*ux);

File diff suppressed because it is too large Load Diff

2113
gpu/lb2_Color_wia_mpi.cpp Normal file

File diff suppressed because it is too large Load Diff

256
include/Array.cpp Normal file
View File

@ -0,0 +1,256 @@
#include "Array.h"
/*
* Array.cpp
*
* Created by James Mcclure on 3/31/09.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/
// *****************************************
// ******** class IntArray ****************
// *****************************************
IntArray::IntArray()
{
m=n=o=Length=0;
}
IntArray::IntArray(int size)
{
data = new int [size];
Length = size;
m = size;
n = 1;
o = 1;
}
IntArray::IntArray(int nx, int ny)
{
m = nx;
n = ny;
o = 1;
Length = m*n;
data = new int [Length];
}
IntArray::IntArray(int nx, int ny, int nz)
{
m = nx;
n = ny;
o = nz;
Length = m*n*o;
data = new int [Length];
}
IntArray::~IntArray()
{
delete data;
}
void IntArray::New(int size)
{
m=size;
n = 1;
o = 1;
data = new int [size];
Length = size;
}
void IntArray::New(int nx, int ny)
{
m = nx;
n = ny;
o = 1;
Length = m*n;
data = new int [Length];
}
void IntArray::New(int nx, int ny,int nz)
{
m = nx;
n = ny;
o = nz;
Length = m*n*o;
data = new int [Length];
}
int IntArray::e(int i)
{
return data[i];
}
int IntArray::e(int i, int j)
{
return data[m*j+i];
}
int IntArray::e(int i, int j, int k)
{
return data[m*n*k+m*j+i];
}
// *****************************************
// ******** class DoubleArray **************
// *****************************************
DoubleArray::DoubleArray()
{
m=n=o=Length=0;
}
DoubleArray::DoubleArray(int size)
{
m=size;
n = 1;
o = 1;
data = new double [size];
Length = size;
}
DoubleArray::DoubleArray(int nx, int ny)
{
m = nx;
n = ny;
o = 1;
Length = m*n;
data = new double [Length];
}
DoubleArray::DoubleArray(int nx, int ny,int nz)
{
m = nx;
n = ny;
o = nz;
Length = m*n*o;
data = new double [Length];
}
void DoubleArray::New(int size)
{
m=size;
n = 1;
o = 1;
data = new double [size];
Length = size;
}
void DoubleArray::New(int nx, int ny)
{
m = nx;
n = ny;
o = 1;
Length = m*n;
data = new double [Length];
}
void DoubleArray::New(int nx, int ny,int nz)
{
m = nx;
n = ny;
o = nz;
Length = m*n*o;
data = new double [Length];
}
DoubleArray::~DoubleArray()
{
delete data;
}
double DoubleArray::e(int i)
{
return data[i];
}
double DoubleArray::e(int i, int j)
{
return data[j*m+i];
}
double DoubleArray::e(int i, int j, int k)
{
return data[k*m*n+j*m+i];
}
extern DoubleArray IncreaseSize(DoubleArray &A, int addLength)
{
if (addLength<0) {
printf("IncreaseSize(Array,Length)","Length needs to be >0.");
return DoubleArray();
}
int newM,newN,newO;
if (A.o>1) {
if (addLength%(A.m*A.n)!=0) {
printf("IncreaseSize(Array,Length)","Length needs to be a multiple of m*n");
return DoubleArray();
}
newM = A.m;
newN = A.n;
newO = A.o + addLength/(A.m*A.n);
}
else if (A.n>1) {
if (addLength%(A.m)!=0) {
printf("IncreaseSize(Array,Length)","Length needs to be a multiple of m");
return DoubleArray();
}
newM = A.m;
newN = A.n + addLength/A.m;
newO = 1;
}
else {
newM = A.m + addLength;
newN = 1;
newO = 1;
}
DoubleArray toReturn(newM,newN,newO);
memcpy(toReturn.Pointer(),A.Pointer(),A.Length*sizeof(double));
return toReturn;
}
extern IntArray IncreaseSize(IntArray &A, int addLength)
{
if (addLength<0) {
printf("IncreaseSize(Array,Length)","Length needs to be >0.");
return IntArray();
}
int newM,newN,newO;
if (A.o>1) {
if (addLength%(A.m*A.n)!=0) {
printf("IncreaseSize(Array,Length)","Length needs to be a multiple of m*n");
return IntArray();
}
newM = A.m;
newN = A.n;
newO = A.o + addLength/(A.m*A.n);
}
else if (A.n>1) {
if (addLength%(A.m)!=0) {
printf("IncreaseSize(Array,Length)","Length needs to be a multiple of m");
return IntArray();
}
newM = A.m;
newN = A.n + addLength/A.m;
newO = 1;
}
else {
newM = A.m + addLength;
newN = 1;
newO = 1;
}
IntArray toReturn(newM,newN,newO);
memcpy(toReturn.Pointer(),A.Pointer(),A.Length*sizeof(int));
return toReturn;
}
DoubleArray DoubleArray::Copy()
{
DoubleArray CopyInto(m,n,o);
// Check that the allocation worked.
if (CopyInto.Length!=Length) return CopyInto; // Failed. Already printed an error message.
memcpy(CopyInto.Pointer(),Pointer(),Length*sizeof(double));
return CopyInto;
}

393
include/Array.h Normal file
View File

@ -0,0 +1,393 @@
#ifndef ARRAY_H_INC
#define ARRAY_H_INC
#include <iostream>
// ********** ARRAY CLASS INFO **************************************
/*
//..............................................................
// Overview of array classes in Array.h
//......... Declaration of array objects........................
// supports integer data (IntArray) or double data (DoubleArray)
// supports one, two or three dimensional arrays
IntArray A(m); // array of integers, Length n
IntArray A(m,n); // array of integers, dimensions: m x n
DoubleArray A(m,n,o); // array of doubles, dimensions m x n x o
//............ Access the size of the array.....................
A.m; // size of first dimension
A.n; // size of second dimension
A.o; // size of third dimension
A.Length; // total number of values stored
//........... Access the array entries .........................
A(i); // return data[i]
A(i,j); // return data[j*m+i]
A(i,j,k); // return data[k*m*n+j*m+i]
//..............................................................
*/
using namespace std;
class IntArray{
public:
IntArray Copy();
int Length;
int m,n,o;
int *data;
IntArray();
IntArray(int size);
IntArray(int nx,int ny);
IntArray(int nx,int ny,int nz);
~IntArray();
void New(int size);
void New(int nx, int ny);
void New(int nx, int ny, int nz);
int & operator()(int index)
{return data[index];}
int & operator()(int i, int j)
{ return data[j*m+i];}
int & operator()(int i, int j, int k)
{ return data[k*m*n+j*m+i];}
int e(int i);
int e(int i, int j);
int e(int i, int j, int k);
int *Pointer() {return data;}
};
class DoubleArray{
public:
DoubleArray Copy();
int Length;
int m;
int n;
int o;
double *data;
DoubleArray();
DoubleArray(int size);
DoubleArray(int nx, int ny);
DoubleArray(int nx, int ny, int nz);
~DoubleArray();
void New(int size);
void New(int nx, int ny);
void New(int nx, int ny, int nz);
double & operator()(int index)
{return data[index];}
double & operator()(int i, int j)
{return data[j*m+i];}
double & operator()(int i, int j, int k)
{return data[k*m*n+j*m+i];}
double e(int i);
double e(int i, int j);
double e(int i, int j, int k);
double *Pointer() {return data;}
};
/*
* Array.cpp
*
* Created by James Mcclure on 3/31/09.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/
// *****************************************
// ******** class IntArray ****************
// *****************************************
/*IntArray::IntArray();
IntArray::IntArray(int size);
IntArray::IntArray(int nx, int ny);
IntArray::IntArray(int nx, int ny, int nz);
IntArray::~IntArray();
void IntArray::New(int size);
void IntArray::New(int nx, int ny);
void IntArray::New(int nx, int ny,int nz);
int IntArray::e(int i);
int IntArray::e(int i, int j);
int IntArray::e(int i, int j, int k);
// *****************************************
// ******** class DoubleArray **************
// *****************************************
DoubleArray::DoubleArray();
DoubleArray::DoubleArray(int size);
DoubleArray::DoubleArray(int nx, int ny);
DoubleArray::DoubleArray(int nx, int ny,int nz);
DoubleArray::~DoubleArray();
void DoubleArray::New(int size);
void DoubleArray::New(int nx, int ny);
void DoubleArray::New(int nx, int ny,int nz);
double DoubleArray::e(int i);
double DoubleArray::e(int i, int j);
double DoubleArray::e(int i, int j, int k);
extern DoubleArray IncreaseSize(DoubleArray &A, int addLength);
extern IntArray IncreaseSize(IntArray &A, int addLength);
*/
/*
* Array.cpp
*
* Created by James Mcclure on 3/31/09.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/
/*
* Array.cpp
*
* Created by James Mcclure on 3/31/09.
* Copyright 2009 __MyCompanyName__. All rights reserved.
*
*/
IntArray::IntArray()
{
m=n=o=Length=0;
}
IntArray::IntArray(int size)
{
data = new int [size];
Length = size;
m = size;
n = 1;
o = 1;
}
IntArray::IntArray(int nx, int ny)
{
m = nx;
n = ny;
o = 1;
Length = m*n;
data = new int [Length];
}
IntArray::IntArray(int nx, int ny, int nz)
{
m = nx;
n = ny;
o = nz;
Length = m*n*o;
data = new int [Length];
}
IntArray::~IntArray()
{
// delete [] data;
}
void IntArray::New(int size)
{
m=size;
n = 1;
o = 1;
data = new int [size];
Length = size;
}
void IntArray::New(int nx, int ny)
{
m = nx;
n = ny;
o = 1;
Length = m*n;
data = new int [Length];
}
void IntArray::New(int nx, int ny,int nz)
{
m = nx;
n = ny;
o = nz;
Length = m*n*o;
data = new int [Length];
}
int IntArray::e(int i)
{
return data[i];
}
int IntArray::e(int i, int j)
{
return data[m*j+i];
}
int IntArray::e(int i, int j, int k)
{
return data[m*n*k+m*j+i];
}
// *****************************************
// ******** class DoubleArray **************
// *****************************************
DoubleArray::DoubleArray()
{
m=n=o=Length=0;
}
DoubleArray::DoubleArray(int size)
{
m=size;
n = 1;
o = 1;
data = new double [size];
Length = size;
}
DoubleArray::DoubleArray(int nx, int ny)
{
m = nx;
n = ny;
o = 1;
Length = m*n;
data = new double [Length];
}
DoubleArray::DoubleArray(int nx, int ny,int nz)
{
m = nx;
n = ny;
o = nz;
Length = m*n*o;
data = new double [Length];
}
void DoubleArray::New(int size)
{
m=size;
n = 1;
o = 1;
data = new double [size];
Length = size;
}
void DoubleArray::New(int nx, int ny)
{
m = nx;
n = ny;
o = 1;
Length = m*n;
data = new double [Length];
}
void DoubleArray::New(int nx, int ny,int nz)
{
m = nx;
n = ny;
o = nz;
Length = m*n*o;
data = new double [Length];
}
DoubleArray::~DoubleArray()
{
// delete [] data;
}
double DoubleArray::e(int i)
{
return data[i];
}
double DoubleArray::e(int i, int j)
{
return data[j*m+i];
}
double DoubleArray::e(int i, int j, int k)
{
return data[k*m*n+j*m+i];
}
extern DoubleArray IncreaseSize(DoubleArray &A, int addLength)
{
if (addLength<0) {
printf("IncreaseSize(Array,Length)","Length needs to be >0.");
return DoubleArray();
}
int newM,newN,newO;
if (A.o>1) {
if (addLength%(A.m*A.n)!=0) {
printf("IncreaseSize(Array,Length)","Length needs to be a multiple of m*n");
return DoubleArray();
}
newM = A.m;
newN = A.n;
newO = A.o + addLength/(A.m*A.n);
}
else if (A.n>1) {
if (addLength%(A.m)!=0) {
printf("IncreaseSize(Array,Length)","Length needs to be a multiple of m");
return DoubleArray();
}
newM = A.m;
newN = A.n + addLength/A.m;
newO = 1;
}
else {
newM = A.m + addLength;
newN = 1;
newO = 1;
}
DoubleArray toReturn(newM,newN,newO);
memcpy(toReturn.Pointer(),A.Pointer(),A.Length*sizeof(double));
return toReturn;
}
extern IntArray IncreaseSize(IntArray &A, int addLength)
{
if (addLength<0) {
printf("IncreaseSize(Array,Length)","Length needs to be >0.");
return IntArray();
}
int newM,newN,newO;
if (A.o>1) {
if (addLength%(A.m*A.n)!=0) {
printf("IncreaseSize(Array,Length)","Length needs to be a multiple of m*n");
return IntArray();
}
newM = A.m;
newN = A.n;
newO = A.o + addLength/(A.m*A.n);
}
else if (A.n>1) {
if (addLength%(A.m)!=0) {
printf("IncreaseSize(Array,Length)","Length needs to be a multiple of m");
return IntArray();
}
newM = A.m;
newN = A.n + addLength/A.m;
newO = 1;
}
else {
newM = A.m + addLength;
newN = 1;
newO = 1;
}
IntArray toReturn(newM,newN,newO);
memcpy(toReturn.Pointer(),A.Pointer(),A.Length*sizeof(int));
return toReturn;
}
DoubleArray DoubleArray::Copy()
{
DoubleArray CopyInto(m,n,o);
// Check that the allocation worked.
if (CopyInto.Length!=Length) return CopyInto; // Failed. Already printed an error message.
memcpy(CopyInto.Pointer(),Pointer(),Length*sizeof(double));
return CopyInto;
}
#endif

181
include/PointList.h Normal file
View File

@ -0,0 +1,181 @@
#include <math.h>
struct Point {
Point() : x(0.0), y(0.0), z(0.0) {}
Point(double xv,double yv,double zv) : x(xv), y(yv), z(zv) {}
double x,y,z;
};
inline Point operator+(const Point &A,const Point &B) {return Point(A.x+B.x,A.y+B.y,A.z+B.z);}
inline Point operator-(const Point &A,const Point &B) {return Point(A.x-B.x,A.y-B.y,A.z-B.z);}
inline Point operator*(const Point &A,double v) {return Point(A.x*v,A.y*v,A.z*v);}
inline Point operator*(double v,const Point &A) {return Point(A.x*v,A.y*v,A.z*v);}
inline Point operator/(const Point &A,double v) {return Point(A.x/v,A.y/v,A.z/v);}
inline Point operator-(const Point &A) {return Point(-A.x,-A.y,-A.z);}
inline bool operator==(const Point &A,const Point &B) {return (A.x==B.x && A.y==B.y && A.z==B.z);}
inline bool operator!=(const Point &A,const Point &B) {return (A.x!=B.x || A.y!=B.y || A.z!=B.z);}
inline double Norm(const Point &A) {return sqrt(A.x*A.x+A.y*A.y+A.z*A.z);}
inline Point Cross(const Point &A,const Point &B) {return Point(A.y*B.z-A.z*B.y,B.x*A.z-A.x*B.z,A.x*B.y-A.y*B.x);}
inline double Dot(const Point &A,const Point &B) {return (A.x*B.x+A.y*B.y+A.z*B.z);}
inline double Distance(const Point &A,const Point &B) {return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));}
/*
class PointList{
public:
int length;
int m;
int index;
Point pt;
double *data;
PointList();
PointList(int size);
~PointList();
void New(int size);
Point & operator()(int idx)
{
index = idx;
pt.x = data[3*index];
pt.y = data[3*index+1];
pt.z = data[3*index+2];
return pt;
}
Point &operator=(Point &P){
pt.x = P.x;
pt.y = P.y;
pt.z = P.z;
data[3*index]=pt.x;
data[3*index+1]=pt.y;
data[3*index+2]=pt.z;
}
};
// *****************************************
// ******** class PointList **************
// *****************************************
PointList::PointList()
{
m=length=0;
}
PointList::PointList(int size)
{
m=size;
data = new double [3*size];
length = size;
}
void PointList::New(int size)
{
m=size;
data = new double [3*size];
length = size;
}
PointList::~PointList()
{
delete data;
}
*/
template <class T>
class DTList {
public:
DTList() : Data(0), length(0), refCount(new size_t(1)), outOfRange() {}
DTList(const DTList<T> &A) : Data(A.Data), length(A.length), refCount(A.refCount), outOfRange() {++(*refCount);}
protected:
DTList(size_t len) : Data(len<=0 ? 0 : new T[len]), length(len<=0 ? 0 : len), refCount(new size_t(1)), outOfRange() {}
public:
virtual ~DTList() {
// --(*refCount);
// if (*refCount==0) {delete [] Data; delete refCount;}
// Data = 0; refCount = 0; length=0;
}
DTList<T> &operator=(const DTList<T> &A) {
if (A.refCount!=refCount) { // Otherwise doing A=A.
--(*refCount);
if (*refCount==0) {delete [] Data; delete refCount;}
refCount = A.refCount;
++(*refCount);
length = A.length;
Data = A.Data;
}
return *this;
}
size_t MemoryUsed(void) const {return length*sizeof(T);}
const T *Pointer(void) const {return Data;}
size_t IsEmpty(void) const {return (Data==0);}
size_t Length(void) const {return length;}
#if DTRangeCheck
const T operator()(size_t i) const {if (i>= length) {printf("DTList: out of range"); return outOfRange;} return Data[i];}
#else
const T operator()(size_t i) const {return Data[i];}
#endif
protected:
T *Data;
size_t length;
size_t *refCount;
// Should be static.
T outOfRange;
};
template <class T>
class DTMutableList : public DTList<T> {
public:
DTMutableList() : DTList<T>() {}
DTMutableList(size_t len) : DTList<T>(len) {}
DTMutableList(const DTMutableList<T> &A) : DTList<T>(A) {}
DTMutableList<T> &operator=(const DTMutableList<T> &A) {DTList<T>::operator=(A); return *this;}
T *Pointer(void) {return DTList<T>::Data;}
const T *Pointer(void) const {return DTList<T>::Data;}
#if DTRangeCheck
T &operator()(size_t i) {if (i>=DTList<T>::length) {DTErrorOutOfRange("DTList<T>",i,DTList<T>::length); return DTList<T>::outOfRange;} return DTList<T>::Data[i];}
T operator()(size_t i) const {if (i<0 || i>= DTList<T>::length) {DTErrorOutOfRange("DTList<T>",i,DTList<T>::length); return DTList<T>::outOfRange;} return DTList<T>::Data[i];}
#else
T &operator()(size_t i) {return DTList<T>::Data[i];}
T operator()(size_t i) const {return DTList<T>::Data[i];}
#endif
DTMutableList<T> &operator=(T v) {for (size_t i=0;i<DTList<T>::length;i++) DTList<T>::Data[i] = v; return *this;}
};
template <class T> DTMutableList<T> TruncateSize(const DTList<T> &A,size_t length)
{
if (length>A.Length()) length = A.Length();
DTMutableList<T> toReturn(length);
const T *fromP = A.Pointer();
T *toP = toReturn.Pointer();
for (size_t i=0;i<length;i++) toP[i] = fromP[i];
return toReturn;
}
template <class T> DTMutableList<T> IncreaseSize(const DTList<T> &A,size_t addLength)
{
DTMutableList<T> toReturn(A.Length()+(addLength>=0 ? addLength : 0));
size_t len = A.Length();
const T *fromP = A.Pointer();
T *toP = toReturn.Pointer();
for (size_t i=0;i<len;i++) toP[i] = fromP[i];
return toReturn;
}

3225
include/pmmc.h Normal file

File diff suppressed because it is too large Load Diff

242
pmmc/AssignBlobID.cpp Normal file
View File

@ -0,0 +1,242 @@
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <math.h>
#include <Array.h>
using namespace std;
//--------------------------------------------------------------------------------------------------------
inline double PhaseAverageScalar(int *PhaseID, double *Scalar, int N, int Np)
{
int i;
// Store the averaged values for each phase
double *PhaseAveragedValues;
double *PhaseVolumes;
PhaseAveragedValues = new double[Np];
for (i=0; i<N; i++){
}
}
inline int ComputeBlob(IntArray blobs, int &nblobs, int &ncubes, IntArray indicator,
DoubleArray F, DoubleArray S, double vf, double vs, int startx, int starty,
int startz, IntArray temp)
{
// Compute the blob (F>vf|S>vs) starting from (i,j,k) - oil blob
// F>vf => oil phase S>vs => in porespace
// update the list of blobs, indicator mesh
int m = F.m; // maxima for the meshes
int n = F.n;
int o = F.o;
int cubes_in_blob=0;
int nrecent = 1; // number of nodes added at most recent sweep
temp(0,0) = startx; // Set the initial point as a "seed" for the sweeps
temp(1,0) = starty;
temp(2,0) = startz;
int ntotal = 1; // total number of nodes in blob
indicator(startx,starty,startz) = nblobs;
int p,s,x,y,z,start,finish,nodx,nody,nodz;
int imin=startx,imax=startx,jmin=starty,jmax=starty; // initialize maxima / minima
int kmin=startz,kmax=startz;
int d[26][3] = {{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1},
{1,1,0},{1,-1,0},{-1,1,0},{-1,-1,0},{1,0,1},{-1,0,1},
{1,0,-1},{-1,0,-1},{0,1,1},{0,-1,1},{0,1,-1},{0,-1,-1},
{1,1,1},{1,1,-1},{1,-1,1},{1,-1,-1},{-1,1,1},{-1,1,-1},
{-1,-1,1},{-1,-1,-1}}; // directions to neighbors
int cube[8][3] = {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}}; // cube corners
bool status = 1; // status == true => continue to look for points
while (status == 1){
start = ntotal - nrecent;
finish = ntotal;
nrecent = 0; // set recent points back to zero for next sweep through
for (s=start;s<finish;s++){
// Loop over recent points; look for new points
x = temp(0,s);
y = temp(1,s);
z = temp(2,s);
// Looop over the directions
for (p=0;p<26;p++){
nodx=x+d[p][0];
if (nodx < 0 ){ nodx = m-1; } // Periodic BC for x
if (nodx > m-1 ){ nodx = 0; }
nody=y+d[p][1];
if (nody < 0 ){ nody = n-1; } // Periodic BC for y
if (nody > n-1 ){ nody = 0; }
nodz=z+d[p][2];
if (nodz < 0 ){ nodz = 0; } // No periodic BC for z
if (nodz > o-1 ){ nodz = o-1; }
if ( F(nodx,nody,nodz) > vf && S(nodx,nody,nodz) > vs
&& indicator(nodx,nody,nodz) == -1 ){
// Node is a part of the blob - add it to the list
temp(0,ntotal) = nodx;
temp(1,ntotal) = nody;
temp(2,ntotal) = nodz;
ntotal++;
nrecent++;
// Update the indicator map
indicator(nodx,nody,nodz) = nblobs;
// Update the min / max for the cube loop
if ( nodx < imin ){ imin = nodx; }
if ( nodx > imax ){ imax = nodx; }
if ( nody < jmin ){ jmin = nody; }
if ( nody > jmax ){ jmax = nody; }
if ( nodz < kmin ){ kmin = nodz; }
if ( nodz > kmax ){ kmax = nodz; }
}
else if (F(nodx,nody,nodz) > vf && S(nodx,nody,nodz) > vs
&& indicator(nodx,nody,nodz) > -1 && indicator(nodx,nody,nodz) != nblobs){
// Some kind of error in algorithm
printf("Error in blob search algorithm!");
}
}
}
if ( nrecent == 0){
status = 0;
}
}
// Use points in temporary storage array to add cubes to the list of blobs
if ( imin > 0) { imin = imin-1; }
// if ( imax < m-1) { imax = imax+1; }
if ( jmin > 0) { jmin = jmin-1; }
// if ( jmax < n-1) { jmax = jmax+1; }
if ( kmin > 0) { kmin = kmin-1; }
// if ( kmax < o-1) { kmax = kmax+1; }
int i,j,k;
bool add;
for (k=kmin;k<kmax;k++){
for (j=jmin;j<jmax;j++){
for (i=imin;i<imax;i++){
// If cube(i,j,k) has any nodes in blob, add it to the list
// Loop over cube edges
add = 0;
for (p=0;p<8;p++){
nodx = i+cube[p][0];
nody = j+cube[p][1];
nodz = k+cube[p][2];
if ( indicator(nodx,nody,nodz) == nblobs ){
// Cube corner is in this blob
add = 1;
}
}
if (add == 1){
// Add cube to the list
blobs(0,ncubes) = i;
blobs(1,ncubes) = j;
blobs(2,ncubes) = k;
ncubes++;
cubes_in_blob++;
// Loop again to check for overlap
for (p=0;p<8;p++){
nodx = i+cube[p][0];
nody = j+cube[p][1];
nodz = k+cube[p][2];
if (indicator(nodx,nody,nodz) > -1 && indicator(nodx,nody,nodz) != nblobs){
printf("Overlapping cube!");
cout << i << ", " << j << ", " << k << endl;
}
}
}
}
}
}
return cubes_in_blob;
}
int main()
{
int m,n,o;
int p,i,j,k;
double vF,vS;
/* ****************************************************************
IDENTIFY ALL BLOBS: F > vF, S > vS
****************************************************************** */
// Find blob domains, number of blobs
int nblobs = 0; // number of blobs
int ncubes = 0; // total number of nodes in any blob
int N = (m-1)*(n-1)*(o-1); // total number of cubes
IntArray blobs(3,N); // store indices for blobs (cubes)
IntArray temp(3,N); // temporary storage array
IntArray temp2; // temporary storage array
IntArray b(50); // number of nodes in each blob
IntArray indicator(m,n,o);
DoubleArray F(m,n,o);
DoubleArray S(m,n,o);
// Loop over z=0 first -> blobs attached to this end considered "connected" for LB simulation
i=0;
int number=0;
for (k=0;k<1;k++){
for (j=0;j<n;j++){
if ( F(i,j,k) > vF ){
if ( S(i,j,k) > vS ){
// node i,j,k is in the porespace
number = number+ComputeBlob(blobs,nblobs,ncubes,indicator,F,S,vF,vS,i,j,k,temp);
}
}
}
// Specify the blob on the z axis
b(nblobs) = number;
nblobs++;
for (k=0;k<o;k++){
for (j=0;j<n;j++){
for (i=1;i<m;i++){
if ( indicator(i,j,k) == -1 ){
if ( F(i,j,k) > vF ){
if ( S(i,j,k) > vS ){
// node i,j,k is in the porespace
b(nblobs) = ComputeBlob(blobs,nblobs,ncubes,indicator,F,S,vF,vS,i,j,k,temp);
nblobs++;
}
}
}
// Otherwise, this point has already been assigned - ignore
// Make sure list blob_nodes is large enough
if ( nblobs > b.length-1){
b = IncreaseSize(b,b.length);
}
}
}
}
// Go over all cubes again -> add any that do not contain nw phase
bool add=1; // Set to false if any corners contain nw-phase ( F > vF)
int cube[8][3] = {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}}; // cube corners
int count_in=0,count_out=0;
int nodx,nody,nodz;
for (k=0;k<o-1;k++){
for (j=0;j<n-1;j++){
for (i=0;i<m-1;i++){
// Loop over cube corners
add=1; // initialize to true - add unless corner occupied by nw-phase
for (p=0;p<8;p++){
nodx=i+cube[p][0];
nody=j+cube[p][1];
nodz=k+cube[p][2];
if ( indicator(nodx,nody,nodz) > -1 ){
// corner occupied by nw-phase -> do not add
add = 0;
}
}
if ( add == 1 ){
blobs(0,ncubes) = i;
blobs(1,ncubes) = j;
blobs(2,ncubes) = k;
ncubes++;
count_in++;
}
else { count_out++; }
}
}
}
b(nblobs) = count_in;
nblobs++;
}

84
pmmc/CommonCurve.cpp Normal file
View File

@ -0,0 +1,84 @@
//--------------------------------------------------------------------------------------------------------
inline double ContactAngle(DTPoint3D &pt, DTVectorField3D &gradF, DTVectorField3D &gradS)
{
double theta;
int m = gradS.Grid().m();
int n = gradS.Grid().n();
int o = gradS.Grid().o();
double dx = gradS.Grid().dx();
double dy = gradS.Grid().dy();
double dz = gradS.Grid().dz();
DTPoint3D origin = gradS.Grid().Origin();
// Get the gradient arrays
DTFloatArray Fx = gradF.X();
DTFloatArray Fy = gradF.Y();
DTFloatArray Fz = gradF.Z();
DTFloatArray Sx = gradS.X();
DTFloatArray Sy = gradS.Y();
DTFloatArray Sz = gradS.Z();
int i,j,k;
// Determine the cube containing this point
// i = int(floor((pt.x-origin.x)/dx)); // real space
// j = int(floor((pt.y-origin.y)/dy));
// k = int(floor((pt.z-origin.z)/dz));
i = int(floor(pt.x));
j = int(floor(pt.y));
k = int(floor(pt.z));
double x,y,z; // map to 0,1 cube
// x = (pt.x-origin.x-i*dx)/dx; // real space
// y = (pt.y-origin.y-j*dy)/dy;
// z = (pt.z-origin.z-k*dz)/dz;
x = pt.x - double(i);
y = pt.y - double(j);
z = pt.z - double(k);
// evaluate contact angle at corners of the cube
DTMutableDoubleArray cube(2,2,2);
// theta = acos ( -(gradF*gradS) / (|gradF| |gradS|) )
cube(0,0,0) = -( Fx(i,j,k)*Sx(i,j,k)+Fy(i,j,k)*Sy(i,j,k)+Fz(i,j,k)*Sz(i,j,k) )
/( sqrt(pow(Fx(i,j,k),2)+pow(Fy(i,j,k),2)+pow(Fz(i,j,k),2))
*sqrt(pow(Sx(i,j,k),2)+pow(Sy(i,j,k),2)+pow(Sz(i,j,k),2)) );
cube(1,0,0) = -( Fx(i+1,j,k)*Sx(i+1,j,k)+Fy(i+1,j,k)*Sy(i+1,j,k)+Fz(i+1,j,k)*Sz(i+1,j,k) )
/( sqrt(pow(Fx(i+1,j,k),2)+pow(Fy(i+1,j,k),2)+pow(Fz(i+1,j,k),2))
*sqrt(pow(Sx(i+1,j,k),2)+pow(Sy(i+1,j,k),2)+pow(Sz(i+1,j,k),2)) );
cube(0,1,0) = -( Fx(i,j+1,k)*Sx(i,j+1,k)+Fy(i,j+1,k)*Sy(i,j+1,k)+Fz(i,j+1,k)*Sz(i,j+1,k) )
/( sqrt(pow(Fx(i,j+1,k),2)+pow(Fy(i,j+1,k),2)+pow(Fz(i,j+1,k),2))
*sqrt(pow(Sx(i,j+1,k),2)+pow(Sy(i,j+1,k),2)+pow(Sz(i,j+1,k),2)) );
cube(0,0,1) = -( Fx(i,j,k+1)*Sx(i,j,k+1)+Fy(i,j,k+1)*Sy(i,j,k+1)+Fz(i,j,k+1)*Sz(i,j,k+1) )
/( sqrt(pow(Fx(i,j,k+1),2)+pow(Fy(i,j,k+1),2)+pow(Fz(i,j,k+1),2))
*sqrt(pow(Sx(i,j,k+1),2)+pow(Sy(i,j,k+1),2)+pow(Sz(i,j,k+1),2)) );
cube(1,1,0) = -( Fx(i+1,j+1,k)*Sx(i+1,j+1,k)+Fy(i+1,j+1,k)*Sy(i+1,j+1,k)+Fz(i+1,j+1,k)*Sz(i+1,j+1,k) )
/( sqrt(pow(Fx(i+1,j+1,k),2)+pow(Fy(i+1,j+1,k),2)+pow(Fz(i+1,j+1,k),2))
*sqrt(pow(Sx(i+1,j+1,k),2)+pow(Sy(i+1,j+1,k),2)+pow(Sz(i+1,j+1,k),2)) );
cube(1,0,1) = -( Fx(i+1,j,k+1)*Sx(i+1,j,k+1)+Fy(i+1,j,k+1)*Sy(i+1,j,k+1)+Fz(i+1,j,k+1)*Sz(i+1,j,k+1) )
/( sqrt(pow(Fx(i+1,j,k+1),2)+pow(Fy(i+1,j,k+1),2)+pow(Fz(i+1,j,k+1),2))
*sqrt(pow(Sx(i+1,j,k+1),2)+pow(Sy(i+1,j,k+1),2)+pow(Sz(i+1,j,k+1),2)) );
cube(0,1,1) = -( Fx(i,j+1,k+1)*Sx(i,j+1,k+1)+Fy(i,j+1,k+1)*Sy(i,j+1,k+1)+Fz(i,j+1,k+1)*Sz(i,j+1,k+1) )
/( sqrt(pow(Fx(i,j+1,k+1),2)+pow(Fy(i,j+1,k+1),2)+pow(Fz(i,j+1,k+1),2))
*sqrt(pow(Sx(i,j+1,k+1),2)+pow(Sy(i,j+1,k+1),2)+pow(Sz(i,j+1,k+1),2)) );
cube(1,1,1) = -( Fx(i+1,j+1,k+1)*Sx(i+1,j+1,k+1)+Fy(i+1,j+1,k+1)*Sy(i+1,j+1,k+1)+Fz(i+1,j+1,k+1)*Sz(i+1,j+1,k+1) )
/( sqrt(pow(Fx(i+1,j+1,k+1),2)+pow(Fy(i+1,j+1,k+1),2)+pow(Fz(i+1,j+1,k+1),2))
*sqrt(pow(Sx(i+1,j+1,k+1),2)+pow(Sy(i+1,j+1,k+1),2)+pow(Sz(i+1,j+1,k+1),2)) );
// construct polynomial approximation for contact angle
double a,b,c,d,e,f,g,h; // trilinear coefficients: f(x,y,z) = a+bx+cy+dz+exy+fxz+gyz+hxyz
a = cube(0,0,0);
b = cube(1,0,0)-a;
c = cube(0,1,0)-a;
d = cube(0,0,1)-a;
e = cube(1,1,0)-a-b-c;
f = cube(1,0,1)-a-b-d;
g = cube(0,1,1)-a-c-d;
h = cube(1,1,1)-a-b-c-d-e-f-g;
// evaluate at x,y,z
theta = acos (a+b*x+c*y+d*z+e*x*y+f*x*z+g*y*z+h*x*y*z );
return theta;
}

231
pmmc/blob-pmmc.cpp Normal file
View File

@ -0,0 +1,231 @@
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <fstream>
#include <math.h>
#ifndef ARRAY_H_INC
#include "Array.h"
#define ARRAY_H_INC
#endif
#include "PointList.h"
using namespace std;
int main(int argc, char *argv[])
{
double d;
// double *phase;
// double *distance;
int i,j,k,p,q,r, n, Nx,Ny,Nz;
double vS,vF;
double readval;
vS = 0.f;
vF = 0.f;
printf("Solid surface: S(x) = %f \n",vS);
printf("Fluid surface: F(x) = %f \n",vF);
Nx = Ny = Nz = 64;
printf("Domain size is: %i x %i x %i \n",Nx,Ny,Nz);
DoubleArray F(Nx,Ny,Nz);
DoubleArray S(Nx,Ny,Nz);
printf("Reading distance from a file... \n");
ifstream DISTANCE("Distance.in",ios::binary);
for (int k=0;k<Nz;k++){
for (int j=0;j<Ny;j++){
for (int i=0;i<Nx;i++){
DISTANCE.read((char *) (&readval), sizeof(readval));
n = k*Nx*Ny+j*Nx+i;
S(i,j,k) = readval;
}
}
}
DISTANCE.close();
printf("Reading phase from a file... \n");
ifstream PHASE("Phase.in",ios::binary);
for (int k=0;k<Nz;k++){
for (int j=0;j<Ny;j++){
for (int i=0;i<Nx;i++){
PHASE.read((char *) (&readval), sizeof(readval));
n = k*Nx*Ny+j*Nx+i;
F(i,j,k) = -readval;
//phase[n] = d;
}
}
}
PHASE.close();
IntArray indicator(Nx,Ny,Nz); // indicates if (i,j,k) has been assigned yet
for (k=0;k<Nz;k++){
for (j=0;j<Ny;j++){
for (i=0;i<Nx;i++){
// Initialize indicator fucntion to -1
indicator(i,j,k) = -1;
}
}
}
printf("Execute blob identification algorithm... \n");
/* ****************************************************************
IDENTIFY ALL BLOBS: F > vF, S > vS
****************************************************************** */
// Find blob domains, number of blobs
int nblobs = 0; // number of blobs
int ncubes = 0; // total number of nodes in any blob
int N = (Nx-1)*(Ny-1)*(Nz-1); // total number of nodes
IntArray blobs(3,N); // store indices for blobs (cubes)
IntArray temp(3,N); // temporary storage array
IntArray b(50); // number of nodes in each blob
// Loop over z=0 first -> blobs attached to this end considered "connected" for LB simulation
i=0;
int number=0;
for (k=0;k<1;k++){
for (j=0;j<Ny;j++){
if ( F(i,j,k) > vF ){
if ( S(i,j,k) > vS ){
// node i,j,k is in the porespace
number = number+ComputeBlob(blobs,nblobs,ncubes,indicator,F,S,vF,vS,i,j,k,temp);
}
}
}
}
// Specify the blob on the z axis
if (ncubes > 0){
b(nblobs) = number;
printf("Number of blobs is: %i \n",nblobs);
nblobs++;
}
for (k=0;k<Nz;k++){
for (j=0;j<Ny;j++){
for (i=1;i<Nx;i++){
if ( indicator(i,j,k) == -1 ){
if ( F(i,j,k) > vF ){
if ( S(i,j,k) > vS ){
// node i,j,k is in the porespace
b(nblobs) = ComputeBlob(blobs,nblobs,ncubes,indicator,F,S,vF,vS,i,j,k,temp);
nblobs++;
}
}
}
// Otherwise, this point has already been assigned - ignore
// Make sure list blob_nodes is large enough
if ( nblobs > b.Length-1){
printf("Increasing size of blob list \n");
b = IncreaseSize(b,b.Length);
}
}
}
}
// Go over all cubes again -> add any that do not contain nw phase
bool add=1; // Set to false if any corners contain nw-phase ( F > vF)
int cube[8][3] = {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}}; // cube corners
int count_in=0,count_out=0;
int nodx,nody,nodz;
for (k=0;k<Nz-1;k++){
for (j=0;j<Ny-1;j++){
for (i=0;i<Nx-1;i++){
// Loop over cube corners
add=1; // initialize to true - add unless corner occupied by nw-phase
for (p=0;p<8;p++){
nodx=i+cube[p][0];
nody=j+cube[p][1];
nodz=k+cube[p][2];
if ( indicator(nodx,nody,nodz) > -1 ){
// corner occupied by nw-phase -> do not add
add = 0;
}
}
if ( add == 1 ){
blobs(0,ncubes) = i;
blobs(1,ncubes) = j;
blobs(2,ncubes) = k;
ncubes++;
count_in++;
}
else { count_out++; }
}
}
}
b(nblobs) = count_in;
nblobs++;
/* ****************************************************************
COMPUTE GRADIENT OF F,S CURVATURE OF F
****************************************************************** */
// DTVectorField3D gradF = Gradient(Fluid);
// DTVectorField3D gradS = Gradient(Solid);
/* ****************************************************************
VARIABLES FOR THE PMMC ALGORITHM
****************************************************************** */
double area,awn,aws,ans,lwns;
// Initialize arrays for return variables (areas, volumes, etc. for all blobs)
DoubleArray nw_areas(nblobs);
DoubleArray ns_areas(nblobs);
DoubleArray ws_areas(nblobs);
DoubleArray nws_length(nblobs);
DoubleArray volume(nblobs); // Volumes of every blob
for (int a=0; a<nblobs; a++){
nw_areas(a) = 0.f;
ns_areas(a) = 0.f;
ws_areas(a) = 0.f;
nws_length(a) = 0.f;
volume(a) = 0.f;
}
/* ****************************************************************
RUN PMMC ON EACH BLOB
****************************************************************** */
printf("Running the PMMC Algorithm \n");
printf("The number of blobs is %i \n",nblobs);
int n_nw_tris_beg, n_ns_tris_beg, n_ws_tris_beg, n_nws_seg_beg;
int start=0,finish;
int a,c;
int newton_steps = 0;
double blob_volume;
for (a=0;a<nblobs;a++){
finish = start+b(a);
ComputeAreasPMMC(blobs, start, finish, F, S, vF, vS,
blob_volume, ans, aws, awn, lwns, Nx, Ny, Nz);
start = finish;
volume(a) = blob_volume;
ws_areas(a) = aws;
nw_areas(a) = awn;
ns_areas(a) = ans;
// Last "blob" is just the ws interface
if (a+1 < nblobs){
printf("-------------------------------- \n");
printf("Blob id = %i \n", a);
printf("Blob volume = %f \n", blob_volume);
printf("Area wn = %f \n", nw_areas(a));
printf("Area ns = %f \n", ns_areas(a));
printf("-------------------------------- \n");
}
} // End of the blob loop
area = 0.0;
for (a=0;a<nblobs;a++) area+= ws_areas(a);
printf("Area ws = %f \n", area);
printf("Done. \n");
}

439
pmmc/pmmc-areas.cpp Normal file
View File

@ -0,0 +1,439 @@
#include <iostream>
#include <math.h>
#include "pmmc.h"
// Computes the interfacial areas according to the Porous Medium marching cubes (pmmc)
// algorithm developed by McClure, Adalsteinnsson et al. (2007) for a two fluid phase
// system. The common curve length is also computed.
// The wn, ws, ns and solid surfaces are written to disk in the form of triangle lists
int main(int argc, char * argv[])
{
//...........................................................................
int Nx,Ny,Nz,N;
Nx = Ny = Nz = N;
int i,j,k,p,q,r,n;
//...........................................................................
// Interfaces are defined by the F(x,y,z) = 0.0
// input data must be mapped such that this corresponds to the
// desired interface
double fluid_isovalue = 0.0;
double solid_isovalue = 0.0;
//...........................................................................
cout << "Enter the domain length (x): " << endl;
cin >> Nx;
cout << "Enter the domain length (y): " << endl;
cin >> Ny;
cout << "Enter the domain length (z): " << endl;
cin >> Nz;
//...........................................................................
//...........................................................................
DoubleArray SignDist(Nx,Ny,Nz);
DoubleArray Phase(Nx,Ny,Nz);
//...........................................................................
printf("Reading distance from a file... \n");
double readval;
ifstream DISTANCE("Distance.in",ios::binary);
for (int k=0;k<Nz;k++){
for (int j=0;j<Ny;j++){
for (int i=0;i<Nx;i++){
DISTANCE.read((char *) (&readval), sizeof(readval));
n = k*Nx*Ny+j*Nx+i;
SignDist(i,j,k) = readval;
}
}
}
DISTANCE.close();
printf("Reading phase from a file... \n");
ifstream PHASE("Phase.in",ios::binary);
for (int k=0;k<Nz;k++){
for (int j=0;j<Ny;j++){
for (int i=0;i<Nx;i++){
PHASE.read((char *) (&readval), sizeof(readval));
n = k*Nx*Ny+j*Nx+i;
Phase(i,j,k) = readval;
//phase[n] = d;
}
}
}
PHASE.close();
/* ****************************************************************
VARIABLES FOR THE PMMC ALGORITHM
****************************************************************** */
//...........................................................................
// Averaging variables
//...........................................................................
double awn,ans,aws,lwns,nwp_volume;
double As;
double dEs,dAwn,dAns; // Global surface energy (calculated by rank=0)
double awn_global,ans_global,aws_global,lwns_global,nwp_volume_global;
double As_global;
// bool add=1; // Set to false if any corners contain nw-phase ( F > fluid_isovalue)
int cube[8][3] = {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}}; // cube corners
// int count_in=0,count_out=0;
// int nodx,nody,nodz;
// initialize lists for vertices for surfaces, common line
DTMutableList<Point> nw_pts(20);
DTMutableList<Point> ns_pts(20);
DTMutableList<Point> ws_pts(20);
DTMutableList<Point> nws_pts(20);
// initialize triangle lists for surfaces
IntArray nw_tris(3,20);
IntArray ns_tris(3,20);
IntArray ws_tris(3,20);
// initialize list for line segments
IntArray nws_seg(2,20);
DTMutableList<Point> tmp(20);
// IntArray store;
int n_nw_pts=0,n_ns_pts=0,n_ws_pts=0,n_nws_pts=0, map=0;
int n_nw_tris=0, n_ns_tris=0, n_ws_tris=0, n_nws_seg=0;
double s,s1,s2,s3; // Triangle sides (lengths)
Point A,B,C,P;
// double area;
// Initialize arrays for local solid surface
DTMutableList<Point> local_sol_pts(20);
int n_local_sol_pts = 0;
IntArray local_sol_tris(3,18);
int n_local_sol_tris;
DoubleArray values(20);
DTMutableList<Point> local_nws_pts(20);
int n_local_nws_pts;
int n_nw_tris_beg, n_ns_tris_beg, n_ws_tris_beg;
int c;
int newton_steps = 0;
//...........................................................................
int ncubes = (Nx-2)*(Ny-2)*(Nz-2); // Exclude the "upper" halo
IntArray cubeList(3,ncubes);
int nc=0;
//...........................................................................
// Set up the cube list (very regular in this case due to lack of blob-ID)
for (k=0; k<Nz-2; k++){
for (j=0; j<Ny-2; j++){
for (i=0; i<Nx-2; i++){
cubeList(0,nc) = i;
cubeList(1,nc) = j;
cubeList(2,nc) = k;
nc++;
}
}
}
FILE *STRIS;
STRIS = fopen("solid-triangles.out","w");
FILE *WN_TRIS;
WN_TRIS = fopen("wn-tris.out","w");
FILE *NS_TRIS;
NS_TRIS = fopen("ns-tris.out","w");
FILE *WS_TRIS;
WS_TRIS = fopen("ws-tris.out","w");
FILE *WNS_PTS;
WNS_PTS = fopen("wns-pts.out","w");
// End of the loop to set the values
awn = aws = ans = lwns = 0.0;
nwp_volume = 0.0;
As = 0.0;
for (c=0;c<ncubes;c++){
// Get cube from the list
i = cubeList(0,c);
j = cubeList(1,c);
k = cubeList(2,c);
for (p=0;p<8;p++){
if ( Phase(i+cube[p][0],j+cube[p][1],k+cube[p][2]) > 0
&& SignDist(i+cube[p][0],j+cube[p][1],k+cube[p][2]) > 0 ){
nwp_volume += 0.125;
}
}
// Run PMMC
n_local_sol_tris = 0;
n_local_sol_pts = 0;
n_local_nws_pts = 0;
n_nw_pts=0,n_ns_pts=0,n_ws_pts=0,n_nws_pts=0, map=0;
n_nw_tris=0, n_ns_tris=0, n_ws_tris=0, n_nws_seg=0;
n_nw_tris_beg = 0;// n_nw_tris;
n_ns_tris_beg = 0;//n_ns_tris;
n_ws_tris_beg = 0;//n_ws_tris;
// if there is a solid phase interface in the grid cell
if (Interface(SignDist,solid_isovalue,i,j,k) == 1){
/////////////////////////////////////////
/// CONSTRUCT THE LOCAL SOLID SURFACE ///
/////////////////////////////////////////
// find the local solid surface
// SOL_SURF(SignDist,0.0,Phase,fluid_isovalue,i,j,k, Nx,Ny,Nz,local_sol_pts,n_local_sol_pts,
// local_sol_tris,n_local_sol_tris,values);
// find the local solid surface using the regular Marching Cubes algorithm
SolidMarchingCubes(SignDist,0.0,Phase,fluid_isovalue,i,j,k,Nx,Ny,Nz,local_sol_pts,n_local_sol_pts,
local_sol_tris,n_local_sol_tris,values);
/////////////////////////////////////////
//////// TRIM THE SOLID SURFACE /////////
/////////////////////////////////////////
/* TRIM(local_sol_pts, n_local_sol_pts, fluid_isovalue,local_sol_tris, n_local_sol_tris,
ns_pts, n_ns_pts, ns_tris, n_ns_tris, ws_pts, n_ws_pts,
ws_tris, n_ws_tris, values, local_nws_pts, n_local_nws_pts,
Phase, SignDist, i, j, k, newton_steps);
*/
TRIM(local_sol_pts, n_local_sol_pts, fluid_isovalue,local_sol_tris, n_local_sol_tris,
ns_pts, n_ns_pts, ns_tris, n_ns_tris, ws_pts, n_ws_pts,
ws_tris, n_ws_tris, values, local_nws_pts, n_local_nws_pts);
/////////////////////////////////////////
//////// WRITE COMMON LINE POINTS ///////
//////// TO MAIN ARRAYS ///////
/////////////////////////////////////////
// SORT THE LOCAL COMMON LINE POINTS
/////////////////////////////////////////
// Make sure the first common line point is on a face
// Common curve points are located pairwise and must
// be searched and rearranged accordingly
for (p=0; p<n_local_nws_pts-1; p++){
P = local_nws_pts(p);
if ( P.x == 1.0*i || P.x ==1.0*(i+1)||
P.y == 1.0*j || P.y == 1.0*(j+1) ||
P.z == 1.0*k || P.z == 1.0*(k+1) ){
if (p%2 == 0){
// even points
// Swap the pair of points
local_nws_pts(p) = local_nws_pts(0);
local_nws_pts(0) = P;
P = local_nws_pts(p+1);
local_nws_pts(p+1) = local_nws_pts(1);
local_nws_pts(1) = P;
p = n_local_nws_pts;
}
else{
// odd points - flip the order
local_nws_pts(p) = local_nws_pts(p-1);
local_nws_pts(p-1) = P;
p-=2;
}
// guarantee exit from the loop
}
}
// Two common curve points per triangle
// 0-(1=2)-(3=4)-...
for (p=1; p<n_local_nws_pts-1; p+=2){
A = local_nws_pts(p);
for (q=p+1; q<n_local_nws_pts; q++){
B = local_nws_pts(q);
if ( A.x == B.x && A.y == B.y && A.z == B.z){
if (q%2 == 0){
// even points
// Swap the pair of points
local_nws_pts(q) = local_nws_pts(p+1);
local_nws_pts(p+1) = B;
B = local_nws_pts(q+1);
local_nws_pts(q+1) = local_nws_pts(p+2);
local_nws_pts(p+2) = B;
q = n_local_nws_pts;
}
else{
// odd points - flip the order
local_nws_pts(q) = local_nws_pts(q-1);
local_nws_pts(q-1) = B;
q-=2;
}
}
}
}
map = n_nws_pts = 0;
nws_pts(n_nws_pts++) = local_nws_pts(0);
for (p=2; p < n_local_nws_pts; p+=2){
nws_pts(n_nws_pts++) = local_nws_pts(p);
}
nws_pts(n_nws_pts++) = local_nws_pts(n_local_nws_pts-1);
for (q=0; q < n_nws_pts-1; q++){
nws_seg(0,n_nws_seg) = map+q;
nws_seg(1,n_nws_seg) = map+q+1;
n_nws_seg++;
}
// End of the common line sorting algorithm
/////////////////////////////////////////
/////////////////////////////////////////
////// CONSTRUCT THE nw SURFACE /////////
/////////////////////////////////////////
if ( n_local_nws_pts > 0){
n_nw_tris =0;
EDGE(Phase, fluid_isovalue, SignDist, i,j,k, Nx, Ny, Nz, nw_pts, n_nw_pts, nw_tris, n_nw_tris,
nws_pts, n_nws_pts);
}
else {
MC(Phase, fluid_isovalue, SignDist, i,j,k, nw_pts, n_nw_pts, nw_tris, n_nw_tris);
}
}
/////////////////////////////////////////
////// CONSTRUCT THE nw SURFACE /////////
/////////////////////////////////////////
else if (Fluid_Interface(Phase,SignDist,fluid_isovalue,i,j,k) == 1){
MC(Phase, fluid_isovalue, SignDist, i,j,k, nw_pts, n_nw_pts, nw_tris, n_nw_tris);
}
//******END OF BLOB PMMC*********************************************
//*******************************************************************
// Compute the Interfacial Areas, Common Line length for blob p
// nw surface
double temp;
for (r=0;r<n_nw_tris;r++){
A = nw_pts(nw_tris(0,r));
B = nw_pts(nw_tris(1,r));
C = nw_pts(nw_tris(2,r));
// Compute length of sides (assume dx=dy=dz)
s1 = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
s2 = sqrt((A.x-C.x)*(A.x-C.x)+(A.y-C.y)*(A.y-C.y)+(A.z-C.z)*(A.z-C.z));
s3 = sqrt((B.x-C.x)*(B.x-C.x)+(B.y-C.y)*(B.y-C.y)+(B.z-C.z)*(B.z-C.z));
s = 0.5*(s1+s2+s3);
temp = s*(s-s1)*(s-s2)*(s-s3);
if (temp > 0.0) awn += sqrt(temp);
}
for (r=0;r<n_ns_tris;r++){
A = ns_pts(ns_tris(0,r));
B = ns_pts(ns_tris(1,r));
C = ns_pts(ns_tris(2,r));
// Compute length of sides (assume dx=dy=dz)
s1 = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
s2 = sqrt((A.x-C.x)*(A.x-C.x)+(A.y-C.y)*(A.y-C.y)+(A.z-C.z)*(A.z-C.z));
s3 = sqrt((B.x-C.x)*(B.x-C.x)+(B.y-C.y)*(B.y-C.y)+(B.z-C.z)*(B.z-C.z));
s = 0.5*(s1+s2+s3);
//ans=ans+sqrt(s*(s-s1)*(s-s2)*(s-s3));
temp = s*(s-s1)*(s-s2)*(s-s3);
if (temp > 0.0) ans += sqrt(temp);
}
for (r=0;r<n_ws_tris;r++){
A = ws_pts(ws_tris(0,r));
B = ws_pts(ws_tris(1,r));
C = ws_pts(ws_tris(2,r));
// Compute length of sides (assume dx=dy=dz)
s1 = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
s2 = sqrt((A.x-C.x)*(A.x-C.x)+(A.y-C.y)*(A.y-C.y)+(A.z-C.z)*(A.z-C.z));
s3 = sqrt((B.x-C.x)*(B.x-C.x)+(B.y-C.y)*(B.y-C.y)+(B.z-C.z)*(B.z-C.z));
s = 0.5*(s1+s2+s3);
//aws=aws+sqrt(s*(s-s1)*(s-s2)*(s-s3));
temp = s*(s-s1)*(s-s2)*(s-s3);
if (temp > 0.0) aws += sqrt(temp);
}
for (r=0;r<n_local_sol_tris;r++){
A = local_sol_pts(local_sol_tris(0,r));
B = local_sol_pts(local_sol_tris(1,r));
C = local_sol_pts(local_sol_tris(2,r));
// Compute length of sides (assume dx=dy=dz)
s1 = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
s2 = sqrt((A.x-C.x)*(A.x-C.x)+(A.y-C.y)*(A.y-C.y)+(A.z-C.z)*(A.z-C.z));
s3 = sqrt((B.x-C.x)*(B.x-C.x)+(B.y-C.y)*(B.y-C.y)+(B.z-C.z)*(B.z-C.z));
s = 0.5*(s1+s2+s3);
//aws=aws+sqrt(s*(s-s1)*(s-s2)*(s-s3));
temp = s*(s-s1)*(s-s2)*(s-s3);
if (temp > 0.0) As += sqrt(temp);
}
for (p=0; p < n_local_nws_pts-1; p++){
// Extract the line segment
A = local_nws_pts(p);
B = local_nws_pts(p+1);
// Compute the length of the segment
s = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
// Add the length to the common line
lwns += s;
}
//.......................................................................................
// Write the triangle lists to text file
for (r=0;r<n_nw_tris;r++){
A = nw_pts(nw_tris(0,r));
B = nw_pts(nw_tris(1,r));
C = nw_pts(nw_tris(2,r));
fprintf(WN_TRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
}
for (r=0;r<n_ws_tris;r++){
A = ws_pts(ws_tris(0,r));
B = ws_pts(ws_tris(1,r));
C = ws_pts(ws_tris(2,r));
fprintf(WS_TRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
}
for (r=0;r<n_ns_tris;r++){
A = ns_pts(ns_tris(0,r));
B = ns_pts(ns_tris(1,r));
C = ns_pts(ns_tris(2,r));
fprintf(NS_TRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
}
for (p=0; p < n_nws_pts; p++){
P = nws_pts(p);
fprintf(WNS_PTS,"%f %f %f \n",P.x, P.y, P.z);
}
//.......................................................................................
for (r=0;r<n_local_sol_tris;r++){
A = local_sol_pts(local_sol_tris(0,r));
B = local_sol_pts(local_sol_tris(1,r));
C = local_sol_pts(local_sol_tris(2,r));
fprintf(STRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
}
//*******************************************************************
// Reset the triangle counts to zero
n_nw_pts=0,n_ns_pts=0,n_ws_pts=0,n_nws_pts=0, map=0;
n_nw_tris=0, n_ns_tris=0, n_ws_tris=0, n_nws_seg=0;
n_nw_tris_beg = 0;// n_nw_tris;
// n_ns_tris_beg = 0;//n_ns_tris;
// n_ws_tris_beg = 0;//n_ws_tris;
// n_nws_seg_beg = n_nws_seg;
//*******************************************************************
}
fclose(WN_TRIS);
fclose(NS_TRIS);
fclose(WS_TRIS);
fclose(WNS_PTS);
fclose(STRIS);
printf("-------------------------------- \n");
printf("NWP volume = %f \n", nwp_volume);
printf("Area wn = %f \n", awn);
printf("Area ns = %f \n", ans);
printf("Area ws = %f \n", aws);
printf("Area s = %f \n", As);
printf("Length wns = %f \n", lwns);
printf("-------------------------------- \n");
//.........................................................................
/* FILE *PHASE;
PHASE = fopen("Phase.in","wb");
fwrite(Phase,8,SIZE,PHASE);
fclose(PHASE);
FILE *SOLID;
SOLID = fopen("Distance.in","wb");
fwrite(Solid,8,SIZE,SOLID);
fclose(SOLID);
*/
}

2690
pmmc/pmmc.cpp Normal file

File diff suppressed because it is too large Load Diff

BIN
tests/cylindertest Executable file

Binary file not shown.

422
tests/pmmc_cylinder.cpp Normal file
View File

@ -0,0 +1,422 @@
#include <iostream>
#include <math.h>
#include "pmmc.h"
//#include "PointList.h"
//#include "Array.h"
#define RADIUS 15
#define HEIGHT 15.5
#define N 60
#define PI 3.14159
int main (char *argc, char **argv)
{
// printf("Radius = %s \n,"RADIUS);
int SIZE = N*N*N;
int Nx,Ny,Nz;
Nx = Ny = Nz = N;
int i,j,k,p,q,r;
// double *Solid; // cylinder
// double *Phase; // region of the cylinder
// Solid = new double [SIZE];
// Phase = new double [SIZE];
DoubleArray SignDist(Nx,Ny,Nz);
DoubleArray Phase(Nx,Ny,Nz);
double fluid_isovalue = 0.0;
double solid_isovalue = 0.0;
/* ****************************************************************
VARIABLES FOR THE PMMC ALGORITHM
****************************************************************** */
//...........................................................................
// Averaging variables
//...........................................................................
double awn,ans,aws,lwns,nwp_volume;
double As;
double dEs,dAwn,dAns; // Global surface energy (calculated by rank=0)
double awn_global,ans_global,aws_global,lwns_global,nwp_volume_global;
double As_global;
// bool add=1; // Set to false if any corners contain nw-phase ( F > fluid_isovalue)
int cube[8][3] = {{0,0,0},{1,0,0},{0,1,0},{1,1,0},{0,0,1},{1,0,1},{0,1,1},{1,1,1}}; // cube corners
// int count_in=0,count_out=0;
// int nodx,nody,nodz;
// initialize lists for vertices for surfaces, common line
DTMutableList<Point> nw_pts(20);
DTMutableList<Point> ns_pts(20);
DTMutableList<Point> ws_pts(20);
DTMutableList<Point> nws_pts(20);
// initialize triangle lists for surfaces
IntArray nw_tris(3,20);
IntArray ns_tris(3,20);
IntArray ws_tris(3,20);
// initialize list for line segments
IntArray nws_seg(2,20);
DTMutableList<Point> tmp(20);
// IntArray store;
int n_nw_pts=0,n_ns_pts=0,n_ws_pts=0,n_nws_pts=0, map=0;
int n_nw_tris=0, n_ns_tris=0, n_ws_tris=0, n_nws_seg=0;
double s,s1,s2,s3; // Triangle sides (lengths)
Point A,B,C,P;
// double area;
// Initialize arrays for local solid surface
DTMutableList<Point> local_sol_pts(20);
int n_local_sol_pts = 0;
IntArray local_sol_tris(3,18);
int n_local_sol_tris;
DoubleArray values(20);
DTMutableList<Point> local_nws_pts(20);
int n_local_nws_pts;
int n_nw_tris_beg, n_ns_tris_beg, n_ws_tris_beg;
int c;
int newton_steps = 0;
//...........................................................................
int ncubes = (Nx-2)*(Ny-2)*(Nz-2); // Exclude the "upper" halo
IntArray cubeList(3,ncubes);
int nc=0;
//...........................................................................
// Set up the cube list (very regular in this case due to lack of blob-ID)
for (k=0; k<Nz-2; k++){
for (j=0; j<Ny-2; j++){
for (i=0; i<Nx-2; i++){
cubeList(0,nc) = i;
cubeList(1,nc) = j;
cubeList(2,nc) = k;
nc++;
}
}
}
//...........................................................................
double Cx,Cy,Cz;
double dist1,dist2;
Cx = Cy = Cz = N*0.51;
for (k=0; k<N; k++){
for (j=0; j<N; j++){
for (i=0; i<N; i++){
dist1 = sqrt((i-Cx)*(i-Cx)+(j-Cy)*(j-Cy)) - RADIUS;
dist2 = fabs(Cz-k)-HEIGHT;
// printf("distances = %f, %f \n",dist1,dist2);
//Solid.data[k*Nx*Ny+j*Nx+i] = dist1;
//Phase[k*Nx*Ny+j*Nx+i] = dist2;
SignDist(i,j,k) = -dist1;
Phase(i,j,k) = dist2;
}
}
}
FILE *STRIS;
STRIS = fopen("solid-triangles.out","w");
FILE *WN_TRIS;
WN_TRIS = fopen("wn-tris.out","w");
FILE *NS_TRIS;
NS_TRIS = fopen("ns-tris.out","w");
FILE *WS_TRIS;
WS_TRIS = fopen("ws-tris.out","w");
FILE *WNS_PTS;
WNS_PTS = fopen("wns-pts.out","w");
// End of the loop to set the values
awn = aws = ans = lwns = 0.0;
nwp_volume = 0.0;
As = 0.0;
for (c=0;c<ncubes;c++){
// Get cube from the list
i = cubeList(0,c);
j = cubeList(1,c);
k = cubeList(2,c);
for (p=0;p<8;p++){
if ( Phase(i+cube[p][0],j+cube[p][1],k+cube[p][2]) > 0
&& SignDist(i+cube[p][0],j+cube[p][1],k+cube[p][2]) > 0 ){
nwp_volume += 0.125;
}
}
// Run PMMC
n_local_sol_tris = 0;
n_local_sol_pts = 0;
n_local_nws_pts = 0;
n_nw_pts=0,n_ns_pts=0,n_ws_pts=0,n_nws_pts=0, map=0;
n_nw_tris=0, n_ns_tris=0, n_ws_tris=0, n_nws_seg=0;
n_nw_tris_beg = 0;// n_nw_tris;
n_ns_tris_beg = 0;//n_ns_tris;
n_ws_tris_beg = 0;//n_ws_tris;
// if there is a solid phase interface in the grid cell
if (Interface(SignDist,solid_isovalue,i,j,k) == 1){
/////////////////////////////////////////
/// CONSTRUCT THE LOCAL SOLID SURFACE ///
/////////////////////////////////////////
// find the local solid surface
// SOL_SURF(SignDist,0.0,Phase,fluid_isovalue,i,j,k, Nx,Ny,Nz,local_sol_pts,n_local_sol_pts,
// local_sol_tris,n_local_sol_tris,values);
// find the local solid surface using the regular Marching Cubes algorithm
SolidMarchingCubes(SignDist,0.0,Phase,fluid_isovalue,i,j,k,Nx,Ny,Nz,local_sol_pts,n_local_sol_pts,
local_sol_tris,n_local_sol_tris,values);
/////////////////////////////////////////
//////// TRIM THE SOLID SURFACE /////////
/////////////////////////////////////////
/* TRIM(local_sol_pts, n_local_sol_pts, fluid_isovalue,local_sol_tris, n_local_sol_tris,
ns_pts, n_ns_pts, ns_tris, n_ns_tris, ws_pts, n_ws_pts,
ws_tris, n_ws_tris, values, local_nws_pts, n_local_nws_pts,
Phase, SignDist, i, j, k, newton_steps);
*/
TRIM(local_sol_pts, n_local_sol_pts, fluid_isovalue,local_sol_tris, n_local_sol_tris,
ns_pts, n_ns_pts, ns_tris, n_ns_tris, ws_pts, n_ws_pts,
ws_tris, n_ws_tris, values, local_nws_pts, n_local_nws_pts);
/////////////////////////////////////////
//////// WRITE COMMON LINE POINTS ///////
//////// TO MAIN ARRAYS ///////
/////////////////////////////////////////
// SORT THE LOCAL COMMON LINE POINTS
/////////////////////////////////////////
// Make sure the first common line point is on a face
// Common curve points are located pairwise and must
// be searched and rearranged accordingly
for (p=0; p<n_local_nws_pts-1; p++){
P = local_nws_pts(p);
if ( P.x == 1.0*i || P.x ==1.0*(i+1)||
P.y == 1.0*j || P.y == 1.0*(j+1) ||
P.z == 1.0*k || P.z == 1.0*(k+1) ){
if (p%2 == 0){
// even points
// Swap the pair of points
local_nws_pts(p) = local_nws_pts(0);
local_nws_pts(0) = P;
P = local_nws_pts(p+1);
local_nws_pts(p+1) = local_nws_pts(1);
local_nws_pts(1) = P;
p = n_local_nws_pts;
}
else{
// odd points - flip the order
local_nws_pts(p) = local_nws_pts(p-1);
local_nws_pts(p-1) = P;
p-=2;
}
// guarantee exit from the loop
}
}
// Two common curve points per triangle
// 0-(1=2)-(3=4)-...
for (p=1; p<n_local_nws_pts-1; p+=2){
A = local_nws_pts(p);
for (q=p+1; q<n_local_nws_pts; q++){
B = local_nws_pts(q);
if ( A.x == B.x && A.y == B.y && A.z == B.z){
if (q%2 == 0){
// even points
// Swap the pair of points
local_nws_pts(q) = local_nws_pts(p+1);
local_nws_pts(p+1) = B;
B = local_nws_pts(q+1);
local_nws_pts(q+1) = local_nws_pts(p+2);
local_nws_pts(p+2) = B;
q = n_local_nws_pts;
}
else{
// odd points - flip the order
local_nws_pts(q) = local_nws_pts(q-1);
local_nws_pts(q-1) = B;
q-=2;
}
}
}
}
map = n_nws_pts = 0;
nws_pts(n_nws_pts++) = local_nws_pts(0);
for (p=2; p < n_local_nws_pts; p+=2){
nws_pts(n_nws_pts++) = local_nws_pts(p);
}
nws_pts(n_nws_pts++) = local_nws_pts(n_local_nws_pts-1);
for (q=0; q < n_nws_pts-1; q++){
nws_seg(0,n_nws_seg) = map+q;
nws_seg(1,n_nws_seg) = map+q+1;
n_nws_seg++;
}
// End of the common line sorting algorithm
/////////////////////////////////////////
/////////////////////////////////////////
////// CONSTRUCT THE nw SURFACE /////////
/////////////////////////////////////////
if ( n_local_nws_pts > 0){
n_nw_tris =0;
EDGE(Phase, fluid_isovalue, SignDist, i,j,k, Nx, Ny, Nz, nw_pts, n_nw_pts, nw_tris, n_nw_tris,
nws_pts, n_nws_pts);
}
else {
MC(Phase, fluid_isovalue, SignDist, i,j,k, nw_pts, n_nw_pts, nw_tris, n_nw_tris);
}
}
/////////////////////////////////////////
////// CONSTRUCT THE nw SURFACE /////////
/////////////////////////////////////////
else if (Fluid_Interface(Phase,SignDist,fluid_isovalue,i,j,k) == 1){
MC(Phase, fluid_isovalue, SignDist, i,j,k, nw_pts, n_nw_pts, nw_tris, n_nw_tris);
}
//******END OF BLOB PMMC*********************************************
//*******************************************************************
// Compute the Interfacial Areas, Common Line length for blob p
// nw surface
double temp;
for (r=0;r<n_nw_tris;r++){
A = nw_pts(nw_tris(0,r));
B = nw_pts(nw_tris(1,r));
C = nw_pts(nw_tris(2,r));
// Compute length of sides (assume dx=dy=dz)
s1 = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
s2 = sqrt((A.x-C.x)*(A.x-C.x)+(A.y-C.y)*(A.y-C.y)+(A.z-C.z)*(A.z-C.z));
s3 = sqrt((B.x-C.x)*(B.x-C.x)+(B.y-C.y)*(B.y-C.y)+(B.z-C.z)*(B.z-C.z));
s = 0.5*(s1+s2+s3);
temp = s*(s-s1)*(s-s2)*(s-s3);
if (temp > 0.0) awn += sqrt(temp);
}
for (r=0;r<n_ns_tris;r++){
A = ns_pts(ns_tris(0,r));
B = ns_pts(ns_tris(1,r));
C = ns_pts(ns_tris(2,r));
// Compute length of sides (assume dx=dy=dz)
s1 = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
s2 = sqrt((A.x-C.x)*(A.x-C.x)+(A.y-C.y)*(A.y-C.y)+(A.z-C.z)*(A.z-C.z));
s3 = sqrt((B.x-C.x)*(B.x-C.x)+(B.y-C.y)*(B.y-C.y)+(B.z-C.z)*(B.z-C.z));
s = 0.5*(s1+s2+s3);
//ans=ans+sqrt(s*(s-s1)*(s-s2)*(s-s3));
temp = s*(s-s1)*(s-s2)*(s-s3);
if (temp > 0.0) ans += sqrt(temp);
}
for (r=0;r<n_ws_tris;r++){
A = ws_pts(ws_tris(0,r));
B = ws_pts(ws_tris(1,r));
C = ws_pts(ws_tris(2,r));
// Compute length of sides (assume dx=dy=dz)
s1 = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
s2 = sqrt((A.x-C.x)*(A.x-C.x)+(A.y-C.y)*(A.y-C.y)+(A.z-C.z)*(A.z-C.z));
s3 = sqrt((B.x-C.x)*(B.x-C.x)+(B.y-C.y)*(B.y-C.y)+(B.z-C.z)*(B.z-C.z));
s = 0.5*(s1+s2+s3);
//aws=aws+sqrt(s*(s-s1)*(s-s2)*(s-s3));
temp = s*(s-s1)*(s-s2)*(s-s3);
if (temp > 0.0) aws += sqrt(temp);
}
for (r=0;r<n_local_sol_tris;r++){
A = local_sol_pts(local_sol_tris(0,r));
B = local_sol_pts(local_sol_tris(1,r));
C = local_sol_pts(local_sol_tris(2,r));
// Compute length of sides (assume dx=dy=dz)
s1 = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
s2 = sqrt((A.x-C.x)*(A.x-C.x)+(A.y-C.y)*(A.y-C.y)+(A.z-C.z)*(A.z-C.z));
s3 = sqrt((B.x-C.x)*(B.x-C.x)+(B.y-C.y)*(B.y-C.y)+(B.z-C.z)*(B.z-C.z));
s = 0.5*(s1+s2+s3);
//aws=aws+sqrt(s*(s-s1)*(s-s2)*(s-s3));
temp = s*(s-s1)*(s-s2)*(s-s3);
if (temp > 0.0) As += sqrt(temp);
}
for (p=0; p < n_local_nws_pts-1; p++){
// Extract the line segment
A = local_nws_pts(p);
B = local_nws_pts(p+1);
// Compute the length of the segment
s = sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y)+(A.z-B.z)*(A.z-B.z));
// Add the length to the common line
lwns += s;
}
//.......................................................................................
// Write the triangle lists to text file
for (r=0;r<n_nw_tris;r++){
A = nw_pts(nw_tris(0,r));
B = nw_pts(nw_tris(1,r));
C = nw_pts(nw_tris(2,r));
fprintf(WN_TRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
}
for (r=0;r<n_ws_tris;r++){
A = ws_pts(ws_tris(0,r));
B = ws_pts(ws_tris(1,r));
C = ws_pts(ws_tris(2,r));
fprintf(WS_TRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
}
for (r=0;r<n_ns_tris;r++){
A = ns_pts(ns_tris(0,r));
B = ns_pts(ns_tris(1,r));
C = ns_pts(ns_tris(2,r));
fprintf(NS_TRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
}
for (p=0; p < n_nws_pts; p++){
P = nws_pts(p);
fprintf(WNS_PTS,"%f %f %f \n",P.x, P.y, P.z);
}
//.......................................................................................
for (r=0;r<n_local_sol_tris;r++){
A = local_sol_pts(local_sol_tris(0,r));
B = local_sol_pts(local_sol_tris(1,r));
C = local_sol_pts(local_sol_tris(2,r));
fprintf(STRIS,"%f %f %f %f %f %f %f %f %f \n",A.x,A.y,A.z,B.x,B.y,B.z,C.x,C.y,C.z);
}
//*******************************************************************
// Reset the triangle counts to zero
n_nw_pts=0,n_ns_pts=0,n_ws_pts=0,n_nws_pts=0, map=0;
n_nw_tris=0, n_ns_tris=0, n_ws_tris=0, n_nws_seg=0;
n_nw_tris_beg = 0;// n_nw_tris;
// n_ns_tris_beg = 0;//n_ns_tris;
// n_ws_tris_beg = 0;//n_ws_tris;
// n_nws_seg_beg = n_nws_seg;
//*******************************************************************
}
fclose(WN_TRIS);
fclose(NS_TRIS);
fclose(WS_TRIS);
fclose(WNS_PTS);
fclose(STRIS);
printf("-------------------------------- \n");
printf("NWP volume = %f \n", nwp_volume);
printf("Area wn = %f, Analytical = %f \n", awn,2*PI*RADIUS*RADIUS);
printf("Area ns = %f, Analytical = %f \n", ans, 2*PI*RADIUS*(N-2)-4*PI*RADIUS*HEIGHT);
printf("Area ws = %f, Analytical = %f \n", aws, 4*PI*RADIUS*HEIGHT);
printf("Area s = %f, Analytical = %f \n", As, 2*PI*RADIUS*(N-2));
printf("Length wns = %f, Analytical = %f \n", lwns, 4*PI*RADIUS);
printf("-------------------------------- \n");
//.........................................................................
/* FILE *PHASE;
PHASE = fopen("Phase.in","wb");
fwrite(Phase,8,SIZE,PHASE);
fclose(PHASE);
FILE *SOLID;
SOLID = fopen("Distance.in","wb");
fwrite(Solid,8,SIZE,SOLID);
fclose(SOLID);
*/
}