Skip to content

Reply To: Error When Using Checkpoint for Multi-Component

OpenLB – Open Source Lattice Boltzmann Code Forums on OpenLB General Topics Error When Using Checkpoint for Multi-Component Reply To: Error When Using Checkpoint for Multi-Component

#9559
yueyq
Participant

Hi Adrian,
Here is the code for checkpoint saving:

#include "olb2D.h"
#include "olb2D.hh"

using namespace olb;
using namespace olb::descriptors;
using namespace olb::graphics;

using T = FLOATING_POINT_TYPE;
using DESCRIPTOR = D2Q9<FORCE,EXTERNAL_FORCE,STATISTIC>;

using COUPLING = ShanChenForcedPostProcessor<interaction::PsiEqualsRho>;

// Parameters for the simulation setup
const int nx   = 800;
const int ny   = 400;
const int maxIter = 40000;

// Stores geometry information in form of material numbers
void prepareGeometry( SuperGeometry<T,2>& superGeometry )
{

  OstreamManager clout( std::cout,"prepareGeometry" );
  clout << "Prepare Geometry ..." << std::endl;

  // Sets material number for fluid and boundary
  superGeometry.rename( 0,1 );

  Vector<T,2> origin1( -.5, -.5 );
  Vector<T,2> origin2( -.5,ny/2. );
  Vector<T,2> origin3( -.5, ny-1.5 );
  Vector<T,2> extend1( nx+2, 1. );
  Vector<T,2> extend2( nx+2., ny/2.+2. );

  IndicatorCuboid2D<T> bottom( extend1, origin1 );
  IndicatorCuboid2D<T> upper( extend2, origin2 );
  IndicatorCuboid2D<T> top( extend1, origin3 );

  superGeometry.rename( 1,2,upper );
  superGeometry.rename( 1,3,bottom );
  superGeometry.rename( 2,4,top );

  // Removes all not needed boundary voxels outside the surface
  //superGeometry.clean();
  // Removes all not needed boundary voxels inside the surface
  superGeometry.innerClean();
  superGeometry.checkForErrors();

  superGeometry.print();

  clout << "Prepare Geometry ... OK" << std::endl;
}

template <typename SuperLatticeCoupling>
void prepareLattice(SuperLattice<T,DESCRIPTOR>& sLatticeOne,
                    SuperLattice<T,DESCRIPTOR>& sLatticeTwo,
                    SuperLatticeCoupling& coupling,
                    SuperGeometry<T,2>& superGeometry)
{
  OstreamManager clout( std::cout,"prepareLattice" );
  clout << "Prepare Lattice ..." << std::endl;

  const T omega1 = 1.0;
  const T omega2 = 1.0;
  AnalyticalConst2D<T,T> rho0(0.0);
  AnalyticalConst2D<T,T> rho1(1.0);

  // The setup is: periodicity along horizontal direction, bounce-back on top
  // and bottom. The upper half is initially filled with fluid 1 + random noise,
  // and the lower half with fluid 2. Only fluid 1 experiences a forces,
  // directed downwards.

  using BulkDynamics = ForcedBGKdynamics<T,DESCRIPTOR,momenta::ExternalVelocityTuple>;

  sLatticeOne.defineDynamics<BulkDynamics>(superGeometry, 1);
  sLatticeOne.defineDynamics<BulkDynamics>(superGeometry, 2);
  sLatticeOne.defineDynamics<BulkDynamics>(superGeometry, 3);
  sLatticeOne.defineDynamics<BulkDynamics>(superGeometry, 4);

  sLatticeTwo.defineDynamics<BulkDynamics>(superGeometry, 1);
  sLatticeTwo.defineDynamics<BulkDynamics>(superGeometry, 2);
  sLatticeTwo.defineDynamics<BulkDynamics>(superGeometry, 3);
  sLatticeTwo.defineDynamics<BulkDynamics>(superGeometry, 4);

  setBounceBackBoundary(sLatticeOne, superGeometry, 3);
  setBounceBackBoundary(sLatticeOne, superGeometry, 4);
  setBounceBackBoundary(sLatticeTwo, superGeometry, 3);
  setBounceBackBoundary(sLatticeTwo, superGeometry, 4);

  sLatticeOne.setParameter<descriptors::OMEGA>(omega1);
  sLatticeTwo.setParameter<descriptors::OMEGA>(omega2);

  // A bounce-back node with fictitious density 0, which is experienced by the partner fluid
  sLatticeOne.defineRho(superGeometry, 3, rho0);
  sLatticeTwo.defineRho(superGeometry, 4, rho0);
  // A bounce-back node with fictitious density 0, which is experienced by the partner fluid
  sLatticeOne.defineRho(superGeometry, 4, rho1);
  sLatticeTwo.defineRho(superGeometry, 3, rho1);

  coupling.template setParameter<COUPLING::RHO0>({1, 1});
  coupling.template setParameter<COUPLING::G>(T(3.));
  coupling.template setParameter<COUPLING::OMEGA_A>(omega1);
  coupling.template setParameter<COUPLING::OMEGA_B>(omega2);

  sLatticeOne.addPostProcessor<stage::PreCoupling>(meta::id<RhoStatistics>());
  sLatticeTwo.addPostProcessor<stage::PreCoupling>(meta::id<RhoStatistics>());

  {
    auto& communicator = sLatticeOne.getCommunicator(stage::PreCoupling());
    communicator.requestOverlap(1);
    communicator.requestField<STATISTIC>();
    communicator.exchangeRequests();
  }

  {
    auto& communicator = sLatticeTwo.getCommunicator(stage::PreCoupling());
    communicator.requestOverlap(1);
    communicator.requestField<STATISTIC>();
    communicator.exchangeRequests();
  }

  clout << "Prepare Lattice ... OK" << std::endl;
}

void setBoundaryValues( SuperLattice<T, DESCRIPTOR>& sLatticeOne,
                        SuperLattice<T, DESCRIPTOR>& sLatticeTwo,
                        T force, int iT, SuperGeometry<T,2>& superGeometry )
{
  if ( iT==0 ) {

    AnalyticalConst2D<T,T> noise( 4.e-2 );
    std::vector<T> v( 2,T() );
    AnalyticalConst2D<T,T> zeroV( v );
    AnalyticalConst2D<T,T> zero( 1.e-6 );
    AnalyticalLinear2D<T,T> one( 0.,-force*invCs2<T,DESCRIPTOR>(),0.98+force*ny*invCs2<T,DESCRIPTOR>() );
    AnalyticalConst2D<T,T> onePlus( 0.98+force*ny/2.*invCs2<T,DESCRIPTOR>() );
    AnalyticalRandom2D<T,T> random;
    AnalyticalIdentity2D<T,T> randomOne( random*noise+one );
    AnalyticalIdentity2D<T,T> randomPlus( random*noise+onePlus );
    std::vector<T> F( 2,T() );
    F[1] = -force;
    AnalyticalConst2D<T,T> f( F );

    // for each material set the defineRhou and the Equilibrium

    sLatticeOne.defineRhoU( superGeometry, 1, zero, zeroV );
    sLatticeOne.iniEquilibrium( superGeometry, 1, zero, zeroV );
    sLatticeOne.defineField<descriptors::EXTERNAL_FORCE>( superGeometry, 1, f );
    sLatticeTwo.defineRhoU( superGeometry, 1, randomPlus, zeroV );
    sLatticeTwo.iniEquilibrium( superGeometry, 1, randomPlus, zeroV );

    sLatticeOne.defineRhoU( superGeometry, 2, randomOne, zeroV );
    sLatticeOne.iniEquilibrium( superGeometry, 2, randomOne, zeroV );
    sLatticeOne.defineField<descriptors::EXTERNAL_FORCE>( superGeometry, 2, f );
    sLatticeTwo.defineRhoU( superGeometry, 2, zero, zeroV );
    sLatticeTwo.iniEquilibrium( superGeometry, 2, zero, zeroV );

    // Make the lattice ready for simulation
    sLatticeOne.initialize();
    sLatticeTwo.initialize();
  }
}

void getResults( SuperLattice<T, DESCRIPTOR>&    sLatticeTwo,
                 SuperLattice<T, DESCRIPTOR>&    sLatticeOne, int iT,
                 SuperGeometry<T,2>& superGeometry, util::Timer<T>& timer )
{

  OstreamManager clout( std::cout,"getResults" );
  SuperVTMwriter2D<T> vtmWriter( "rayleighTaylor2dsLatticeOne" );

  const int vtkIter  = 1000;
  const int statIter = 1000;

  if ( iT==0 ) {
    // Writes the geometry, cuboid no. and rank no. as vti file for visualization
    SuperLatticeGeometry2D<T, DESCRIPTOR> geometry( sLatticeOne, superGeometry );
    SuperLatticeCuboid2D<T, DESCRIPTOR> cuboid( sLatticeOne );
    SuperLatticeRank2D<T, DESCRIPTOR> rank( sLatticeOne );
    vtmWriter.write( geometry );
    vtmWriter.write( cuboid );
    vtmWriter.write( rank );
    vtmWriter.createMasterFile();
  }

  // Get statistics
  if ( iT%statIter==0 && iT > 0 ) {
    // Timer console output
    timer.update( iT );
    timer.printStep();

    clout << "averageRhoFluidOne="   << sLatticeOne.getStatistics().getAverageRho();
    clout << "; averageRhoFluidTwo=" << sLatticeTwo.getStatistics().getAverageRho() << std::endl;
  }

  // Writes the VTK files
  if ( iT % vtkIter==0 ) {
    sLatticeOne.setProcessingContext(ProcessingContext::Evaluation);
    sLatticeTwo.setProcessingContext(ProcessingContext::Evaluation);

    SuperLatticeVelocity2D<T, DESCRIPTOR> velocity( sLatticeOne );
    SuperLatticeDensity2D<T, DESCRIPTOR> density( sLatticeOne );
    vtmWriter.addFunctor( velocity );
    vtmWriter.addFunctor( density );
    vtmWriter.write( iT );

    BlockReduction2D2D<T> planeReduction( density, 600, BlockDataSyncMode::ReduceOnly );
    // write output as JPEG
    heatmap::write(planeReduction, iT);

    sLatticeOne.save( "rayleighTaylorOne" );
    sLatticeTwo.save( "rayleighTaylorTwo" );
  }
}

int main( int argc, char *argv[] )
{
  // === 1st Step: Initialization ===

  olbInit( &argc, &argv );
  singleton::directories().setOutputDir( "./tmp/" );
  OstreamManager clout( std::cout,"main" );

  T force = 30./( T )ny/( T )ny;

  // === 2nd Step: Prepare Geometry ===
  // Instantiation of a cuboidGeometry with weights

#ifdef PARALLEL_MODE_MPI
  CuboidGeometry2D<T> cGeometry( 0, 0, 1, nx, ny, singleton::mpi().getSize() );
#else
  CuboidGeometry2D<T> cGeometry( 0, 0, 1, nx, ny, 1 );
#endif

  cGeometry.setPeriodicity( true, false );

  HeuristicLoadBalancer<T> loadBalancer( cGeometry );

  SuperGeometry<T,2> superGeometry( cGeometry, loadBalancer, 2 );

  prepareGeometry( superGeometry );

  // === 3rd Step: Prepare Lattice ===

  SuperLattice<T, DESCRIPTOR> sLatticeOne( superGeometry );
  SuperLattice<T, DESCRIPTOR> sLatticeTwo( superGeometry );

  SuperLatticeCoupling coupling(
    ShanChenForcedPostProcessor<interaction::PsiEqualsRho>{},
    names::A{}, sLatticeOne,
    names::B{}, sLatticeTwo);

  prepareLattice( sLatticeOne, sLatticeTwo, coupling, superGeometry );

  // === 4th Step: Main Loop with Timer ===
  int iT = 0;
  clout << "starting simulation..." << std::endl;
  util::Timer<T> timer( maxIter, superGeometry.getStatistics().getNvoxel() );
  timer.start();

  //sLatticeOne.load( "rayleighTaylorOne" );
  //sLatticeTwo.load( "rayleighTaylorTwo" );

  for ( iT=0; iT<maxIter; ++iT ) {
    // === 5th Step: Definition of Initial and Boundary Conditions ===
    setBoundaryValues( sLatticeOne, sLatticeTwo, force, iT, superGeometry );

    // === 6th Step: Collide and Stream Execution ===
    sLatticeOne.collideAndStream();
    sLatticeTwo.collideAndStream();

    sLatticeOne.executePostProcessors(stage::PreCoupling());
    sLatticeTwo.executePostProcessors(stage::PreCoupling());
    coupling.execute();

    // === 7th Step: Computation and Output of the Results ===
    getResults( sLatticeTwo, sLatticeOne, iT, superGeometry, timer );
  }

  timer.stop();
  timer.printSummary();
}

Then, when it shows [Timer] step=3000; percent=7.5; passedTime=87.541; remTime=1079.67; MLUPs=10.9901 on the terminal, I run:


#include "olb2D.h"
#include "olb2D.hh"

using namespace olb;
using namespace olb::descriptors;
using namespace olb::graphics;

using T = FLOATING_POINT_TYPE;
using DESCRIPTOR = D2Q9<FORCE,EXTERNAL_FORCE,STATISTIC>;

using COUPLING = ShanChenForcedPostProcessor<interaction::PsiEqualsRho>;

// Parameters for the simulation setup
const int nx   = 800;
const int ny   = 400;
const int maxIter = 40000;

// Stores geometry information in form of material numbers
void prepareGeometry( SuperGeometry<T,2>& superGeometry )
{

  OstreamManager clout( std::cout,"prepareGeometry" );
  clout << "Prepare Geometry ..." << std::endl;

  // Sets material number for fluid and boundary
  superGeometry.rename( 0,1 );

  Vector<T,2> origin1( -.5, -.5 );
  Vector<T,2> origin2( -.5,ny/2. );
  Vector<T,2> origin3( -.5, ny-1.5 );
  Vector<T,2> extend1( nx+2, 1. );
  Vector<T,2> extend2( nx+2., ny/2.+2. );

  IndicatorCuboid2D<T> bottom( extend1, origin1 );
  IndicatorCuboid2D<T> upper( extend2, origin2 );
  IndicatorCuboid2D<T> top( extend1, origin3 );

  superGeometry.rename( 1,2,upper );
  superGeometry.rename( 1,3,bottom );
  superGeometry.rename( 2,4,top );

  // Removes all not needed boundary voxels outside the surface
  //superGeometry.clean();
  // Removes all not needed boundary voxels inside the surface
  superGeometry.innerClean();
  superGeometry.checkForErrors();

  superGeometry.print();

  clout << "Prepare Geometry ... OK" << std::endl;
}

template <typename SuperLatticeCoupling>
void prepareLattice(SuperLattice<T,DESCRIPTOR>& sLatticeOne,
                    SuperLattice<T,DESCRIPTOR>& sLatticeTwo,
                    SuperLatticeCoupling& coupling,
                    SuperGeometry<T,2>& superGeometry)
{
  OstreamManager clout( std::cout,"prepareLattice" );
  clout << "Prepare Lattice ..." << std::endl;

  const T omega1 = 1.0;
  const T omega2 = 1.0;
  AnalyticalConst2D<T,T> rho0(0.0);
  AnalyticalConst2D<T,T> rho1(1.0);

  // The setup is: periodicity along horizontal direction, bounce-back on top
  // and bottom. The upper half is initially filled with fluid 1 + random noise,
  // and the lower half with fluid 2. Only fluid 1 experiences a forces,
  // directed downwards.

  using BulkDynamics = ForcedBGKdynamics<T,DESCRIPTOR,momenta::ExternalVelocityTuple>;

  sLatticeOne.defineDynamics<BulkDynamics>(superGeometry, 1);
  sLatticeOne.defineDynamics<BulkDynamics>(superGeometry, 2);
  sLatticeOne.defineDynamics<BulkDynamics>(superGeometry, 3);
  sLatticeOne.defineDynamics<BulkDynamics>(superGeometry, 4);

  sLatticeTwo.defineDynamics<BulkDynamics>(superGeometry, 1);
  sLatticeTwo.defineDynamics<BulkDynamics>(superGeometry, 2);
  sLatticeTwo.defineDynamics<BulkDynamics>(superGeometry, 3);
  sLatticeTwo.defineDynamics<BulkDynamics>(superGeometry, 4);

  setBounceBackBoundary(sLatticeOne, superGeometry, 3);
  setBounceBackBoundary(sLatticeOne, superGeometry, 4);
  setBounceBackBoundary(sLatticeTwo, superGeometry, 3);
  setBounceBackBoundary(sLatticeTwo, superGeometry, 4);

  sLatticeOne.setParameter<descriptors::OMEGA>(omega1);
  sLatticeTwo.setParameter<descriptors::OMEGA>(omega2);

  // A bounce-back node with fictitious density 0, which is experienced by the partner fluid
  sLatticeOne.defineRho(superGeometry, 3, rho0);
  sLatticeTwo.defineRho(superGeometry, 4, rho0);
  // A bounce-back node with fictitious density 0, which is experienced by the partner fluid
  sLatticeOne.defineRho(superGeometry, 4, rho1);
  sLatticeTwo.defineRho(superGeometry, 3, rho1);

  coupling.template setParameter<COUPLING::RHO0>({1, 1});
  coupling.template setParameter<COUPLING::G>(T(3.));
  coupling.template setParameter<COUPLING::OMEGA_A>(omega1);
  coupling.template setParameter<COUPLING::OMEGA_B>(omega2);

  sLatticeOne.addPostProcessor<stage::PreCoupling>(meta::id<RhoStatistics>());
  sLatticeTwo.addPostProcessor<stage::PreCoupling>(meta::id<RhoStatistics>());

  {
    auto& communicator = sLatticeOne.getCommunicator(stage::PreCoupling());
    communicator.requestOverlap(1);
    communicator.requestField<STATISTIC>();
    communicator.exchangeRequests();
  }

  {
    auto& communicator = sLatticeTwo.getCommunicator(stage::PreCoupling());
    communicator.requestOverlap(1);
    communicator.requestField<STATISTIC>();
    communicator.exchangeRequests();
  }

  clout << "Prepare Lattice ... OK" << std::endl;
}

void setBoundaryValues( SuperLattice<T, DESCRIPTOR>& sLatticeOne,
                        SuperLattice<T, DESCRIPTOR>& sLatticeTwo,
                        T force, int iT, SuperGeometry<T,2>& superGeometry )
{
  if ( iT==0 ) {

    AnalyticalConst2D<T,T> noise( 4.e-2 );
    std::vector<T> v( 2,T() );
    AnalyticalConst2D<T,T> zeroV( v );
    AnalyticalConst2D<T,T> zero( 1.e-6 );
    AnalyticalLinear2D<T,T> one( 0.,-force*invCs2<T,DESCRIPTOR>(),0.98+force*ny*invCs2<T,DESCRIPTOR>() );
    AnalyticalConst2D<T,T> onePlus( 0.98+force*ny/2.*invCs2<T,DESCRIPTOR>() );
    AnalyticalRandom2D<T,T> random;
    AnalyticalIdentity2D<T,T> randomOne( random*noise+one );
    AnalyticalIdentity2D<T,T> randomPlus( random*noise+onePlus );
    std::vector<T> F( 2,T() );
    F[1] = -force;
    AnalyticalConst2D<T,T> f( F );

    // for each material set the defineRhou and the Equilibrium

    sLatticeOne.defineRhoU( superGeometry, 1, zero, zeroV );
    sLatticeOne.iniEquilibrium( superGeometry, 1, zero, zeroV );
    sLatticeOne.defineField<descriptors::EXTERNAL_FORCE>( superGeometry, 1, f );
    sLatticeTwo.defineRhoU( superGeometry, 1, randomPlus, zeroV );
    sLatticeTwo.iniEquilibrium( superGeometry, 1, randomPlus, zeroV );

    sLatticeOne.defineRhoU( superGeometry, 2, randomOne, zeroV );
    sLatticeOne.iniEquilibrium( superGeometry, 2, randomOne, zeroV );
    sLatticeOne.defineField<descriptors::EXTERNAL_FORCE>( superGeometry, 2, f );
    sLatticeTwo.defineRhoU( superGeometry, 2, zero, zeroV );
    sLatticeTwo.iniEquilibrium( superGeometry, 2, zero, zeroV );

    // Make the lattice ready for simulation
    sLatticeOne.initialize();
    sLatticeTwo.initialize();
  }
}

void getResults( SuperLattice<T, DESCRIPTOR>&    sLatticeTwo,
                 SuperLattice<T, DESCRIPTOR>&    sLatticeOne, int iT,
                 SuperGeometry<T,2>& superGeometry, util::Timer<T>& timer )
{

  OstreamManager clout( std::cout,"getResults" );
  SuperVTMwriter2D<T> vtmWriter( "rayleighTaylor2dsLatticeOne" );

  const int vtkIter  = 1000;
  const int statIter = 1000;

  if ( iT==0 ) {
    // Writes the geometry, cuboid no. and rank no. as vti file for visualization
    SuperLatticeGeometry2D<T, DESCRIPTOR> geometry( sLatticeOne, superGeometry );
    SuperLatticeCuboid2D<T, DESCRIPTOR> cuboid( sLatticeOne );
    SuperLatticeRank2D<T, DESCRIPTOR> rank( sLatticeOne );
    vtmWriter.write( geometry );
    vtmWriter.write( cuboid );
    vtmWriter.write( rank );
    vtmWriter.createMasterFile();
  }

  // Get statistics
  if ( iT%statIter==0 && iT > 0 ) {
    // Timer console output
    timer.update( iT );
    timer.printStep();

    clout << "averageRhoFluidOne="   << sLatticeOne.getStatistics().getAverageRho();
    clout << "; averageRhoFluidTwo=" << sLatticeTwo.getStatistics().getAverageRho() << std::endl;
  }

  // Writes the VTK files
  if ( iT % vtkIter==0 ) {
    sLatticeOne.setProcessingContext(ProcessingContext::Evaluation);
    sLatticeTwo.setProcessingContext(ProcessingContext::Evaluation);

    SuperLatticeVelocity2D<T, DESCRIPTOR> velocity( sLatticeOne );
    SuperLatticeDensity2D<T, DESCRIPTOR> density( sLatticeOne );
    vtmWriter.addFunctor( velocity );
    vtmWriter.addFunctor( density );
    vtmWriter.write( iT );

    BlockReduction2D2D<T> planeReduction( density, 600, BlockDataSyncMode::ReduceOnly );
    // write output as JPEG
    heatmap::write(planeReduction, iT);

    sLatticeOne.save( "rayleighTaylorOne" );
    sLatticeTwo.save( "rayleighTaylorTwo" );
  }
}

int main( int argc, char *argv[] )
{
  // === 1st Step: Initialization ===

  olbInit( &argc, &argv );
  singleton::directories().setOutputDir( "./tmp/" );
  OstreamManager clout( std::cout,"main" );

  T force = 30./( T )ny/( T )ny;

  // === 2nd Step: Prepare Geometry ===
  // Instantiation of a cuboidGeometry with weights

#ifdef PARALLEL_MODE_MPI
  CuboidGeometry2D<T> cGeometry( 0, 0, 1, nx, ny, singleton::mpi().getSize() );
#else
  CuboidGeometry2D<T> cGeometry( 0, 0, 1, nx, ny, 1 );
#endif

  cGeometry.setPeriodicity( true, false );

  HeuristicLoadBalancer<T> loadBalancer( cGeometry );

  SuperGeometry<T,2> superGeometry( cGeometry, loadBalancer, 2 );

  prepareGeometry( superGeometry );

  // === 3rd Step: Prepare Lattice ===

  SuperLattice<T, DESCRIPTOR> sLatticeOne( superGeometry );
  SuperLattice<T, DESCRIPTOR> sLatticeTwo( superGeometry );

  SuperLatticeCoupling coupling(
    ShanChenForcedPostProcessor<interaction::PsiEqualsRho>{},
    names::A{}, sLatticeOne,
    names::B{}, sLatticeTwo);

  prepareLattice( sLatticeOne, sLatticeTwo, coupling, superGeometry );

  // === 4th Step: Main Loop with Timer ===
  int iT = 0;
  clout << "starting simulation..." << std::endl;
  util::Timer<T> timer( maxIter, superGeometry.getStatistics().getNvoxel() );
  timer.start();

  sLatticeOne.load( "rayleighTaylorOne" );
  sLatticeTwo.load( "rayleighTaylorTwo" );

  for ( iT=3000; iT<maxIter; ++iT ) {
    // === 5th Step: Definition of Initial and Boundary Conditions ===
    setBoundaryValues( sLatticeOne, sLatticeTwo, force, iT, superGeometry );

    // === 6th Step: Collide and Stream Execution ===
    sLatticeOne.collideAndStream();
    sLatticeTwo.collideAndStream();

    sLatticeOne.executePostProcessors(stage::PreCoupling());
    sLatticeTwo.executePostProcessors(stage::PreCoupling());
    coupling.execute();

    // === 7th Step: Computation and Output of the Results ===
    getResults( sLatticeTwo, sLatticeOne, iT, superGeometry, timer );
  }

  timer.stop();
  timer.printSummary();
}

Also, I wonder how to use the checkpoint for resolved-particle cases.
Thank you!

Best,
yueyq