Merge branch 'morphLBM' of github.com:JamesEMcClure/LBPM-WIA
This commit is contained in:
422
analysis/morphology.cpp
Normal file
422
analysis/morphology.cpp
Normal file
@@ -0,0 +1,422 @@
|
||||
#include <analysis/morphology.h>
|
||||
// Implementation of morphological opening routine
|
||||
|
||||
inline void PackID(int *list, int count, char *sendbuf, char *ID){
|
||||
// Fill in the phase ID values from neighboring processors
|
||||
// This packs up the values that need to be sent from one processor to another
|
||||
int idx,n;
|
||||
|
||||
for (idx=0; idx<count; idx++){
|
||||
n = list[idx];
|
||||
sendbuf[idx] = ID[n];
|
||||
}
|
||||
}
|
||||
//***************************************************************************************
|
||||
|
||||
inline void UnpackID(int *list, int count, char *recvbuf, char *ID){
|
||||
// Fill in the phase ID values from neighboring processors
|
||||
// This unpacks the values once they have been recieved from neighbors
|
||||
int idx,n;
|
||||
|
||||
for (idx=0; idx<count; idx++){
|
||||
n = list[idx];
|
||||
ID[n] = recvbuf[idx];
|
||||
}
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
double MorphOpen(DoubleArray &SignDist, char *id, std::shared_ptr<Domain> Dm, double VoidFraction){
|
||||
// SignDist is the distance to the object that you want to constaing the morphological opening
|
||||
// VoidFraction is the the empty space where the object inst
|
||||
// id is a labeled map
|
||||
// Dm contains information about the domain structure
|
||||
|
||||
int nx = Dm->Nx;
|
||||
int ny = Dm->Ny;
|
||||
int nz = Dm->Nz;
|
||||
int iproc = Dm->iproc();
|
||||
int jproc = Dm->jproc();
|
||||
int kproc = Dm->kproc();
|
||||
int nprocx = Dm->nprocx();
|
||||
int nprocy = Dm->nprocy();
|
||||
int nprocz = Dm->nprocz();
|
||||
int rank = Dm->rank();
|
||||
|
||||
int n;
|
||||
double final_void_fraction;
|
||||
double count,countGlobal,totalGlobal;
|
||||
count = 0.f;
|
||||
double maxdist=-200.f;
|
||||
double maxdistGlobal;
|
||||
for (int k=1; k<nz-1; k++){
|
||||
for (int j=1; j<ny-1; j++){
|
||||
for (int i=1; i<nx-1; i++){
|
||||
n = k*nx*ny+j*nx+i;
|
||||
// extract maximum distance for critical radius
|
||||
if ( SignDist(i,j,k) > maxdist) maxdist=SignDist(i,j,k);
|
||||
if ( SignDist(i,j,k) > 0.0 ){
|
||||
count += 1.0;
|
||||
id[n] = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MPI_Barrier(Dm->Comm);
|
||||
|
||||
// total Global is the number of nodes in the pore-space
|
||||
MPI_Allreduce(&count,&totalGlobal,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
|
||||
MPI_Allreduce(&maxdist,&maxdistGlobal,1,MPI_DOUBLE,MPI_MAX,Dm->Comm);
|
||||
double volume=double(nprocx*nprocy*nprocz)*double(nx-2)*double(ny-2)*double(nz-2);
|
||||
double volume_fraction=totalGlobal/volume;
|
||||
if (rank==0) printf("Volume fraction for morphological opening: %f \n",volume_fraction);
|
||||
if (rank==0) printf("Maximum pore size: %f \n",maxdistGlobal);
|
||||
|
||||
// Communication buffers
|
||||
char *sendID_x, *sendID_y, *sendID_z, *sendID_X, *sendID_Y, *sendID_Z;
|
||||
char *sendID_xy, *sendID_yz, *sendID_xz, *sendID_Xy, *sendID_Yz, *sendID_xZ;
|
||||
char *sendID_xY, *sendID_yZ, *sendID_Xz, *sendID_XY, *sendID_YZ, *sendID_XZ;
|
||||
char *recvID_x, *recvID_y, *recvID_z, *recvID_X, *recvID_Y, *recvID_Z;
|
||||
char *recvID_xy, *recvID_yz, *recvID_xz, *recvID_Xy, *recvID_Yz, *recvID_xZ;
|
||||
char *recvID_xY, *recvID_yZ, *recvID_Xz, *recvID_XY, *recvID_YZ, *recvID_XZ;
|
||||
// send buffers
|
||||
sendID_x = new char [Dm->sendCount_x];
|
||||
sendID_y = new char [Dm->sendCount_y];
|
||||
sendID_z = new char [Dm->sendCount_z];
|
||||
sendID_X = new char [Dm->sendCount_X];
|
||||
sendID_Y = new char [Dm->sendCount_Y];
|
||||
sendID_Z = new char [Dm->sendCount_Z];
|
||||
sendID_xy = new char [Dm->sendCount_xy];
|
||||
sendID_yz = new char [Dm->sendCount_yz];
|
||||
sendID_xz = new char [Dm->sendCount_xz];
|
||||
sendID_Xy = new char [Dm->sendCount_Xy];
|
||||
sendID_Yz = new char [Dm->sendCount_Yz];
|
||||
sendID_xZ = new char [Dm->sendCount_xZ];
|
||||
sendID_xY = new char [Dm->sendCount_xY];
|
||||
sendID_yZ = new char [Dm->sendCount_yZ];
|
||||
sendID_Xz = new char [Dm->sendCount_Xz];
|
||||
sendID_XY = new char [Dm->sendCount_XY];
|
||||
sendID_YZ = new char [Dm->sendCount_YZ];
|
||||
sendID_XZ = new char [Dm->sendCount_XZ];
|
||||
//......................................................................................
|
||||
// recv buffers
|
||||
recvID_x = new char [Dm->recvCount_x];
|
||||
recvID_y = new char [Dm->recvCount_y];
|
||||
recvID_z = new char [Dm->recvCount_z];
|
||||
recvID_X = new char [Dm->recvCount_X];
|
||||
recvID_Y = new char [Dm->recvCount_Y];
|
||||
recvID_Z = new char [Dm->recvCount_Z];
|
||||
recvID_xy = new char [Dm->recvCount_xy];
|
||||
recvID_yz = new char [Dm->recvCount_yz];
|
||||
recvID_xz = new char [Dm->recvCount_xz];
|
||||
recvID_Xy = new char [Dm->recvCount_Xy];
|
||||
recvID_xZ = new char [Dm->recvCount_xZ];
|
||||
recvID_xY = new char [Dm->recvCount_xY];
|
||||
recvID_yZ = new char [Dm->recvCount_yZ];
|
||||
recvID_Yz = new char [Dm->recvCount_Yz];
|
||||
recvID_Xz = new char [Dm->recvCount_Xz];
|
||||
recvID_XY = new char [Dm->recvCount_XY];
|
||||
recvID_YZ = new char [Dm->recvCount_YZ];
|
||||
recvID_XZ = new char [Dm->recvCount_XZ];
|
||||
//......................................................................................
|
||||
int sendtag,recvtag;
|
||||
sendtag = recvtag = 7;
|
||||
|
||||
int x,y,z;
|
||||
int ii,jj,kk;
|
||||
int Nx = nx;
|
||||
int Ny = ny;
|
||||
int Nz = nz;
|
||||
|
||||
double void_fraction_old=1.0;
|
||||
double void_fraction_new=1.0;
|
||||
double void_fraction_diff_old = 1.0;
|
||||
double void_fraction_diff_new = 1.0;
|
||||
|
||||
// Increase the critical radius until the target saturation is met
|
||||
double deltaR=0.05; // amount to change the radius in voxel units
|
||||
double Rcrit_old;
|
||||
|
||||
double GlobalNumber = 1.f;
|
||||
int imin,jmin,kmin,imax,jmax,kmax;
|
||||
|
||||
double Rcrit_new = maxdistGlobal;
|
||||
//if (argc>2){
|
||||
// Rcrit_new = strtod(argv[2],NULL);
|
||||
// if (rank==0) printf("Max. distance =%f, Initial critical radius = %f \n",maxdistGlobal,Rcrit_new);
|
||||
//}
|
||||
|
||||
while (void_fraction_new > VoidFraction)
|
||||
{
|
||||
void_fraction_diff_old = void_fraction_diff_new;
|
||||
void_fraction_old = void_fraction_new;
|
||||
Rcrit_old = Rcrit_new;
|
||||
Rcrit_new -= deltaR*Rcrit_old;
|
||||
int Window=round(Rcrit_new);
|
||||
if (Window == 0) Window = 1; // If Window = 0 at the begining, after the following process will have sw=1.0
|
||||
// and sw<Sw will be immediately broken
|
||||
double LocalNumber=0.f;
|
||||
for(int k=0; k<Nz; k++){
|
||||
for(int j=0; j<Ny; j++){
|
||||
for(int i=0; i<Nx; i++){
|
||||
n = k*nx*ny + j*nx+i;
|
||||
if (SignDist(i,j,k) > Rcrit_new){
|
||||
// loop over the window and update
|
||||
imin=max(1,i-Window);
|
||||
jmin=max(1,j-Window);
|
||||
kmin=max(1,k-Window);
|
||||
imax=min(Nx-1,i+Window);
|
||||
jmax=min(Ny-1,j+Window);
|
||||
kmax=min(Nz-1,k+Window);
|
||||
for (kk=kmin; kk<kmax; kk++){
|
||||
for (jj=jmin; jj<jmax; jj++){
|
||||
for (ii=imin; ii<imax; ii++){
|
||||
int nn = kk*nx*ny+jj*nx+ii;
|
||||
double dsq = double((ii-i)*(ii-i)+(jj-j)*(jj-j)+(kk-k)*(kk-k));
|
||||
if (id[nn] == 2 && dsq <= Rcrit_new*Rcrit_new){
|
||||
LocalNumber+=1.0;
|
||||
id[nn]=1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// move on
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pack and send the updated ID values
|
||||
PackID(Dm->sendList_x, Dm->sendCount_x ,sendID_x, id);
|
||||
PackID(Dm->sendList_X, Dm->sendCount_X ,sendID_X, id);
|
||||
PackID(Dm->sendList_y, Dm->sendCount_y ,sendID_y, id);
|
||||
PackID(Dm->sendList_Y, Dm->sendCount_Y ,sendID_Y, id);
|
||||
PackID(Dm->sendList_z, Dm->sendCount_z ,sendID_z, id);
|
||||
PackID(Dm->sendList_Z, Dm->sendCount_Z ,sendID_Z, id);
|
||||
PackID(Dm->sendList_xy, Dm->sendCount_xy ,sendID_xy, id);
|
||||
PackID(Dm->sendList_Xy, Dm->sendCount_Xy ,sendID_Xy, id);
|
||||
PackID(Dm->sendList_xY, Dm->sendCount_xY ,sendID_xY, id);
|
||||
PackID(Dm->sendList_XY, Dm->sendCount_XY ,sendID_XY, id);
|
||||
PackID(Dm->sendList_xz, Dm->sendCount_xz ,sendID_xz, id);
|
||||
PackID(Dm->sendList_Xz, Dm->sendCount_Xz ,sendID_Xz, id);
|
||||
PackID(Dm->sendList_xZ, Dm->sendCount_xZ ,sendID_xZ, id);
|
||||
PackID(Dm->sendList_XZ, Dm->sendCount_XZ ,sendID_XZ, id);
|
||||
PackID(Dm->sendList_yz, Dm->sendCount_yz ,sendID_yz, id);
|
||||
PackID(Dm->sendList_Yz, Dm->sendCount_Yz ,sendID_Yz, id);
|
||||
PackID(Dm->sendList_yZ, Dm->sendCount_yZ ,sendID_yZ, id);
|
||||
PackID(Dm->sendList_YZ, Dm->sendCount_YZ ,sendID_YZ, id);
|
||||
//......................................................................................
|
||||
MPI_Sendrecv(sendID_x,Dm->sendCount_x,MPI_CHAR,Dm->rank_x(),sendtag,
|
||||
recvID_X,Dm->recvCount_X,MPI_CHAR,Dm->rank_X(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_X,Dm->sendCount_X,MPI_CHAR,Dm->rank_X(),sendtag,
|
||||
recvID_x,Dm->recvCount_x,MPI_CHAR,Dm->rank_x(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_y,Dm->sendCount_y,MPI_CHAR,Dm->rank_y(),sendtag,
|
||||
recvID_Y,Dm->recvCount_Y,MPI_CHAR,Dm->rank_Y(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Y,Dm->sendCount_Y,MPI_CHAR,Dm->rank_Y(),sendtag,
|
||||
recvID_y,Dm->recvCount_y,MPI_CHAR,Dm->rank_y(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_z,Dm->sendCount_z,MPI_CHAR,Dm->rank_z(),sendtag,
|
||||
recvID_Z,Dm->recvCount_Z,MPI_CHAR,Dm->rank_Z(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Z,Dm->sendCount_Z,MPI_CHAR,Dm->rank_Z(),sendtag,
|
||||
recvID_z,Dm->recvCount_z,MPI_CHAR,Dm->rank_z(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_xy,Dm->sendCount_xy,MPI_CHAR,Dm->rank_xy(),sendtag,
|
||||
recvID_XY,Dm->recvCount_XY,MPI_CHAR,Dm->rank_XY(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_XY,Dm->sendCount_XY,MPI_CHAR,Dm->rank_XY(),sendtag,
|
||||
recvID_xy,Dm->recvCount_xy,MPI_CHAR,Dm->rank_xy(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Xy,Dm->sendCount_Xy,MPI_CHAR,Dm->rank_Xy(),sendtag,
|
||||
recvID_xY,Dm->recvCount_xY,MPI_CHAR,Dm->rank_xY(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_xY,Dm->sendCount_xY,MPI_CHAR,Dm->rank_xY(),sendtag,
|
||||
recvID_Xy,Dm->recvCount_Xy,MPI_CHAR,Dm->rank_Xy(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_xz,Dm->sendCount_xz,MPI_CHAR,Dm->rank_xz(),sendtag,
|
||||
recvID_XZ,Dm->recvCount_XZ,MPI_CHAR,Dm->rank_XZ(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_XZ,Dm->sendCount_XZ,MPI_CHAR,Dm->rank_XZ(),sendtag,
|
||||
recvID_xz,Dm->recvCount_xz,MPI_CHAR,Dm->rank_xz(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Xz,Dm->sendCount_Xz,MPI_CHAR,Dm->rank_Xz(),sendtag,
|
||||
recvID_xZ,Dm->recvCount_xZ,MPI_CHAR,Dm->rank_xZ(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_xZ,Dm->sendCount_xZ,MPI_CHAR,Dm->rank_xZ(),sendtag,
|
||||
recvID_Xz,Dm->recvCount_Xz,MPI_CHAR,Dm->rank_Xz(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_yz,Dm->sendCount_yz,MPI_CHAR,Dm->rank_yz(),sendtag,
|
||||
recvID_YZ,Dm->recvCount_YZ,MPI_CHAR,Dm->rank_YZ(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_YZ,Dm->sendCount_YZ,MPI_CHAR,Dm->rank_YZ(),sendtag,
|
||||
recvID_yz,Dm->recvCount_yz,MPI_CHAR,Dm->rank_yz(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Yz,Dm->sendCount_Yz,MPI_CHAR,Dm->rank_Yz(),sendtag,
|
||||
recvID_yZ,Dm->recvCount_yZ,MPI_CHAR,Dm->rank_yZ(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_yZ,Dm->sendCount_yZ,MPI_CHAR,Dm->rank_yZ(),sendtag,
|
||||
recvID_Yz,Dm->recvCount_Yz,MPI_CHAR,Dm->rank_Yz(),recvtag,Dm->Comm,MPI_STATUS_IGNORE);
|
||||
//......................................................................................
|
||||
UnpackID(Dm->recvList_x, Dm->recvCount_x ,recvID_x, id);
|
||||
UnpackID(Dm->recvList_X, Dm->recvCount_X ,recvID_X, id);
|
||||
UnpackID(Dm->recvList_y, Dm->recvCount_y ,recvID_y, id);
|
||||
UnpackID(Dm->recvList_Y, Dm->recvCount_Y ,recvID_Y, id);
|
||||
UnpackID(Dm->recvList_z, Dm->recvCount_z ,recvID_z, id);
|
||||
UnpackID(Dm->recvList_Z, Dm->recvCount_Z ,recvID_Z, id);
|
||||
UnpackID(Dm->recvList_xy, Dm->recvCount_xy ,recvID_xy, id);
|
||||
UnpackID(Dm->recvList_Xy, Dm->recvCount_Xy ,recvID_Xy, id);
|
||||
UnpackID(Dm->recvList_xY, Dm->recvCount_xY ,recvID_xY, id);
|
||||
UnpackID(Dm->recvList_XY, Dm->recvCount_XY ,recvID_XY, id);
|
||||
UnpackID(Dm->recvList_xz, Dm->recvCount_xz ,recvID_xz, id);
|
||||
UnpackID(Dm->recvList_Xz, Dm->recvCount_Xz ,recvID_Xz, id);
|
||||
UnpackID(Dm->recvList_xZ, Dm->recvCount_xZ ,recvID_xZ, id);
|
||||
UnpackID(Dm->recvList_XZ, Dm->recvCount_XZ ,recvID_XZ, id);
|
||||
UnpackID(Dm->recvList_yz, Dm->recvCount_yz ,recvID_yz, id);
|
||||
UnpackID(Dm->recvList_Yz, Dm->recvCount_Yz ,recvID_Yz, id);
|
||||
UnpackID(Dm->recvList_yZ, Dm->recvCount_yZ ,recvID_yZ, id);
|
||||
UnpackID(Dm->recvList_YZ, Dm->recvCount_YZ ,recvID_YZ, id);
|
||||
//......................................................................................
|
||||
|
||||
MPI_Allreduce(&LocalNumber,&GlobalNumber,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
|
||||
|
||||
count = 0.f;
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
n=k*Nx*Ny+j*Nx+i;
|
||||
if (id[n] == 2){
|
||||
count+=1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MPI_Allreduce(&count,&countGlobal,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
|
||||
void_fraction_new = countGlobal/totalGlobal;
|
||||
void_fraction_diff_new = abs(void_fraction_new-VoidFraction);
|
||||
if (rank==0){
|
||||
printf(" %f ",void_fraction_new);
|
||||
printf(" %f\n",Rcrit_new);
|
||||
}
|
||||
}
|
||||
|
||||
if (void_fraction_diff_new<void_fraction_diff_old){
|
||||
final_void_fraction=void_fraction_new;
|
||||
if (rank==0){
|
||||
printf("Final void fraction =%f\n",void_fraction_new);
|
||||
printf("Final critical radius=%f\n",Rcrit_new);
|
||||
}
|
||||
}
|
||||
else{
|
||||
final_void_fraction=void_fraction_old;
|
||||
if (rank==0){
|
||||
printf("Final void fraction=%f\n",void_fraction_old);
|
||||
printf("Final critical radius=%f\n",Rcrit_old);
|
||||
}
|
||||
}
|
||||
return final_void_fraction;
|
||||
}
|
||||
/*
|
||||
double morph_open()
|
||||
{
|
||||
|
||||
fillHalo<char> fillChar(Dm->Comm,Dm->rank_info,{Nx-2,Ny-2,Nz-2},{1,1,1},0,1);
|
||||
|
||||
|
||||
MPI_Allreduce(&LocalNumber,&GlobalNumber,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
|
||||
|
||||
count = 0.f;
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
n=k*Nx*Ny+j*Nx+i;
|
||||
if (id[n] == 2){
|
||||
count+=1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MPI_Allreduce(&count,&countGlobal,1,MPI_DOUBLE,MPI_SUM,Dm->Comm);
|
||||
return countGlobal;
|
||||
}
|
||||
*/
|
||||
|
||||
double MorphGrow(DoubleArray &BoundaryDist, DoubleArray &Dist, Array<char> &id, std::shared_ptr<Domain> Dm, double TargetGrowth){
|
||||
|
||||
int Nx = Dm->Nx;
|
||||
int Ny = Dm->Ny;
|
||||
int Nz = Dm->Nz;
|
||||
int iproc = Dm->iproc();
|
||||
int jproc = Dm->jproc();
|
||||
int kproc = Dm->kproc();
|
||||
int nprocx = Dm->nprocx();
|
||||
int nprocy = Dm->nprocy();
|
||||
int nprocz = Dm->nprocz();
|
||||
int rank = Dm->rank();
|
||||
|
||||
double count=0.0;
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
if (Dist(i,j,k) < 0.0){
|
||||
count+=1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
double count_original=sumReduce( Dm->Comm, count);
|
||||
|
||||
// Estimate morph_delta
|
||||
double morph_delta = 0.0;
|
||||
if (TargetGrowth > 0.0) morph_delta = 0.1;
|
||||
else morph_delta = -0.1;
|
||||
double morph_delta_previous = 0.0;
|
||||
double GrowthEstimate = 0.0;
|
||||
double GrowthPrevious = 0.0;
|
||||
int COUNT_FOR_LOOP = 0;
|
||||
double ERROR = 100.0;
|
||||
if (rank == 0) printf("Estimate delta for growth=%f \n",TargetGrowth);
|
||||
while ( ERROR > 0.01 && COUNT_FOR_LOOP < 10 ){
|
||||
COUNT_FOR_LOOP++;
|
||||
count = 0.0;
|
||||
double MAX_DISPLACEMENT = 0.0;
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
double walldist=BoundaryDist(i,j,k);
|
||||
double wallweight = 1.0 / (1+exp(-5.f*(walldist-1.f)));
|
||||
//wallweight = 1.0;
|
||||
if (fabs(wallweight*morph_delta) > MAX_DISPLACEMENT) MAX_DISPLACEMENT= fabs(wallweight*morph_delta);
|
||||
|
||||
if (Dist(i,j,k) - wallweight*morph_delta < 0.0){
|
||||
count+=1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
count=sumReduce( Dm->Comm, count);
|
||||
MAX_DISPLACEMENT = maxReduce( Dm->Comm, MAX_DISPLACEMENT);
|
||||
GrowthEstimate = count - count_original;
|
||||
ERROR = fabs((GrowthEstimate-TargetGrowth) /TargetGrowth);
|
||||
|
||||
if (rank == 0) printf(" delta=%f, growth=%f, max. displacement = %f \n",morph_delta, GrowthEstimate, MAX_DISPLACEMENT);
|
||||
// Now adjust morph_delta
|
||||
double step_size = (TargetGrowth - GrowthEstimate)*(morph_delta - morph_delta_previous) / (GrowthEstimate - GrowthPrevious);
|
||||
GrowthPrevious = GrowthEstimate;
|
||||
morph_delta_previous = morph_delta;
|
||||
morph_delta += step_size;
|
||||
if (morph_delta / morph_delta_previous > 2.0 ) morph_delta = morph_delta_previous*2.0;
|
||||
|
||||
//MAX_DISPLACEMENT *= max(TargetGrowth/GrowthEstimate,1.25);
|
||||
if (MAX_DISPLACEMENT > 1.0 ){
|
||||
if (morph_delta > 0.0 ) morph_delta = 1.0;
|
||||
else morph_delta = -1.0;
|
||||
|
||||
//if (COUNT_FOR_LOOP > 2) COUNT_FOR_LOOP = 100;
|
||||
COUNT_FOR_LOOP = 100; // exit loop if displacement is too large
|
||||
}
|
||||
}
|
||||
if (rank == 0) printf("Final delta=%f \n",morph_delta);
|
||||
|
||||
count = 0.0;
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
double walldist=BoundaryDist(i,j,k);
|
||||
double wallweight = 1.0 / (1+exp(-5.f*(walldist-1.f)));
|
||||
//wallweight = 1.0;
|
||||
Dist(i,j,k) -= wallweight*morph_delta;
|
||||
if (Dist(i,j,k) < 0.0) count+=1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
count=sumReduce( Dm->Comm, count);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
6
analysis/morphology.h
Normal file
6
analysis/morphology.h
Normal file
@@ -0,0 +1,6 @@
|
||||
// Morphological opening routine
|
||||
#include "common/Array.h"
|
||||
#include "common/Domain.h"
|
||||
|
||||
double MorphOpen(DoubleArray &SignDist, char *id, std::shared_ptr<Domain> Dm, double VoidFraction);
|
||||
double MorphGrow(DoubleArray &BoundaryDist, DoubleArray &Dist, Array<char> &id, std::shared_ptr<Domain> Dm, double TargetVol);
|
||||
@@ -50,7 +50,7 @@
|
||||
#include <dlfcn.h>
|
||||
#include <mach/mach.h>
|
||||
#include <unistd.h>
|
||||
#elif defined(__linux) || defined(__unix) || defined(__posix)
|
||||
#elif defined( __linux ) || defined( __linux__ ) || defined( __unix ) || defined( __posix )
|
||||
#define USE_LINUX
|
||||
#include <sys/time.h>
|
||||
#include <execinfo.h>
|
||||
|
||||
@@ -18,6 +18,7 @@ color lattice boltzmann model
|
||||
*/
|
||||
#include "models/ColorModel.h"
|
||||
#include "analysis/distance.h"
|
||||
#include "analysis/morphology.h"
|
||||
|
||||
ScaLBL_ColorModel::ScaLBL_ColorModel(int RANK, int NP, MPI_Comm COMM):
|
||||
rank(RANK), nprocs(NP), Restart(0),timestep(0),timestepMax(0),tauA(0),tauB(0),rhoA(0),rhoB(0),alpha(0),beta(0),
|
||||
@@ -184,8 +185,8 @@ void ScaLBL_ColorModel::AssignComponentLabels(double *phase)
|
||||
ERROR("Error: ComponentLabels and ComponentAffinity must be the same length! \n");
|
||||
}
|
||||
|
||||
int label_count[NLABELS];
|
||||
int label_count_global[NLABELS];
|
||||
double label_count[NLABELS];
|
||||
double label_count_global[NLABELS];
|
||||
// Assign the labels
|
||||
|
||||
for (int idx=0; idx<NLABELS; idx++) label_count[idx]=0;
|
||||
@@ -200,7 +201,7 @@ void ScaLBL_ColorModel::AssignComponentLabels(double *phase)
|
||||
//printf("idx=%i, value=%i, %i, \n",idx, VALUE,LabelList[idx]);
|
||||
if (VALUE == LabelList[idx]){
|
||||
AFFINITY=AffinityList[idx];
|
||||
label_count[idx]++;
|
||||
label_count[idx] += 1.0;
|
||||
idx = NLABELS;
|
||||
Mask->id[n] = 0; // set mask to zero since this is an immobile component
|
||||
}
|
||||
@@ -215,14 +216,14 @@ void ScaLBL_ColorModel::AssignComponentLabels(double *phase)
|
||||
// Set Dm to match Mask
|
||||
for (int i=0; i<Nx*Ny*Nz; i++) Dm->id[i] = Mask->id[i];
|
||||
|
||||
MPI_Allreduce(&label_count[0],&label_count_global[0],NLABELS,MPI_INT,MPI_SUM,Dm->Comm);
|
||||
for (int idx=0; idx<NLABELS; idx++) label_count_global[idx]=sumReduce( Dm->Comm, label_count[idx]);
|
||||
|
||||
if (rank==0){
|
||||
printf("Components labels: %lu \n",NLABELS);
|
||||
for (unsigned int idx=0; idx<NLABELS; idx++){
|
||||
VALUE=LabelList[idx];
|
||||
AFFINITY=AffinityList[idx];
|
||||
double volume_fraction = double(label_count_global[idx])/double((Nx-2)*(Ny-2)*(Nz-2)*nprocz);
|
||||
double volume_fraction = double(label_count_global[idx])/double((Nx-2)*(Ny-2)*(Nz-2)*nprocs);
|
||||
printf(" label=%i, affinity=%f, volume fraction==%f\n",int(VALUE),AFFINITY,volume_fraction);
|
||||
}
|
||||
}
|
||||
@@ -426,6 +427,8 @@ void ScaLBL_ColorModel::Run(){
|
||||
bool SET_CAPILLARY_NUMBER = false;
|
||||
bool MORPH_ADAPT = false;
|
||||
bool USE_MORPH = false;
|
||||
int MAX_MORPH_TIMESTEPS = 20000;
|
||||
int CURRENT_MORPH_TIMESTEPS=0;
|
||||
int morph_interval;
|
||||
double morph_delta;
|
||||
int morph_timesteps = 0;
|
||||
@@ -434,13 +437,18 @@ void ScaLBL_ColorModel::Run(){
|
||||
double tolerance = 1.f;
|
||||
double Ca_previous = 0.f;
|
||||
|
||||
|
||||
double delta_volume = 0.0;
|
||||
double delta_volume_target = 0.0;
|
||||
|
||||
/* double TARGET_SATURATION = 0.f;
|
||||
int target_saturation_index=0;
|
||||
std::vector<double> target_saturation;
|
||||
double TARGET_SATURATION = 0.f;
|
||||
if (color_db->keyExists( "target_saturation" )){
|
||||
target_saturation = color_db->getVector<double>( "target_saturation" );
|
||||
TARGET_SATURATION = target_saturation[0];
|
||||
}
|
||||
*/
|
||||
if (color_db->keyExists( "capillary_number" )){
|
||||
capillary_number = color_db->getScalar<double>( "capillary_number" );
|
||||
SET_CAPILLARY_NUMBER=true;
|
||||
@@ -456,7 +464,8 @@ void ScaLBL_ColorModel::Run(){
|
||||
morph_delta = analysis_db->getScalar<double>( "morph_delta" );
|
||||
}
|
||||
else{
|
||||
morph_delta=0.5;
|
||||
morph_delta=0.0;
|
||||
USE_MORPH = false;
|
||||
}
|
||||
if (analysis_db->keyExists( "morph_interval" )){
|
||||
morph_interval = analysis_db->getScalar<int>( "morph_interval" );
|
||||
@@ -570,12 +579,13 @@ void ScaLBL_ColorModel::Run(){
|
||||
|
||||
MPI_Barrier(comm);
|
||||
PROFILE_STOP("Update");
|
||||
|
||||
|
||||
// Run the analysis
|
||||
analysis.run( timestep, *Averages, Phi, Pressure, Velocity, fq, Den );
|
||||
|
||||
// allow initial ramp-up to get closer to steady state
|
||||
if (timestep > ramp_timesteps && timestep%analysis_interval == analysis_interval-20 && USE_MORPH){
|
||||
if (timestep > ramp_timesteps && timestep%analysis_interval == 0 && USE_MORPH){
|
||||
analysis.finish();
|
||||
if ( morph_timesteps > morph_interval ){
|
||||
|
||||
double volB = Averages->Volume_w();
|
||||
@@ -592,7 +602,7 @@ void ScaLBL_ColorModel::Run(){
|
||||
double flow_rate_A = sqrt(vA_x*vA_x + vA_y*vA_y + vA_z*vA_z);
|
||||
double flow_rate_B = sqrt(vB_x*vB_x + vB_y*vB_y + vB_z*vB_z);
|
||||
double current_saturation = volB/(volA+volB);
|
||||
double Ca = fabs(volA*muA*flow_rate_A + volB*muB*flow_rate_B)/(5.796*alpha*double(Nx*Ny*Nz*nprocs));
|
||||
double Ca = fabs(volA*muA*flow_rate_A + volB*muB*flow_rate_B)/(5.796*alpha*double((Nx-2)*(Ny-2)*(Nz-2)*nprocs));
|
||||
|
||||
double force_magnitude = sqrt(Fx*Fx + Fy*Fy + Fz*Fz);
|
||||
//double krA = muA*volA*flow_rate_A/force_magnitude/double(Nx*Ny*Nz*nprocs);
|
||||
@@ -600,11 +610,13 @@ void ScaLBL_ColorModel::Run(){
|
||||
|
||||
if (fabs((Ca - Ca_previous)/Ca) < tolerance ){
|
||||
MORPH_ADAPT = true;
|
||||
CURRENT_MORPH_TIMESTEPS=0;
|
||||
delta_volume_target = (volA + volB)*morph_delta; // set target volume chnage
|
||||
if (rank==0){
|
||||
printf("** WRITE STEADY POINT *** ");
|
||||
printf("Ca = %f, (previous = %f) \n",Ca,Ca_previous);
|
||||
volA /= double((Nx-2)*(Ny-2)*(Nz-2)*nprocz);
|
||||
volB /= double((Nx-2)*(Ny-2)*(Nz-2)*nprocz);
|
||||
volA /= double((Nx-2)*(Ny-2)*(Nz-2)*nprocs);
|
||||
volB /= double((Nx-2)*(Ny-2)*(Nz-2)*nprocs);
|
||||
FILE * kr_log_file = fopen("relperm.csv","a");
|
||||
fprintf(kr_log_file,"%i %.5g %.5g %.5g %.5g %.5g %.5g ",timestep-analysis_interval+20,muA,muB,5.796*alpha,Fx,Fy,Fz);
|
||||
fprintf(kr_log_file,"%.5g %.5g %.5g %.5g %.5g %.5g %.5g %.5g\n",volA,volB,vA_x,vA_y,vA_z,vB_x,vB_y,vB_z);
|
||||
@@ -632,7 +644,7 @@ void ScaLBL_ColorModel::Run(){
|
||||
Averages->SetParams(rhoA,rhoB,tauA,tauB,Fx,Fy,Fz,alpha);
|
||||
}
|
||||
|
||||
if (morph_delta > 0.f){
|
||||
/*if (morph_delta > 0.f){
|
||||
// wetting phase saturation will decrease
|
||||
while (current_saturation < TARGET_SATURATION && target_saturation_index < target_saturation.size() ){
|
||||
TARGET_SATURATION = target_saturation[target_saturation_index++];
|
||||
@@ -645,6 +657,7 @@ void ScaLBL_ColorModel::Run(){
|
||||
if (rank==0) printf(" Set target saturation as %f (currently %f)\n",TARGET_SATURATION,current_saturation);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
else{
|
||||
if (rank==0){
|
||||
@@ -656,22 +669,25 @@ void ScaLBL_ColorModel::Run(){
|
||||
Ca_previous = Ca;
|
||||
}
|
||||
if (MORPH_ADAPT ){
|
||||
if (rank==0) printf("***Morphological step with target saturation %f ***\n",TARGET_SATURATION);
|
||||
double volB = Averages->Volume_w();
|
||||
double volA = Averages->Volume_n();
|
||||
double delta_volume = MorphInit(beta,morph_delta);
|
||||
double delta_volume_target = volB - (volA + volB)*TARGET_SATURATION; // change in volume to A
|
||||
// update the volume
|
||||
volA += delta_volume;
|
||||
volB -= delta_volume;
|
||||
if ((delta_volume_target - delta_volume) / delta_volume > 0.f){
|
||||
CURRENT_MORPH_TIMESTEPS += analysis_interval;
|
||||
if (rank==0) printf("***Morphological step with target volume change %f ***\n", delta_volume_target);
|
||||
//double delta_volume_target = volB - (volA + volB)*TARGET_SATURATION; // change in volume to A
|
||||
delta_volume += MorphInit(beta,delta_volume_target-delta_volume);
|
||||
if ( (delta_volume - delta_volume_target)/delta_volume_target > 0.0 ){
|
||||
MORPH_ADAPT = false;
|
||||
delta_volume = 0.0;
|
||||
}
|
||||
else if (CURRENT_MORPH_TIMESTEPS > MAX_MORPH_TIMESTEPS) {
|
||||
MORPH_ADAPT = false;
|
||||
}
|
||||
/*if ((delta_volume_target - delta_volume) / delta_volume > 0.f){
|
||||
morph_delta *= 1.01*min((delta_volume_target - delta_volume) / delta_volume, 2.0);
|
||||
if (morph_delta > 1.f) morph_delta = 1.f;
|
||||
if (morph_delta < -1.f) morph_delta = -1.f;
|
||||
if (fabs(morph_delta) < 0.05 ) morph_delta = 0.05*(morph_delta)/fabs(morph_delta); // set minimum
|
||||
if (rank==0) printf(" Adjust morph delta: %f \n", morph_delta);
|
||||
}
|
||||
if (morph_delta < 0.f){
|
||||
if (delta_volume_target < 0.f){
|
||||
if (volB/(volA + volB) > TARGET_SATURATION){
|
||||
MORPH_ADAPT = false;
|
||||
TARGET_SATURATION = target_saturation[target_saturation_index++];
|
||||
@@ -683,8 +699,8 @@ void ScaLBL_ColorModel::Run(){
|
||||
TARGET_SATURATION = target_saturation[target_saturation_index++];
|
||||
}
|
||||
}
|
||||
*/
|
||||
MPI_Barrier(comm);
|
||||
morph_timesteps = 0;
|
||||
}
|
||||
morph_timesteps += analysis_interval;
|
||||
}
|
||||
@@ -712,47 +728,61 @@ void ScaLBL_ColorModel::Run(){
|
||||
// ************************************************************************
|
||||
}
|
||||
|
||||
double ScaLBL_ColorModel::MorphInit(const double beta, const double morph_delta){
|
||||
double ScaLBL_ColorModel::MorphInit(const double beta, const double target_delta_volume){
|
||||
const RankInfoStruct rank_info(rank,nprocx,nprocy,nprocz);
|
||||
|
||||
double vF = 0.f;
|
||||
double vS = 0.f;
|
||||
double delta_volume;
|
||||
|
||||
DoubleArray phase(Nx,Ny,Nz);
|
||||
IntArray phase_label(Nx,Ny,Nz);;
|
||||
DoubleArray phase_distance(Nx,Ny,Nz);
|
||||
Array<char> phase_id(Nx,Ny,Nz);
|
||||
fillHalo<double> fillDouble(Dm->Comm,Dm->rank_info,{Nx-2,Ny-2,Nz-2},{1,1,1},0,1);
|
||||
|
||||
// Basic algorithm to
|
||||
// 1. Copy phase field to CPU
|
||||
ScaLBL_CopyToHost(phase.data(), Phi, N*sizeof(double));
|
||||
|
||||
double count,count_global,volume_initial,volume_final;
|
||||
double count,count_global,volume_initial,volume_final,volume_connected;
|
||||
count = 0.f;
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
if (phase(i,j,k) > 0.f && Averages->SDs(i,j,k) > 0.f) count+=1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
MPI_Allreduce(&count,&count_global,1,MPI_DOUBLE,MPI_SUM,comm);
|
||||
volume_initial = count_global;
|
||||
|
||||
volume_initial = sumReduce( Dm->Comm, count);
|
||||
/*
|
||||
sprintf(LocalRankFilename,"phi_initial.%05i.raw",rank);
|
||||
FILE *INPUT = fopen(LocalRankFilename,"wb");
|
||||
fwrite(phase.data(),8,N,INPUT);
|
||||
fclose(INPUT);
|
||||
*/
|
||||
// 2. Identify connected components of phase field -> phase_label
|
||||
BlobIDstruct new_index;
|
||||
ComputeGlobalBlobIDs(Nx-2,Ny-2,Nz-2,rank_info,phase,Averages->SDs,vF,vS,phase_label,comm);
|
||||
MPI_Barrier(comm);
|
||||
|
||||
// only operate on component "0"
|
||||
count = 0.0;
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
int label = phase_label(i,j,k);
|
||||
if (label == 0 ) phase_id(i,j,k) = 0;
|
||||
else phase_id(i,j,k) = 1;
|
||||
if (label == 0 ){
|
||||
phase_id(i,j,k) = 0;
|
||||
count += 1.0;
|
||||
}
|
||||
else
|
||||
phase_id(i,j,k) = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
volume_connected = sumReduce( Dm->Comm, count);
|
||||
|
||||
// 3. Generate a distance map to the largest object -> phase_distance
|
||||
CalcDist(phase_distance,phase_id,*Dm);
|
||||
|
||||
@@ -771,56 +801,84 @@ double ScaLBL_ColorModel::MorphInit(const double beta, const double morph_delta)
|
||||
if (fabs(value) < 0.8 && Averages->SDs(i,j,k) > 1.f ){
|
||||
phase_distance(i,j,k) = temp;
|
||||
}
|
||||
// erase the original object
|
||||
phase(i,j,k) = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Apply erosion / dilation operation to phase_distance
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
double walldist=Averages->SDs(i,j,k);
|
||||
double wallweight = 1.f / (1+exp(-5.f*(walldist-1.f)));
|
||||
phase_distance(i,j,k) -= wallweight*morph_delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Update phase indicator field based on new distnace
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
int n = k*Nx*Ny + j*Nx + i;
|
||||
double d = phase_distance(i,j,k);
|
||||
if (Averages->SDs(i,j,k) > 0.f){
|
||||
// only update phase field in immediate proximity of largest component
|
||||
if (d < 3.f){
|
||||
phase(i,j,k) = (2.f*(exp(-2.f*beta*d))/(1.f+exp(-2.f*beta*d))-1.f);
|
||||
if (volume_connected < 0.05*volume_initial){
|
||||
// if connected volume is less than 5% just delete the whole thing
|
||||
if (rank==0) printf("Connected region has shrunk to less than 5% of total fluid volume (remove the whole thing) \n");
|
||||
}
|
||||
else {
|
||||
if (rank==0) printf("MorphGrow with target volume fraction change %f \n", target_delta_volume/volume_initial);
|
||||
double target_delta_volume_incremental = target_delta_volume;
|
||||
if (fabs(target_delta_volume) > 0.01*volume_initial)
|
||||
target_delta_volume_incremental = 0.01*volume_initial*target_delta_volume/fabs(target_delta_volume);
|
||||
delta_volume = MorphGrow(Averages->SDs,phase_distance,phase_id,Averages->Dm, target_delta_volume_incremental);
|
||||
|
||||
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
if (phase_distance(i,j,k) < 0.0 ) phase_id(i,j,k) = 0;
|
||||
else phase_id(i,j,k) = 1;
|
||||
//if (phase_distance(i,j,k) < 0.0 ) phase(i,j,k) = 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CalcDist(phase_distance,phase_id,*Dm); // re-calculate distance
|
||||
|
||||
// 5. Update phase indicator field based on new distnace
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
int n = k*Nx*Ny + j*Nx + i;
|
||||
double d = phase_distance(i,j,k);
|
||||
if (Averages->SDs(i,j,k) > 0.f){
|
||||
if (d < 3.f){
|
||||
//phase(i,j,k) = -1.0;
|
||||
phase(i,j,k) = (2.f*(exp(-2.f*beta*d))/(1.f+exp(-2.f*beta*d))-1.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fillDouble.fill(phase);
|
||||
}
|
||||
|
||||
count = 0.f;
|
||||
for (int k=0; k<Nz; k++){
|
||||
for (int j=0; j<Ny; j++){
|
||||
for (int i=0; i<Nx; i++){
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
if (phase(i,j,k) > 0.f && Averages->SDs(i,j,k) > 0.f) count+=1.f;
|
||||
}
|
||||
}
|
||||
}
|
||||
MPI_Allreduce(&count,&count_global,1,MPI_DOUBLE,MPI_SUM,comm);
|
||||
volume_final=count_global;
|
||||
volume_final= sumReduce( Dm->Comm, count);
|
||||
|
||||
double delta_volume = (volume_final-volume_initial);
|
||||
delta_volume = (volume_final-volume_initial);
|
||||
if (rank == 0) printf("MorphInit: change fluid volume fraction by %f \n", delta_volume/volume_initial);
|
||||
if (rank == 0) printf(" new saturation = %f \n", volume_final/(0.238323*double((Nx-2)*(Ny-2)*(Nz-2)*nprocs)));
|
||||
|
||||
// 6. copy back to the device
|
||||
//if (rank==0) printf("MorphInit: copy data back to device\n");
|
||||
ScaLBL_CopyToDevice(Phi,phase.data(),N*sizeof(double));
|
||||
|
||||
/*
|
||||
sprintf(LocalRankFilename,"dist_final.%05i.raw",rank);
|
||||
FILE *DIST = fopen(LocalRankFilename,"wb");
|
||||
fwrite(phase_distance.data(),8,N,DIST);
|
||||
fclose(DIST);
|
||||
|
||||
sprintf(LocalRankFilename,"phi_final.%05i.raw",rank);
|
||||
FILE *PHI = fopen(LocalRankFilename,"wb");
|
||||
fwrite(phase.data(),8,N,PHI);
|
||||
fclose(PHI);
|
||||
*/
|
||||
// 7. Re-initialize phase field and density
|
||||
ScaLBL_PhaseField_Init(dvcMap, Phi, Den, Aq, Bq, 0, ScaLBL_Comm->LastExterior(), Np);
|
||||
ScaLBL_PhaseField_Init(dvcMap, Phi, Den, Aq, Bq, ScaLBL_Comm->FirstInterior(), ScaLBL_Comm->LastInterior(), Np);
|
||||
|
||||
@@ -12,39 +12,13 @@
|
||||
#include "common/Array.h"
|
||||
#include "common/Domain.h"
|
||||
#include "analysis/distance.h"
|
||||
|
||||
#include "analysis/morphology.h"
|
||||
|
||||
//*************************************************************************
|
||||
// Morpohologica pre-processor
|
||||
// Initialize phase distribution using morphological approach
|
||||
// Signed distance function is used to determine fluid configuration
|
||||
//*************************************************************************
|
||||
inline void PackID(int *list, int count, char *sendbuf, char *ID){
|
||||
// Fill in the phase ID values from neighboring processors
|
||||
// This packs up the values that need to be sent from one processor to another
|
||||
int idx,n;
|
||||
|
||||
for (idx=0; idx<count; idx++){
|
||||
n = list[idx];
|
||||
sendbuf[idx] = ID[n];
|
||||
}
|
||||
}
|
||||
//***************************************************************************************
|
||||
|
||||
inline void UnpackID(int *list, int count, char *recvbuf, char *ID){
|
||||
// Fill in the phase ID values from neighboring processors
|
||||
// This unpacks the values once they have been recieved from neighbors
|
||||
int idx,n;
|
||||
|
||||
for (idx=0; idx<count; idx++){
|
||||
n = list[idx];
|
||||
ID[n] = recvbuf[idx];
|
||||
}
|
||||
}
|
||||
|
||||
//***************************************************************************************
|
||||
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
@@ -89,8 +63,11 @@ int main(int argc, char **argv)
|
||||
auto WriteValues = domain_db->getVector<char>( "WriteValues" );
|
||||
SW = domain_db->getScalar<double>("Sw");
|
||||
|
||||
if (rank==0) printf("Target saturation %f \n",SW);
|
||||
|
||||
// Generate the NWP configuration
|
||||
//if (rank==0) printf("Initializing morphological distribution with critical radius %f \n", Rcrit);
|
||||
if (rank==0) printf("Performing morphological opening with target saturation %f \n", SW);
|
||||
// GenerateResidual(id,nx,ny,nz,Saturation);
|
||||
|
||||
nx = size[0];
|
||||
ny = size[1];
|
||||
nz = size[2];
|
||||
@@ -115,7 +92,6 @@ int main(int argc, char **argv)
|
||||
if (readID != size_t(N)) printf("lbpm_morphopen_pp: Error reading ID (rank=%i) \n",rank);
|
||||
fclose(IDFILE);
|
||||
|
||||
|
||||
nx+=2; ny+=2; nz+=2;
|
||||
// Generate the signed distance map
|
||||
// Initialize the domain and communication
|
||||
@@ -148,278 +124,63 @@ int main(int argc, char **argv)
|
||||
CalcDist(SignDist,id_solid,*Dm);
|
||||
|
||||
MPI_Barrier(comm);
|
||||
double count,countGlobal,totalGlobal;
|
||||
count = 0.f;
|
||||
double maxdist=-200.f;
|
||||
double maxdistGlobal;
|
||||
for (int k=1; k<nz-1; k++){
|
||||
for (int j=1; j<ny-1; j++){
|
||||
for (int i=1; i<nx-1; i++){
|
||||
n = k*nx*ny+j*nx+i;
|
||||
// extract maximum distance for critical radius
|
||||
if ( SignDist(i,j,k) > maxdist) maxdist=SignDist(i,j,k);
|
||||
|
||||
// Run the morphological opening
|
||||
MorphOpen(SignDist, id, Dm, SW);
|
||||
|
||||
// calculate distance to non-wetting fluid
|
||||
if (domain_db->keyExists( "HistoryLabels" )){
|
||||
if (rank==0) printf("Relabel solid components that touch fluid 1 \n");
|
||||
auto LabelList = domain_db->getVector<char>( "ComponentLabels" );
|
||||
auto HistoryLabels = domain_db->getVector<char>( "HistoryLabels" );
|
||||
size_t NLABELS=LabelList.size();
|
||||
if (rank==0){
|
||||
for (unsigned int idx=0; idx < NLABELS; idx++){
|
||||
char VALUE = LabelList[idx];
|
||||
char NEWVAL = HistoryLabels[idx];
|
||||
printf(" Relabel component %d as %d \n", VALUE, NEWVAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int k=0; k<nz; k++){
|
||||
for (int j=0; j<ny; j++){
|
||||
for (int i=0; i<nx; i++){
|
||||
n = k*nx*ny+j*nx+i;
|
||||
if (SignDist(i,j,k) < 0.f){
|
||||
// don't do anything
|
||||
for (int k=0;k<nz;k++){
|
||||
for (int j=0;j<ny;j++){
|
||||
for (int i=0;i<nx;i++){
|
||||
int n = k*nx*ny+j*nx+i;
|
||||
// Initialize the solid phase
|
||||
if (id[n] == 1) id_solid(i,j,k) = 0;
|
||||
else id_solid(i,j,k) = 1;
|
||||
}
|
||||
else{
|
||||
// initially saturated with wetting phase
|
||||
id[n] = 2;
|
||||
count+=1.0;
|
||||
}
|
||||
// don't let halo be the maximum dist
|
||||
if ( SignDist(i,j,k) > maxdist) SignDist(i,j,k) = maxdist;
|
||||
}
|
||||
}
|
||||
}
|
||||
MPI_Barrier(comm);
|
||||
// total Global is the number of nodes in the pore-space
|
||||
MPI_Allreduce(&count,&totalGlobal,1,MPI_DOUBLE,MPI_SUM,comm);
|
||||
MPI_Allreduce(&maxdist,&maxdistGlobal,1,MPI_DOUBLE,MPI_MAX,comm);
|
||||
double volume=double(nprocx*nprocy*nprocz)*double(nx-2)*double(ny-2)*double(nz-2);
|
||||
double porosity=totalGlobal/volume;
|
||||
if (rank==0) printf("Media Porosity: %f \n",porosity);
|
||||
if (rank==0) printf("Maximum pore size: %f \n",maxdistGlobal);\
|
||||
|
||||
Dm->CommInit();
|
||||
int iproc = Dm->iproc();
|
||||
int jproc = Dm->jproc();
|
||||
int kproc = Dm->kproc();
|
||||
|
||||
// Generate the NWP configuration
|
||||
//if (rank==0) printf("Initializing morphological distribution with critical radius %f \n", Rcrit);
|
||||
if (rank==0) printf("Performing morphological opening with target saturation %f \n", SW);
|
||||
// GenerateResidual(id,nx,ny,nz,Saturation);
|
||||
|
||||
// Communication buffers
|
||||
char *sendID_x, *sendID_y, *sendID_z, *sendID_X, *sendID_Y, *sendID_Z;
|
||||
char *sendID_xy, *sendID_yz, *sendID_xz, *sendID_Xy, *sendID_Yz, *sendID_xZ;
|
||||
char *sendID_xY, *sendID_yZ, *sendID_Xz, *sendID_XY, *sendID_YZ, *sendID_XZ;
|
||||
char *recvID_x, *recvID_y, *recvID_z, *recvID_X, *recvID_Y, *recvID_Z;
|
||||
char *recvID_xy, *recvID_yz, *recvID_xz, *recvID_Xy, *recvID_Yz, *recvID_xZ;
|
||||
char *recvID_xY, *recvID_yZ, *recvID_Xz, *recvID_XY, *recvID_YZ, *recvID_XZ;
|
||||
// send buffers
|
||||
sendID_x = new char [Dm->sendCount_x];
|
||||
sendID_y = new char [Dm->sendCount_y];
|
||||
sendID_z = new char [Dm->sendCount_z];
|
||||
sendID_X = new char [Dm->sendCount_X];
|
||||
sendID_Y = new char [Dm->sendCount_Y];
|
||||
sendID_Z = new char [Dm->sendCount_Z];
|
||||
sendID_xy = new char [Dm->sendCount_xy];
|
||||
sendID_yz = new char [Dm->sendCount_yz];
|
||||
sendID_xz = new char [Dm->sendCount_xz];
|
||||
sendID_Xy = new char [Dm->sendCount_Xy];
|
||||
sendID_Yz = new char [Dm->sendCount_Yz];
|
||||
sendID_xZ = new char [Dm->sendCount_xZ];
|
||||
sendID_xY = new char [Dm->sendCount_xY];
|
||||
sendID_yZ = new char [Dm->sendCount_yZ];
|
||||
sendID_Xz = new char [Dm->sendCount_Xz];
|
||||
sendID_XY = new char [Dm->sendCount_XY];
|
||||
sendID_YZ = new char [Dm->sendCount_YZ];
|
||||
sendID_XZ = new char [Dm->sendCount_XZ];
|
||||
//......................................................................................
|
||||
// recv buffers
|
||||
recvID_x = new char [Dm->recvCount_x];
|
||||
recvID_y = new char [Dm->recvCount_y];
|
||||
recvID_z = new char [Dm->recvCount_z];
|
||||
recvID_X = new char [Dm->recvCount_X];
|
||||
recvID_Y = new char [Dm->recvCount_Y];
|
||||
recvID_Z = new char [Dm->recvCount_Z];
|
||||
recvID_xy = new char [Dm->recvCount_xy];
|
||||
recvID_yz = new char [Dm->recvCount_yz];
|
||||
recvID_xz = new char [Dm->recvCount_xz];
|
||||
recvID_Xy = new char [Dm->recvCount_Xy];
|
||||
recvID_xZ = new char [Dm->recvCount_xZ];
|
||||
recvID_xY = new char [Dm->recvCount_xY];
|
||||
recvID_yZ = new char [Dm->recvCount_yZ];
|
||||
recvID_Yz = new char [Dm->recvCount_Yz];
|
||||
recvID_Xz = new char [Dm->recvCount_Xz];
|
||||
recvID_XY = new char [Dm->recvCount_XY];
|
||||
recvID_YZ = new char [Dm->recvCount_YZ];
|
||||
recvID_XZ = new char [Dm->recvCount_XZ];
|
||||
//......................................................................................
|
||||
int sendtag,recvtag;
|
||||
sendtag = recvtag = 7;
|
||||
|
||||
int x,y,z;
|
||||
int ii,jj,kk;
|
||||
int Nx = nx;
|
||||
int Ny = ny;
|
||||
int Nz = nz;
|
||||
|
||||
double sw_old=1.0;
|
||||
double sw_new=1.0;
|
||||
double sw_diff_old = 1.0;
|
||||
double sw_diff_new = 1.0;
|
||||
|
||||
// Increase the critical radius until the target saturation is met
|
||||
double deltaR=0.05; // amount to change the radius in voxel units
|
||||
double Rcrit_old;
|
||||
|
||||
double GlobalNumber = 1.f;
|
||||
int imin,jmin,kmin,imax,jmax,kmax;
|
||||
|
||||
Rcrit_new = maxdistGlobal;
|
||||
//if (argc>2){
|
||||
// Rcrit_new = strtod(argv[2],NULL);
|
||||
// if (rank==0) printf("Max. distance =%f, Initial critical radius = %f \n",maxdistGlobal,Rcrit_new);
|
||||
//}
|
||||
while (sw_new > SW)
|
||||
{
|
||||
sw_diff_old = sw_diff_new;
|
||||
sw_old = sw_new;
|
||||
Rcrit_old = Rcrit_new;
|
||||
Rcrit_new -= deltaR*Rcrit_old;
|
||||
int Window=round(Rcrit_new);
|
||||
if (Window == 0) Window = 1; // If Window = 0 at the begining, after the following process will have sw=1.0
|
||||
// and sw<Sw will be immediately broken
|
||||
double LocalNumber=0.f;
|
||||
for(k=0; k<Nz; k++){
|
||||
for(j=0; j<Ny; j++){
|
||||
for(i=0; i<Nx; i++){
|
||||
n = k*nx*ny + j*nx+i;
|
||||
if (SignDist(i,j,k) > Rcrit_new){
|
||||
// loop over the window and update
|
||||
imin=max(1,i-Window);
|
||||
jmin=max(1,j-Window);
|
||||
kmin=max(1,k-Window);
|
||||
imax=min(Nx-1,i+Window);
|
||||
jmax=min(Ny-1,j+Window);
|
||||
kmax=min(Nz-1,k+Window);
|
||||
for (kk=kmin; kk<kmax; kk++){
|
||||
for (jj=jmin; jj<jmax; jj++){
|
||||
for (ii=imin; ii<imax; ii++){
|
||||
int nn = kk*nx*ny+jj*nx+ii;
|
||||
double dsq = double((ii-i)*(ii-i)+(jj-j)*(jj-j)+(kk-k)*(kk-k));
|
||||
if (id[nn] == 2 && dsq <= Rcrit_new*Rcrit_new){
|
||||
LocalNumber+=1.0;
|
||||
id[nn]=1;
|
||||
}
|
||||
}
|
||||
// Initialize the signed distance function
|
||||
for (int k=0;k<nz;k++){
|
||||
for (int j=0;j<ny;j++){
|
||||
for (int i=0;i<nx;i++){
|
||||
int n = k*nx*ny+j*nx+i;
|
||||
// Initialize distance to +/- 1
|
||||
SignDist(i,j,k) = 2.0*double(id_solid(i,j,k))-1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
CalcDist(SignDist,id_solid,*Dm);
|
||||
// re-label IDs near the non-wetting fluid
|
||||
for (int k=0;k<nz;k++){
|
||||
for (int j=0;j<ny;j++){
|
||||
for (int i=0;i<nx;i++){
|
||||
int n = k*nx*ny+j*nx+i;
|
||||
signed char LOCVAL = id[n];
|
||||
for (unsigned int idx=0; idx < NLABELS; idx++){
|
||||
char VALUE=LabelList[idx];
|
||||
char NEWVALUE=HistoryLabels[idx];
|
||||
if (LOCVAL == VALUE){
|
||||
idx = NLABELS;
|
||||
if (SignDist(i,j,k) < 1.0){
|
||||
id[n] = NEWVALUE;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
// move on
|
||||
}
|
||||
}
|
||||
}
|
||||
// Pack and send the updated ID values
|
||||
PackID(Dm->sendList_x, Dm->sendCount_x ,sendID_x, id);
|
||||
PackID(Dm->sendList_X, Dm->sendCount_X ,sendID_X, id);
|
||||
PackID(Dm->sendList_y, Dm->sendCount_y ,sendID_y, id);
|
||||
PackID(Dm->sendList_Y, Dm->sendCount_Y ,sendID_Y, id);
|
||||
PackID(Dm->sendList_z, Dm->sendCount_z ,sendID_z, id);
|
||||
PackID(Dm->sendList_Z, Dm->sendCount_Z ,sendID_Z, id);
|
||||
PackID(Dm->sendList_xy, Dm->sendCount_xy ,sendID_xy, id);
|
||||
PackID(Dm->sendList_Xy, Dm->sendCount_Xy ,sendID_Xy, id);
|
||||
PackID(Dm->sendList_xY, Dm->sendCount_xY ,sendID_xY, id);
|
||||
PackID(Dm->sendList_XY, Dm->sendCount_XY ,sendID_XY, id);
|
||||
PackID(Dm->sendList_xz, Dm->sendCount_xz ,sendID_xz, id);
|
||||
PackID(Dm->sendList_Xz, Dm->sendCount_Xz ,sendID_Xz, id);
|
||||
PackID(Dm->sendList_xZ, Dm->sendCount_xZ ,sendID_xZ, id);
|
||||
PackID(Dm->sendList_XZ, Dm->sendCount_XZ ,sendID_XZ, id);
|
||||
PackID(Dm->sendList_yz, Dm->sendCount_yz ,sendID_yz, id);
|
||||
PackID(Dm->sendList_Yz, Dm->sendCount_Yz ,sendID_Yz, id);
|
||||
PackID(Dm->sendList_yZ, Dm->sendCount_yZ ,sendID_yZ, id);
|
||||
PackID(Dm->sendList_YZ, Dm->sendCount_YZ ,sendID_YZ, id);
|
||||
//......................................................................................
|
||||
MPI_Sendrecv(sendID_x,Dm->sendCount_x,MPI_CHAR,Dm->rank_x(),sendtag,
|
||||
recvID_X,Dm->recvCount_X,MPI_CHAR,Dm->rank_X(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_X,Dm->sendCount_X,MPI_CHAR,Dm->rank_X(),sendtag,
|
||||
recvID_x,Dm->recvCount_x,MPI_CHAR,Dm->rank_x(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_y,Dm->sendCount_y,MPI_CHAR,Dm->rank_y(),sendtag,
|
||||
recvID_Y,Dm->recvCount_Y,MPI_CHAR,Dm->rank_Y(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Y,Dm->sendCount_Y,MPI_CHAR,Dm->rank_Y(),sendtag,
|
||||
recvID_y,Dm->recvCount_y,MPI_CHAR,Dm->rank_y(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_z,Dm->sendCount_z,MPI_CHAR,Dm->rank_z(),sendtag,
|
||||
recvID_Z,Dm->recvCount_Z,MPI_CHAR,Dm->rank_Z(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Z,Dm->sendCount_Z,MPI_CHAR,Dm->rank_Z(),sendtag,
|
||||
recvID_z,Dm->recvCount_z,MPI_CHAR,Dm->rank_z(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_xy,Dm->sendCount_xy,MPI_CHAR,Dm->rank_xy(),sendtag,
|
||||
recvID_XY,Dm->recvCount_XY,MPI_CHAR,Dm->rank_XY(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_XY,Dm->sendCount_XY,MPI_CHAR,Dm->rank_XY(),sendtag,
|
||||
recvID_xy,Dm->recvCount_xy,MPI_CHAR,Dm->rank_xy(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Xy,Dm->sendCount_Xy,MPI_CHAR,Dm->rank_Xy(),sendtag,
|
||||
recvID_xY,Dm->recvCount_xY,MPI_CHAR,Dm->rank_xY(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_xY,Dm->sendCount_xY,MPI_CHAR,Dm->rank_xY(),sendtag,
|
||||
recvID_Xy,Dm->recvCount_Xy,MPI_CHAR,Dm->rank_Xy(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_xz,Dm->sendCount_xz,MPI_CHAR,Dm->rank_xz(),sendtag,
|
||||
recvID_XZ,Dm->recvCount_XZ,MPI_CHAR,Dm->rank_XZ(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_XZ,Dm->sendCount_XZ,MPI_CHAR,Dm->rank_XZ(),sendtag,
|
||||
recvID_xz,Dm->recvCount_xz,MPI_CHAR,Dm->rank_xz(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Xz,Dm->sendCount_Xz,MPI_CHAR,Dm->rank_Xz(),sendtag,
|
||||
recvID_xZ,Dm->recvCount_xZ,MPI_CHAR,Dm->rank_xZ(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_xZ,Dm->sendCount_xZ,MPI_CHAR,Dm->rank_xZ(),sendtag,
|
||||
recvID_Xz,Dm->recvCount_Xz,MPI_CHAR,Dm->rank_Xz(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_yz,Dm->sendCount_yz,MPI_CHAR,Dm->rank_yz(),sendtag,
|
||||
recvID_YZ,Dm->recvCount_YZ,MPI_CHAR,Dm->rank_YZ(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_YZ,Dm->sendCount_YZ,MPI_CHAR,Dm->rank_YZ(),sendtag,
|
||||
recvID_yz,Dm->recvCount_yz,MPI_CHAR,Dm->rank_yz(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_Yz,Dm->sendCount_Yz,MPI_CHAR,Dm->rank_Yz(),sendtag,
|
||||
recvID_yZ,Dm->recvCount_yZ,MPI_CHAR,Dm->rank_yZ(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
MPI_Sendrecv(sendID_yZ,Dm->sendCount_yZ,MPI_CHAR,Dm->rank_yZ(),sendtag,
|
||||
recvID_Yz,Dm->recvCount_Yz,MPI_CHAR,Dm->rank_Yz(),recvtag,comm,MPI_STATUS_IGNORE);
|
||||
//......................................................................................
|
||||
UnpackID(Dm->recvList_x, Dm->recvCount_x ,recvID_x, id);
|
||||
UnpackID(Dm->recvList_X, Dm->recvCount_X ,recvID_X, id);
|
||||
UnpackID(Dm->recvList_y, Dm->recvCount_y ,recvID_y, id);
|
||||
UnpackID(Dm->recvList_Y, Dm->recvCount_Y ,recvID_Y, id);
|
||||
UnpackID(Dm->recvList_z, Dm->recvCount_z ,recvID_z, id);
|
||||
UnpackID(Dm->recvList_Z, Dm->recvCount_Z ,recvID_Z, id);
|
||||
UnpackID(Dm->recvList_xy, Dm->recvCount_xy ,recvID_xy, id);
|
||||
UnpackID(Dm->recvList_Xy, Dm->recvCount_Xy ,recvID_Xy, id);
|
||||
UnpackID(Dm->recvList_xY, Dm->recvCount_xY ,recvID_xY, id);
|
||||
UnpackID(Dm->recvList_XY, Dm->recvCount_XY ,recvID_XY, id);
|
||||
UnpackID(Dm->recvList_xz, Dm->recvCount_xz ,recvID_xz, id);
|
||||
UnpackID(Dm->recvList_Xz, Dm->recvCount_Xz ,recvID_Xz, id);
|
||||
UnpackID(Dm->recvList_xZ, Dm->recvCount_xZ ,recvID_xZ, id);
|
||||
UnpackID(Dm->recvList_XZ, Dm->recvCount_XZ ,recvID_XZ, id);
|
||||
UnpackID(Dm->recvList_yz, Dm->recvCount_yz ,recvID_yz, id);
|
||||
UnpackID(Dm->recvList_Yz, Dm->recvCount_Yz ,recvID_Yz, id);
|
||||
UnpackID(Dm->recvList_yZ, Dm->recvCount_yZ ,recvID_yZ, id);
|
||||
UnpackID(Dm->recvList_YZ, Dm->recvCount_YZ ,recvID_YZ, id);
|
||||
//......................................................................................
|
||||
|
||||
MPI_Allreduce(&LocalNumber,&GlobalNumber,1,MPI_DOUBLE,MPI_SUM,comm);
|
||||
|
||||
count = 0.f;
|
||||
for (int k=1; k<Nz-1; k++){
|
||||
for (int j=1; j<Ny-1; j++){
|
||||
for (int i=1; i<Nx-1; i++){
|
||||
n=k*Nx*Ny+j*Nx+i;
|
||||
if (id[n] == 2){
|
||||
count+=1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MPI_Allreduce(&count,&countGlobal,1,MPI_DOUBLE,MPI_SUM,comm);
|
||||
sw_new = countGlobal/totalGlobal;
|
||||
sw_diff_new = abs(sw_new-SW);
|
||||
if (rank==0){
|
||||
printf(" %f ",sw_new);
|
||||
printf(" %f\n",Rcrit_new);
|
||||
}
|
||||
}
|
||||
|
||||
if (sw_diff_new<sw_diff_old){
|
||||
if (rank==0){
|
||||
printf("Final saturation=%f\n",sw_new);
|
||||
printf("Final critical radius=%f\n",Rcrit_new);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (rank==0){
|
||||
printf("Final saturation=%f\n",sw_old);
|
||||
printf("Final critical radius=%f\n",Rcrit_old);
|
||||
}
|
||||
}
|
||||
|
||||
if (rank==0) printf("Writing ID file \n");
|
||||
|
||||
@@ -53,7 +53,9 @@ int main(int argc, char **argv)
|
||||
int64_t i,j,k,n;
|
||||
int BC=0;
|
||||
int64_t xStart,yStart,zStart;
|
||||
// char fluidValue,solidValue;
|
||||
int checkerSize;
|
||||
int inlet_count_x, inlet_count_y, inlet_count_z;
|
||||
// char fluidValue,solidValue;
|
||||
|
||||
xStart=yStart=zStart=0;
|
||||
// read the input database
|
||||
@@ -72,6 +74,15 @@ int main(int argc, char **argv)
|
||||
yStart = offset[1];
|
||||
zStart = offset[2];
|
||||
}
|
||||
if (domain_db->keyExists( "InletLayers" )){
|
||||
auto InletCount = domain_db->getVector<int>( "InletLayers" );
|
||||
inlet_count_x = InletCount[0];
|
||||
inlet_count_y = InletCount[1];
|
||||
inlet_count_z = InletCount[2];
|
||||
}
|
||||
if (domain_db->keyExists( "checkerSize" )){
|
||||
checkerSize = domain_db->getScalar<int>( "checkerSize" );
|
||||
}
|
||||
auto ReadValues = domain_db->getVector<char>( "ReadValues" );
|
||||
auto WriteValues = domain_db->getVector<char>( "WriteValues" );
|
||||
auto ReadType = domain_db->getScalar<std::string>( "ReadType" );
|
||||
@@ -136,6 +147,63 @@ int main(int argc, char **argv)
|
||||
printf("Read segmented data from %s \n",Filename.c_str());
|
||||
}
|
||||
|
||||
if (inlet_count_x > 0){
|
||||
// use checkerboard pattern
|
||||
printf("Checkerboard pattern at x inlet for %i layers \n",inlet_count_x);
|
||||
for (int k = 0; k<Nz; k++){
|
||||
for (int j = 0; j<Ny; j++){
|
||||
for (int i = xStart; i < xStart+inlet_count_x; i++){
|
||||
if ( (j/checkerSize + k/checkerSize)%2 == 0){
|
||||
// solid checkers
|
||||
SegData[k*Nx*Ny+j*Nx+i] = 0;
|
||||
}
|
||||
else{
|
||||
// void checkers
|
||||
SegData[k*Nx*Ny+j*Nx+i] = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inlet_count_y > 0){
|
||||
printf("Checkerboard pattern at y inlet for %i layers \n",inlet_count_y);
|
||||
// use checkerboard pattern
|
||||
for (int k = 0; k<Nz; k++){
|
||||
for (int j = yStart; i < yStart+inlet_count_y; j++){
|
||||
for (int i = 0; i<Nx; i++){
|
||||
if ( (i/checkerSize + k/checkerSize)%2 == 0){
|
||||
// solid checkers
|
||||
SegData[k*Nx*Ny+j*Nx+i] = 0;
|
||||
}
|
||||
else{
|
||||
// void checkers
|
||||
SegData[k*Nx*Ny+j*Nx+i] = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inlet_count_z > 0){
|
||||
printf("Checkerboard pattern at z inlet for %i layers \n",inlet_count_z);
|
||||
// use checkerboard pattern
|
||||
for (int k = zStart; k < zStart+inlet_count_z; k++){
|
||||
for (int j = 0; j<Ny; j++){
|
||||
for (int i = 0; i<Nx; i++){
|
||||
if ( (i/checkerSize+j/checkerSize)%2 == 0){
|
||||
// solid checkers
|
||||
SegData[k*Nx*Ny+j*Nx+i] = 0;
|
||||
}
|
||||
else{
|
||||
// void checkers
|
||||
SegData[k*Nx*Ny+j*Nx+i] = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get the rank info
|
||||
int64_t N = (nx+2)*(ny+2)*(nz+2);
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#define USE_WINDOWS
|
||||
#elif defined(__APPLE__)
|
||||
#define USE_MAC
|
||||
#elif defined(__linux) || defined(__unix) || defined(__posix)
|
||||
#elif defined( __linux ) || defined( __linux__ ) || defined( __unix ) || defined( __posix )
|
||||
#define USE_LINUX
|
||||
#else
|
||||
#error Unknown OS
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
// Using MAC
|
||||
#define USE_MAC
|
||||
#include <libkern/OSAtomic.h>
|
||||
#elif defined( __linux ) || defined( __unix ) || defined( __posix )
|
||||
#elif defined( __linux ) || defined( __linux__ ) || defined( __unix ) || defined( __posix )
|
||||
// Using Linux
|
||||
#define USE_LINUX
|
||||
#include <unistd.h>
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
#define USE_WINDOWS
|
||||
#elif defined( __APPLE__ )
|
||||
#define USE_MAC
|
||||
#elif defined( __linux ) || defined( __unix ) || defined( __posix )
|
||||
#elif defined( __linux ) || defined( __linux__ ) || defined( __unix ) || defined( __posix )
|
||||
#define USE_LINUX
|
||||
#else
|
||||
#error Unknown OS
|
||||
|
||||
Reference in New Issue
Block a user