// Copyright(C) 2021, 2022, 2023 National Technology & Engineering Solutions // of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with // NTESS, the U.S. Government retains certain rights in this software. // // See packages/seacas/LICENSE for details #include #include #include #include #include "add_to_log.h" #include "fmt/chrono.h" #include "fmt/color.h" #include "fmt/ostream.h" #include "time_stamp.h" #include "tokenize.h" #include #include #include #include #include #include #include "Grid.h" #include "ZE_SystemInterface.h" #ifdef SEACAS_HAVE_MPI #include #endif //! \file namespace { Grid define_lattice(SystemInterface &interFace, Ioss::ParallelUtils &pu); } // namespace std::string tsFormat = "[{:%H:%M:%S}]"; unsigned int debug_level = 0; template double zellij(SystemInterface &interFace, INT dummy); int main(int argc, char *argv[]) { #ifdef SEACAS_HAVE_MPI MPI_Init(&argc, &argv); #endif Ioss::ParallelUtils pu{}; int my_rank = pu.parallel_rank(); try { if (my_rank == 0) { SystemInterface::show_version(); #ifdef SEACAS_HAVE_MPI fmt::print("\tParallel Capability Enabled.\n"); #else fmt::print("\tParallel Capability Not Enabled.\n"); #endif } Ioss::Init::Initializer io; SystemInterface interFace(my_rank); bool ok = interFace.parse_options(argc, argv); if (!ok) { fmt::print(stderr, fmt::fg(fmt::color::red), "\nERROR: Problems parsing command line arguments.\n\n"); exit(EXIT_FAILURE); } debug_level = interFace.debug(); if (debug_level & 1) { ex_opts(EX_VERBOSE | EX_DEBUG); } else { ex_opts(0); } double time = 0.0; if (interFace.ints32bit()) { time = zellij(interFace, 0); } else { time = zellij(interFace, static_cast(0)); } if (my_rank == 0) { fmt::print("\n Zellij execution successful.\n"); add_to_log(argv[0], time); } #ifdef SEACAS_HAVE_MPI MPI_Finalize(); #endif } catch (std::exception &e) { fmt::print(stderr, fmt::fg(fmt::color::red), "ERROR: Standard exception: {}\n", e.what()); } } template double zellij(SystemInterface &interFace, INT /*dummy*/) { double begin = Ioss::Utils::timer(); Ioss::ParallelUtils pu{}; if (debug_level & 2) { fmt::print(stderr, "{} Begin Execution\n", time_stamp(tsFormat)); } auto grid = define_lattice(interFace, pu); grid.generate_sidesets(); grid.set_coordinate_offsets(); grid.decompose(interFace.decomp_method()); if (debug_level & 2) { fmt::print(stderr, "{} Lattice Decomposed\n", time_stamp(tsFormat)); } // All unit cells have been mapped into the IxJ grid, now calculate all node / element offsets // and the global node and element counts... // // Iterate through the grid starting with (0,0) and accumulate node and element counts... grid.process(interFace, (INT)0); /*************************************************************************/ // EXIT program if (debug_level & 2) { fmt::print(stderr, "{} Execution Complete\n", time_stamp(tsFormat)); } double end = Ioss::Utils::timer(); double hwm = (double)Ioss::MemoryUtils::get_hwm_memory_info() / 1024.0 / 1024.0; if (pu.parallel_rank() == 0) { fmt::print("\n Total Execution Time = {:.5} seconds.\n", end - begin); fmt::print(" High-Water Memory Use = {:.3} MiBytes.\n", hwm); } return (end - begin); } namespace { Grid define_lattice(SystemInterface &interFace, Ioss::ParallelUtils &pu) { int my_rank = pu.parallel_rank(); Grid grid(interFace); if (debug_level & 2) { pu.progress("Defining Unit Cells..."); } std::string filename = interFace.lattice(); std::ifstream input(filename, std::ios::in); if (!input.is_open()) { fmt::print(stderr, fmt::fg(fmt::color::red), "\nERROR: Could not open/access lattice file '{}'\n", filename); exit(EXIT_FAILURE); } bool in_dictionary{false}; bool in_lattice{false}; std::string line; while (getline(input, line)) { if (line.empty()) { continue; } auto tokens = Ioss::tokenize(line, " "); if (tokens[0] == "BEGIN_DICTIONARY") { SMART_ASSERT(!in_lattice && !in_dictionary); in_dictionary = true; } else if (tokens[0] == "END_DICTIONARY") { SMART_ASSERT(!in_lattice && in_dictionary); in_dictionary = false; if (debug_level & 2) { pu.progress("Unit Cells Defined..."); } } else if (in_dictionary) { if (tokens.size() != 2) { fmt::print(stderr, fmt::fg(fmt::color::red), "\nERROR: There are {} entries on a lattice dictionary line; there should be " "only 2:\n\t'{}'.\n\n", tokens.size(), line); exit(EXIT_FAILURE); } grid.add_unit_cell(tokens[0], tokens[1], interFace.ints32bit()); } else if (tokens[0] == "BEGIN_LATTICE") { SMART_ASSERT(!in_lattice && !in_dictionary); in_lattice = true; break; } } if (!in_lattice) { fmt::print( stderr, fmt::fg(fmt::color::red), "\nERROR: Reached end of input file without finding a 'BEGIN_LATTICE' command\n\n"); exit(EXIT_FAILURE); } // Tokenize line to get I J K size of lattice auto tokens = Ioss::tokenize(line, " "); SMART_ASSERT(tokens[0] == "BEGIN_LATTICE")(tokens[0])(line); if (tokens.size() != 4) { fmt::print(stderr, fmt::fg(fmt::color::red), "\nERROR: The 'BEGIN_LATTICE' line has incorrect syntax. It should be " "'BEGIN_LATTICE I J K'\n" "\tThe line was '{}'\n\n", line); exit(EXIT_FAILURE); } SMART_ASSERT(tokens.size() == 4)(tokens.size())(line); int II = std::stoi(tokens[1]); int JJ = std::stoi(tokens[2]); int KK = std::stoi(tokens[3]); SMART_ASSERT(KK == 1); if (interFace.repeat() > 1) { II *= interFace.repeat(); JJ *= interFace.repeat(); } grid.set_extent(II, JJ, KK); grid.handle_file_count(); if (my_rank == 0) { fmt::print("\n Lattice:\tUnit Cells: {},\tGrid Size: {} x {} x {}\n", fmt::group_digits(grid.unit_cells().size()), fmt::group_digits(II), fmt::group_digits(JJ), fmt::group_digits(KK)); } if (interFace.ranks() > 1) { fmt::print(" \t[{}] Ranks: {}, Outputting {} ranks starting at rank {}.\n", my_rank, fmt::group_digits(interFace.ranks()), fmt::group_digits(interFace.rank_count()), fmt::group_digits(interFace.start_rank())); } // Now process the lattice portion of the lattice file... size_t row{0}; while (getline(input, line)) { if (line.empty()) { continue; } tokens = Ioss::tokenize(line, " "); if (tokens[0] == "END_LATTICE") { SMART_ASSERT(in_lattice && !in_dictionary); in_lattice = false; // Check row count to make sure matches 'J' size of lattice if (row != grid.JJ()) { fmt::print(stderr, fmt::fg(fmt::color::red), "\nERROR: Only {} rows of the {} x {} lattice were defined.\n\n", row, II, JJ); exit(EXIT_FAILURE); } break; } else if (in_lattice) { // TODO: Currently assumes that each row in the lattice is defined on a single row; // This will need to be relaxed since a lattice of 5000x5000 would result in // lines that are too long and would be easier to split a row over multiple lines... if (tokens.size() * interFace.repeat() != grid.II()) { fmt::print( stderr, fmt::fg(fmt::color::red), "\nERROR: Line {} of the lattice definition has {} entries. It should have {}.\n\n", row + 1, tokens.size() * interFace.repeat(), grid.II()); exit(EXIT_FAILURE); } if (row >= grid.JJ()) { fmt::print(stderr, fmt::fg(fmt::color::red), "\nERROR: There are too many rows in the lattice definition. The lattice is " "{} x {}.\n\n", grid.II(), grid.JJ()); exit(EXIT_FAILURE); } if (tokens.size() * interFace.repeat() != grid.II()) { fmt::print(stderr, fmt::fg(fmt::color::red), "\nERROR: In row {}, there is an incorrect number of entries. There should " "be {}, but found {}.\n", row + 1, grid.II(), tokens.size() * interFace.repeat()); exit(EXIT_FAILURE); } auto repeat = interFace.repeat(); for (int j = 0; j < repeat; j++) { size_t col = 0; for (auto &key : tokens) { for (int i = 0; i < repeat; i++) { if (!grid.initialize(col++, row, key)) { fmt::print( stderr, fmt::fg(fmt::color::red), "\nERROR: In row {}, column {}, the lattice specifies a unit cell ({}) that " "has not been defined.\n\n", row + 1, col + 1, key); exit(EXIT_FAILURE); } } } row++; } } } if (debug_level & 2) { fmt::print(stderr, "{} Lattice Defined\n", time_stamp(tsFormat)); } return grid; } } // namespace