#include // Implementation of morphological opening routine inline void PackID(const int *list, int count, signed char *sendbuf, signed 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 Dm, DoubleArray &Distance){ /* Loop over all faces and determine overlaps */ size_t Nx = Dm->Nx; size_t Ny = Dm->Ny; size_t Nz = Dm->Nz; size_t N = Nx*Ny*Nz; int *tmpShift_x, *tmpShift_y, *tmpShift_z; double *tmpDistance; tmpShift_x = new int [N]; tmpShift_y= new int [N]; tmpShift_z = new int [N]; tmpDistance = new double [N]; double distance, boundary_distance; /* Loop over the local sub-domain and create overlap lists for each neighboring sub-domain */ int sendLoc = 0; // counter for the local sub-domain send values int recvLoc = 0; // counter for the local recv //................................................... /* x face */ sendCount = recvCount = 0; for (size_t k=1; k boundary_distance){ tmpShift_x[sendCount] = Nx + i-2; tmpShift_y[sendCount] = j; tmpShift_z[sendCount] = k; tmpDistance[sendCount++] = distance; int n = k*Nx*Ny + j*Nx + i; sendID.push_back(n); } } } } Dm->Comm.Irecv(&recvCount,1,Dm->rank_X(),recvtag+0); Dm->Comm.send(&sendCount,1,Dm->rank_x(),sendtag+0); Dm->Comm.barrier(); sendOffset_x = sendLoc; recvOffset_X = recvLoc; sendLoc += sendCount; recvLoc += recvCount; sendCount_x = sendCount; recvCount_X = recvCount; /* grow the arrays */ xShift.resize(recvLoc); yShift.resize(recvLoc); zShift.resize(recvLoc); morphRadius.resize(recvLoc); //.............................. /* send the morphological radius */ Dm->Comm.Irecv(&morphRadius[recvOffset_X],recvCount,Dm->rank_X(),recvtag+0); Dm->Comm.send(&tmpDistance[0],sendCount,Dm->rank_x(),sendtag+0); /* send the shift values */ Dm->Comm.Irecv(&xShift[recvOffset_X],recvCount,Dm->rank_X(),recvtag+1); Dm->Comm.send(&tmpShift_x[0],sendCount,Dm->rank_x(),sendtag+1); Dm->Comm.Irecv(&yShift[recvOffset_X],recvCount,Dm->rank_X(),recvtag+2); Dm->Comm.send(&tmpShift_y[0],sendCount,Dm->rank_x(),sendtag+2); Dm->Comm.Irecv(&zShift[recvOffset_X],recvCount,Dm->rank_X(),recvtag+3); Dm->Comm.send(&tmpShift_z[0],sendCount,Dm->rank_x(),sendtag+3); Dm->Comm.barrier(); //................................................... //................................................... /* X face */ sendCount = recvCount = 0; for (size_t k=1; k boundary_distance){ tmpShift_x[sendCount] = (i)-(Nx-2); tmpShift_y[sendCount] = j; tmpShift_z[sendCount] = k; tmpDistance[sendCount++] = distance; int n = k*Nx*Ny + j*Nx + i; sendID.push_back(n); } } } } Dm->Comm.Irecv(&recvCount,1,Dm->rank_x(),recvtag+0); Dm->Comm.send(&sendCount,1,Dm->rank_X(),sendtag+0); Dm->Comm.barrier(); sendOffset_X = sendLoc; recvOffset_x = recvLoc; sendLoc += sendCount; recvLoc += recvCount; sendCount_X = sendCount; recvCount_x = recvCount; /* grow the arrays */ xShift.resize(recvLoc); yShift.resize(recvLoc); zShift.resize(recvLoc); morphRadius.resize(recvLoc); //.............................. /* send the morphological radius */ Dm->Comm.Irecv(&morphRadius[recvOffset_x],recvCount,Dm->rank_x(),recvtag+0); Dm->Comm.send(&tmpDistance[0],sendCount,Dm->rank_X(),sendtag+0); /* send the shift values */ Dm->Comm.Irecv(&xShift[recvOffset_x],recvCount,Dm->rank_x(),recvtag+1); Dm->Comm.send(&tmpShift_x[0],sendCount,Dm->rank_X(),sendtag+1); Dm->Comm.Irecv(&yShift[recvOffset_x],recvCount,Dm->rank_x(),recvtag+2); Dm->Comm.send(&tmpShift_y[0],sendCount,Dm->rank_X(),sendtag+2); Dm->Comm.Irecv(&zShift[recvOffset_x],recvCount,Dm->rank_x(),recvtag+3); Dm->Comm.send(&tmpShift_z[0],sendCount,Dm->rank_X(),sendtag+3); Dm->Comm.barrier(); //................................................... //................................................... /* y face */ sendCount = recvCount = 0; for (size_t k=1; k boundary_distance){ tmpShift_x[sendCount] = i; tmpShift_y[sendCount] = Ny + j-2; tmpShift_z[sendCount] = k; tmpDistance[sendCount++] = distance; int n = k*Nx*Ny + j*Nx + i; sendID.push_back(n); } } } } Dm->Comm.Irecv(&recvCount,1,Dm->rank_Y(),recvtag+0); Dm->Comm.send(&sendCount,1,Dm->rank_y(),sendtag+0); Dm->Comm.barrier(); sendOffset_y = sendLoc; recvOffset_Y = recvLoc; sendLoc += sendCount; recvLoc += recvCount; sendCount_y = sendCount; recvCount_Y = recvCount; /* grow the arrays */ xShift.resize(recvLoc); yShift.resize(recvLoc); zShift.resize(recvLoc); morphRadius.resize(recvLoc); //.............................. /* send the morphological radius */ Dm->Comm.Irecv(&morphRadius[recvOffset_Y],recvCount,Dm->rank_Y(),recvtag+0); Dm->Comm.send(&tmpDistance[0],sendCount,Dm->rank_y(),sendtag+0); /* send the shift values */ Dm->Comm.Irecv(&xShift[recvOffset_Y],recvCount,Dm->rank_Y(),recvtag+1); Dm->Comm.send(&tmpShift_x[0],sendCount,Dm->rank_y(),sendtag+1); Dm->Comm.Irecv(&yShift[recvOffset_Y],recvCount,Dm->rank_Y(),recvtag+2); Dm->Comm.send(&tmpShift_y[0],sendCount,Dm->rank_y(),sendtag+2); Dm->Comm.Irecv(&zShift[recvOffset_Y],recvCount,Dm->rank_Y(),recvtag+3); Dm->Comm.send(&tmpShift_z[0],sendCount,Dm->rank_y(),sendtag+3); Dm->Comm.barrier(); //................................................... //................................................... /* X face */ sendCount = recvCount = 0; for (size_t k=1; k boundary_distance){ tmpShift_x[sendCount] = i; tmpShift_y[sendCount] = j-(Ny-2); tmpShift_z[sendCount] = k; tmpDistance[sendCount++] = distance; int n = k*Nx*Ny + j*Nx + i; sendID.push_back(n); } } } } Dm->Comm.Irecv(&recvCount,1,Dm->rank_y(),recvtag+0); Dm->Comm.send(&sendCount,1,Dm->rank_Y(),sendtag+0); Dm->Comm.barrier(); sendOffset_Y = sendLoc; recvOffset_y = recvLoc; sendLoc += sendCount; recvLoc += recvCount; sendCount_Y = sendCount; recvCount_y = recvCount; /* grow the arrays */ xShift.resize(recvLoc); yShift.resize(recvLoc); zShift.resize(recvLoc); morphRadius.resize(recvLoc); //.............................. /* send the morphological radius */ Dm->Comm.Irecv(&morphRadius[recvOffset_y],recvCount,Dm->rank_y(),recvtag+0); Dm->Comm.send(&tmpDistance[0],sendCount,Dm->rank_Y(),sendtag+0); /* send the shift values */ Dm->Comm.Irecv(&xShift[recvOffset_y],recvCount,Dm->rank_y(),recvtag+1); Dm->Comm.send(&tmpShift_x[0],sendCount,Dm->rank_Y(),sendtag+1); Dm->Comm.Irecv(&yShift[recvOffset_y],recvCount,Dm->rank_y(),recvtag+2); Dm->Comm.send(&tmpShift_y[0],sendCount,Dm->rank_Y(),sendtag+2); Dm->Comm.Irecv(&zShift[recvOffset_y],recvCount,Dm->rank_y(),recvtag+3); Dm->Comm.send(&tmpShift_z[0],sendCount,Dm->rank_Y(),sendtag+3); Dm->Comm.barrier(); //................................................... //................................................... /* z face */ sendCount = recvCount = 0; for (size_t k=1; k boundary_distance){ tmpShift_x[sendCount] = i; tmpShift_y[sendCount] = j; tmpShift_z[sendCount] = (Nz-2) + k; tmpDistance[sendCount++] = distance; int n = k*Nx*Ny + j*Nx + i; sendID.push_back(n); } } } } Dm->Comm.Irecv(&recvCount,1,Dm->rank_Z(),recvtag+0); Dm->Comm.send(&sendCount,1,Dm->rank_z(),sendtag+0); Dm->Comm.barrier(); sendOffset_z = sendLoc; recvOffset_Z = recvLoc; sendLoc += sendCount; recvLoc += recvCount; sendCount_z = sendCount; recvCount_Z = recvCount; /* grow the arrays */ xShift.resize(recvLoc); yShift.resize(recvLoc); zShift.resize(recvLoc); morphRadius.resize(recvLoc); //.............................. /* send the morphological radius */ Dm->Comm.Irecv(&morphRadius[recvOffset_Z],recvCount,Dm->rank_Z(),recvtag+0); Dm->Comm.send(&tmpDistance[0],sendCount,Dm->rank_z(),sendtag+0); /* send the shift values */ Dm->Comm.Irecv(&xShift[recvOffset_Z],recvCount,Dm->rank_Z(),recvtag+1); Dm->Comm.send(&tmpShift_x[0],sendCount,Dm->rank_z(),sendtag+1); Dm->Comm.Irecv(&yShift[recvOffset_Z],recvCount,Dm->rank_Z(),recvtag+2); Dm->Comm.send(&tmpShift_y[0],sendCount,Dm->rank_z(),sendtag+2); Dm->Comm.Irecv(&zShift[recvOffset_Z],recvCount,Dm->rank_Z(),recvtag+3); Dm->Comm.send(&tmpShift_z[0],sendCount,Dm->rank_z(),sendtag+3); Dm->Comm.barrier(); //................................................... /* Z face */ sendCount = recvCount = 0; for (size_t k=1; k boundary_distance){ tmpShift_x[sendCount] = i; tmpShift_y[sendCount] = j; tmpShift_z[sendCount] = k-(Nz-2); tmpDistance[sendCount++] = distance; int n = k*Nx*Ny + j*Nx + i; sendID.push_back(n); } } } } Dm->Comm.Irecv(&recvCount,1,Dm->rank_z(),recvtag+0); Dm->Comm.send(&sendCount,1,Dm->rank_Z(),sendtag+0); Dm->Comm.barrier(); sendOffset_Z = sendLoc; recvOffset_z = recvLoc; sendLoc += sendCount; recvLoc += recvCount; sendCount_Z = sendCount; recvCount_z = recvCount; /* grow the arrays */ xShift.resize(recvLoc); yShift.resize(recvLoc); zShift.resize(recvLoc); morphRadius.resize(recvLoc); //.............................. /* send the morphological radius */ Dm->Comm.Irecv(&morphRadius[recvOffset_z],recvCount,Dm->rank_z(),recvtag+0); Dm->Comm.send(&tmpDistance[0],sendCount,Dm->rank_Z(),sendtag+0); /* send the shift values */ Dm->Comm.Irecv(&xShift[recvOffset_z],recvCount,Dm->rank_z(),recvtag+1); Dm->Comm.send(&tmpShift_x[0],sendCount,Dm->rank_Z(),sendtag+1); Dm->Comm.Irecv(&yShift[recvOffset_z],recvCount,Dm->rank_z(),recvtag+2); Dm->Comm.send(&tmpShift_y[0],sendCount,Dm->rank_Z(),sendtag+2); Dm->Comm.Irecv(&zShift[recvOffset_z],recvCount,Dm->rank_z(),recvtag+3); Dm->Comm.send(&tmpShift_z[0],sendCount,Dm->rank_Z(),sendtag+3); Dm->Comm.barrier(); //................................................... /* resize the send / recv lists */ sendCount = sendLoc; recvCount = recvLoc; sendList.resize(sendLoc); recvList.resize(recvLoc); localID.resize(sendCount); nonlocalID.resize(recvCount); /*printf(" offset %i for send (x) %i \n", sendOffset_x, sendCount_x); printf(" offset %i for send (X) %i \n", sendOffset_X, sendCount_X); printf(" offset %i for send (y) %i \n", sendOffset_y, sendCount_y); printf(" offset %i for send (Y) %i \n", sendOffset_Y, sendCount_Y); printf(" offset %i for send (z) %i \n", sendOffset_z, sendCount_z); printf(" offset %i for send (Z) %i \n", sendOffset_Z, sendCount_Z); */ } int Morphology::GetOverlaps(std::shared_ptr Dm, signed char *id, const signed char ErodeLabel, const signed char NewLabel){ int Nx = Dm->Nx; int Ny = Dm->Ny; int Nz = Dm->Nz; int LocalNumber=0; int i,j,k,ii,jj,kk; int imin,jmin,kmin,imax,jmax,kmax; for (int idx=0; idxComm.Irecv(&nonlocalID[recvOffset_X],recvCount_X,Dm->rank_x(),recvtag+2); Dm->Comm.send(&localID[sendOffset_x],sendCount_x,Dm->rank_X(),sendtag+2); //printf("send X \n"); Dm->Comm.Irecv(&nonlocalID[recvOffset_x],recvCount_x,Dm->rank_X(),recvtag+3); Dm->Comm.send(&localID[sendOffset_X],sendCount_X,Dm->rank_x(),sendtag+3); //printf("send y \n"); Dm->Comm.Irecv(&nonlocalID[recvOffset_Y],recvCount_Y,Dm->rank_y(),recvtag+4); Dm->Comm.send(&localID[sendOffset_y],sendCount_y,Dm->rank_Y(),sendtag+4); //printf("send Y \n"); Dm->Comm.Irecv(&nonlocalID[recvOffset_y],recvCount_y,Dm->rank_Y(),recvtag+5); Dm->Comm.send(&localID[sendOffset_Y],sendCount_Y,Dm->rank_y(),sendtag+5); //printf("send z \n"); Dm->Comm.Irecv(&nonlocalID[recvOffset_Z],recvCount_Z,Dm->rank_z(),recvtag+6); Dm->Comm.send(&localID[sendOffset_z],sendCount_z,Dm->rank_Z(),sendtag+6); //printf("send Z \n"); Dm->Comm.Irecv(&nonlocalID[recvOffset_z],recvCount_z,Dm->rank_Z(),recvtag+7); Dm->Comm.send(&localID[sendOffset_Z],sendCount_Z,Dm->rank_z(),sendtag+7); for (int idx=0; idxComm.barrier(); return LocalNumber; } //*************************************************************************************** double MorphOpen(DoubleArray &SignDist, signed char *id, std::shared_ptr Dm, double VoidFraction, signed char ErodeLabel, signed char NewLabel){ // 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 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 maxdist) maxdist=SignDist(i,j,k); if ( id[n] == ErodeLabel){ count += 1.0; //id[n] = 2; } } } } Dm->Comm.barrier(); Morphology Structure; Structure.Initialize(Dm,SignDist); // total Global is the number of nodes in the pore-space totalGlobal = Dm->Comm.sumReduce( count ); maxdistGlobal = Dm->Comm.sumReduce( maxdist ); 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); final_void_fraction = volume_fraction; //initialize int ii,jj,kk; int imin,jmin,kmin,imax,jmax,kmax; 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; if (ErodeLabel == 1){ VoidFraction = 1.0 - VoidFraction; } // 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 = maxdistGlobal; double Rcrit_new = maxdistGlobal; int numTry = 0; int maxTry = 100; while (void_fraction_new > VoidFraction && numTry < maxTry) { numTry++; void_fraction_diff_old = void_fraction_diff_new; void_fraction_old = void_fraction_new; Rcrit_old = Rcrit_new; Rcrit_new -= deltaR*Rcrit_old; if (Rcrit_new < 0.5 ){ numTry = maxTry; } 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 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; kkComm.sumReduce( count ); 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 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 signed char ErodeLabel = 2; signed char NewLabel = 1; int nx = Dm->Nx; int ny = Dm->Ny; int nz = Dm->Nz; int nprocx = Dm->nprocx(); int nprocy = Dm->nprocy(); int nprocz = Dm->nprocz(); int rank = Dm->rank(); DoubleArray phase(nx,ny,nz); IntArray phase_label(nx,ny,nz); Array ID(nx,ny,nz); fillHalo fillChar(Dm->Comm,Dm->rank_info,{nx-2,ny-2,nz-2},{1,1,1},0,1); Morphology Structure; Structure.Initialize(Dm,SignDist); int n; double final_void_fraction; double count,countGlobal,totalGlobal; count = 0.f; double maxdist=-200.f; double maxdistGlobal; for (int k=1; k maxdist) maxdist=SignDist(i,j,k); if ( SignDist(i,j,k) > 0.0 ){ count += 1.0; id[n] = ErodeLabel; } ID(i,j,k) = id[n]; } } } fillChar.fill(ID); Dm->Comm.barrier(); // total Global is the number of nodes in the pore-space totalGlobal = Dm->Comm.sumReduce( count ); maxdistGlobal = Dm->Comm.sumReduce( maxdist ); 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); int ii,jj,kk; int imin,jmin,kmin,imax,jmax,kmax; 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 = maxdistGlobal; 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); //} Dm->Comm.barrier(); FILE *DRAIN = fopen("morphdrain.csv","w"); fprintf(DRAIN,"sw radius\n"); while (void_fraction_new > VoidFraction && Rcrit_new > 0.5) { 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 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; kkComm.barrier(); for (int k=0; krank_info,phase,SignDist,vF,vS,phase_label,Dm->Comm); Dm->Comm.barrier(); for (int k=0; k 1){ ID(i,j,k) = ErodeLabel; } id[n] = ID(i,j,k); } } } count = 0.f; for (int k=1; k 1){ count+=1.0; } } } } countGlobal = Dm->Comm.sumReduce( count ); void_fraction_new = countGlobal/totalGlobal; void_fraction_diff_new = abs(void_fraction_new-VoidFraction); if (rank==0){ fprintf(DRAIN,"%f ",void_fraction_new); fprintf(DRAIN,"%f\n",Rcrit_new); printf(" %f ",void_fraction_new); printf(" %f\n",Rcrit_new); } } if (void_fraction_diff_new 1){ id[n] = 2; } } } } return final_void_fraction; } //double MorphGrow(DoubleArray &BoundaryDist, DoubleArray &Dist, Array &id, std::shared_ptr Dm, double TargetGrowth) double MorphGrow(DoubleArray &BoundaryDist, DoubleArray &Dist, Array &id, std::shared_ptr Dm, double TargetGrowth, double WallFactor) { int Nx = Dm->Nx; int Ny = Dm->Ny; int Nz = Dm->Nz; int rank = Dm->rank(); double count=0.0; for (int k=1; kComm.sumReduce( 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 MAX_DISPLACEMENT) MAX_DISPLACEMENT= fabs(wallweight*morph_delta); if (Dist(i,j,k) - wallweight*morph_delta < 0.0){ count+=1.0; } } } } count = Dm->Comm.sumReduce( count ); MAX_DISPLACEMENT = Dm->Comm.maxReduce( 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 if (fabs(GrowthEstimate - GrowthPrevious) > 0.0) { 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 (morph_delta > 0.0 ){ // object is growing if (MAX_DISPLACEMENT > 3.0 ){ morph_delta = 3.0; COUNT_FOR_LOOP = 100; // exit loop if displacement is too large } } else{ // object is shrinking if (MAX_DISPLACEMENT > 1.0 ){ morph_delta = -1.0; 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; kComm.sumReduce( count ); return count; }