Skip to content

Commit

Permalink
fix issue reading meshes of n doms in m files flavor, add several rou…
Browse files Browse the repository at this point in the history
…ndtrip diffs in unit tests
  • Loading branch information
cyrush committed Jan 7, 2021
1 parent 872a429 commit 95d4b2a
Show file tree
Hide file tree
Showing 6 changed files with 356 additions and 86 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -23,6 +23,7 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s
#### Relay
- Added Relay IO Handle mode support for `a` (append) and `t` (truncate). Truncate allows you to overwrite files when the handle is opened. The default is append, which preserves prior IO Handle behavior.
- Added `conduit::relay::io::blueprint::save_mesh` variants, these overwrite existing files (providing relay save semantics) instead of adding mesh data to existing files. We recommend using `save_mesh` for most uses cases, b/c in many cases `write_mesh` to an existing HDF5 file set can fail due to conflicts with the current HDF5 tree.
- Added `conduit::relay::io::blueprint::load_mesh` variants, these reset the passed node before reading mesh data (providing relay load semantics). We recommend using `load_mesh` for most uses cases.
- Added `truncate` option to `conduit::relay::io::blueprint::write_mesh`, this is used by `save_mesh`.
- Improve capture and reporting of I/O errors in `conduit::relay::[mpi::]io::blueprint::{save_mesh|write_mesh}`. Now in the MPI case, If any rank fails to open or write to a file all ranks will throw an exception.

Expand Down
179 changes: 130 additions & 49 deletions src/libs/relay/conduit_relay_io_blueprint.cpp
Expand Up @@ -86,20 +86,73 @@ namespace blueprint
namespace detail
{

//-----------------------------------------------------------------------------
void gen_domain_to_file_map(int num_domains,
int num_files,
Node &out)
{
int num_domains_per_file = num_domains / num_files;
int left_overs = num_domains % num_files;

out["global_domains_per_file"].set(DataType::int32(num_files));
out["global_domain_offsets"].set(DataType::int32(num_files));
out["global_domain_to_file"].set(DataType::int32(num_domains));

int32_array v_domains_per_file = out["global_domains_per_file"].value();
int32_array v_domains_offsets = out["global_domain_offsets"].value();
int32_array v_domain_to_file = out["global_domain_to_file"].value();

// setup domains per file
for(int f=0; f < num_files; f++)
{
v_domains_per_file[f] = num_domains_per_file;
if( f < left_overs)
v_domains_per_file[f]+=1;
}

// prefix sum to calc offsets
for(int f=0; f < num_files; f++)
{
v_domains_offsets[f] = v_domains_per_file[f];
if(f > 0)
v_domains_offsets[f] += v_domains_offsets[f-1];
}

// do assignment, create simple map
int f_idx = 0;
for(int d=0; d < num_domains; d++)
{
if(d >= v_domains_offsets[f_idx])
f_idx++;
v_domain_to_file[d] = f_idx;
}
}


class BlueprintTreePathGenerator
{
public:
//-------------------------------------------------------------------//
BlueprintTreePathGenerator(const std::string &file_pattern,
const std::string &tree_pattern,
index_t num_files,
index_t num_trees,
const std::string &protocol,
const Node &mesh_index)
: m_file_pattern(file_pattern),
m_tree_pattern(tree_pattern),
m_num_files(num_files),
m_num_trees(num_trees),
m_protocol(protocol),
m_mesh_index(mesh_index)
{

// if we need domain to file map, gen it
if( m_num_files > 1 && (m_num_trees != m_num_files) )
{
gen_domain_to_file_map(m_num_trees,
m_num_files,
m_d2f_map);
}
}

//-------------------------------------------------------------------//
Expand Down Expand Up @@ -148,12 +201,25 @@ class BlueprintTreePathGenerator
return pattern;
}


//-------------------------------------------------------------------//
std::string GenerateFilePath(int tree_id) const
{
// for now, we only support 1 tree per file.
int file_id = tree_id;
int file_id = -1;

if(m_num_trees == m_num_files)
{
file_id = tree_id;
}
else if(m_num_files == 1)
{
file_id = 0;
}
else
{
int32_array v_d2f = m_d2f_map["global_domain_to_file"].value();
file_id = v_d2f[tree_id];
}

return Expand(m_file_pattern,file_id);
}

Expand All @@ -172,9 +238,11 @@ class BlueprintTreePathGenerator
private:
std::string m_file_pattern;
std::string m_tree_pattern;
index_t m_num_files;
index_t m_num_trees;
std::string m_protocol;
Node m_mesh_index;

Node m_mesh_index;
Node m_d2f_map;
};

bool global_someone_agrees(bool vote
Expand Down Expand Up @@ -459,49 +527,6 @@ identify_protocol(const std::string &path)
return io_type;
}

//-----------------------------------------------------------------------------
void gen_domain_to_file_map(int num_domains,
int num_files,
Node &out)
{
int num_domains_per_file = num_domains / num_files;
int left_overs = num_domains % num_files;

out["global_domains_per_file"].set(DataType::int32(num_files));
out["global_domain_offsets"].set(DataType::int32(num_files));
out["global_domain_to_file"].set(DataType::int32(num_domains));

int32_array v_domains_per_file = out["global_domains_per_file"].value();
int32_array v_domains_offsets = out["global_domain_offsets"].value();
int32_array v_domain_to_file = out["global_domain_to_file"].value();

// setup domains per file
for(int f=0; f < num_files; f++)
{
v_domains_per_file[f] = num_domains_per_file;
if( f < left_overs)
v_domains_per_file[f]+=1;
}

// prefix sum to calc offsets
for(int f=0; f < num_files; f++)
{
v_domains_offsets[f] = v_domains_per_file[f];
if(f > 0)
v_domains_offsets[f] += v_domains_offsets[f-1];
}

// do assignment, create simple map
int f_idx = 0;
for(int d=0; d < num_domains; d++)
{
if(d >= v_domains_offsets[f_idx])
f_idx++;
v_domain_to_file[d] = f_idx;
}
}



//-----------------------------------------------------------------------------
// -- end conduit::relay::<mpi>::io_blueprint::detail --
Expand Down Expand Up @@ -1356,6 +1381,47 @@ void write_mesh(const Node &mesh,
#endif
}

//-----------------------------------------------------------------------------
// The load semantics, the mesh node is reset before reading.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
void load_mesh(const std::string &root_file_path,
conduit::Node &mesh
CONDUIT_RELAY_COMMUNICATOR_ARG(MPI_Comm mpi_comm))
{
mesh.reset();

#ifdef CONDUIT_RELAY_IO_MPI_ENABLED
read_mesh(root_file_path,
mesh,
mpi_comm);
#else
read_mesh(root_file_path,
mesh);
#endif
}

//-----------------------------------------------------------------------------
void load_mesh(const std::string &root_file_path,
const conduit::Node &opts,
conduit::Node &mesh
CONDUIT_RELAY_COMMUNICATOR_ARG(MPI_Comm mpi_comm))
{
mesh.reset();

#ifdef CONDUIT_RELAY_IO_MPI_ENABLED
read_mesh(root_file_path,
opts,
mesh,
mpi_comm);
#else
read_mesh(root_file_path,
opts,
mesh);
#endif
}

//-----------------------------------------------------------------------------
void read_mesh(const std::string &root_file_path,
Node &mesh
Expand Down Expand Up @@ -1475,10 +1541,25 @@ void read_mesh(const std::string &root_file_path,
data_protocol = root_node["protocol/name"].as_string();
}

// NOTE: future cases (per mesh maps, won't need these)
// but they are needed for all current cases
if(!root_node.has_child("number_of_trees"))
{
CONDUIT_ERROR("Root missing `number_of_trees`");
}

if(!root_node.has_child("number_of_files"))
{
CONDUIT_ERROR("Root missing `number_of_files`");
}

// read all domains for given mesh
int num_domains = root_node["number_of_trees"].to_int();
int num_files = root_node["number_of_files"].to_int();
detail::BlueprintTreePathGenerator gen(root_node["file_pattern"].as_string(),
root_node["tree_pattern"].as_string(),
num_files,
num_domains,
data_protocol,
mesh_index);

Expand Down
22 changes: 22 additions & 0 deletions src/libs/relay/conduit_relay_io_blueprint.hpp
Expand Up @@ -153,6 +153,28 @@ void CONDUIT_RELAY_API read_mesh(const std::string &root_file_path,
const conduit::Node &opts,
conduit::Node &mesh);


//-----------------------------------------------------------------------------
// The load semantics, the mesh node is reset before reading.
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
void CONDUIT_RELAY_API load_mesh(const std::string &root_file_path,
conduit::Node &mesh);


//-----------------------------------------------------------------------------
///
/// opts:
/// mesh_name: "{name}"
/// provide explicit mesh name, for cases where bp data includes
/// more than one mesh.
//-----------------------------------------------------------------------------
void CONDUIT_RELAY_API load_mesh(const std::string &root_file_path,
const conduit::Node &opts,
conduit::Node &mesh);


//-----------------------------------------------------------------------------
}
//-----------------------------------------------------------------------------
Expand Down
18 changes: 18 additions & 0 deletions src/libs/relay/conduit_relay_mpi_io_blueprint.hpp
Expand Up @@ -171,6 +171,24 @@ void CONDUIT_RELAY_API read_mesh(const std::string &root_file_path,
conduit::Node &mesh,
MPI_Comm comm);

//-----------------------------------------------------------------------------
void CONDUIT_RELAY_API load_mesh(const std::string &root_file_path,
conduit::Node &mesh,
MPI_Comm comm);


//-----------------------------------------------------------------------------
///
/// opts:
/// mesh_name: "{name}"
/// provide explicit mesh name, for cases where bp data includes
/// more than one mesh.
//-----------------------------------------------------------------------------
void CONDUIT_RELAY_API load_mesh(const std::string &root_file_path,
const conduit::Node &opts,
conduit::Node &mesh,
MPI_Comm comm);

}
//-----------------------------------------------------------------------------
// -- end conduit::relay::mpi::io::blueprint --
Expand Down

0 comments on commit 95d4b2a

Please sign in to comment.