Working on filter for lbpm_uCT_pp

This commit is contained in:
Mark Berrill 2016-06-15 09:24:59 -04:00
parent 9aa3145e8a
commit 0284d4acd0
6 changed files with 301 additions and 191 deletions

View File

@ -20,7 +20,7 @@ ENDIF()
# Set the project name
PROJECT( LBPM-WIA )
IF ( NOT CXX_STD )
SET( CXX_STD 98 )
SET( CXX_STD 11 )
ENDIF()

View File

@ -269,6 +269,12 @@ public:
*/
void scale( const TYPE &scale );
/*!
* Set the values of this array to pow(base, exp)
* @param base Base array
* @param exp Exponent value
*/
void pow( const Array<TYPE> &baseArray, const TYPE &exp );
//! Destructor
~Array();
@ -283,7 +289,7 @@ public:
//! Return the size of the Array
std::vector<size_t> size() const;
inline std::vector<size_t> size() const { return std::vector<size_t>( d_N, d_N + d_ndim ); }
//! Return the size of the Array
@ -356,6 +362,13 @@ public:
template <class TYPE2>
void copySubset( const std::vector<size_t> &index, const Array<TYPE2> &subset );
/*!
* Add data from an array into a subset of this array
* @param index Index of the subset (imin,imax,jmin,jmax,kmin,kmax,...)
* @param subset The subset array to add from
*/
void addSubset( const std::vector<size_t> &index, const Array<TYPE> &subset );
/*!
* Access the desired element
@ -526,6 +539,9 @@ public:
//! Coarsen an array using the given filter
Array<TYPE> coarsen( const Array<TYPE>& filter ) const;
//! Coarsen an array using the given filter
Array<TYPE> coarsen( const std::vector<size_t>& ratio, std::function<TYPE(const Array<TYPE>&)> filter ) const;
private:
int d_ndim; // Number of dimensions in array
size_t d_N[ARRAY_NDIM_MAX]; // Size of each dimension

View File

@ -147,18 +147,6 @@ void Array<TYPE>::clear()
}
/********************************************************
* Return the size of the array *
********************************************************/
template <class TYPE>
std::vector<size_t> Array<TYPE>::size() const
{
if ( d_ndim==0 )
return std::vector<size_t>();
return std::vector<size_t>( d_N, d_N + d_ndim );
}
/********************************************************
* Check if the size of the array matches rhs *
********************************************************/
@ -416,6 +404,34 @@ void Array<TYPE>::copySubset( const std::vector<size_t> &index, const Array<TYPE
}
}
}
template <class TYPE>
void Array<TYPE>::addSubset( const std::vector<size_t> &index, const Array<TYPE> &subset )
{
// Get the subset indices
checkSubsetIndex( index );
std::array<size_t,5> first, last, N1;
getSubsetArrays( index, first, last, N1 );
std::array<size_t,5> N2 = getDimArray();
// add the sub-array
#if ARRAY_NDIM_MAX > 5
#error Function programmed for more than 5 dimensions
#endif
for (size_t i4=first[4]; i4<=last[4]; i4++) {
for (size_t i3=first[3]; i3<=last[3]; i3++) {
for (size_t i2=first[2]; i2<=last[2]; i2++) {
for (size_t i1=first[1]; i1<=last[1]; i1++) {
for (size_t i0=first[0]; i0<=last[0]; i0++) {
size_t k1 = GET_ARRAY_INDEX5D( N1, i0-first[0],
i1-first[1], i2-first[2], i3-first[3], i4-first[4] );
size_t k2 = GET_ARRAY_INDEX5D( N2, i0, i1, i2, i3, i4 );
d_data[k2] += subset.d_data[k1];
}
}
}
}
}
}
// clang-format on
@ -613,7 +629,17 @@ void Array<TYPE>::scale( const TYPE &value )
for ( size_t i = 0; i < d_length; i++ )
d_data[i] *= value;
}
template <class TYPE>
void Array<TYPE>::pow(const Array<TYPE> &baseArray, const TYPE &exp )
{
// not insisting on the shapes being the same
// but insisting on the total size being the same
AMP_ASSERT(d_length==baseArray.length());
const auto base_data = baseArray.data();
for ( size_t i = 0; i < d_length; i++ )
d_data[i] = std::pow(base_data[i], exp);
}
/********************************************************
* Simple math operations *
@ -996,6 +1022,35 @@ Array<TYPE> Array<TYPE>::coarsen( const Array<TYPE>& filter ) const
}
return y;
}
template <class TYPE>
Array<TYPE> Array<TYPE>::coarsen( const std::vector<size_t>& ratio, std::function<TYPE(const Array<TYPE>&)> filter ) const
{
ASSERT((int)ratio.size()==d_ndim);
auto S2 = size();
for (size_t i=0; i<S2.size(); i++) {
S2[i] /= ratio[i];
INSIST(S2[i]*ratio[i]==size(i),"Array must be multiple of filter size");
}
Array<TYPE> tmp(ratio);
TYPE* tmp2 = tmp.data();
Array<TYPE> y( S2 );
INSIST(d_ndim<=3,"Function programmed for more than 3 dimensions");
for (size_t k1=0; k1<y.d_N[2]; k1++) {
for (size_t j1=0; j1<y.d_N[1]; j1++) {
for (size_t i1=0; i1<y.d_N[0]; i1++) {
for (size_t k2=0; k2<ratio[2]; k2++) {
for (size_t j2=0; j2<ratio[1]; j2++) {
for (size_t i2=0; i2<ratio[0]; i2++) {
tmp2[GET_ARRAY_INDEX3D(tmp.d_N,i2,j2,k2)] = this->operator()(i1*ratio[0]+i2,j1*ratio[1]+j2,k1*ratio[2]+k2);
}
}
}
y(i1,j1,k1) = filter(tmp);
}
}
}
return y;
}
#endif

View File

@ -169,6 +169,44 @@ void unpack( std::set<TYPE>& data, const char *buffer );
// Helper functions
inline float sumReduce( MPI_Comm comm, float x )
{
float y = 0;
MPI_Allreduce(&x,&y,1,MPI_FLOAT,MPI_SUM,comm);
return y;
}
inline int sumReduce( MPI_Comm comm, int x )
{
int y = 0;
MPI_Allreduce(&x,&y,1,MPI_INT,MPI_SUM,comm);
return y;
}
inline bool sumReduce( MPI_Comm comm, bool x )
{
int y = sumReduce( comm, x?1:0 );
return y>0;
}
inline std::vector<float> sumReduce( MPI_Comm comm, const std::vector<float>& x )
{
auto y = x;
MPI_Allreduce(x.data(),y.data(),x.size(),MPI_FLOAT,MPI_SUM,comm);
return y;
}
inline std::vector<int> sumReduce( MPI_Comm comm, const std::vector<int>& x )
{
auto y = x;
MPI_Allreduce(x.data(),y.data(),x.size(),MPI_INT,MPI_SUM,comm);
return y;
}
inline float maxReduce( MPI_Comm comm, float x )
{
float y = 0;
MPI_Allreduce(&x,&y,1,MPI_FLOAT,MPI_MAX,comm);
return y;
}
#endif

View File

@ -133,7 +133,7 @@ int main(int argc, char **argv)
sprintf(LocalRankFilename,"SignDist.%05i",rank);
FILE *DIST = fopen(LocalRankFilename,"rb");
size_t ReadSignDist;
ReadSignDist=fread(SignDist.get(),8,N,DIST);
ReadSignDist=fread(SignDist.data(),8,N,DIST);
if (ReadSignDist != size_t(N)) printf("lbpm_morphdrain_pp: Error reading signed distance function (rank=%i)\n",rank);
fclose(DIST);

View File

@ -21,27 +21,17 @@
#include "IO/Writer.h"
#include "IO/netcdf.h"
#include "analysis/analysis.h"
#include "analysis/eikonal.h"
#include "ProfilerApp.h"
float sumReduce( MPI_Comm comm, float x )
template<class T>
inline int sign( T x )
{
float y = 0;
MPI_Allreduce(&x,&y,1,MPI_FLOAT,MPI_SUM,comm);
return y;
}
int sumReduce( MPI_Comm comm, int x )
{
int y = 0;
MPI_Allreduce(&x,&y,1,MPI_INT,MPI_SUM,comm);
return y;
}
float maxReduce( MPI_Comm comm, float x )
{
float y = 0;
MPI_Allreduce(&x,&y,1,MPI_FLOAT,MPI_MAX,comm);
return y;
if ( x==0 )
return 0;
return x>0 ? 1:-1;
}
@ -172,160 +162,6 @@ inline void InterpolateMesh( const Array<float> &Coarse, Array<float> &Fine )
PROFILE_STOP("InterpolateMesh");
}
inline float minmod(float &a, float &b){
float value;
value = a;
if ( a*b < 0.0) value=0.0;
else if (fabs(a) > fabs(b)) value = b;
return value;
}
inline float Eikonal3D( Array<float> &Distance, const Array<char> &ID, const Domain &Dm, const int timesteps)
{
PROFILE_START("Eikonal3D");
/*
* 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 Physics 229
*/
int i,j,k;
float dt=0.1;
float Dx,Dy,Dz;
float Dxp,Dxm,Dyp,Dym,Dzp,Dzm;
float Dxxp,Dxxm,Dyyp,Dyym,Dzzp,Dzzm;
float sign,norm;
float LocalVar,GlobalVar,LocalMax,GlobalMax;
int xdim,ydim,zdim;
xdim=Dm.Nx-2;
ydim=Dm.Ny-2;
zdim=Dm.Nz-2;
fillHalo<float> fillData(Dm.Comm, Dm.rank_info,xdim,ydim,zdim,1,1,1,0,1);
// Arrays to store the second derivatives
Array<float> Dxx(Dm.Nx,Dm.Ny,Dm.Nz);
Array<float> Dyy(Dm.Nx,Dm.Ny,Dm.Nz);
Array<float> 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<Dm.Nz-1;k++){
for (j=1;j<Dm.Ny-1;j++){
for (i=1;i<Dm.Nx-1;i++){
Dxx(i,j,k) = Distance(i+1,j,k) + Distance(i-1,j,k) - 2*Distance(i,j,k);
Dyy(i,j,k) = Distance(i,j+1,k) + Distance(i,j-1,k) - 2*Distance(i,j,k);
Dzz(i,j,k) = Distance(i,j,k+1) + Distance(i,j,k-1) - 2*Distance(i,j,k);
}
}
}
fillData.fill(Dxx);
fillData.fill(Dyy);
fillData.fill(Dzz);
LocalMax=LocalVar=0.0;
// Execute the next timestep
// f(n+1) = f(n) + dt*sign(1-|grad f|)
for (k=1;k<Dm.Nz-1;k++){
for (j=1;j<Dm.Ny-1;j++){
for (i=1;i<Dm.Nx-1;i++){
int n = k*Dm.Nx*Dm.Ny + j*Dm.Nx + i;
sign = -1;
if (ID(i,j,k) == 1) sign = 1;
// local second derivative terms
Dxxp = minmod(Dxx(i,j,k),Dxx(i+1,j,k));
Dyyp = minmod(Dyy(i,j,k),Dyy(i,j+1,k));
Dzzp = minmod(Dzz(i,j,k),Dzz(i,j,k+1));
Dxxm = minmod(Dxx(i,j,k),Dxx(i-1,j,k));
Dyym = minmod(Dyy(i,j,k),Dyy(i,j-1,k));
Dzzm = minmod(Dzz(i,j,k),Dzz(i,j,k-1));
/* //............Compute upwind derivatives ...................
Dxp = Distance(i+1,j,k) - Distance(i,j,k) + 0.5*Dxxp;
Dyp = Distance(i,j+1,k) - Distance(i,j,k) + 0.5*Dyyp;
Dzp = Distance(i,j,k+1) - Distance(i,j,k) + 0.5*Dzzp;
Dxm = Distance(i,j,k) - Distance(i-1,j,k) + 0.5*Dxxm;
Dym = Distance(i,j,k) - Distance(i,j-1,k) + 0.5*Dyym;
Dzm = Distance(i,j,k) - Distance(i,j,k-1) + 0.5*Dzzm;
*/
Dxp = Distance(i+1,j,k);
Dyp = Distance(i,j+1,k);
Dzp = Distance(i,j,k+1);
Dxm = Distance(i-1,j,k);
Dym = Distance(i,j-1,k);
Dzm = Distance(i,j,k-1);
// Compute upwind derivatives for Godunov Hamiltonian
if (sign < 0.0){
if (Dxp > Dxm) Dx = Dxp - Distance(i,j,k) + 0.5*Dxxp;
else Dx = Distance(i,j,k) - Dxm + 0.5*Dxxm;
if (Dyp > Dym) Dy = Dyp - Distance(i,j,k) + 0.5*Dyyp;
else Dy = Distance(i,j,k) - Dym + 0.5*Dyym;
if (Dzp > Dzm) Dz = Dzp - Distance(i,j,k) + 0.5*Dzzp;
else Dz = Distance(i,j,k) - Dzm + 0.5*Dzzm;
}
else{
if (Dxp < Dxm) Dx = Dxp - Distance(i,j,k) + 0.5*Dxxp;
else Dx = Distance(i,j,k) - Dxm + 0.5*Dxxm;
if (Dyp < Dym) Dy = Dyp - Distance(i,j,k) + 0.5*Dyyp;
else Dy = Distance(i,j,k) - Dym + 0.5*Dyym;
if (Dzp < Dzm) Dz = Dzp - Distance(i,j,k) + 0.5*Dzzp;
else Dz = Distance(i,j,k) - Dzm + 0.5*Dzzm;
}
norm=sqrt(Dx*Dx+Dy*Dy+Dz*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_FLOAT,MPI_SUM,Dm.Comm);
MPI_Allreduce(&LocalMax,&GlobalMax,1,MPI_FLOAT,MPI_MAX,Dm.Comm);
GlobalVar /= (Dm.Nx-2)*(Dm.Ny-2)*(Dm.Nz-2)*Dm.nprocx*Dm.nprocy*Dm.nprocz;
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;
}
}
PROFILE_STOP("Eikonal3D");
return GlobalVar;
}
inline int NLM3D( const Array<float> &Input, Array<float> &Mean,
const Array<float> &Distance, Array<float> &Output, const int d, const float h)
@ -509,6 +345,7 @@ void solve( const Array<float>& VOL, Array<float>& Mean, Array<char>& ID,
Array<float>& Dist, Array<float>& MultiScaleSmooth, Array<float>& NonLocalMean,
fillHalo<float>& fillFloat, const Domain& Dm, int nprocx )
{
PROFILE_SCOPED(timer,"solve");
// Compute the median filter on the sparse array
Med3D( VOL, Mean );
fillFloat.fill( Mean );
@ -529,8 +366,9 @@ void solve( const Array<float>& VOL, Array<float>& Mean, Array<char>& ID,
void refine( const Array<float>& Dist_coarse,
const Array<float>& VOL, Array<float>& Mean, Array<char>& ID,
Array<float>& Dist, Array<float>& MultiScaleSmooth, Array<float>& NonLocalMean,
fillHalo<float>& fillFloat, const Domain& Dm, int nprocx, bool solve_eikonal=true )
fillHalo<float>& fillFloat, const Domain& Dm, int nprocx, int level )
{
PROFILE_SCOPED(timer,"refine");
int ratio[3] = { int(Dist.size(0)/Dist_coarse.size(0)),
int(Dist.size(1)/Dist_coarse.size(1)),
int(Dist.size(2)/Dist_coarse.size(2)) };
@ -573,13 +411,144 @@ void refine( const Array<float>& Dist_coarse,
// Remove disconnected domains
//removeDisconnected( ID, Dm );
// Compute the distance using the segmented volume
if ( solve_eikonal ) {
Eikonal3D( Dist, ID, Dm, ID.size(0)*nprocx );
if ( level > 0 ) {
//Eikonal3D( Dist, ID, Dm, ID.size(0)*nprocx );
//CalcDist3D( Dist, ID, Dm );
CalcDistMultiLevel( Dist, ID, Dm );
fillFloat.fill(Dist);
}
}
// Remove regions that are likely noise by shrinking the volumes by dx,
// removing all values that are more than dx+delta from the surface, and then
// growing by dx+delta and intersecting with the original data
void filter_final( Array<char>& ID, Array<float>& Dist,
fillHalo<float>& fillFloat, const Domain& Dm,
Array<float>& Mean, Array<float>& Dist1, Array<float>& Dist2 )
{
PROFILE_SCOPED(timer,"filter_final");
int rank;
MPI_Comm_rank(Dm.Comm,&rank);
int Nx = Dm.Nx-2;
int Ny = Dm.Ny-2;
int Nz = Dm.Nz-2;
// Calculate the distance
CalcDistMultiLevel( Dist, ID, Dm );
fillFloat.fill(Dist);
// Compute the range to shrink the volume based on the L2 norm of the distance
Array<float> Dist0(Nx,Ny,Nz);
fillFloat.copy(Dist,Dist0);
float tmp = 0;
for (size_t i=0; i<Dist0.length(); i++)
tmp += Dist0(i)*Dist0(i);
tmp = sqrt( sumReduce(Dm.Comm,tmp) / sumReduce(Dm.Comm,(float)Dist0.length()) );
const float dx1 = 0.3*tmp;
const float dx2 = 1.05*dx1;
if (rank==0)
printf(" %0.1f %0.1f %0.1f\n",tmp,dx1,dx2);
// Update the IDs/Distance removing regions that are < dx of the range
Dist1 = Dist;
Dist2 = Dist;
Array<char> ID1 = ID;
Array<char> ID2 = ID;
for (size_t i=0; i<ID.length(); i++) {
ID1(i) = Dist(i)<-dx1 ? 1:0;
ID2(i) = Dist(i)> dx1 ? 1:0;
}
//Array<float> Dist1 = Dist;
//Array<float> Dist2 = Dist;
CalcDistMultiLevel( Dist1, ID1, Dm );
CalcDistMultiLevel( Dist2, ID2, Dm );
fillFloat.fill(Dist1);
fillFloat.fill(Dist2);
// Keep those regions that are within dx2 of the new volumes
Mean = Dist;
for (size_t i=0; i<ID.length(); i++) {
if ( Dist1(i)+dx2>0 && ID(i)<=0 ) {
Mean(i) = -1;
} else if ( Dist2(i)+dx2>0 && ID(i)>0 ) {
Mean(i) = 1;
} else {
Mean(i) = Dist(i)>0 ? 0.5:-0.5;
}
}
// Find regions of uncertainty that are entirely contained within another region
fillHalo<double> fillDouble(Dm.Comm,Dm.rank_info,Nx,Ny,Nz,1,1,1,0,1);
fillHalo<BlobIDType> fillInt(Dm.Comm,Dm.rank_info,Nx,Ny,Nz,1,1,1,0,1);
BlobIDArray GlobalBlobID;
DoubleArray SignDist(ID.size());
for (size_t i=0; i<ID.length(); i++)
SignDist(i) = fabs(Mean(i))==1 ? -1:1;
fillDouble.fill(SignDist);
DoubleArray Phase(ID.size());
Phase.fill(1);
ComputeGlobalBlobIDs( Nx, Ny, Nz, Dm.rank_info, Phase, SignDist, 0, 0, GlobalBlobID, Dm.Comm );
fillInt.fill(GlobalBlobID);
int N_blobs = maxReduce(Dm.Comm,GlobalBlobID.max()+1);
std::vector<float> mean(N_blobs,0);
std::vector<int> count(N_blobs,0);
for (int k=1; k<=Nz; k++) {
for (int j=1; j<=Ny; j++) {
for (int i=1; i<=Nx; i++) {
int id = GlobalBlobID(i,j,k);
if ( id >= 0 ) {
if ( GlobalBlobID(i-1,j,k)<0 ) {
mean[id] += Mean(i-1,j,k);
count[id]++;
}
if ( GlobalBlobID(i+1,j,k)<0 ) {
mean[id] += Mean(i+1,j,k);
count[id]++;
}
if ( GlobalBlobID(i,j-1,k)<0 ) {
mean[id] += Mean(i,j-1,k);
count[id]++;
}
if ( GlobalBlobID(i,j+1,k)<0 ) {
mean[id] += Mean(i,j+1,k);
count[id]++;
}
if ( GlobalBlobID(i,j,k-1)<0 ) {
mean[id] += Mean(i,j,k-1);
count[id]++;
}
if ( GlobalBlobID(i,j,k+1)<0 ) {
mean[id] += Mean(i,j,k+1);
count[id]++;
}
}
}
}
}
mean = sumReduce(Dm.Comm,mean);
count = sumReduce(Dm.Comm,count);
for (size_t i=0; i<mean.size(); i++)
mean[i] /= count[i];
/*if (rank==0) {
for (size_t i=0; i<mean.size(); i++)
printf("%i %0.4f\n",i,mean[i]);
}*/
for (size_t i=0; i<Mean.length(); i++) {
int id = GlobalBlobID(i);
if ( id >= 0 ) {
if ( fabs(mean[id]) > 0.95 ) {
// Isolated domain surrounded by one domain
GlobalBlobID(i) = -2;
Mean(i) = sign(mean[id]);
} else {
// Boarder volume, set to liquid
Mean(i) = 1;
}
}
}
// Perform the final segmentation and update the distance
fillFloat.fill(Mean);
segment( Mean, ID, 0.01 );
CalcDistMultiLevel( Dist, ID, Dm );
fillFloat.fill(Dist);
}
int main(int argc, char **argv)
{
@ -590,6 +559,7 @@ int main(int argc, char **argv)
MPI_Comm comm = MPI_COMM_WORLD;
MPI_Comm_rank(comm,&rank);
MPI_Comm_size(comm,&nprocs);
Utilities::setErrorHandlers();
PROFILE_START("Main");
//std::vector<std::string> filenames;
@ -806,14 +776,22 @@ int main(int argc, char **argv)
if (rank==0)
printf("Refine mesh\n");
for (int i=int(Nx.size())-2; i>=0; i--) {
printf(" Refining to level %i\n",int(i));
if (rank==0)
printf(" Refining to level %i\n",int(i));
refine( Dist[i+1], LOCVOL[i], Mean[i], ID[i], Dist[i], MultiScaleSmooth[i],
NonLocalMean[i], *fillFloat[i], *Dm[i], nprocx, i>0 );
NonLocalMean[i], *fillFloat[i], *Dm[i], nprocx, i );
}
PROFILE_STOP("Refine distance");
removeDisconnected( ID[0], *Dm[0] );
// Perform a final filter
PROFILE_START("Filtering final domains");
if (rank==0)
printf("Filtering final domains\n");
Array<float> filter_Mean, filter_Dist1, filter_Dist2;
filter_final( ID[0], Dist[0], *fillFloat[0], *Dm[0], filter_Mean, filter_Dist1, filter_Dist2 );
PROFILE_STOP("Filtering final domains");
//removeDisconnected( ID[0], *Dm[0] );
// Write the results to visit
if (rank==0) printf("Writing output \n");
@ -863,6 +841,29 @@ removeDisconnected( ID[0], *Dm[0] );
meshData[i].vars.push_back(SmoothData);
fillDouble[i]->copy( MultiScaleSmooth[i], SmoothData->data );
}
#if 0
std::shared_ptr<IO::Variable> filter_Mean_var( new IO::Variable() );
filter_Mean_var->name = "Mean";
filter_Mean_var->type = IO::VolumeVariable;
filter_Mean_var->dim = 1;
filter_Mean_var->data.resize(Nx[0],Ny[0],Nz[0]);
meshData[0].vars.push_back(filter_Mean_var);
fillDouble[0]->copy( filter_Mean, filter_Mean_var->data );
std::shared_ptr<IO::Variable> filter_Dist1_var( new IO::Variable() );
filter_Dist1_var->name = "Dist1";
filter_Dist1_var->type = IO::VolumeVariable;
filter_Dist1_var->dim = 1;
filter_Dist1_var->data.resize(Nx[0],Ny[0],Nz[0]);
meshData[0].vars.push_back(filter_Dist1_var);
fillDouble[0]->copy( filter_Dist1, filter_Dist1_var->data );
std::shared_ptr<IO::Variable> filter_Dist2_var( new IO::Variable() );
filter_Dist2_var->name = "Dist2";
filter_Dist2_var->type = IO::VolumeVariable;
filter_Dist2_var->dim = 1;
filter_Dist2_var->data.resize(Nx[0],Ny[0],Nz[0]);
meshData[0].vars.push_back(filter_Dist2_var);
fillDouble[0]->copy( filter_Dist2, filter_Dist2_var->data );
#endif
// Write visulization data
IO::writeData( 0, meshData, 2, comm );