// Sequential blob analysis // Reads parallel simulation data and performs connectivity analysis // and averaging on a blob-by-blob basis // James E. McClure 2014 #include #include #include "common/pmmc.h" #include "analysis/analysis.h" //#include "Domain.h" #define NUM_AVERAGES 30 using namespace std; inline void ReadCheckpoint(char *FILENAME, double *cDen, double *cDistEven, double *cDistOdd, int N) { int q,n; double value; ifstream File(FILENAME,ios::binary); for (n=0; n> nprocx; domain >> nprocy; domain >> nprocz; domain >> nx; domain >> ny; domain >> nz; domain >> nspheres; domain >> Lx; domain >> Ly; domain >> Lz; //....................................................................... nx+=2; ny+=2; nz+=2; nprocs = nprocx*nprocy*nprocz; printf("Number of MPI ranks: %i \n", nprocs); Nx = (nx-2)*nprocx+2; Ny = (ny-2)*nprocy+2; Nz = (nz-2)*nprocz+2; printf("Full domain size: %i x %i x %i \n", Nx,Ny,Nz); DoubleArray Phase(Nx,Ny,Nz); DoubleArray SignDist(Nx,Ny,Nz); DoubleArray Press(Nx,Ny,Nz); DoubleArray Vel_x(Nx,Ny,Nz); // Velocity DoubleArray Vel_y(Nx,Ny,Nz); DoubleArray Vel_z(Nx,Ny,Nz); DoubleArray dPdt(Nx,Ny,Nz); // Filenames used char LocalRankString[8]; char LocalRankFilename[40]; char BaseFilename[20]; sprintf(BaseFilename,"%s","dPdt."); int proc,iglobal,kglobal,jglobal; double * Temp; Temp = new double[nx*ny*nz]; for (k=0; k 0.0){ Press(i,j,k) = 0.34; } else { Press(i,j,k) = 0.32; } } } } #else // read the files and populate main arrays for ( kproc=0; kproc 0.0){ porosity += 1.0; } } } } porosity /= (Nx*Ny*Nz*1.0); printf("Media porosity is %f \n",porosity); /* **************************************************************** VARIABLES FOR THE PMMC ALGORITHM ****************************************************************** */ //........................................................................... // Averaging variables //........................................................................... double awn,ans,aws,lwns,nwp_volume; double sw,vol_n,vol_w,paw,pan; double efawns,Jwn,Kwn; double trawn,trJwn,trRwn; double As,dummy; // double dEs,dAwn,dAns; // Global surface energy (calculated by rank=0) // bool add=1; // Set to false if any corners contain nw-phase ( F > fluid_isovalue) int n_nw_pts=0,n_ns_pts=0,n_ws_pts=0,n_nws_pts=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; 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 nw_pts(20); DTMutableList ns_pts(20); DTMutableList ws_pts(20); DTMutableList 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 tmp(20); // Initialize arrays for local solid surface DTMutableList 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 local_nws_pts(20); int n_local_nws_pts; DoubleArray CubeValues(2,2,2); DoubleArray Values(20); DoubleArray ContactAngle(20); DoubleArray Curvature(20); DoubleArray DistValues(20); DoubleArray InterfaceSpeed(20); DoubleArray NormalVector(60); DoubleArray van(3); DoubleArray vaw(3); DoubleArray vawn(3); DoubleArray Gwn(6); DoubleArray Gns(6); DoubleArray Gws(6); //........................................................................... 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(N); // number of nodes in each blob /* std::vector BlobList; BlobList.reserve[10000]; std::vector TempBlobList; TempBlobList.reserve[10000]; */ double vF=0.0; double vS=0.0; double trimdist=1.0; // 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 vF ){ if ( SignDist(i,j,k) > vS ){ // node i,j,k is in the porespace number = number+ComputeBlob(blobs,nblobs,ncubes,LocalBlobID,Phase,SignDist,vF,vS,i,j,k,temp); } } } } // Specify the blob on the z axis if (ncubes > 0){ b(nblobs) = number; // BlobList.push_back[number]; printf("Number of non-wetting phase blobs is: %i \n",nblobs-1); nblobs++; } for (k=0;k vF ){ if ( SignDist(i,j,k) > vS ){ // node i,j,k is in the porespace b(nblobs) = ComputeBlob(blobs,nblobs,ncubes,LocalBlobID,Phase,SignDist,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 > (int)b.length()-1){ printf("Increasing size of blob list \n"); b.resize(2*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 -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++; DoubleArray BlobAverages(NUM_AVERAGES,nblobs); // Map the signed distance for the analysis for (i=0; i 0.0){ porosity += 1.0; } } } } porosity /= (Nx*Ny*Nz*1.0); printf("Media porosity is %f \n",porosity); /* **************************************************************** RUN TCAT AVERAGING ON EACH BLOB ****************************************************************** */ int n_nw_tris_beg, n_ns_tris_beg, n_ws_tris_beg, n_nws_seg_beg; int start=0,finish; int a,c; printf("-----------------------------------------------\n"); printf("Computing TCAT averages based on connectivity \n"); printf("The number of non-wetting phase features is %i \n",nblobs-1); printf("-----------------------------------------------\n"); // Wetting phase averages assume global connectivity As = 0.0; vol_w = 0.0; paw = 0.0; aws = 0.0; vaw(0) = vaw(1) = vaw(2) = 0.0; Gws(0) = Gws(1) = Gws(2) = 0.0; Gws(3) = Gws(4) = Gws(5) = 0.0; // Don't compute the last blob unless specified // the last blob is the entire wetting phase // nblobs -=1; #ifdef WP nblobs+=1; #endif for (a=0;a 0 ){ n = i+cube[p][0] + Nx*(j+cube[p][1]) + Nx*Ny*(k+cube[p][2]); // Compute the non-wetting phase volume contribution if ( Phase(i+cube[p][0],j+cube[p][1],k+cube[p][2]) > 0 ) nwp_volume += 0.125; // volume averages over the non-wetting phase if ( Phase(i+cube[p][0],j+cube[p][1],k+cube[p][2]) > 0.99 ){ // volume the excludes the interfacial region vol_n += 0.125; // pressure pan += 0.125*Press(n); // velocity van(0) += 0.125*Vel_x(n); van(1) += 0.125*Vel_y(n); van(2) += 0.125*Vel_z(n); } // volume averages over the wetting phase if ( Phase(i+cube[p][0],j+cube[p][1],k+cube[p][2]) < -0.99 ){ // volume the excludes the interfacial region vol_w += 0.125; // pressure paw += 0.125*Press(n); // velocity vaw(0) += 0.125*Vel_x(n); vaw(1) += 0.125*Vel_y(n); vaw(2) += 0.125*Vel_z(n); } } } // Interface and common curve averages n_local_sol_tris = 0; n_local_sol_pts = 0; n_local_nws_pts = 0; //........................................................................... // Construct the interfaces and common curve pmmc_ConstructLocalCube(SignDist, Phase, vS, vF, nw_pts, nw_tris, values, ns_pts, ns_tris, ws_pts, ws_tris, local_nws_pts, nws_pts, nws_seg, local_sol_pts, local_sol_tris, n_local_sol_tris, n_local_sol_pts, n_nw_pts, n_nw_tris, n_ws_pts, n_ws_tris, n_ns_tris, n_ns_pts, n_local_nws_pts, n_nws_pts, n_nws_seg, i, j, k, Nx, Ny, Nz); // Integrate the contact angle efawns += pmmc_CubeContactAngle(CubeValues,Values,Phase_x,Phase_y,Phase_z,SignDist_x,SignDist_y,SignDist_z, local_nws_pts,i,j,k,n_local_nws_pts); // Integrate the mean curvature Jwn += pmmc_CubeSurfaceInterpValue(CubeValues,MeanCurvature,nw_pts,nw_tris,Values,i,j,k,n_nw_pts,n_nw_tris); Kwn += pmmc_CubeSurfaceInterpValue(CubeValues,GaussCurvature,nw_pts,nw_tris,Values,i,j,k,n_nw_pts,n_nw_tris); // Integrate the trimmed mean curvature (hard-coded to use a distance of 4 pixels) pmmc_CubeTrimSurfaceInterpValues(CubeValues,MeanCurvature,SignDist,nw_pts,nw_tris,Values,DistValues, i,j,k,n_nw_pts,n_nw_tris,trimdist,trawn,trJwn); pmmc_CubeTrimSurfaceInterpInverseValues(CubeValues,MeanCurvature,SignDist,nw_pts,nw_tris,Values,DistValues, i,j,k,n_nw_pts,n_nw_tris,trimdist,dummy,trRwn); // Compute the normal speed of the interface pmmc_InterfaceSpeed(dPdt, Phase_x, Phase_y, Phase_z, CubeValues, nw_pts, nw_tris, NormalVector, InterfaceSpeed, vawn, i, j, k, n_nw_pts, n_nw_tris); As += pmmc_CubeSurfaceArea(local_sol_pts,local_sol_tris,n_local_sol_tris); // Compute the surface orientation and the interfacial area awn += pmmc_CubeSurfaceOrientation(Gwn,nw_pts,nw_tris,n_nw_tris); ans += pmmc_CubeSurfaceOrientation(Gns,ns_pts,ns_tris,n_ns_tris); aws += pmmc_CubeSurfaceOrientation(Gws,ws_pts,ws_tris,n_ws_tris); lwns += pmmc_CubeCurveLength(local_nws_pts,n_local_nws_pts); //........................................................................... //******************************************************************* // Reset the triangle counts to zero n_nw_pts=0,n_ns_pts=0,n_ws_pts=0,n_nws_pts=0; n_nw_tris=0, n_ns_tris=0, n_ws_tris=0, n_nws_seg=0; n_nw_tris_beg = n_nw_tris; n_ns_tris_beg = n_ns_tris; n_ws_tris_beg = n_ws_tris; n_nws_seg_beg = n_nws_seg; //******************************************************************* } start = finish; if (a < nblobs-1){ if (vol_n > 0.0){ pan /= vol_n; for (i=0;i<3;i++) van(i) /= vol_n; } if (awn > 0.0){ Jwn /= awn; Kwn /= awn; for (i=0;i<3;i++) vawn(i) /= awn; for (i=0;i<6;i++) Gwn(i) /= awn; } if (lwns > 0.0){ efawns /= lwns; } if (ans > 0.0){ for (i=0;i<6;i++) Gns(i) /= ans; } if (trawn > 0.0){ trJwn /= trawn; } BlobAverages(0,a) = nwp_volume; BlobAverages(1,a) = pan; BlobAverages(2,a) = awn; BlobAverages(3,a) = ans; BlobAverages(4,a) = Jwn; BlobAverages(5,a) = Kwn; BlobAverages(6,a) = lwns; BlobAverages(7,a) = efawns; BlobAverages(8,a) = van(0); BlobAverages(9,a) = van(1); BlobAverages(10,a) = van(2); BlobAverages(11,a) = vawn(0); BlobAverages(12,a) = vawn(1); BlobAverages(13,a) = vawn(2); BlobAverages(14,a) = Gwn(0); BlobAverages(15,a) = Gwn(1); BlobAverages(16,a) = Gwn(2); BlobAverages(17,a) = Gwn(3); BlobAverages(18,a) = Gwn(4); BlobAverages(19,a) = Gwn(5); BlobAverages(20,a) = Gns(0); BlobAverages(21,a) = Gns(1); BlobAverages(22,a) = Gns(2); BlobAverages(23,a) = Gns(3); BlobAverages(24,a) = Gns(4); BlobAverages(25,a) = Gns(5); BlobAverages(26,a) = trawn; BlobAverages(27,a) = trJwn; BlobAverages(28,a) = vol_n; BlobAverages(29,a) = trRwn; printf("Computed TCAT averages for feature = %i \n", a); } } // End of the blob loop NULL_USE(n_nw_tris_beg); NULL_USE(n_ns_tris_beg); NULL_USE(n_ws_tris_beg); NULL_USE(n_nws_seg_beg); nblobs -= 1; printf("-----------------------------------------------\n"); printf("Sorting the blobs based on volume \n"); printf("-----------------------------------------------\n"); int TempLabel,aa,bb; double TempValue; IntArray OldLabel(nblobs); for (a=0; a -1){ TempLabel = NewLabel(LocalBlobID(i,j,k)); LocalBlobID(i,j,k) = TempLabel; } } } } FILE *BLOBLOG= fopen("blobs.tcat","a"); for (a=0; a0; a--){ // Subtract the features one-by-one nwp_volume -= BlobAverages(0,a); pan -= BlobAverages(1,a)*BlobAverages(28,a); pwn -= (BlobAverages(1,a)-pw)*BlobAverages(2,a); awn -= BlobAverages(2,a); ans -= BlobAverages(3,a); Jwn -= BlobAverages(4,a)*BlobAverages(2,a); Kwn -= BlobAverages(5,a)*BlobAverages(2,a); lwns -= BlobAverages(6,a); efawns -= BlobAverages(7,a)*BlobAverages(6,a); van(0) -= BlobAverages(8,a)*BlobAverages(28,a); van(1) -= BlobAverages(9,a)*BlobAverages(28,a); van(2) -= BlobAverages(10,a)*BlobAverages(28,a); vawn(0) -= BlobAverages(11,a)*BlobAverages(2,a); vawn(1) -= BlobAverages(12,a)*BlobAverages(2,a); vawn(2) -= BlobAverages(13,a)*BlobAverages(2,a); Gwn(0) -= BlobAverages(14,a)*BlobAverages(2,a); Gwn(1) -= BlobAverages(15,a)*BlobAverages(2,a); Gwn(2) -= BlobAverages(16,a)*BlobAverages(2,a); Gwn(3) -= BlobAverages(17,a)*BlobAverages(2,a); Gwn(4) -= BlobAverages(18,a)*BlobAverages(2,a); Gwn(5) -= BlobAverages(19,a)*BlobAverages(2,a); Gns(0) -= BlobAverages(20,a)*BlobAverages(3,a); Gns(1) -= BlobAverages(21,a)*BlobAverages(3,a); Gns(2) -= BlobAverages(22,a)*BlobAverages(3,a); Gns(3) -= BlobAverages(23,a)*BlobAverages(3,a); Gns(4) -= BlobAverages(24,a)*BlobAverages(3,a); Gns(5) -= BlobAverages(25,a)*BlobAverages(3,a); trawn -= BlobAverages(26,a); trJwn -= BlobAverages(27,a)*BlobAverages(26,a); vol_n -= BlobAverages(28,a); // Update wetting phase averages aws += BlobAverages(3,a); Gws(0) += BlobAverages(20,a)*BlobAverages(3,a); Gws(1) += BlobAverages(21,a)*BlobAverages(3,a); Gws(2) += BlobAverages(22,a)*BlobAverages(3,a); Gws(3) += BlobAverages(23,a)*BlobAverages(3,a); Gws(4) += BlobAverages(24,a)*BlobAverages(3,a); Gws(5) += BlobAverages(25,a)*BlobAverages(3,a); if (fabs(1.0 - nwp_volume*iVol/porosity - sw) > 0.0025 || a == 1){ sw = 1.0 - nwp_volume*iVol/porosity; JwnD = -Jwn*D/awn; pn = pan/vol_n; trJwnD = -trJwn*D/trawn; cwns = -efawns / lwns; awnD = awn*D*iVol; awsD = aws*D*iVol; ansD = ans*D*iVol; lwnsDD = lwns*D*D*iVol; pc = pwn*D/0.058/awn; // hard-coded surface tension due to being lazy fprintf(BLOBSTATES,"%.5g %.5g %.5g ",sw,pn,pw); fprintf(BLOBSTATES,"%.5g %.5g %.5g %.5g ",awnD,awsD,ansD,lwnsDD); fprintf(BLOBSTATES,"%.5g %.5g %.5g %.5g %i\n",pc,JwnD,trJwnD,cwns,a); } } fclose(BLOBSTATES); start = 0; for (a=0;a