#include "analysis/distance.h" /****************************************************************** * A fast distance calculation * ******************************************************************/ template void CalcDist( Array &Distance, const Array &ID, const Domain &Dm, const std::array& periodic, const std::array& dx ) { ASSERT( Distance.size() == ID.size() ); std::array n = { Dm.Nx-2, Dm.Ny-2, Dm.Nz-2 }; fillHalo fillData( Dm.Comm, Dm.rank_info, n, {1,1,1}, 50, 1, {true,false,false}, periodic ); Array id(ID.size()); Array vecDist(Distance.size()); for (size_t i=0; i &d, const Array &ID, double dx, double dy, double dz ) { d.fill( Vec( 1e50, 1e50, 1e50 ) ); const double dx0 = 0.5*dx; const double dy0 = 0.5*dy; const double dz0 = 0.5*dz; //const double dxy0 = 0.25*sqrt( dx*dx + dy*dy ); //const double dxz0 = 0.25*sqrt( dx*dx + dz*dz ); //const double dyz0 = 0.25*sqrt( dy*dy + dz*dz ); //const double dxyz0 = sqrt( dx*dx + dy*dy + dz*dz ); int Nx = d.size(0); int Ny = d.size(1); int Nz = d.size(2); for (int k=1; k &d, double dx, double dy, double dz ) { double err = 0; int Nx = d.size(0); int Ny = d.size(1); int Nz = d.size(2); // Propagate (+,+,+) for (int k=1; k=0; k--) { for (int j=Ny-2; j>=0; j--) { for (int i=Nx-2; i>=0; i--) { auto vx = d(i+1,j,k); auto vy = d(i,j+1,k); auto vz = d(i,j,k+1); vx.x -= dx; vy.y -= dy; vz.z -= dz; auto v = std::min( std::min(vx,vy), vz ); double d1 = v.norm2(); double d2 = d(i,j,k).norm2(); if ( d1 < d2 ) { d(i,j,k) = v; err = std::max( err, sqrt(d2)-sqrt(d1) ); } } } } return err; } /****************************************************************** * Vector-based distance calculation * ******************************************************************/ void CalcVecDist( Array &d, const Array &ID0, const Domain &Dm, const std::array& periodic, const std::array& dx ) { std::array N = { Dm.Nx, Dm.Ny, Dm.Nz }; std::array n = { Dm.Nx-2, Dm.Ny-2, Dm.Nz-2 }; // Create ID with ghosts Array ID(N[0],N[1],N[2]); fillHalo fillDataID( Dm.Comm, Dm.rank_info, n, {1,1,1}, 50, 1, {true,true,true}, periodic ); fillDataID.copy( ID0, ID ); // Fill ghosts with nearest neighbor for (int k=1; k fillData( Dm.Comm, Dm.rank_info, n, {1,1,1}, 50, 1, {true,false,false}, periodic ); // Calculate the local distances calcVecInitialize( d, ID, dx[0], dx[1], dx[2] ); double err = 1e100; double tol = 0.5 * std::min( std::min(dx[0],dx[1]), dx[2] ); for (int it=0; it<=50 && err>tol; it++) { err = calcVecUpdateInterior( d, dx[0], dx[1], dx[2] ); } // Calculate the global distances int N_it = Dm.nprocx() + Dm.nprocy() + Dm.nprocz() + 100; for ( int it=0; it &ID, Domain &Dm, int timesteps, const std::array& periodic){ /* * This routine converts the data in the Distance array to a signed distance * by solving the equation df/dt = sign(1-|grad f|), where Distance provides * the values of f on the mesh associated with domain Dm * It has been tested with segmented data initialized to values [-1,1] * and will converge toward the signed distance to the surface bounding the associated phases * * Reference: * Min C (2010) On reinitializing level set functions, Journal of Computational Physics229 */ int i,j,k; double dt=0.1; double Dx,Dy,Dz; double Dxp,Dxm,Dyp,Dym,Dzp,Dzm; double Dxxp,Dxxm,Dyyp,Dyym,Dzzp,Dzzm; double sign,norm; double LocalVar,GlobalVar,LocalMax,GlobalMax; int xdim,ydim,zdim; xdim=Dm.Nx-2; ydim=Dm.Ny-2; zdim=Dm.Nz-2; //fillHalo fillData(Dm.Comm, Dm.rank_info,xdim,ydim,zdim,1,1,1,0,1); fillHalo fillData( Dm.Comm, Dm.rank_info, {xdim, ydim, zdim}, {1,1,1}, 50, 1, {true,true,true}, periodic ); // Arrays to store the second derivatives DoubleArray Dxx(Dm.Nx,Dm.Ny,Dm.Nz); DoubleArray Dyy(Dm.Nx,Dm.Ny,Dm.Nz); DoubleArray Dzz(Dm.Nx,Dm.Ny,Dm.Nz); int count = 0; while (count < timesteps){ // Communicate the halo of values fillData.fill(Distance); // Compute second order derivatives for (k=1;k 0.f) Dx = Dxp*Dxp; else Dx = Dxm*Dxm; if (Dyp + Dym > 0.f) Dy = Dyp*Dyp; else Dy = Dym*Dym; if (Dzp + Dzm > 0.f) Dz = Dzp*Dzp; else Dz = Dzm*Dzm; } else{ if (Dxp + Dxm < 0.f) Dx = Dxp*Dxp; else Dx = Dxm*Dxm; if (Dyp + Dym < 0.f) Dy = Dyp*Dyp; else Dy = Dym*Dym; if (Dzp + Dzm < 0.f) Dz = Dzp*Dzp; else Dz = Dzm*Dzm; } //Dx = max(Dxp*Dxp,Dxm*Dxm); //Dy = max(Dyp*Dyp,Dym*Dym); //Dz = max(Dzp*Dzp,Dzm*Dzm); norm=sqrt(Dx + Dy + Dz); if (norm > 1.0) norm=1.0; Distance(i,j,k) += dt*sign*(1.0 - norm); LocalVar += dt*sign*(1.0 - norm); if (fabs(dt*sign*(1.0 - norm)) > LocalMax) LocalMax = fabs(dt*sign*(1.0 - norm)); } } } MPI_Allreduce(&LocalVar,&GlobalVar,1,MPI_DOUBLE,MPI_SUM,Dm.Comm); MPI_Allreduce(&LocalMax,&GlobalMax,1,MPI_DOUBLE,MPI_MAX,Dm.Comm); GlobalVar /= Dm.Volume; count++; if (count%50 == 0 && Dm.rank()==0 ) printf("Time=%i, Max variation=%f, Global variation=%f \n",count,GlobalMax,GlobalVar); if (fabs(GlobalMax) < 1e-5){ if (Dm.rank()==0) printf("Exiting with max tolerance of 1e-5 \n"); count=timesteps; } } return GlobalVar; } // Explicit instantiations template void CalcDist( Array&, const Array&, const Domain&, const std::array&, const std::array& ); template void CalcDist( Array&, const Array&, const Domain&, const std::array&, const std::array& );