Skip to content

Commit

Permalink
Merge pull request #1263 from LLNL/bugfix/whitlock/fix_mcarray_single…
Browse files Browse the repository at this point in the history
…_component_partition

Fix single component mcarray partitioning.
  • Loading branch information
BradWhitlock authored Mar 15, 2024
2 parents 494d2eb + bc1761a commit f195235
Show file tree
Hide file tree
Showing 2 changed files with 96 additions and 20 deletions.
41 changes: 31 additions & 10 deletions src/libs/blueprint/conduit_blueprint_mesh_partition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8642,6 +8642,18 @@ namespace fields
{

//-------------------------------------------------------------------------
/**
@brief Determine an appropriate schema to hold data based on the input.

@param in The input node, which should be field "values" node.
@param ntuples The number of tuples in the input node.
@param[out] out_ncomps The number of components detected in the input field.
@param[out] out_schema The schema to use when creating the output node, if
that needs to be done.

@note The out_ncomps parameter is 0 for scalars and 1 or more for vectors.
This way we can tell scalars from vectors down the line.
*/
static void
determine_schema(const Node &in,
const index_t ntuples, index_t &out_ncomps,
Expand Down Expand Up @@ -8714,7 +8726,7 @@ determine_schema(const Node &in,
}
else
{
out_ncomps = 1;
out_ncomps = 0;
out_schema.set(DataType(in.dtype().id(), ntuples));
}
}
Expand Down Expand Up @@ -8776,13 +8788,16 @@ map_vertex_field(const std::vector<const Node*> &in_nodes,
// Most likely, if we're mapping back, the original mesh contained the
// field we're mapping in the first place. We don't want to totally reset in
// case that field points to external data.
if(total_storage_size(out_node) != (num_vertices * ncomps))
const index_t detected_size = total_storage_size(out_node);
const index_t actual_ncomps = std::max(ncomps, static_cast<index_t>(1));
const index_t expected_size = num_vertices * actual_ncomps;
if(detected_size != expected_size)
{
out_node.reset();
out_node.set(out_schema);

#if defined(CONDUIT_DEBUG_PARTITIONER_MAPBACK)
std::cout << out_node.path() << ": resetting to hold " << num_vertices << "*" << ncomps << " values." << std::endl;
std::cout << out_node.path() << ": resetting to hold " << num_vertices << "*" << actual_ncomps << " values." << std::endl;
//out_schema.print();
//out_node.print();
#endif
Expand All @@ -8795,7 +8810,7 @@ map_vertex_field(const std::vector<const Node*> &in_nodes,
#endif

const index_t npmaps = (index_t)pointmaps.size();
if(ncomps > 1)
if(ncomps > 0)
{
for(index_t fi = 0; fi < npmaps; fi++)
{
Expand Down Expand Up @@ -8870,13 +8885,16 @@ map_vertex_field(const std::vector<const Node*> &in_nodes,
// Most likely, if we're mapping back, the original mesh contained the
// field we're mapping in the first place. We don't want to totally reset in
// case that field points to external data.
if(total_storage_size(out_node) != (num_vertices * ncomps))
const index_t detected_size = total_storage_size(out_node);
const index_t actual_ncomps = std::max(ncomps, static_cast<index_t>(1));
const index_t expected_size = num_vertices * actual_ncomps;
if(detected_size != expected_size)
{
out_node.reset();
out_node.set(out_schema);

#if defined(CONDUIT_DEBUG_PARTITIONER_MAPBACK)
std::cout << out_node.path() << ": resetting to hold " << num_vertices << "*" << ncomps << " values." << std::endl;
std::cout << out_node.path() << ": resetting to hold " << num_vertices << "*" << actual_ncomps << " values." << std::endl;
//out_schema.print();
//out_node.print();
#endif
Expand All @@ -8888,7 +8906,7 @@ map_vertex_field(const std::vector<const Node*> &in_nodes,
}
#endif

if(ncomps > 1)
if(ncomps > 0)
{
for(index_t i = 0; i < num_vertices; i++)
{
Expand Down Expand Up @@ -8961,13 +8979,16 @@ map_element_field(const std::vector<const Node*> &in_nodes,
// Most likely, if we're mapping back, the original mesh contained the
// field we're mapping in the first place. We don't want to totally reset in
// case that field points to external data.
if(total_storage_size(out_node) != (nelements * ncomps))
const index_t detected_size = total_storage_size(out_node);
const index_t actual_ncomps = std::max(ncomps, static_cast<index_t>(1));
const index_t expected_size = nelements * actual_ncomps;
if(detected_size != expected_size)
{
out_node.reset();
out_node.set(out_schema);

#ifdef CONDUIT_DEBUG_PARTITIONER_MAPBACK
std::cout << out_node.path() << ": resetting to hold " << nelements << "*" << ncomps << " values." << std::endl;
std::cout << out_node.path() << ": resetting to hold " << nelements << "*" << actual_ncomps << " values." << std::endl;
//out_schema.print();
//out_node.print();
#endif
Expand All @@ -8979,7 +9000,7 @@ map_element_field(const std::vector<const Node*> &in_nodes,
}
#endif

if(ncomps > 1)
if(ncomps > 0)
{
for(index_t out_idx = 0; out_idx < nelements; out_idx++)
{
Expand Down
75 changes: 65 additions & 10 deletions src/tests/blueprint/t_blueprint_mesh_partition.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2706,19 +2706,20 @@ TEST(conduit_blueprint_mesh_partition, generate_boundary_partition)
}

//-----------------------------------------------------------------------------
TEST(conduit_blueprint_mesh_partition, map_back_set_external)
std::vector<double> blend(double x0, double x1, int n)
{
auto blend = [](double x0, double x1, int n)
std::vector<double> values(n);
for(int i = 0; i < n; i++)
{
std::vector<double> values(n);
for(int i = 0; i < n; i++)
{
double t = static_cast<double>(i) / static_cast<double>(n - 1);
values[i] = (1. - t) * x0 + t * x1;
}
return values;
};
double t = static_cast<double>(i) / static_cast<double>(n - 1);
values[i] = (1. - t) * x0 + t * x1;
}
return values;
}

//-----------------------------------------------------------------------------
TEST(conduit_blueprint_mesh_partition, map_back_set_external)
{
#define F_XYC(X,Y,C) (static_cast<double>((C) + 1) * sqrt((X)*(X) + (Y)*(Y)))

auto compute_nodal_field = [](conduit::Node &mesh, conduit::Node &f)
Expand Down Expand Up @@ -2938,3 +2939,57 @@ TEST(conduit_blueprint_mesh_partition, map_back_set_external)
}
#undef F_XYC
}

//-----------------------------------------------------------------------------
TEST(conduit_blueprint_mesh_partition, partition_single_group)
{
// This test is designed to make sure that we can send an mcarray with a single
// component through partitioning when the partitioner causes domain recombining.
// There was a problem where this was not quite working due to the mcarray being
// treated as a scalar (had the wrong schema).
const double extents[3][4] = {{0.,1., 0., 1.},{1.,2., 0., 1.},{0.,2., 1., 2.}};
constexpr int dims[3][2] = {{5,5}, {5,5}, {9,5}};

conduit::Node mesh;
for(int d = 0; d < 3; d++)
{
char name[32];
sprintf(name, "domain_%05d", d);
conduit::Node &dom = mesh[name];
const int nnodes = dims[d][0] * dims[d][1];

dom["coordsets/coords/type"] = "rectilinear";
dom["coordsets/coords/values/x"].set(blend(extents[d][0], extents[d][1], dims[d][0]));
dom["coordsets/coords/values/y"].set(blend(extents[d][2], extents[d][3], dims[d][1]));

dom["topologies/main/type"] = "rectilinear";
dom["topologies/main/coordset"] = "coords";

dom["state/cycle"] = 123;
dom["state/domain_id"] = d;

// Make a mcarray with 1 component. We'll send this through partition to the part mesh
// where it won't exist but will need to be created, testing the partitioner's vector vs
// scalar logic for 1 component.
dom["fields/single_group/topology"] = "main";
dom["fields/single_group/association"] = "vertex";
dom["fields/single_group/values/group0"].set(conduit::DataType::int32(nnodes));
int *sg = dom["fields/single_group/values/group0"].as_int_ptr();
std::iota(sg, sg + nnodes, 0);
}

// Repartition the mesh from 3 domains into 2 domains.
conduit::Node part, options;
options["target"] = 2;
options["mapping"] = 1;
conduit::blueprint::mesh::partition(mesh, options, part);

// Check the part mesh.
EXPECT_EQ(part.number_of_children(), 2);
for(conduit::index_t d = 0; d < part.number_of_children(); d++)
{
conduit::Node &dom = part[d];
EXPECT_TRUE(dom.has_path("fields/single_group/values/group0"));
EXPECT_EQ(dom.fetch_existing("fields/single_group/values").number_of_children(), 1);
}
}

0 comments on commit f195235

Please sign in to comment.