/** * Main program for the simulation on a single SWE_WavePropagationBlock. */ int main( int argc, char** argv ) { /** * Initialization. */ // Parse command line parameters tools::Args args; #ifndef READXML args.addOption("grid-size-x", 'x', "Number of cells in x direction"); args.addOption("grid-size-y", 'y', "Number of cells in y direction"); args.addOption("output-basepath", 'o', "Output base file name"); #endif tools::Args::Result ret = args.parse(argc, argv); switch (ret) { case tools::Args::Error: return 1; case tools::Args::Help: return 0; } //! number of grid cells in x- and y-direction. int l_nX, l_nY; //! l_baseName of the plots. std::string l_baseName; // read command line parameters #ifndef READXML l_nX = args.getArgument<int>("grid-size-x"); l_nY = args.getArgument<int>("grid-size-y"); l_baseName = args.getArgument<std::string>("output-basepath"); #endif // read xml file #ifdef READXML assert(false); //TODO: not implemented. if(argc != 2) { s_sweLogger.printString("Aborting. Please provide a proper input file."); s_sweLogger.printString("Example: ./SWE_gnu_debug_none_augrie config.xml"); return 1; } s_sweLogger.printString("Reading xml-file."); std::string l_xmlFile = std::string(argv[1]); s_sweLogger.printString(l_xmlFile); CXMLConfig l_xmlConfig; l_xmlConfig.loadConfig(l_xmlFile.c_str()); #endif #ifdef ASAGI /* Information about the example bathymetry grid (tohoku_gebco_ucsb3_500m_hawaii_bath.nc): * * Pixel node registration used [Cartesian grid] * Grid file format: nf = GMT netCDF format (float) (COARDS-compliant) * x_min: -500000 x_max: 6500000 x_inc: 500 name: x nx: 14000 * y_min: -2500000 y_max: 1500000 y_inc: 500 name: y ny: 8000 * z_min: -6.48760175705 z_max: 16.1780223846 name: z * scale_factor: 1 add_offset: 0 * mean: 0.00217145586762 stdev: 0.245563641735 rms: 0.245573241263 */ //simulation area float simulationArea[4]; simulationArea[0] = -450000; simulationArea[1] = 6450000; simulationArea[2] = -2450000; simulationArea[3] = 1450000; SWE_AsagiScenario l_scenario( ASAGI_INPUT_DIR "tohoku_gebco_ucsb3_500m_hawaii_bath.nc", ASAGI_INPUT_DIR "tohoku_gebco_ucsb3_500m_hawaii_displ.nc", (float) 28800., simulationArea); #else // create a simple artificial scenario SWE_RadialDamBreakScenario l_scenario; #endif //! number of checkpoints for visualization (at each checkpoint in time, an output file is written). int l_numberOfCheckPoints = 200; //! size of a single cell in x- and y-direction float l_dX, l_dY; // compute the size of a single cell l_dX = (l_scenario.getBoundaryPos(BND_RIGHT) - l_scenario.getBoundaryPos(BND_LEFT) )/l_nX; l_dY = (l_scenario.getBoundaryPos(BND_TOP) - l_scenario.getBoundaryPos(BND_BOTTOM) )/l_nY; // create a single wave propagation block #ifndef CUDA SWE_WavePropagationBlock l_wavePropgationBlock(l_nX,l_nY,l_dX,l_dY); #else SWE_WavePropagationBlockCuda l_wavePropgationBlock(l_nX,l_nY,l_dX,l_dY); #endif //! origin of the simulation domain in x- and y-direction float l_originX, l_originY; // get the origin from the scenario l_originX = l_scenario.getBoundaryPos(BND_LEFT); l_originY = l_scenario.getBoundaryPos(BND_BOTTOM); // initialize the wave propagation block l_wavePropgationBlock.initScenario(l_originX, l_originY, l_scenario); //! time when the simulation ends. float l_endSimulation = l_scenario.endSimulation(); //! checkpoints when output files are written. float* l_checkPoints = new float[l_numberOfCheckPoints+1]; // compute the checkpoints in time for(int cp = 0; cp <= l_numberOfCheckPoints; cp++) { l_checkPoints[cp] = cp*(l_endSimulation/l_numberOfCheckPoints); } // Init fancy progressbar tools::ProgressBar progressBar(l_endSimulation); // write the output at time zero tools::Logger::logger.printOutputTime((float) 0.); progressBar.update(0.); std::string l_fileName = generateBaseFileName(l_baseName,0,0); //boundary size of the ghost layers io::BoundarySize l_boundarySize = {{1, 1, 1, 1}}; #ifdef WRITENETCDF //construct a NetCdfWriter io::NetCdfWriter l_writer( l_fileName, l_wavePropgationBlock.getBathymetry(), l_boundarySize, l_nX, l_nY, l_dX, l_dY, l_originX, l_originY); #else // consturct a VtkWriter io::VtkWriter l_writer( l_fileName, l_wavePropgationBlock.getBathymetry(), l_boundarySize, l_nX, l_nY, l_dX, l_dY ); #endif // Write zero time step l_writer.writeTimeStep( l_wavePropgationBlock.getWaterHeight(), l_wavePropgationBlock.getDischarge_hu(), l_wavePropgationBlock.getDischarge_hv(), (float) 0.); /** * Simulation. */ // print the start message and reset the wall clock time progressBar.clear(); tools::Logger::logger.printStartMessage(); tools::Logger::logger.initWallClockTime(time(NULL)); //! simulation time. float l_t = 0.0; progressBar.update(l_t); unsigned int l_iterations = 0; // loop over checkpoints for(int c=1; c<=l_numberOfCheckPoints; c++) { // do time steps until next checkpoint is reached while( l_t < l_checkPoints[c] ) { // set values in ghost cells: l_wavePropgationBlock.setGhostLayer(); // reset the cpu clock tools::Logger::logger.resetClockToCurrentTime("Cpu"); // approximate the maximum time step // TODO: This calculation should be replaced by the usage of the wave speeds occuring during the flux computation // Remark: The code is executed on the CPU, therefore a "valid result" depends on the CPU-GPU-synchronization. // l_wavePropgationBlock.computeMaxTimestep(); // compute numerical flux on each edge l_wavePropgationBlock.computeNumericalFluxes(); //! maximum allowed time step width. float l_maxTimeStepWidth = l_wavePropgationBlock.getMaxTimestep(); // update the cell values l_wavePropgationBlock.updateUnknowns(l_maxTimeStepWidth); // update the cpu time in the logger tools::Logger::logger.updateTime("Cpu"); // update simulation time with time step width. l_t += l_maxTimeStepWidth; l_iterations++; // print the current simulation time progressBar.clear(); tools::Logger::logger.printSimulationTime(l_t); progressBar.update(l_t); } // print current simulation time of the output progressBar.clear(); tools::Logger::logger.printOutputTime(l_t); progressBar.update(l_t); // write output l_writer.writeTimeStep( l_wavePropgationBlock.getWaterHeight(), l_wavePropgationBlock.getDischarge_hu(), l_wavePropgationBlock.getDischarge_hv(), l_t); } /** * Finalize. */ // write the statistics message progressBar.clear(); tools::Logger::logger.printStatisticsMessage(); // print the cpu time tools::Logger::logger.printTime("Cpu", "CPU time"); // print the wall clock time (includes plotting) tools::Logger::logger.printWallClockTime(time(NULL)); // printer iteration counter tools::Logger::logger.printIterationsDone(l_iterations); return 0; }
int main( int argc, char** argv ) { //! Number of cells in x direction int l_nX = 0; //! Number of cells in y direction int l_nY = 0; //! coarseness factor float l_coarseness = 1.0; //! l_baseName of the plots. std::string l_baseName; //! bathymetry input file name std::string l_bathymetryFileName; //! displacement input file name std::string l_displacementFileName; //! checkpoint input file name std::string l_checkpointFileName; //! the total simulation time int l_simulationTime = 0.0; #ifdef USEOPENCL //! Maximum number of computing devices to be used (OpenCL specific, 0 = unlimited) unsigned int l_maxDevices = 0; //! Maximum kernel group size size_t l_maxGroupSize = 1024; //! Chosen kernel optimization type KernelType l_kernelType = MEM_GLOBAL; #endif //! type of boundary conditions at LEFT, RIGHT, TOP, and BOTTOM boundary BoundaryType l_boundaryTypes[4]; //! whether to override the scenario-defined conditions (true) or not (false) bool l_overwriteBoundaryTypes = false; //! List of defined scenarios typedef enum { SCENARIO_TSUNAMI, SCENARIO_CHECKPOINT_TSUNAMI, SCENARIO_ARTIFICIAL_TSUNAMI, SCENARIO_PARTIAL_DAMBREAK } ScenarioName; //! the name of the chosen scenario ScenarioName l_scenarioName; #ifdef WRITENETCDF l_scenarioName = SCENARIO_TSUNAMI; #else l_scenarioName = SCENARIO_PARTIAL_DAMBREAK; #endif //! number of checkpoints for visualization (at each checkpoint in time, an output file is written). int l_numberOfCheckPoints = 20; // Option Parsing // REQUIRED // -x <num> // Number of cells in x-dir // -y <num> // Number of cells in y-dir // -o <file> // Output file basename // OPTIONAL (may be required for certain scenarios) // -i <file> // initial bathymetry data file name (REQUIRED for certain scenarios) // -d <file> // input displacement data file name (REQUIRED for certain scenarios) // -c <file> // checkpoints data file name // -f <float> // output coarseness factor // -l <num> // maximum number of computing devices // -m <code> // Kernel memory optimization type // -g <num // Kernel work group size // -n <num> // Number of checkpoints // -t <float> // Simulation time in seconds // -s <scenario> // Artificial scenario name ("artificialtsunami", "partialdambreak") // -b <code> // Boundary conditions, "w" or "o" // // 1 value: for all // // 2 values: first is left/right, second is top/bottom // // 4 values: left, right, bottom, top int c; int showUsage = 0; std::string optstr; while ((c = getopt(argc, argv, "x:y:o:i:d:c:n:t:b:s:f:l:m:g:")) != -1) { switch(c) { case 'x': l_nX = atoi(optarg); break; case 'y': l_nY = atoi(optarg); break; case 'o': l_baseName = std::string(optarg); break; #ifdef WRITENETCDF case 'i': l_bathymetryFileName = std::string(optarg); break; case 'd': l_displacementFileName = std::string(optarg); break; case 'c': l_checkpointFileName = std::string(optarg); break; #endif case 'l': #ifdef USEOPENCL l_maxDevices = atoi(optarg); #endif break; case 'g': #ifdef USEOPENCL l_maxGroupSize = atoi(optarg); #endif break; case 'm': #ifdef USEOPENCL optstr = std::string(optarg); if(optstr == "g" || optstr == "global") l_kernelType = MEM_GLOBAL; else l_kernelType = MEM_LOCAL; #endif break; case 'n': l_numberOfCheckPoints = atoi(optarg); break; case 't': l_simulationTime = atof(optarg); break; case 'b': optstr = std::string(optarg); l_overwriteBoundaryTypes = true; switch(optstr.length()) { case 1: // one option for all boundaries for(int i = 0; i < 4; i++) l_boundaryTypes[i] = (optstr[0] == 'w') ? WALL : OUTFLOW; break; case 2: // first: left/right, second: top/bottom for(int i = 0; i < 2; i++) l_boundaryTypes[i] = (optstr[0] == 'w') ? WALL : OUTFLOW; for(int i = 2; i < 4; i++) l_boundaryTypes[i] = (optstr[1] == 'w') ? WALL : OUTFLOW; break; case 4: // left right bottom top for(int i = 0; i < 4; i++) l_boundaryTypes[i] = (optstr[i] == 'w') ? WALL : OUTFLOW; break; default: std::cerr << "Invalid option argument: Invalid boundary specification (-b)" << std::endl; showUsage = 1; break; } break; case 's': optstr = std::string(optarg); if(optstr == "artificialtsunami") { l_scenarioName = SCENARIO_ARTIFICIAL_TSUNAMI; } else if(optstr == "partialdambreak") { l_scenarioName = SCENARIO_PARTIAL_DAMBREAK; } else { std::cerr << "Invalid option argument: Unknown scenario (-s)" << std::endl; showUsage = 1; } break; case 'f': l_coarseness = atof(optarg); break; default: showUsage = 1; break; } } // Do several checks on supplied options if(!showUsage) { // Check for required arguments x and y cells unless we can get the info from a checkpoint file if((l_nX == 0 || l_nY == 0) && l_checkpointFileName.empty()) { std::cerr << "Missing required arguments: number of cells in X (-x) and Y (-y) direction" << std::endl; showUsage = 1; } // Check for required output base file name if(l_baseName.empty() && l_checkpointFileName.empty()) { std::cerr << "Missing required argument: base name of output file (-o)" << std::endl; showUsage = 1; } // Check for valid number of checkpoints if(l_numberOfCheckPoints <= 0) { std::cerr << "Invalid option argument: Number of checkpoints must be greater than zero (-n)" << std::endl; showUsage = 1; } if(l_coarseness < 1.0) { std::cerr << "Invalid option argument: The coarseness factor must be greater than or equal to 1.0 (-f)" << std::endl; showUsage = 1; } // Check if a checkpoint-file is given as input. If so, switch to checkpoint scenario if(!l_checkpointFileName.empty()) { l_scenarioName = SCENARIO_CHECKPOINT_TSUNAMI; // We handle the file name of checkpoint and output data files without the ".nc" // extension internally, so we're removing the extension here in case it is supplied int cpLength = l_checkpointFileName.length(); if(l_checkpointFileName.substr(cpLength-3, 3).compare(".nc") == 0) { l_checkpointFileName.erase(cpLength-3, 3); } if(l_nX > 0 || l_nY > 0) std::cerr << "WARNING: Supplied number of grid cells will be ignored (reading from checkpoint)" << std::endl; if(l_simulationTime > 0.0) std::cerr << "WARNING: Supplied simulation time will be ignored (reading from checkpoint)" << std::endl; } if(l_scenarioName == SCENARIO_TSUNAMI) { // We've got no checkpoint and no artificial scenario // => Bathymetry and displacement data must be supplied if(l_bathymetryFileName.empty() || l_displacementFileName.empty()) { std::cerr << "Missing required argument: bathymetry (-i) and displacement (-d) files must be supplied" << std::endl; showUsage = 1; } } else { if(!l_bathymetryFileName.empty() || !l_displacementFileName.empty()) std::cerr << "WARNING: Supplied bathymetry and displacement data will be ignored" << std::endl; } #ifdef USEOPENCL if(l_maxGroupSize == 0 || (l_maxGroupSize & (l_maxGroupSize - 1))) { std::cout << "Group size must be greater than zero and a power of two!" << std::endl; showUsage = 1; } #endif } if(showUsage) { std::cout << "Usage:" << std::endl; std::cout << "Simulating a tsunami with bathymetry and displacement input:" << std::endl; std::cout << " ./SWE_<opt> -i <bathymetryfile> -d <displacementfile> [OPTIONS]" << std::endl; std::cout << "Resuming a crashed simulation from checkpoint file:" << std::endl; std::cout << " ./SWE_<opt> -c <checkpointfile> [-o <outputfile>]" << std::endl; std::cout << "Simulating an artificial scenario:" << std::endl; std::cout << " ./SWE_<opt> -s <scenarioname> [OPTIONS]" << std::endl; std::cout << "" << std::endl; std::cout << "Options:" << std::endl; std::cout << " -o <filename> The output file base name" << std::endl; std::cout << " Note: If the file already exists it is assumed to be a checkpointfile" << std::endl; std::cout << " from which to resume simulation. Input options are ignored then." << std::endl; std::cout << " -x <num> The number of cells in x-direction" << std::endl; std::cout << " -y <num> The number of cells in y-direction" << std::endl; std::cout << " -n <num> Number of checkpoints to be written" << std::endl; std::cout << " -t <time> Total simulation time" << std::endl; std::cout << " -f <num> Coarseness factor (> 1.0)" << std::endl; std::cout << " -l <num> Maximum number of computing devices (OpenCL only)" << std::endl; std::cout << " -b <code> Boundary Conditions" << std::endl; std::cout << " Codes: Combination of 'w' (WALL) and 'o' (OUTFLOW)" << std::endl; std::cout << " One char: Option for ALL boundaries" << std::endl; std::cout << " Two chars: Options for left/right and top/bottom boundaries" << std::endl; std::cout << " Four chars: Options for left, right, bottom, top boundaries" << std::endl; std::cout << " -i <filename> Name of bathymetry data file" << std::endl; std::cout << " -d <filename> Name of displacement data file" << std::endl; std::cout << " -c <filename> Name of checkpointfile" << std::endl; std::cout << " -s <scenario> Name of artificial scenario" << std::endl; std::cout << " Scenarios: 'artificialtsunami', 'partialdambreak'" << std::endl; std::cout << "" << std::endl; std::cout << "Notes when using a checkpointfile:" << std::endl; std::cout << " -x, -y, -n, -t, -b, -i, -d, -s are ignored (values are read from checkpointfile)" << std::endl; std::cout << " An output file (-o) can be specified. In that case, the checkpointfile" << std::endl; std::cout << " is copied to that location and output is appended to the output file." << std::endl; std::cout << " If no output file is specified, output is appended to the checkpointfile." << std::endl; std::cout << "" << std::endl; std::cout << "Example: " << std::endl; std::cout << "./SWE_<compiler>_<build>_none_dimsplit -x 100 -y 200 -o out -i b.nc -d d.nc -n 50 -b owwo" << std::endl; std::cout << " will simulate a tsunami scenario using bathymetry from 'b.nc' and displacements "; std::cout << "from 'd.nc' on a grid of size 100 x 200 using outflow conditions for left and "; std::cout << "top boundary and wall conditions for right and bottom boundary, writing 50 checkpoints "; std::cout << "to out_<num>.nc" << std::endl; return 0; } //! output file basename (with block coordinates) std::string l_outputFileName = generateBaseFileName(l_baseName,0,0); #ifdef WRITENETCDF if(l_scenarioName != SCENARIO_CHECKPOINT_TSUNAMI) { // This is a tsunami scenario, check if the output file (with .nc-extension) exists // In that case switch to checkpoint scenario int ncOutputFile; int status = nc_open((l_outputFileName + ".nc").c_str(), NC_NOWRITE, &ncOutputFile); if(status == NC_NOERR) { // Output file exists and is a NetCDF file => switch to checkpointing l_scenarioName = SCENARIO_CHECKPOINT_TSUNAMI; l_checkpointFileName = l_outputFileName; nc_close(ncOutputFile); } } #endif //! Pointer to instance of chosen scenario SWE_Scenario *l_scenario; // Create scenario according to chosen options switch(l_scenarioName) { #ifdef WRITENETCDF case SCENARIO_TSUNAMI: l_scenario = new SWE_TsunamiScenario(l_bathymetryFileName, l_displacementFileName); // overwrite boundary conditions from scenario in case they have // been explicitly set using command line arguments if(l_overwriteBoundaryTypes) ((SWE_TsunamiScenario *)l_scenario)->setBoundaryTypes(l_boundaryTypes); break; case SCENARIO_CHECKPOINT_TSUNAMI: l_scenario = new SWE_CheckpointTsunamiScenario(l_checkpointFileName + ".nc"); // Read number if grid cells from checkpoint ((SWE_CheckpointTsunamiScenario *)l_scenario)->getNumberOfCells(l_nX, l_nY); if(l_overwriteBoundaryTypes) std::cerr << "WARNING: Loading checkpointed Simulation does not support " << "explicitly setting boundary conditions" << std::endl; break; #endif case SCENARIO_ARTIFICIAL_TSUNAMI: l_scenario = new SWE_ArtificialTsunamiScenario(); // overwrite boundary conditions from scenario in case they have // been explicitly set using command line arguments if(l_overwriteBoundaryTypes) ((SWE_ArtificialTsunamiScenario *)l_scenario)->setBoundaryTypes(l_boundaryTypes); break; case SCENARIO_PARTIAL_DAMBREAK: l_scenario = new SWE_PartialDambreak(); if(l_overwriteBoundaryTypes) std::cerr << "WARNING: PartialDambreak-Scenario does not support " << "explicitly setting boundary conditions" << std::endl; break; default: std::cerr << "Invalid Scenario" << std::endl; exit(1); break; } //! size of a single cell in x- and y-direction float l_dX, l_dY; // compute the size of a single cell l_dX = (l_scenario->getBoundaryPos(BND_RIGHT) - l_scenario->getBoundaryPos(BND_LEFT) )/l_nX; l_dY = (l_scenario->getBoundaryPos(BND_TOP) - l_scenario->getBoundaryPos(BND_BOTTOM) )/l_nY; //! Dimensional Splitting Block #ifndef USEOPENCL SWE_DimensionalSplitting l_dimensionalSplitting(l_nX, l_nY, l_dX, l_dY); #else SWE_DimensionalSplittingOpenCL l_dimensionalSplitting(l_nX, l_nY, l_dX, l_dY, 0, l_maxDevices, l_kernelType, l_maxGroupSize); l_dimensionalSplitting.printDeviceInformation(); #endif //! origin of the simulation domain in x- and y-direction float l_originX, l_originY; // get the origin from the scenario l_originX = l_scenario->getBoundaryPos(BND_LEFT); l_originY = l_scenario->getBoundaryPos(BND_BOTTOM); // initialize the wave propagation block l_dimensionalSplitting.initScenario(l_originX, l_originY, *l_scenario); //! time when the simulation ends. float l_endSimulation; if(l_simulationTime <= 0.0) { // We haven't got a valid simulation time as arguments, use the pre-defied one from scenario l_endSimulation = l_scenario->endSimulation(); } else { // Use time given from command line l_endSimulation = l_simulationTime; } //! simulation time. float l_t = 0.0; //! checkpoint counter int l_checkpoint = 1; #ifdef WRITENETCDF if(l_scenarioName == SCENARIO_CHECKPOINT_TSUNAMI) { // read total number of checkpoints l_numberOfCheckPoints = ((SWE_CheckpointTsunamiScenario *)l_scenario)->getNumberOfCheckpoints(); // load last checkpoint and timestep from scenario (checkpoint-file) ((SWE_CheckpointTsunamiScenario *)l_scenario)->getLastCheckpoint(l_checkpoint, l_t); l_checkpoint++; // forace coarseness of 1 if reading from checkpoint data l_coarseness = 1.0; } #endif // read actual boundary types (command line merged with scenario) l_boundaryTypes[BND_LEFT] = l_scenario->getBoundaryType(BND_LEFT); l_boundaryTypes[BND_RIGHT] = l_scenario->getBoundaryType(BND_RIGHT); l_boundaryTypes[BND_BOTTOM] = l_scenario->getBoundaryType(BND_BOTTOM); l_boundaryTypes[BND_TOP] = l_scenario->getBoundaryType(BND_TOP); //! checkpoints when output files are written. float* l_checkPoints = new float[l_numberOfCheckPoints+1]; // compute the checkpoints in time for(int cp = 0; cp <= l_numberOfCheckPoints; cp++) { l_checkPoints[cp] = cp*(l_endSimulation/l_numberOfCheckPoints); } // Init fancy progressbar tools::ProgressBar progressBar(l_endSimulation); // write the output at time zero tools::Logger::logger.printOutputTime((float) l_t); progressBar.update(l_t); //boundary size of the ghost layers io::BoundarySize l_boundarySize = {{1, 1, 1, 1}}; // Delete scenarioto free resources and close opened files delete l_scenario; #ifdef WRITENETCDF if(l_scenarioName == SCENARIO_CHECKPOINT_TSUNAMI) { if(l_baseName.empty()) { // If there is no output file name given, use the checkpoint file l_outputFileName = l_checkpointFileName; } else if(l_outputFileName.compare(l_checkpointFileName) != 0) { // output file name given and it is not equal to the checkpoint file // therefore, we have to make a copy of our checkpointfile // in order to continue the simulation std::ifstream src((l_checkpointFileName + ".nc").c_str()); std::ofstream dst((l_outputFileName + ".nc").c_str()); dst << src.rdbuf(); } } //construct a NetCdfWriter io::NetCdfWriter l_writer( l_outputFileName, l_dimensionalSplitting.getBathymetry(), l_boundarySize, l_nX, l_nY, l_dX, l_dY, l_originX, l_originY, l_coarseness); l_writer.writeSimulationInfo(l_numberOfCheckPoints, l_endSimulation, l_boundaryTypes); #else // consturct a VtkWriter io::VtkWriter l_writer( l_outputFileName, l_dimensionalSplitting.getBathymetry(), l_boundarySize, l_nX, l_nY, l_dX, l_dY, 0, 0, l_coarseness); #endif if(l_scenarioName != SCENARIO_CHECKPOINT_TSUNAMI) { // Write zero time step l_writer.writeTimeStep( l_dimensionalSplitting.getWaterHeight(), l_dimensionalSplitting.getDischarge_hu(), l_dimensionalSplitting.getDischarge_hv(), (float) 0.); } /** * Simulation. */ // print the start message and reset the wall clock time progressBar.clear(); tools::Logger::logger.printStartMessage(); tools::Logger::logger.initWallClockTime(time(NULL)); progressBar.update(l_t); unsigned int l_iterations = 0; // loop over checkpoints while(l_checkpoint <= l_numberOfCheckPoints) { // do time steps until next checkpoint is reached while( l_t < l_checkPoints[l_checkpoint] ) { // set values in ghost cells: l_dimensionalSplitting.setGhostLayer(); // reset the cpu clock tools::Logger::logger.resetCpuClockToCurrentTime(); // compute numerical flux on each edge l_dimensionalSplitting.computeNumericalFluxes(); //! maximum allowed time step width. float l_maxTimeStepWidth = l_dimensionalSplitting.getMaxTimestep(); // update the cell values l_dimensionalSplitting.updateUnknowns(l_maxTimeStepWidth); // update the cpu time in the logger tools::Logger::logger.updateCpuTime(); // update simulation time with time step width. l_t += l_maxTimeStepWidth; l_iterations++; // print the current simulation time progressBar.clear(); tools::Logger::logger.printSimulationTime(l_t); progressBar.update(l_t); } // print current simulation time of the output progressBar.clear(); tools::Logger::logger.printOutputTime(l_t); progressBar.update(l_t); // write output l_writer.writeTimeStep( l_dimensionalSplitting.getWaterHeight(), l_dimensionalSplitting.getDischarge_hu(), l_dimensionalSplitting.getDischarge_hv(), l_t); l_checkpoint++; } /** * Finalize. */ // write the statistics message progressBar.clear(); tools::Logger::logger.printStatisticsMessage(); // print the cpu time tools::Logger::logger.printCpuTime(); // print the wall clock time (includes plotting) tools::Logger::logger.printWallClockTime(time(NULL)); // printer iteration counter tools::Logger::logger.printIterationsDone(l_iterations); // print average time per cell per iteration tools::Logger::logger.printAverageCPUTimePerCellPerIteration(l_iterations, l_nX*(l_nY+2)); #ifdef USEOPENCL // print opencl stats l_dimensionalSplitting.printProfilingInformation(); #endif return 0; }
/** * Main program for the simulation on a single SWE_WavePropagationBlock. */ int main( int argc, char** argv ) { /** * Initialization. */ //! MPI Rank of a process. int l_mpiRank; //! number of MPI processes. int l_numberOfProcesses; // initialize MPI if ( MPI_Init(&argc,&argv) != MPI_SUCCESS ) { std::cerr << "MPI_Init failed." << std::endl; } // determine local MPI rank MPI_Comm_rank(MPI_COMM_WORLD,&l_mpiRank); // determine total number of processes MPI_Comm_size(MPI_COMM_WORLD,&l_numberOfProcesses); // initialize a logger for every MPI process tools::Logger::logger.setProcessRank(l_mpiRank); // print the welcome message tools::Logger::logger.printWelcomeMessage(); // set current wall clock time within the solver tools::Logger::logger.initWallClockTime( MPI_Wtime() ); //print the number of processes tools::Logger::logger.printNumberOfProcesses(l_numberOfProcesses); // check if the necessary command line input parameters are given #ifndef READXML std::vector<std::string> vargs; vargs.push_back(argv[0]); vargs.push_back("grid_size_x"); vargs.push_back("grid_size_y"); vargs.push_back("output_basepath"); vargs.push_back("output_steps_count"); #ifdef ASAGI vargs.push_back("bathymetry_file"); vargs.push_back("displacement_file"); vargs.push_back("simul_area_min_x"); vargs.push_back("simul_area_max_x"); vargs.push_back("simul_area_min_y"); vargs.push_back("simul_area_max_y"); vargs.push_back("simul_duration_secs"); #endif if (argc != vargs.size()) { std::cout << "Usage: " << vargs[0]; for (int i = 1, e = vargs.size(); i != e; i++) std::cout << " <" << vargs[i] << ">"; std::cout << std::endl << std::flush; MPI_Finalize(); return 1; } #endif //! total number of grid cell in x- and y-direction. int l_nX, l_nY; //! l_baseName of the plots. std::string l_baseName; // read command line parameters #ifndef READXML l_nX = atoi(ARG("grid_size_x")); l_nY = atoi(ARG("grid_size_y")); l_baseName = std::string(ARG("output_basepath")); #endif // read xml file #ifdef READXML assert(false); //TODO: not implemented. if(argc != 2) { l_sweLogger.printString("Aborting. Please provide a proper input file."); l_sweLogger.printString("Example: ./SWE_gnu_debug_none_augrie config.xml"); return 1; } l_sweLogger.printString("Reading xml-file."); std::string l_xmlFile = std::string(argv[1]); l_sweLogger.printString(l_xmlFile); CXMLConfig l_xmlConfig; l_xmlConfig.loadConfig(l_xmlFile.c_str()); #endif // READXML //! number of SWE_Blocks in x- and y-direction. int l_blocksX, l_blocksY; // determine the layout of MPI-ranks: use l_blocksX*l_blocksY grid blocks l_blocksY = computeNumberOfBlockRows(l_numberOfProcesses); l_blocksX = l_numberOfProcesses/l_blocksY; // print information about the grid tools::Logger::logger.printNumberOfCells(l_nX, l_nY); tools::Logger::logger.printNumberOfBlocks(l_blocksX, l_blocksY); //! local position of each MPI process in x- and y-direction. int l_blockPositionX, l_blockPositionY; // determine local block coordinates of each SWE_Block l_blockPositionX = l_mpiRank / l_blocksY; l_blockPositionY = l_mpiRank % l_blocksY; #ifdef ASAGI /* * Pixel node registration used [Cartesian grid] * Grid file format: nf = GMT netCDF format (float) (COARDS-compliant) * x_min: -500000 x_max: 6500000 x_inc: 500 name: x nx: 14000 * y_min: -2500000 y_max: 1500000 y_inc: 500 name: y ny: 8000 * z_min: -6.48760175705 z_max: 16.1780223846 name: z * scale_factor: 1 add_offset: 0 * mean: 0.00217145586762 stdev: 0.245563641735 rms: 0.245573241263 */ //simulation area float simulationArea[4]; simulationArea[0] = atof(ARG("simul_area_min_x")); simulationArea[1] = atof(ARG("simul_area_max_x")); simulationArea[2] = atof(ARG("simul_area_min_y")); simulationArea[3] = atof(ARG("simul_area_max_y")); float simulationDuration = atof(ARG("simul_duration_secs")); SWE_AsagiScenario l_scenario(ARG("bathymetry_file"), ARG("displacement_file"), simulationDuration, simulationArea); #else // create a simple artificial scenario SWE_BathymetryDamBreakScenario l_scenario; #endif //! number of checkpoints for visualization (at each checkpoint in time, an output file is written). int l_numberOfCheckPoints = atoi(ARG("output_steps_count")); //! number of grid cells in x- and y-direction per process. int l_nXLocal, l_nYLocal; //! size of a single cell in x- and y-direction float l_dX, l_dY; // compute local number of cells for each SWE_Block l_nXLocal = (l_blockPositionX < l_blocksX-1) ? l_nX/l_blocksX : l_nX - (l_blocksX-1)*(l_nX/l_blocksX); l_nYLocal = (l_blockPositionY < l_blocksY-1) ? l_nY/l_blocksY : l_nY - (l_blocksY-1)*(l_nY/l_blocksY); // compute the size of a single cell l_dX = (l_scenario.getBoundaryPos(BND_RIGHT) - l_scenario.getBoundaryPos(BND_LEFT) )/l_nX; l_dY = (l_scenario.getBoundaryPos(BND_TOP) - l_scenario.getBoundaryPos(BND_BOTTOM) )/l_nY; // print information about the cell size and local number of cells tools::Logger::logger.printCellSize(l_dX, l_dY); tools::Logger::logger.printNumberOfCellsPerProcess(l_nXLocal, l_nYLocal); //! origin of the simulation domain in x- and y-direction float l_originX, l_originY; // get the origin from the scenario l_originX = l_scenario.getBoundaryPos(BND_LEFT) + l_blockPositionX*l_nXLocal*l_dX;; l_originY = l_scenario.getBoundaryPos(BND_BOTTOM) + l_blockPositionY*l_nYLocal*l_dY; // create a single wave propagation block #ifndef CUDA SWE_WavePropagationBlock l_wavePropgationBlock(l_nXLocal,l_nYLocal,l_dX,l_dY); #else //! number of CUDA devices per node TODO: hardcoded int l_cudaDevicesPerNode = 7; //! the id of the node local GPU int l_cudaDeviceId = l_mpiRank % l_cudaDevicesPerNode; SWE_BlockCUDA::init(l_cudaDeviceId); SWE_WavePropagationBlockCuda l_wavePropgationBlock(l_nXLocal,l_nYLocal,l_dX,l_dY); #endif // initialize the wave propgation block l_wavePropgationBlock.initScenario(l_originX, l_originY, l_scenario, true); //! time when the simulation ends. float l_endSimulation = l_scenario.endSimulation(); //! checkpoints when output files are written. float* l_checkPoints = new float[l_numberOfCheckPoints+1]; // compute the checkpoints in time for(int cp = 0; cp <= l_numberOfCheckPoints; cp++) { l_checkPoints[cp] = cp*(l_endSimulation/l_numberOfCheckPoints); } /* * Connect SWE blocks at boundaries */ // left and right boundaries tools::Logger::logger.printString("Connecting SWE blocks at left boundaries."); SWE_Block1D* l_leftInflow = l_wavePropgationBlock.grabGhostLayer(BND_LEFT); SWE_Block1D* l_leftOutflow = l_wavePropgationBlock.registerCopyLayer(BND_LEFT); if (l_blockPositionX == 0) l_wavePropgationBlock.setBoundaryType(BND_LEFT, OUTFLOW); tools::Logger::logger.printString("Connecting SWE blocks at right boundaries."); SWE_Block1D* l_rightInflow = l_wavePropgationBlock.grabGhostLayer(BND_RIGHT); SWE_Block1D* l_rightOutflow = l_wavePropgationBlock.registerCopyLayer(BND_RIGHT); if (l_blockPositionX == l_blocksX-1) l_wavePropgationBlock.setBoundaryType(BND_RIGHT, OUTFLOW); // bottom and top boundaries tools::Logger::logger.printString("Connecting SWE blocks at bottom boundaries."); SWE_Block1D* l_bottomInflow = l_wavePropgationBlock.grabGhostLayer(BND_BOTTOM); SWE_Block1D* l_bottomOutflow = l_wavePropgationBlock.registerCopyLayer(BND_BOTTOM); if (l_blockPositionY == 0) l_wavePropgationBlock.setBoundaryType(BND_BOTTOM, OUTFLOW); tools::Logger::logger.printString("Connecting SWE blocks at top boundaries."); SWE_Block1D* l_topInflow = l_wavePropgationBlock.grabGhostLayer(BND_TOP); SWE_Block1D* l_topOutflow = l_wavePropgationBlock.registerCopyLayer(BND_TOP); if (l_blockPositionY == l_blocksY-1) l_wavePropgationBlock.setBoundaryType(BND_TOP, OUTFLOW); /* * The grid is stored column wise in memory: * * ************************** . . . ********** * * * ny+2 *2(ny+2)* * (ny+1)* * * ny+1 * +ny+1 * +ny+1 * * (ny+2)* * * * * * * +ny+1 * * ************************** . . . ********** * * * * * * * * . . . . . . * . . . . . . * . . . . . . * * * * * * * * ************************** . . . ********** * * * ny+2 *2(ny+2)* * (ny+1)* * * 1 * +1 * +1 * * (ny+2)* * * * * * * +1 * * ************************** . . . ********** * * * ny+2 *2(ny+2)* * (ny+1)* * * 0 * +0 * +0 * * (ny+2)* * * * * * * +0 * * ************************** . . . *********** * * * -> The stride for a row is ny+2, because we have to jump over a whole column * for every row-element. This holds only in the CPU-version, in CUDA a buffer is implemented. * See SWE_BlockCUDA.hh/.cu for details. * -> The stride for a column is 1, because we can access the elements linear in memory. */ //! MPI row-vector: l_nXLocal+2 blocks, 1 element per block, stride of l_nYLocal+2 MPI_Datatype l_mpiRow; #ifndef CUDA MPI_Type_vector(l_nXLocal+2, 1 , l_nYLocal+2, MPI_FLOAT, &l_mpiRow); #else MPI_Type_vector(1, l_nXLocal+2, 1 , MPI_FLOAT, &l_mpiRow); #endif MPI_Type_commit(&l_mpiRow); //! MPI row-vector: 1 block, l_nYLocal+2 elements per block, stride of 1 MPI_Datatype l_mpiCol; MPI_Type_vector(1, l_nYLocal+2, 1, MPI_FLOAT, &l_mpiCol); MPI_Type_commit(&l_mpiCol); //! MPI ranks of the neighbors int l_leftNeighborRank, l_rightNeighborRank, l_bottomNeighborRank, l_topNeighborRank; // compute MPI ranks of the neighbour processes l_leftNeighborRank = (l_blockPositionX > 0) ? l_mpiRank-l_blocksY : MPI_PROC_NULL; l_rightNeighborRank = (l_blockPositionX < l_blocksX-1) ? l_mpiRank+l_blocksY : MPI_PROC_NULL; l_bottomNeighborRank = (l_blockPositionY > 0) ? l_mpiRank-1 : MPI_PROC_NULL; l_topNeighborRank = (l_blockPositionY < l_blocksY-1) ? l_mpiRank+1 : MPI_PROC_NULL; // print the MPI grid tools::Logger::logger.cout() << "neighbors: " << l_leftNeighborRank << " (left), " << l_rightNeighborRank << " (right), " << l_bottomNeighborRank << " (bottom), " << l_topNeighborRank << " (top)" << std::endl; // intially exchange ghost and copy layers exchangeLeftRightGhostLayers( l_leftNeighborRank, l_leftInflow, l_leftOutflow, l_rightNeighborRank, l_rightInflow, l_rightOutflow, l_mpiCol ); exchangeBottomTopGhostLayers( l_bottomNeighborRank, l_bottomInflow, l_bottomOutflow, l_topNeighborRank, l_topInflow, l_topOutflow, l_mpiRow ); // Init fancy progressbar tools::ProgressBar progressBar(l_endSimulation, l_mpiRank); // write the output at time zero tools::Logger::logger.printOutputTime(0); progressBar.update(0.); std::string l_fileName = generateBaseFileName(l_baseName,l_blockPositionX,l_blockPositionY); //boundary size of the ghost layers io::BoundarySize l_boundarySize = {{1, 1, 1, 1}}; #ifdef WRITENETCDF //construct a NetCdfWriter io::NetCdfWriter l_writer( l_fileName, l_wavePropgationBlock.getBathymetry(), l_boundarySize, l_nXLocal, l_nYLocal, l_dX, l_dY, l_originX, l_originY ); #else // Construct a VtkWriter io::VtkWriter l_writer( l_fileName, l_wavePropgationBlock.getBathymetry(), l_boundarySize, l_nXLocal, l_nYLocal, l_dX, l_dY, l_blockPositionX*l_nXLocal, l_blockPositionY*l_nYLocal ); #endif // Write zero time step l_writer.writeTimeStep( l_wavePropgationBlock.getWaterHeight(), l_wavePropgationBlock.getDischarge_hu(), l_wavePropgationBlock.getDischarge_hv(), (float) 0.); /** * Simulation. */ // print the start message and reset the wall clock time progressBar.clear(); tools::Logger::logger.printStartMessage(); tools::Logger::logger.initWallClockTime(time(NULL)); //! simulation time. float l_t = 0.0; progressBar.update(l_t); unsigned int l_iterations = 0; // loop over checkpoints for(int c=1; c<=l_numberOfCheckPoints; c++) { // do time steps until next checkpoint is reached while( l_t < l_checkPoints[c] ) { //reset CPU-Communication clock tools::Logger::logger.resetCpuCommunicationClockToCurrentTime(); // exchange ghost and copy layers exchangeLeftRightGhostLayers( l_leftNeighborRank, l_leftInflow, l_leftOutflow, l_rightNeighborRank, l_rightInflow, l_rightOutflow, l_mpiCol ); exchangeBottomTopGhostLayers( l_bottomNeighborRank, l_bottomInflow, l_bottomOutflow, l_topNeighborRank, l_topInflow, l_topOutflow, l_mpiRow ); // reset the cpu clock tools::Logger::logger.resetCpuClockToCurrentTime(); // set values in ghost cells l_wavePropgationBlock.setGhostLayer(); // compute numerical flux on each edge l_wavePropgationBlock.computeNumericalFluxes(); //! maximum allowed time step width within a block. float l_maxTimeStepWidth = l_wavePropgationBlock.getMaxTimestep(); // update the cpu time in the logger tools::Logger::logger.updateCpuTime(); //! maximum allowed time steps of all blocks float l_maxTimeStepWidthGlobal; // determine smallest time step of all blocks MPI_Allreduce(&l_maxTimeStepWidth, &l_maxTimeStepWidthGlobal, 1, MPI_FLOAT, MPI_MIN, MPI_COMM_WORLD); // reset the cpu time tools::Logger::logger.resetCpuClockToCurrentTime(); // update the cell values l_wavePropgationBlock.updateUnknowns(l_maxTimeStepWidthGlobal); // update the cpu and CPU-communication time in the logger tools::Logger::logger.updateCpuTime(); tools::Logger::logger.updateCpuCommunicationTime(); // update simulation time with time step width. l_t += l_maxTimeStepWidthGlobal; l_iterations++; // print the current simulation time progressBar.clear(); tools::Logger::logger.printSimulationTime(l_t); progressBar.update(l_t); } // print current simulation time progressBar.clear(); tools::Logger::logger.printOutputTime(l_t); progressBar.update(l_t); // write output l_writer.writeTimeStep( l_wavePropgationBlock.getWaterHeight(), l_wavePropgationBlock.getDischarge_hu(), l_wavePropgationBlock.getDischarge_hv(), l_t); } /** * Finalize. */ #ifdef ASAGI // Free ASAGI resources l_scenario.deleteGrids(); #endif progressBar.clear(); // write the statistics message tools::Logger::logger.printStatisticsMessage(); // print the cpu time tools::Logger::logger.printCpuTime("CPU time"); // print CPU + Communication time tools::Logger::logger.printCpuCommunicationTime(); // print the wall clock time (includes plotting) tools::Logger::logger.printWallClockTime(time(NULL)); // printer iteration counter tools::Logger::logger.printIterationsDone(l_iterations); // print the finish message tools::Logger::logger.printFinishMessage(); // finalize MPI execution MPI_Finalize(); return 0; }
/** * Main program for the simulation of dimensionalsplitting. */ int main( int argc, char** argv ) { /** * Initialization. */ // Parse command line parameters tools::Args args; #ifndef READXML args.addOption("grid-size-x", 'x', "Number of cells in x direction"); args.addOption("grid-size-y", 'y', "Number of cells in y direction"); args.addOption("output-basepath", 'o', "Output base file name"); //add Options for Simulation Time and Boundary Condition arguments args.addOption("simulated-time", 't', "Simulation time"); args.addOption("boundary-condition", 'b', "Boundary Condition"); #endif tools::Args::Result ret = args.parse(argc, argv); switch (ret) { case tools::Args::Error: return 1; case tools::Args::Help: return 0; } //! number of grid cells in x- and y-direction. int l_nX, l_nY; //! l_baseName of the plots. std::string l_baseName; int l_simTime; BoundaryType l_boundaryCond; // read command line parameters #ifndef READXML l_nX = args.getArgument<int>("grid-size-x"); l_nY = args.getArgument<int>("grid-size-y"); l_baseName = args.getArgument<std::string>("output-basepath"); //read simulation-time and boundary-condition arguments l_simTime= args.getArgument<int>("simulation-time"); std::string boundaryCondString= args.getArgument<std::string>("boundary-condition"); if(boundaryCondString.compare("WALL")){ l_boundaryCond=WALL; }else if(boundaryCondString.compare("INFLOW")){ l_boundaryCond=INFLOW; }else if(boundaryCondString.compare("CONNECT")){ l_boundaryCond=CONNECT; }else if(boundaryCondString.compare("PASSIVE")){ l_boundaryCond=PASSIVE; }else{//Outflow per default l_boundaryCond=OUTFLOW; } #endif // create a simple artificial scenario //SWE_RadialDamBreakScenario l_scenario; //SWE_ArtificialTsunamiScenario l_scenario; //TsunamiScenario with NetCDF TsunamiScenario l_scenario; l_scenario.simTime=l_simTime; l_scenario.boundaryCond=l_boundaryCond; //! number of checkpoints for visualization (at each checkpoint in time, an output file is written). int l_numberOfCheckPoints = 100; //! size of a single cell in x- and y-direction float l_dX, l_dY; // compute the size of a single cell l_dX = (l_scenario.getBoundaryPos(BND_RIGHT) - l_scenario.getBoundaryPos(BND_LEFT) )/l_nX; l_dY = (l_scenario.getBoundaryPos(BND_TOP) - l_scenario.getBoundaryPos(BND_BOTTOM) )/l_nY; // create a single wave propagation block SWE_DimensionalSplitting l_wavePropgationBlock(l_nX,l_nY,l_dX,l_dY); //! origin of the simulation domain in x- and y-direction float l_originX, l_originY; // get the origin from the scenario l_originX = l_scenario.getBoundaryPos(BND_LEFT); l_originY = l_scenario.getBoundaryPos(BND_BOTTOM); // initialize the wave propagation block l_wavePropgationBlock.initScenario(l_originX, l_originY, l_scenario); //! time when the simulation ends. float l_endSimulation = l_scenario.endSimulation(); //! checkpoints when output files are written. float* l_checkPoints = new float[l_numberOfCheckPoints+1]; // compute the checkpoints in time for(int cp = 0; cp <= l_numberOfCheckPoints; cp++) { l_checkPoints[cp] = cp*(l_endSimulation/l_numberOfCheckPoints); } // Init fancy progressbar //tools::ProgressBar progressBar(l_endSimulation); // write the output at time zero tools::Logger::logger.printOutputTime((float) 0.); //progressBar.update(0.); std::string l_fileName = generateBaseFileName(l_baseName,0,0); //boundary size of the ghost layers io::BoundarySize l_boundarySize = {{1, 1, 1, 1}}; // consturct a VtkWriter io::VtkWriter l_writer( l_fileName, l_wavePropgationBlock.getBathymetry(), l_boundarySize, l_nX, l_nY, l_dX, l_dY ); // Write zero time step l_writer.writeTimeStep( l_wavePropgationBlock.getWaterHeight(), l_wavePropgationBlock.getDischarge_hu(), l_wavePropgationBlock.getDischarge_hv(), (float) 0.); /** * Simulation. */ // print the start message and reset the wall clock time //progressBar.clear(); tools::Logger::logger.printStartMessage(); tools::Logger::logger.initWallClockTime(time(NULL)); //! simulation time. float l_t = 0.0; //progressBar.update(l_t); unsigned int l_iterations = 0; // loop over checkpoints for(int c=1; c<=l_numberOfCheckPoints; c++) { // do time steps until next checkpoint is reached while( l_t < l_checkPoints[c] ) { // set values in ghost cells: l_wavePropgationBlock.setGhostLayer(); // reset the cpu clock tools::Logger::logger.resetClockToCurrentTime("Cpu"); // compute numerical flux on each edge l_wavePropgationBlock.computeNumericalFluxes(); //! maximum allowed time step width. float l_maxTimeStepWidth = l_wavePropgationBlock.getMaxTimestep(); // update the cell values l_wavePropgationBlock.updateUnknowns(l_maxTimeStepWidth); // update the cpu time in the logger tools::Logger::logger.updateTime("Cpu"); // update simulation time with time step width. l_t += l_maxTimeStepWidth; l_iterations++; // print the current simulation time //progressBar.clear(); tools::Logger::logger.printSimulationTime(l_t); //progressBar.update(l_t); } // print current simulation time of the output //progressBar.clear(); tools::Logger::logger.printOutputTime(l_t); //progressBar.update(l_t); // write output l_writer.writeTimeStep( l_wavePropgationBlock.getWaterHeight(), l_wavePropgationBlock.getDischarge_hu(), l_wavePropgationBlock.getDischarge_hv(), l_t); } /** * Finalize. */ // write the statistics message //progressBar.clear(); tools::Logger::logger.printStatisticsMessage(); // print the cpu time tools::Logger::logger.printTime("Cpu", "CPU time"); // print the wall clock time (includes plotting) tools::Logger::logger.printWallClockTime(time(NULL)); // printer iteration counter tools::Logger::logger.printIterationsDone(l_iterations); return 0; }