/** In order to do so, first a reasonable dt for stability is calculated and F,G,RHS are evaluated. Afterwards, the Poisson pressure equation is solved and the velocitys are updated. \param[in] printInfo boolean if additional informations on the fields and rediduum of p are printed \param[in] verbose boolean if debbuging information should be printed (standard: false) */ void Compute::TimeStep(bool printInfo, bool verbose=false) { // TODO: test // compute dt if (verbose) std::cout << "Computing the timestep width..." << std::flush; // only for debugging issues real_t dt = compute_dt(); if (verbose) std::cout << "Done.\n" << std::flush; // only for debugging issues // compute F, G MomentumEqu(dt); update_boundary_values(); //update boundary values // compute rhs RHS(dt); // solve Poisson equation real_t residual(_epslimit + 1.0); index_t iteration(0); //while (iteration <= _param->IterMax() && residual > _epslimit){ while (true){ // one solver cycle is done here residual = _solver->Cycle(_p, _rhs); iteration++; if (iteration > _param->IterMax()){ //if (printInfo) { std::cout << "Warning: Solver did not converge! Residual: " << residual << "\n"; //} break; } else if (residual < _epslimit){ //if (printInfo) { std::cout << "Solver converged after " << iteration << " timesteps. Residual: " << residual << "\n"; //} break; } } // compute new velocitys u, v NewVelocities(dt); update_boundary_values(); //update total time _t += dt; // print information if (printInfo){ std::cout << "============================================================\n"; // total simulated time std::cout << "Total simulated time: t = " << _t << "\n"; // timestep std::cout << "Last timestep: dt = " << dt << "\n"; // magnitudes of the fields std::cout << "max(F) = " << _F->AbsMax() << ", max(G) = " << _G->AbsMax() << ", max(rhs) = " << _rhs->AbsMax() << "\n"; std::cout << "max(u) = " << _u->AbsMax() << ", max(v) = " << _v->AbsMax() << ", max(p) = " << _p->AbsMax() << "\n"; //std::cout << "Average value of rhs: " << _rhs->average_value() << "\n"; std::cout << "============================================================\n"; } }
int main (int argc, char* argv[]) { BoxLib::Initialize(argc,argv); // What time is it now? We'll use this to compute total run time. Real strt_time = ParallelDescriptor::second(); std::cout << std::setprecision(15); // ParmParse is way of reading inputs from the inputs file ParmParse pp; int verbose = 0; pp.query("verbose", verbose); // We need to get n_cell from the inputs file - this is the number of cells on each side of // a square (or cubic) domain. int n_cell; pp.get("n_cell",n_cell); int max_grid_size; pp.get("max_grid_size",max_grid_size); // Default plot_int to 1, allow us to set it to something else in the inputs file // If plot_int < 0 then no plot files will be written int plot_int = 1; pp.query("plot_int",plot_int); // Default nsteps to 0, allow us to set it to something else in the inputs file int nsteps = 0; pp.query("nsteps",nsteps); pp.query("do_tiling", do_tiling); // Define a single box covering the domain IntVect dom_lo(0,0,0); IntVect dom_hi(n_cell-1,n_cell-1,n_cell-1); Box domain(dom_lo,dom_hi); // Initialize the boxarray "bs" from the single box "bx" BoxArray bs(domain); // Break up boxarray "bs" into chunks no larger than "max_grid_size" along a direction bs.maxSize(max_grid_size); // This defines the physical size of the box. Right now the box is [-1,1] in each direction. RealBox real_box; for (int n = 0; n < BL_SPACEDIM; n++) { real_box.setLo(n,-1.0); real_box.setHi(n, 1.0); } // This says we are using Cartesian coordinates int coord = 0; // This sets the boundary conditions to be doubly or triply periodic int is_per[BL_SPACEDIM]; for (int i = 0; i < BL_SPACEDIM; i++) is_per[i] = 1; // This defines a Geometry object which is useful for writing the plotfiles Geometry geom(domain,&real_box,coord,is_per); // This defines the mesh spacing Real dx[BL_SPACEDIM]; for ( int n=0; n<BL_SPACEDIM; n++ ) dx[n] = ( geom.ProbHi(n) - geom.ProbLo(n) )/domain.length(n); // Nghost = number of ghost cells for each array int Nghost = 1; // Ncomp = number of components for each array int Ncomp = 1; pp.query("ncomp", Ncomp); // Allocate space for the old_phi and new_phi -- we define old_phi and new_phi as PArray < MultiFab > phis(2, PArrayManage); phis.set(0, new MultiFab(bs, Ncomp, Nghost)); phis.set(1, new MultiFab(bs, Ncomp, Nghost)); MultiFab* old_phi = &phis[0]; MultiFab* new_phi = &phis[1]; // Initialize both to zero (just because) old_phi->setVal(0.0); new_phi->setVal(0.0); // Initialize phi by calling a Fortran routine. // MFIter = MultiFab Iterator #ifdef _OPENMP #pragma omp parallel #endif for ( MFIter mfi(*new_phi,true); mfi.isValid(); ++mfi ) { const Box& bx = mfi.tilebox(); init_phi(bx.loVect(),bx.hiVect(), BL_TO_FORTRAN((*new_phi)[mfi]),Ncomp, dx,geom.ProbLo(),geom.ProbHi()); } // Call the compute_dt routine to return a time step which we will pass to advance Real dt = compute_dt(dx[0]); // Write a plotfile of the initial data if plot_int > 0 (plot_int was defined in the inputs file) if (plot_int > 0) { int n = 0; const std::string& pltfile = BoxLib::Concatenate("plt",n,5); writePlotFile(pltfile, *new_phi, geom); } Real adv_start_time = ParallelDescriptor::second(); for (int n = 1; n <= nsteps; n++) { // Swap the pointers so we don't have to allocate and de-allocate data std::swap(old_phi, new_phi); // new_phi = old_phi + dt * (something) advance(old_phi, new_phi, dx, dt, geom); // Tell the I/O Processor to write out which step we're doing if (verbose && ParallelDescriptor::IOProcessor()) std::cout << "Advanced step " << n << std::endl; // Write a plotfile of the current data (plot_int was defined in the inputs file) if (plot_int > 0 && n%plot_int == 0) { const std::string& pltfile = BoxLib::Concatenate("plt",n,5); writePlotFile(pltfile, *new_phi, geom); } } // Call the timer again and compute the maximum difference between the start time and stop time // over all processors Real advance_time = ParallelDescriptor::second() - adv_start_time; Real stop_time = ParallelDescriptor::second() - strt_time; const int IOProc = ParallelDescriptor::IOProcessorNumber(); ParallelDescriptor::ReduceRealMax(stop_time,IOProc); ParallelDescriptor::ReduceRealMax(advance_time,IOProc); ParallelDescriptor::ReduceRealMax(kernel_time,IOProc); ParallelDescriptor::ReduceRealMax(FB_time,IOProc); // Tell the I/O Processor to write out the "run time" if (ParallelDescriptor::IOProcessor()) { std::cout << "Kernel time = " << kernel_time << std::endl; std::cout << "FB time = " << FB_time << std::endl; std::cout << "Advance time = " << advance_time << std::endl; std::cout << "Total run time = " << stop_time << std::endl; } // Say goodbye to MPI, etc... BoxLib::Finalize(); }
int main (int argc, char* argv[]) { BoxLib::Initialize(argc,argv); // What time is it now? We'll use this to compute total run time. Real strt_time = ParallelDescriptor::second(); std::cout << std::setprecision(15); // ParmParse is way of reading inputs from the inputs file ParmParse pp; // We need to get n_cell from the inputs file - this is the number of cells on each side of // a square (or cubic) domain. int n_cell; pp.get("n_cell",n_cell); // Default nsteps to 0, allow us to set it to something else in the inputs file int max_grid_size; pp.get("max_grid_size",max_grid_size); // Default plot_int to 1, allow us to set it to something else in the inputs file // If plot_int < 0 then no plot files will be written int plot_int = 1; pp.query("plot_int",plot_int); // Default nsteps to 0, allow us to set it to something else in the inputs file int nsteps = 0; pp.query("nsteps",nsteps); // Define a single box covering the domain #if (BL_SPACEDIM == 2) IntVect dom_lo(0,0); IntVect dom_hi(n_cell-1,n_cell-1); #else IntVect dom_lo(0,0,0); IntVect dom_hi(n_cell-1,n_cell-1,n_cell-1); #endif Box domain(dom_lo,dom_hi); // Initialize the boxarray "bs" from the single box "bx" BoxArray bs(domain); // Break up boxarray "bs" into chunks no larger than "max_grid_size" along a direction bs.maxSize(max_grid_size); // This defines the physical size of the box. Right now the box is [-1,1] in each direction. RealBox real_box; for (int n = 0; n < BL_SPACEDIM; n++) { real_box.setLo(n,-1.0); real_box.setHi(n, 1.0); } // This says we are using Cartesian coordinates int coord = 0; // This sets the boundary conditions to be doubly or triply periodic int is_per[BL_SPACEDIM]; for (int i = 0; i < BL_SPACEDIM; i++) is_per[i] = 1; // This defines a Geometry object which is useful for writing the plotfiles Geometry geom(domain,&real_box,coord,is_per); // This defines the mesh spacing Real dx[BL_SPACEDIM]; for ( int n=0; n<BL_SPACEDIM; n++ ) dx[n] = ( geom.ProbHi(n) - geom.ProbLo(n) )/domain.length(n); // Nghost = number of ghost cells for each array int Nghost = 1; // Ncomp = number of components for each array int Ncomp = 1; // Make sure we can fill the ghost cells from the adjacent grid if (Nghost > max_grid_size) std::cout << "NGHOST < MAX_GRID_SIZE -- grids are too small! " << std::endl; // Allocate space for the old_phi and new_phi -- we define old_phi and new_phi as // pointers to the MultiFabs MultiFab* old_phi = new MultiFab(bs, Ncomp, Nghost); MultiFab* new_phi = new MultiFab(bs, Ncomp, Nghost); // Initialize both to zero (just because) old_phi->setVal(0.0); new_phi->setVal(0.0); // Initialize the old_phi by calling a Fortran routine. // MFIter = MultiFab Iterator for ( MFIter mfi(*new_phi); mfi.isValid(); ++mfi ) { const Box& bx = mfi.validbox(); FORT_INIT_PHI((*new_phi)[mfi].dataPtr(), bx.loVect(),bx.hiVect(), &Nghost, dx,geom.ProbLo(),geom.ProbHi()); } // Call the compute_dt routine to return a time step which we will pass to advance Real dt = compute_dt(dx[0]); // Write a plotfile of the initial data if plot_int > 0 (plot_int was defined in the inputs file) if (plot_int > 0) { int n = 0; const std::string& pltfile = BoxLib::Concatenate("plt",n,5); writePlotFile(pltfile, *new_phi, geom); } // build the flux multifabs MultiFab* flux = new MultiFab[BL_SPACEDIM]; for (int dir = 0; dir < BL_SPACEDIM; dir++) { BoxArray edge_grids(bs); // flux(dir) has one component, zero ghost cells, and is nodal in direction dir edge_grids.surroundingNodes(dir); flux[dir].define(edge_grids,1,0,Fab_allocate); } for (int n = 1; n <= nsteps; n++) { // Swap the pointers so we don't have to allocate and de-allocate data std::swap(old_phi, new_phi); // new_phi = old_phi + dt * (something) advance(old_phi, new_phi, flux, dx, dt, geom); // Tell the I/O Processor to write out which step we're doing if (ParallelDescriptor::IOProcessor()) std::cout << "Advanced step " << n << std::endl; // Write a plotfile of the current data (plot_int was defined in the inputs file) if (plot_int > 0 && n%plot_int == 0) { const std::string& pltfile = BoxLib::Concatenate("plt",n,5); writePlotFile(pltfile, *new_phi, geom); } } // Call the timer again and compute the maximum difference between the start time and stop time // over all processors Real stop_time = ParallelDescriptor::second() - strt_time; const int IOProc = ParallelDescriptor::IOProcessorNumber(); ParallelDescriptor::ReduceRealMax(stop_time,IOProc); // Tell the I/O Processor to write out the "run time" if (ParallelDescriptor::IOProcessor()) std::cout << "Run time = " << stop_time << std::endl; // Say goodbye to MPI, etc... BoxLib::Finalize(); }