You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
659 lines
26 KiB
659 lines
26 KiB
/*
|
|
* Copyright(C) 1999-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 "exodusII.h" // for ex_inquire, ex_opts, etc
|
|
#include "fmt/ostream.h"
|
|
#include "globals.h" // for ELEM_COMM_MAP, etc
|
|
#include "nem_spread.h" // for NemSpread, etc
|
|
#include "pe_common.h" // for PEX_MAX
|
|
#include "rf_allo.h" // for array_alloc, safe_free
|
|
#include "rf_io_const.h" // for Debug_Flag, Exo_LB_File
|
|
#include "rf_util.h" // for print_line
|
|
#include "sort_utils.h" // for gds_qsort
|
|
#include <cassert>
|
|
#include <cstddef> // for size_t
|
|
#include <cstdio> // for stderr, etc
|
|
#include <cstdlib> // for exit
|
|
#include <string>
|
|
|
|
char **qa_record_ptr, **inf_record_ptr;
|
|
int num_inf_rec = 0, num_qa_rec = 0, length_qa = 0;
|
|
|
|
/****************************************************************************
|
|
****************************************************************************
|
|
****************************************************************************
|
|
* This function reads load-balance information for salsa on a parallel
|
|
* computer.
|
|
*
|
|
* Author: Gary L. Hennigan (1421)
|
|
*---------------------------------------------------------------------------
|
|
* Revision History.
|
|
*
|
|
* Gary Hennigan:
|
|
* 08 November 1993 - Modified scalar version to write information out
|
|
* to the parallel disk array once processed.
|
|
****************************************************************************
|
|
****************************************************************************
|
|
****************************************************************************/
|
|
template void NemSpread<float, int>::load_lb_info();
|
|
template void NemSpread<double, int>::load_lb_info();
|
|
template void NemSpread<float, int64_t>::load_lb_info();
|
|
template void NemSpread<double, int64_t>::load_lb_info();
|
|
|
|
template <typename T, typename INT> void NemSpread<T, INT>::load_lb_info()
|
|
|
|
/*
|
|
* load_lb_info:
|
|
*
|
|
* This function reads and distributes the load balance information.
|
|
* This information is defined as the following scalars, which are specific
|
|
* to each processor:
|
|
*
|
|
* Num_Internal_Nodes
|
|
* Num_Border_Nodes
|
|
* Num_External_Nodes
|
|
* globals.Num_Internal_Elems
|
|
* globals.Num_Border_Elems
|
|
*
|
|
* and the following vectors, also specific to each processor:
|
|
*
|
|
* globals.GNodes [Num_Internal_Nodes+Num_Border_Nodes+Num_External_Nodes]
|
|
* globals.GElems [globals.Num_Internal_Elems+globals.Num_Border_Elems]
|
|
*
|
|
* For the 1 processor case, this routine fills in appropriate values
|
|
* for these quantities.
|
|
*/
|
|
{
|
|
|
|
int lb_exoid = 0;
|
|
INT cmap_max_size = 0;
|
|
char Title[MAX_LINE_LENGTH + 1];
|
|
float version;
|
|
|
|
int cpu_ws = 0;
|
|
|
|
/******************************** START EXECUTION ****************************/
|
|
if (Debug_Flag != 0) {
|
|
fmt::print("\nStart to read in and distribute the load balance info\n");
|
|
}
|
|
|
|
/* Open the Load Balance exoII file for reading */
|
|
|
|
fmt::print("EXODUS II load-balance file: {}\n", Exo_LB_File);
|
|
cpu_ws = io_ws;
|
|
int mode = EX_READ | int64api;
|
|
int iio_ws = 0; // Don't interfere with exodus files; this is the nemesis file.
|
|
if ((lb_exoid = ex_open(Exo_LB_File.c_str(), mode, &cpu_ws, &iio_ws, &version)) == -1) {
|
|
fmt::print(stderr, "[{}] ERROR: Couldn\'t open lb file, {}\n", __func__, Exo_LB_File);
|
|
exit(1);
|
|
}
|
|
|
|
/* Read information about the processor configuration */
|
|
read_proc_init(lb_exoid, Proc_Info, Proc_Ids);
|
|
|
|
/* Allocate space for the counts */
|
|
globals.Num_Internal_Nodes.resize(Proc_Info[2]);
|
|
globals.Num_Border_Nodes.resize(Proc_Info[2]);
|
|
globals.Num_External_Nodes.resize(Proc_Info[2]);
|
|
globals.Num_Internal_Elems.resize(Proc_Info[2]);
|
|
globals.Num_Border_Elems.resize(Proc_Info[2]);
|
|
globals.Num_N_Comm_Maps.resize(Proc_Info[2]);
|
|
globals.Num_E_Comm_Maps.resize(Proc_Info[2]);
|
|
|
|
/* Allocate space for each processor entity */
|
|
globals.GNodes.resize(Proc_Info[2]);
|
|
globals.GElems.resize(Proc_Info[2]);
|
|
globals.Elem_Map.resize(Proc_Info[2]);
|
|
|
|
/* Allocate contiguous space for the pointer vectors on all processors */
|
|
std::vector<INT> Int_Space(1);
|
|
std::vector<INT> Int_Node_Num(Proc_Info[0]);
|
|
std::vector<INT> Bor_Node_Num(Proc_Info[0]);
|
|
std::vector<INT> Ext_Node_Num(Proc_Info[0]);
|
|
std::vector<INT> Int_Elem_Num(Proc_Info[0]);
|
|
std::vector<INT> Bor_Elem_Num(Proc_Info[0]);
|
|
std::vector<INT> Node_Comm_Num(Proc_Info[0]);
|
|
std::vector<INT> Elem_Comm_Num(Proc_Info[0]);
|
|
|
|
/* Read the initial information contained in the load balance file */
|
|
read_lb_init(lb_exoid, Int_Space, Int_Node_Num, Bor_Node_Num, Ext_Node_Num, Int_Elem_Num,
|
|
Bor_Elem_Num, Node_Comm_Num, Elem_Comm_Num, Title);
|
|
|
|
/* Allocate memory for the communication map arrays */
|
|
globals.N_Comm_Map.resize(Proc_Info[2]);
|
|
globals.E_Comm_Map.resize(Proc_Info[2]);
|
|
|
|
for (int iproc = 0; iproc < Proc_Info[2]; iproc++) {
|
|
|
|
/*
|
|
* Error check:
|
|
* Currently a maximum of one nodal communication map and one
|
|
* elemental communication map is supported.
|
|
*/
|
|
if (globals.Num_N_Comm_Maps[iproc] > 1 || globals.Num_E_Comm_Maps[iproc] > 1) {
|
|
fmt::print(stderr,
|
|
"[{}] ERROR. Only 1 nodal and elemental comm map "
|
|
"is supported\n",
|
|
__func__);
|
|
exit(1);
|
|
}
|
|
else {
|
|
/* Always allocate at least one and initialize the counts to 0 */
|
|
globals.N_Comm_Map[iproc].node_cnt = 0;
|
|
globals.E_Comm_Map[iproc].elem_cnt = 0;
|
|
}
|
|
} /* End "for (int iproc=0; iproc <Proc_Info[2]; iproc++)" */
|
|
|
|
/* Set up each processor for the communication map parameters */
|
|
read_cmap_params(lb_exoid,globals.E_Comm_Map, globals.N_Comm_Map, &cmap_max_size);
|
|
|
|
/*
|
|
* loop through the processors, one at a time, to read
|
|
* their load balance information
|
|
*
|
|
* NOTE: From here on there are no provisions for multiple nodal
|
|
* or elemental communication maps.
|
|
*/
|
|
|
|
for (int iproc = 0; iproc < Proc_Info[0]; iproc++) {
|
|
|
|
/* Get the node map for processor "iproc" */
|
|
size_t itotal_nodes = globals.Num_Internal_Nodes[iproc] + globals.Num_Border_Nodes[iproc] +
|
|
globals.Num_External_Nodes[iproc];
|
|
globals.GNodes[iproc].resize(itotal_nodes);
|
|
if (ex_get_processor_node_maps(
|
|
lb_exoid, &globals.GNodes[iproc][0], &globals.GNodes[iproc][Int_Node_Num[iproc]],
|
|
&globals.GNodes[iproc][Int_Node_Num[iproc] + Bor_Node_Num[iproc]], iproc) < 0) {
|
|
fmt::print(stderr, "[{}] ERROR, failed to get node map for Proc {}!\n", __func__, iproc);
|
|
exit(1);
|
|
}
|
|
|
|
/* Get the element map for processor number "iproc" */
|
|
size_t itotal_elems = globals.Num_Internal_Elems[iproc] + globals.Num_Border_Elems[iproc];
|
|
globals.GElems[iproc].resize(itotal_elems);
|
|
globals.Elem_Map[iproc].resize(itotal_elems);
|
|
|
|
if (ex_get_processor_elem_maps(lb_exoid, &globals.GElems[iproc][0],
|
|
&globals.GElems[iproc][Int_Elem_Num[iproc]], iproc) < 0) {
|
|
fmt::print(stderr, "[{}] ERROR, failed to get element map for Proc {}!\n", __func__, iproc);
|
|
exit(1);
|
|
}
|
|
globals.Elem_Map[iproc] = globals.GElems[iproc];
|
|
|
|
if (Node_Comm_Num[iproc] > 0) {
|
|
globals.N_Comm_Map[iproc].node_ids.resize(globals.N_Comm_Map[iproc].node_cnt);
|
|
globals.N_Comm_Map[iproc].proc_ids.resize(globals.N_Comm_Map[iproc].node_cnt);
|
|
|
|
if (ex_get_node_cmap(lb_exoid, globals.N_Comm_Map[iproc].map_id,
|
|
globals.N_Comm_Map[iproc].node_ids.data(),
|
|
globals.N_Comm_Map[iproc].proc_ids.data(), iproc) < 0) {
|
|
/*
|
|
* If there are disconnected mesh pieces, then it is
|
|
* possible that there is no communication between the
|
|
* pieces and there will be no communication maps. Normally
|
|
* this is a problem, so output a warning, but don't abort.
|
|
*/
|
|
fmt::print(stderr, "[{}] WARNING. Failed to get nodal comm map for Proc {}!\n", __func__,
|
|
iproc);
|
|
}
|
|
}
|
|
|
|
if (Elem_Comm_Num[iproc] > 0) {
|
|
globals.E_Comm_Map[iproc].elem_ids.resize(globals.E_Comm_Map[iproc].elem_cnt);
|
|
globals.E_Comm_Map[iproc].side_ids.resize(globals.E_Comm_Map[iproc].elem_cnt);
|
|
globals.E_Comm_Map[iproc].proc_ids.resize(globals.E_Comm_Map[iproc].elem_cnt);
|
|
|
|
if (ex_get_elem_cmap(lb_exoid, globals.E_Comm_Map[iproc].map_id,
|
|
globals.E_Comm_Map[iproc].elem_ids.data(),
|
|
globals.E_Comm_Map[iproc].side_ids.data(),
|
|
globals.E_Comm_Map[iproc].proc_ids.data(), iproc) < 0) {
|
|
fmt::print(stderr, "[{}] ERROR. Failed to get elemental comm map for Proc {}!\n", __func__,
|
|
iproc);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Communicate load balance information to the correct processor
|
|
* - if iproc = Proc_Ids[*] then process the data instead.
|
|
*/
|
|
assert(Proc_Ids[iproc] == iproc);
|
|
|
|
/*
|
|
* Sort the local element numbers in ascending global element numbers.
|
|
* This means that globals.GElems will be monotonic.
|
|
*/
|
|
gds_qsort(globals.GElems[iproc].data(), globals.Num_Internal_Elems[iproc]);
|
|
gds_qsort(globals.Elem_Map[iproc].data(), globals.Num_Internal_Elems[iproc]);
|
|
|
|
/* Check that globals.GNodes is monotonic, from i = 0 to Num_Internal_Nodes */
|
|
#ifdef DEBUG
|
|
assert(check_monot(globals.GNodes[iproc], globals.Num_Internal_Nodes[iproc]));
|
|
|
|
/*
|
|
* Check that globals.GNodes is monotonic, from i = Num_Internal_Nodes to
|
|
* (Num_Internal_Nodes + Num_Border_Nodes)
|
|
*/
|
|
assert(check_monot(&(globals.GNodes[iproc][globals.Num_Internal_Nodes[iproc]]),
|
|
globals.Num_Border_Nodes[iproc]));
|
|
#endif
|
|
}
|
|
|
|
/* Close the load balance file - we are finished with it */
|
|
if (ex_close(lb_exoid) == -1) {
|
|
fmt::print(stderr, "[{}] ERROR: Error in closing load balance file\n", __func__);
|
|
exit(1);
|
|
}
|
|
|
|
/************************* Cleanup and Printout Phase ***********************/
|
|
|
|
if (num_qa_rec > 0) {
|
|
for (int i = 0; i < length_qa; i++) {
|
|
safe_free(reinterpret_cast<void **>(&(qa_record_ptr[i])));
|
|
}
|
|
safe_free(reinterpret_cast<void **>(&qa_record_ptr));
|
|
}
|
|
|
|
if (num_inf_rec > 0) {
|
|
for (int i = 0; i < num_inf_rec; i++) {
|
|
safe_free(reinterpret_cast<void **>(&(inf_record_ptr[i])));
|
|
}
|
|
safe_free(reinterpret_cast<void **>(&inf_record_ptr));
|
|
}
|
|
|
|
for (int iproc = 0; iproc < Proc_Info[2]; iproc++) {
|
|
if (globals.Num_Internal_Nodes[iproc] == 0 && globals.Num_Border_Nodes[iproc] == 0 &&
|
|
globals.Num_External_Nodes[iproc] == 0) {
|
|
fmt::print(stderr, "\n[{}] WARNING, Processor {} has no nodes!\n", __func__, iproc);
|
|
}
|
|
if (globals.Num_Internal_Elems[iproc] == 0 && globals.Num_Border_Elems[iproc] == 0) {
|
|
fmt::print(stderr, "\n[{}] WARNING, Processor {} has no elements!\n", __func__, iproc);
|
|
}
|
|
}
|
|
|
|
/*========================================================================*/
|
|
|
|
if (Debug_Flag != 0) {
|
|
fmt::print("\nFinished distributing load balance info\n");
|
|
}
|
|
|
|
/* Output Detailed timing information for the program */
|
|
/*
|
|
* Print out a Large table of Load Balance Information if the debug_flag
|
|
* setting is large enough
|
|
*/
|
|
|
|
if (Debug_Flag >= 7) {
|
|
fmt::print("\n\n");
|
|
print_line("=", 79);
|
|
for (int iproc = 0; iproc < Proc_Info[2]; iproc++) {
|
|
fmt::print("\n\t***For Processor {}***\n", Proc_Ids[iproc]);
|
|
fmt::print("\tInternal nodes owned by the current processor\n\t");
|
|
for (INT i = 0; i < globals.Num_Internal_Nodes[iproc]; i++) {
|
|
fmt::print(" {}", globals.GNodes[iproc][i]);
|
|
}
|
|
|
|
fmt::print("\n");
|
|
|
|
fmt::print("\tBorder nodes owned by the current processor\n\t");
|
|
for (INT i = 0; i < globals.Num_Border_Nodes[iproc]; i++) {
|
|
fmt::print(" {}", globals.GNodes[iproc][i + globals.Num_Internal_Nodes[iproc]]);
|
|
}
|
|
|
|
fmt::print("\n");
|
|
|
|
if (globals.Num_External_Nodes[iproc] > 0) {
|
|
fmt::print("\tExternal nodes needed by the current processor\n\t");
|
|
for (INT i = 0; i < globals.Num_External_Nodes[iproc]; i++) {
|
|
fmt::print(" {}", globals.GNodes[iproc][i + globals.Num_Internal_Nodes[iproc] +
|
|
globals.Num_Border_Nodes[iproc]]);
|
|
}
|
|
|
|
fmt::print("\n");
|
|
}
|
|
|
|
fmt::print("\tInternal elements owned by the current processor\n\t");
|
|
for (INT i = 0; i < globals.Num_Internal_Elems[iproc]; i++) {
|
|
fmt::print(" {}", globals.GElems[iproc][i]);
|
|
}
|
|
|
|
fmt::print("\n");
|
|
|
|
if (globals.Num_Border_Elems[iproc] > 0) {
|
|
fmt::print("\tBorder elements owned by the current processor\n\t");
|
|
for (INT i = 0; i < globals.Num_Border_Elems[iproc]; i++) {
|
|
fmt::print(" {}", globals.GElems[iproc][i + globals.Num_Internal_Elems[iproc]]);
|
|
}
|
|
|
|
fmt::print("\n");
|
|
}
|
|
|
|
if (globals.Num_N_Comm_Maps[iproc] > 0) {
|
|
fmt::print("\tNodal Comm Map for the current processor\n");
|
|
fmt::print("\t\tnode IDs:");
|
|
for (size_t i = 0; i < globals.N_Comm_Map[iproc].node_cnt; i++) {
|
|
fmt::print(" {}", globals.N_Comm_Map[iproc].node_ids[i]);
|
|
}
|
|
fmt::print("\n\t\tproc IDs:");
|
|
for (size_t i = 0; i < globals.N_Comm_Map[iproc].node_cnt; i++) {
|
|
fmt::print(" {}", globals.N_Comm_Map[iproc].proc_ids[i]);
|
|
}
|
|
|
|
fmt::print("\n");
|
|
}
|
|
|
|
if (globals.Num_E_Comm_Maps[iproc] > 0) {
|
|
fmt::print("\tElemental Comm Map for the current processor\n");
|
|
fmt::print("\t\telement IDs:");
|
|
for (size_t i = 0; i < globals.E_Comm_Map[iproc].elem_cnt; i++) {
|
|
fmt::print(" {}", globals.E_Comm_Map[iproc].elem_ids[i]);
|
|
}
|
|
fmt::print("\n\t\tside IDs:");
|
|
for (size_t i = 0; i < globals.E_Comm_Map[iproc].elem_cnt; i++) {
|
|
fmt::print(" {}", globals.E_Comm_Map[iproc].side_ids[i]);
|
|
}
|
|
fmt::print("\n\t\tproc IDs:");
|
|
for (size_t i = 0; i < globals.E_Comm_Map[iproc].elem_cnt; i++) {
|
|
fmt::print(" {}", globals.E_Comm_Map[iproc].proc_ids[i]);
|
|
}
|
|
|
|
fmt::print("\n");
|
|
}
|
|
}
|
|
fmt::print("\n");
|
|
print_line("=", 79);
|
|
}
|
|
|
|
} /* END of routine load_lb_info () ******************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
|
|
template <typename T, typename INT>
|
|
void NemSpread<T, INT>::read_proc_init(int lb_exoid, std::array<int, 6> &proc_info,
|
|
std::vector<int> &proc_ids)
|
|
|
|
/*----------------------------------------------------------------------------
|
|
* read_proc_init:
|
|
*
|
|
* This function reads information about the processor configuration
|
|
* which the load balance was generated for and makes assignments for each
|
|
* processor.
|
|
*----------------------------------------------------------------------------
|
|
* Variable Glossary (after return):
|
|
*
|
|
* proc_info[0] = # procs, from load balance file
|
|
* proc_info[1] = # procs for, from load balance file
|
|
* proc_info[2] = # procs this processor is responsible for
|
|
* proc_info[3] = # of extra procs
|
|
*
|
|
*/
|
|
{
|
|
char ftype[2];
|
|
if (ex_get_init_info(lb_exoid, &proc_info[0], &proc_info[1], ftype) < 0) {
|
|
fmt::print(stderr, "[{}] ERROR, could not get init info!\n", __func__);
|
|
exit(1);
|
|
}
|
|
|
|
/* Calculate which processor is responsible for what */
|
|
proc_info[2] = proc_info[0];
|
|
proc_ids.resize(proc_info[2]);
|
|
|
|
for (int i1 = 0; i1 < proc_info[2]; i1++) {
|
|
proc_ids[i1] = i1;
|
|
}
|
|
} /* End of read_proc_init() *************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
|
|
template <typename T, typename INT>
|
|
void NemSpread<T, INT>::read_lb_init(int lb_exoid, std::vector<INT> &Int_Space,
|
|
std::vector<INT> &Int_Node_Num, std::vector<INT> &Bor_Node_Num,
|
|
std::vector<INT> &Ext_Node_Num, std::vector<INT> &Int_Elem_Num,
|
|
std::vector<INT> &Bor_Elem_Num,
|
|
std::vector<INT> &Node_Comm_Num,
|
|
std::vector<INT> &Elem_Comm_Num, char * /*Title*/)
|
|
|
|
/*
|
|
* read_lb_init:
|
|
*
|
|
* This function reads the initial information contained in the
|
|
* load balance file
|
|
*
|
|
*
|
|
*/
|
|
{
|
|
/*********************BEGIN EXECUTABLE STATEMENTS****************************/
|
|
|
|
/* Read Set-up information from the load-balance file on Proc 0 */
|
|
|
|
/*
|
|
* If debugging is not on go ahead and report errors from init. This
|
|
* will show version mismatch information by default.
|
|
*/
|
|
int old_opt = 0;
|
|
if (Debug_Flag == 0) {
|
|
old_opt = ex_opts(EX_VERBOSE);
|
|
}
|
|
|
|
/* Read the title of the LB File and about the size of the mesh */
|
|
INT num_nodes;
|
|
INT num_elem;
|
|
INT num_elem_blk;
|
|
INT num_node_sets;
|
|
INT num_side_sets;
|
|
int error = ex_get_init_global(lb_exoid, &num_nodes, &num_elem, &num_elem_blk, &num_node_sets,
|
|
&num_side_sets);
|
|
|
|
check_exodus_error(error, "ex_get_init");
|
|
|
|
if (Debug_Flag == 0) {
|
|
ex_opts(old_opt);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (Debug_Flag >= 2) {
|
|
fmt::print("---------------------------------------------------------\n"
|
|
"\t\tLoad balance file global information\n"
|
|
"---------------------------------------------------------\n"
|
|
"\tNumber of nodes: {}\n"
|
|
"\tNumber of elements: {}\n"
|
|
"\tNumber of element blocks: {}\n"
|
|
"---------------------------------------------------------\n",
|
|
fmt::group_digits(num_nodes), fmt::group_digits(num_elem),
|
|
fmt::group_digits(num_elem_blk));
|
|
}
|
|
#endif
|
|
|
|
/* Cross-check the load balance file info against the mesh info */
|
|
if (((size_t)num_nodes != globals.Num_Node) || ((size_t)num_elem != globals.Num_Elem) ||
|
|
(num_elem_blk != globals.Num_Elem_Blk)) {
|
|
fmt::print(stderr, "[{}] ERROR: Problem dimensions in the LB File don't match with those \
|
|
in mesh file",
|
|
__func__);
|
|
exit(1);
|
|
}
|
|
|
|
/* Read the QA Records */
|
|
num_qa_rec = ex_inquire_int(lb_exoid, EX_INQ_QA);
|
|
if (num_qa_rec > 0) {
|
|
length_qa = 4 * num_qa_rec;
|
|
qa_record_ptr =
|
|
reinterpret_cast<char **>(array_alloc(__FILE__, __LINE__, 1, length_qa, sizeof(char *)));
|
|
for (int i = 0; i < length_qa; i++) {
|
|
qa_record_ptr[i] = reinterpret_cast<char *>(
|
|
array_alloc(__FILE__, __LINE__, 1, (MAX_STR_LENGTH + 1), sizeof(char)));
|
|
}
|
|
error = ex_get_qa(lb_exoid, reinterpret_cast<char *(*)[4]>(&qa_record_ptr[0]));
|
|
check_exodus_error(error, "ex_get_qa");
|
|
}
|
|
|
|
/* Read the Info Records */
|
|
num_inf_rec = ex_inquire_int(lb_exoid, EX_INQ_INFO);
|
|
if (num_inf_rec > 0) {
|
|
inf_record_ptr =
|
|
reinterpret_cast<char **>(array_alloc(__FILE__, __LINE__, 1, num_inf_rec, sizeof(char *)));
|
|
for (int i = 0; i < num_inf_rec; i++) {
|
|
inf_record_ptr[i] = reinterpret_cast<char *>(
|
|
array_alloc(__FILE__, __LINE__, 1, (MAX_LINE_LENGTH + 2), sizeof(char)));
|
|
}
|
|
error = ex_get_info(lb_exoid, inf_record_ptr);
|
|
check_exodus_error(error, "ex_get_info");
|
|
}
|
|
|
|
Int_Space[0] = 0;
|
|
|
|
for (int i = 0; i < Proc_Info[0]; i++) {
|
|
|
|
if (ex_get_loadbal_param(lb_exoid, &Int_Node_Num[i], &Bor_Node_Num[i], &Ext_Node_Num[i],
|
|
&Int_Elem_Num[i], &Bor_Elem_Num[i], &Node_Comm_Num[i],
|
|
&Elem_Comm_Num[i], i) < 0) {
|
|
fmt::print(stderr, "[{}] ERROR, could not get load balance params!\n", __func__);
|
|
exit(1);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (Debug_Flag >= 5) {
|
|
if (i == 0) {
|
|
fmt::print("--------------------------------------------------------\n"
|
|
"\t\tLoad balance parameters as read by Processor 0\n"
|
|
"--------------------------------------------------------\n");
|
|
}
|
|
fmt::print("Read on processor 0 for processor {}\n"
|
|
"\tNumber internal nodes: {}\n"
|
|
"\tNumber border nodes: {}\n"
|
|
"\tNumber external nodes: {}\n"
|
|
"\tNumber internal elements: {}\n"
|
|
"\tNumber border elements: {}\n"
|
|
"\tNumber of nodal comm maps: {}\n"
|
|
"\tNumber of elemental comm maps: {}\n"
|
|
"--------------------------------------------------------\n",
|
|
fmt::group_digits(i), fmt::group_digits(Int_Node_Num[i]),
|
|
fmt::group_digits(Bor_Node_Num[i]), fmt::group_digits(Ext_Node_Num[i]),
|
|
fmt::group_digits(Int_Elem_Num[i]), fmt::group_digits(Bor_Elem_Num[i]),
|
|
fmt::group_digits(Node_Comm_Num[i]), fmt::group_digits(Elem_Comm_Num[i]));
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
Int_Space[0] = PEX_MAX(Int_Space[0], Int_Node_Num[i] + Bor_Node_Num[i] + Ext_Node_Num[i] +
|
|
Int_Elem_Num[i] + Bor_Elem_Num[i]);
|
|
}
|
|
|
|
/* Each processor extracts the information that it needs */
|
|
for (int i = 0; i < Proc_Info[2]; i++) {
|
|
globals.Num_Internal_Nodes[i] = Int_Node_Num[i];
|
|
globals.Num_Border_Nodes[i] = Bor_Node_Num[i];
|
|
globals.Num_External_Nodes[i] = Ext_Node_Num[i];
|
|
globals.Num_Internal_Elems[i] = Int_Elem_Num[i];
|
|
globals.Num_Border_Elems[i] = Bor_Elem_Num[i];
|
|
globals.Num_N_Comm_Maps[i] = Node_Comm_Num[i];
|
|
globals.Num_E_Comm_Maps[i] = Elem_Comm_Num[i];
|
|
}
|
|
|
|
/*
|
|
* Print Out a Summary of the Load Balance Information, as distributed
|
|
* across the processors, for the appropriate value of Debug_Flag
|
|
*/
|
|
if (Debug_Flag >= 3) {
|
|
print_line("=", 79);
|
|
fmt::print("\n\t\tTABLE OF LOAD BALANCE STATISTICS\n\n");
|
|
fmt::print("{}{}\n", "globals. Int_Nodes Bor_Nodes Ext_Nodes",
|
|
" Int_Elems Bor_Elems N_Comm_Maps E_Comm_Maps");
|
|
print_line("-", 79);
|
|
fmt::print("\n");
|
|
for (int i = 0; i < Proc_Info[2]; i++) {
|
|
fmt::print("{:6d} {:6d} {:6d} {:6d} {:6d} {:6d} {:6d} {:6d}\n", Proc_Ids[i],
|
|
globals.Num_Internal_Nodes[i], globals.Num_Border_Nodes[i],
|
|
globals.Num_External_Nodes[i], globals.Num_Internal_Elems[i],
|
|
globals.Num_Border_Elems[i], globals.Num_N_Comm_Maps[i],
|
|
globals.Num_E_Comm_Maps[i]);
|
|
}
|
|
print_line("=", 79);
|
|
fmt::print("\n\n");
|
|
}
|
|
|
|
} /* END of read_lb_init () **************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
|
|
template <typename T, typename INT>
|
|
void NemSpread<T, INT>::read_cmap_params(int lb_exoid,
|
|
std::vector<ELEM_COMM_MAP<INT>> &E_Comm_Map,
|
|
std::vector<NODE_COMM_MAP<INT>> &N_Comm_Map,
|
|
INT *cmap_max_size)
|
|
{
|
|
for (int iproc = 0; iproc < Proc_Info[0]; iproc++) {
|
|
|
|
std::array<INT, 1> node_cm_ids{0};
|
|
std::array<INT, 1> node_cm_cnts{0};
|
|
std::array<INT, 1> elem_cm_ids{0};
|
|
std::array<INT, 1> elem_cm_cnts{0};
|
|
|
|
/* Read the communication map IDs for processor "iproc" */
|
|
if (ex_get_cmap_params(lb_exoid, node_cm_ids.data(), node_cm_cnts.data(), elem_cm_ids.data(),
|
|
elem_cm_cnts.data(), iproc) < 0) {
|
|
fmt::print(stderr, "[{}] ERROR, unable to read communication map params\n", __func__);
|
|
exit(1);
|
|
}
|
|
|
|
N_Comm_Map[iproc].map_id = node_cm_ids[0];
|
|
N_Comm_Map[iproc].node_cnt = node_cm_cnts[0];
|
|
E_Comm_Map[iproc].map_id = elem_cm_ids[0];
|
|
E_Comm_Map[iproc].elem_cnt = elem_cm_cnts[0];
|
|
|
|
INT psum = 2 * node_cm_cnts[0] + 3 * elem_cm_cnts[0];
|
|
*cmap_max_size = std::max(*cmap_max_size, psum);
|
|
}
|
|
|
|
if (Debug_Flag >= 4) {
|
|
print_line("=", 79);
|
|
fmt::print("\t\tCOMMUNICATION MAP INFORMATION\n");
|
|
fmt::print("\t\t largest cmap = {} integers\n", *cmap_max_size);
|
|
print_line("=", 79);
|
|
|
|
int bprnt_n = 0;
|
|
int bprnt_e = 0;
|
|
|
|
for (int i1 = 0; i1 < Proc_Info[2]; i1++) {
|
|
if (globals.Num_N_Comm_Maps[i1] > 0) {
|
|
bprnt_n = 1;
|
|
}
|
|
if (globals.Num_E_Comm_Maps[i1] > 0) {
|
|
bprnt_e = 1;
|
|
}
|
|
}
|
|
|
|
if (bprnt_n > 0) {
|
|
fmt::print("\tFor Proc\tNode Map ID\tNode Count\n");
|
|
fmt::print("\t------------------------------------------------\n");
|
|
for (int iproc = 0; iproc < Proc_Info[2]; iproc++) {
|
|
if (globals.Num_N_Comm_Maps[iproc] > 0) {
|
|
fmt::print("\t {}\t\t {}\t\t {}\n", Proc_Ids[iproc], N_Comm_Map[iproc].map_id,
|
|
N_Comm_Map[iproc].node_cnt);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bprnt_e > 0) {
|
|
fmt::print("\tFor Proc\tElem Map ID\tElem Count\n");
|
|
fmt::print("\t------------------------------------------------\n");
|
|
for (int iproc = 0; iproc < Proc_Info[2]; iproc++) {
|
|
if (globals.Num_E_Comm_Maps[iproc] > 0) {
|
|
fmt::print("\t {}\t\t {}\t\t {}\n", Proc_Ids[iproc], E_Comm_Map[iproc].map_id,
|
|
E_Comm_Map[iproc].elem_cnt);
|
|
}
|
|
}
|
|
}
|
|
|
|
print_line("=", 79);
|
|
}
|
|
|
|
} /* End of read_cmap_params() ***********************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
/*****************************************************************************/
|
|
|