Skip to content

Commit

Permalink
Merge pull request #1170 from LLNL/bugfix/whitlock/misc_bug_fixes
Browse files Browse the repository at this point in the history
Tiler improvements/fixes
  • Loading branch information
BradWhitlock committed Sep 21, 2023
2 parents 601d2cd + 364f4ac commit d012d0c
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 32 deletions.
45 changes: 26 additions & 19 deletions src/docs/sphinx/blueprint_mesh.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1708,21 +1708,23 @@ main mesh, a boundary mesh, and adjacency sets if the output mesh is to be part
The ``tiled()`` function accepts a Conduit node containing options that influence how the mesh is generated.
If the options contain a ``tile`` node that contains a 2D blueprint topology, the first supplied topology will
be used to override the default tile pattern. The ``reorder`` option indicates the type of point and element
reordering that will be done. Reordering can improve cache-friendliness. The default is to reorder points
and elements, using "kdtree" method. Passing "none" or an empty string will prevent reordering.
The name of the mesh can be given by passing a ``meshname`` option string. Likewise, the name of the boundary
mesh can be supplied using the ``boundarymeshname`` option. The optional ``translate/x`` and ``translate/y``
options determine the tile spacing. If the translation values are not given, they will be determined from
the coordset extents. The output mesh topology will store its integer connectivity information as index_t
by default. The precision of the integer output can turned to int32 by passing a ``datatype`` option containing
the "int", "int32", "integer" strings.

be used to override the default tile pattern. The ``tile`` node may contain additional options.
An important set of options define the left, right, bottom, and top sets of points within the supplied tile
pattern. The values in the ``left`` option identify the list of points that define the left edge of the tile.
These are indices into the coordset and the values should be in consecutive order along the edge. Opposite point
sets must match. In other words, the left and right point sets must contain the same number of points and
they need to proceed along their edges in the same order. The same is true of the bottom and top point sets.
The optional ``translate/x`` and ``translate/y`` options determine the tile spacing. If the translation
values are not given, they will be determined from the coordset extents.

The remaining options described are not part of the ``tile`` node. The ``reorder`` option indicates the
type of point and element reordering that will be done. Reordering can improve cache-friendliness. The
default is to reorder points and elements, using "kdtree" method. Passing "none" or an empty string will
prevent reordering. The name of the mesh can be given by passing a ``meshname`` option string. Likewise,
the name of the boundary mesh can be supplied using the ``boundarymeshname`` option. The output mesh
topology will store its integer connectivity information as index_t by default. The precision of the
integer output can turned to int32 by passing a ``datatype`` option containing the "int", "int32",
"integer" strings.

The ``tiled()`` function also accepts options that simplify the task of generating
mesh domains for a multi-domain dataset. The coordinate extents of the current mesh domain are given using
Expand All @@ -1734,8 +1736,8 @@ This is used to help construct adjacency sets.

.. code:: yaml
# Define the tile topology
tile:
# Define the tile
coordsets:
coords:
type: explicit
Expand All @@ -1749,15 +1751,20 @@ This is used to help construct adjacency sets.
elements:
shape: tri
connectivity: [0,1,4, 0,4,3, 1,2,5, 1,5,4, 3,4,7, 3,7,6, 4,5,8, 4,8,7]
# Define the tile edges
left: [0,3,6]
right: [2,5,8]
bottom: [0,1,2]
top: [6,7,8]
# Optional tile translation
translate:
x: 2.
y: 2.
# Set some options that aid tiling.
reorder: 1
left: [0,3,6]
right: [2,5,8]
bottom: [0,1,2]
top: [6,7,8]
translate:
x: 2.
y: 2.
reorder: kdtree
domain: [0,0,0]
domains: [2,2,2]
extents: [0., 0.5, 0., 0.5, 0., 0.5]
.. figure:: tiled_single.png
:width: 400px
Expand Down
2 changes: 1 addition & 1 deletion src/executables/generate_data/conduit_generate_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
class DomainGenerator
{
public:
virtual ~DomainGenerator() = default;
virtual void generate(int domain[3], conduit::Node &n, conduit::Node &opts) = 0;

void setDims(const int d[3])
Expand Down Expand Up @@ -282,7 +283,6 @@ main(int argc, char *argv[])

MPI_Finalize();
#else
conduit::relay::io::save(n, output + "-inspect.yaml", "yaml");
conduit::relay::io::blueprint::save_mesh(n, output, protocol);
#endif

Expand Down
70 changes: 60 additions & 10 deletions src/libs/blueprint/conduit_blueprint_mesh_examples_tiled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ class Tiler
/// Return the topology (the first one)
const conduit::Node &getTopology() const
{
const conduit::Node &t = m_options.fetch_existing("topologies");
const conduit::Node &t = m_tile.fetch_existing("topologies");
return t[0];
}

Expand All @@ -148,7 +148,7 @@ class Tiler
{
const conduit::Node &t = getTopology();
std::string coordsetName(t.fetch_existing("coordset").as_string());
return m_options.fetch_existing("coordsets/" + coordsetName);
return m_tile.fetch_existing("coordsets/" + coordsetName);
}

/// Return point indices of points along left edge.
Expand All @@ -173,7 +173,8 @@ class Tiler
void addPoints(const double M[3][3],
std::vector<conduit::index_t> &ptids,
std::vector<double> &x,
std::vector<double> &y)
std::vector<double> &y,
std::vector<conduit::index_t> &srcPointId)
{
// Iterate through points in the template and add them if they have
// not been created yet.
Expand All @@ -193,6 +194,8 @@ class Tiler
yc /= h;
x.push_back(xc);
y.push_back(yc);

srcPointId.push_back(i);
}
}
}
Expand Down Expand Up @@ -414,14 +417,14 @@ class Tiler
const conduit::Node &options,
conduit::Node &out) const;
private:
conduit::Node m_options;
conduit::Node m_tile;
double m_width, m_height;
std::vector<conduit::index_t> m_left, m_right, m_bottom, m_top;
std::string meshName, boundaryMeshName;
};

//---------------------------------------------------------------------------
Tiler::Tiler() : m_options(), m_width(0.), m_height(0.),
Tiler::Tiler() : m_tile(), m_width(0.), m_height(0.),
m_left(), m_right(), m_bottom(), m_top(),
meshName("mesh"), boundaryMeshName("boundary")
{
Expand All @@ -437,6 +440,7 @@ Tiler::initialize()
const double x[] = {0., 1., 0., 1.};
const double y[] = {0., 0., 1., 1.};
const conduit::index_t conn[] = {0,1,3,2};
const conduit::index_t color[] = {0};

const conduit::index_t left[] = {0,2};
const conduit::index_t right[] = {1,3};
Expand Down Expand Up @@ -499,6 +503,13 @@ Tiler::initialize()
26,27,32,31
};

const conduit::index_t color[] = {
0, 1, 1, 1, 1, 0,
1, 0, 1, 1, 0, 1,
1, 1, 0, 0, 1, 1,
0, 1, 1, 1, 1, 0
};

const conduit::index_t left[] = {0,5,14,24,28};
const conduit::index_t right[] = {4,8,18,27,32};
const conduit::index_t bottom[] = {0,1,2,3,4};
Expand All @@ -517,6 +528,9 @@ Tiler::initialize()
opts["topologies/tile/elements/connectivity"].set(conn, nelem * 4);
std::vector<conduit::index_t> size(nelem, 4);
opts["topologies/tile/elements/sizes"].set(size.data(), size.size());
opts["fields/color/association"] = "element";
opts["fields/color/topology"] = "tile";
opts["fields/color/values"].set(color, sizeof(color) / sizeof(conduit::index_t));

// Define tile boundary indices.
opts["left"].set(left, sizeof(left) / sizeof(conduit::index_t));
Expand Down Expand Up @@ -554,8 +568,8 @@ Tiler::initialize(const conduit::Node &t)
CONDUIT_ERROR("bottom/top vectors have different lengths.");
}

// Save the tile definition options.
m_options.set(t);
// Save the tile definition.
m_tile.set(t);

// Make sure the coordset is 2D, explicit.
if(conduit::blueprint::mesh::coordset::dims(getCoordset()) != 2)
Expand All @@ -573,7 +587,7 @@ Tiler::initialize(const conduit::Node &t)
}
if(getTopology()["type"].as_string() != "unstructured")
{
CONDUIT_ERROR("The tile topology must be 2D.");
CONDUIT_ERROR("The tile topology must be unstructured.");
}

// Compute the tile extents.
Expand Down Expand Up @@ -611,7 +625,7 @@ Tiler::generate(conduit::index_t nx, conduit::index_t ny, conduit::index_t nz,
const conduit::Node &options)
{
std::vector<double> x, y, z;
std::vector<conduit::index_t> conn, sizes, bconn, bsizes;
std::vector<conduit::index_t> conn, sizes, bconn, bsizes, srcPointIds;
std::vector<int> btype;

// Process any options.
Expand Down Expand Up @@ -704,7 +718,7 @@ Tiler::generate(conduit::index_t nx, conduit::index_t ny, conduit::index_t nz,
current.setPointIds(bottom(), prevY.getPointIds(top()));
}

addPoints(M, current.getPointIds(), x, y);
addPoints(M, current.getPointIds(), x, y, srcPointIds);
M[2][0] += tx;
}
M[2][1] += ty;
Expand Down Expand Up @@ -745,6 +759,7 @@ Tiler::generate(conduit::index_t nx, conduit::index_t ny, conduit::index_t nz,
x.reserve(ptsPerPlane * nplanes);
y.reserve(ptsPerPlane * nplanes);
z.reserve(ptsPerPlane * nplanes);
srcPointIds.reserve(ptsPerPlane * nplanes);
for(conduit::index_t i = 0; i < ptsPerPlane; i++)
z.push_back(origin[2]);
for(conduit::index_t p = 1; p < nplanes; p++)
Expand All @@ -756,6 +771,7 @@ Tiler::generate(conduit::index_t nx, conduit::index_t ny, conduit::index_t nz,
x.push_back(x[i]);
y.push_back(y[i]);
z.push_back(zvalue);
srcPointIds.push_back(srcPointIds[i]);
}
}

Expand Down Expand Up @@ -830,6 +846,40 @@ Tiler::generate(conduit::index_t nx, conduit::index_t ny, conduit::index_t nz,
res["fields/dist/values"].set(dist);
#endif

// If there are any fields on the mesh then replicate them.
if(m_tile.has_child("fields"))
{
// Make source cell ids list.
auto nTileElem = conduit::blueprint::mesh::utils::topology::length(getTopology());
std::vector<conduit::index_t> srcCellIds;
srcCellIds.reserve(nTileElem * nx * ny * std::max(nz, conduit::index_t{1}));
for(conduit::index_t k = 0; k < std::max(nz, conduit::index_t{1}); k++)
for(conduit::index_t j = 0; j < ny; j++)
for(conduit::index_t i = 0; i < nx; i++)
{
for(conduit::index_t ci = 0; ci < nTileElem; ci++)
srcCellIds.push_back(ci);
}

// Make new fields.
const conduit::Node &fields = m_tile.fetch_existing("fields");
for(conduit::index_t fi = 0; fi < fields.number_of_children(); fi++)
{
const conduit::Node &f = fields[fi];
if(f["topology"].as_string() == getTopology().name())
{
conduit::Node &newfields = res["fields"];
conduit::Node &destField = newfields[f.name()];
destField["topology"] = meshName;
destField["association"] = f["association"];
if(f["association"].as_string() == "element")
conduit::blueprint::mesh::utils::slice_field(f["values"], srcCellIds, destField["values"]);
else if(f["association"].as_string() == "vertex")
conduit::blueprint::mesh::utils::slice_field(f["values"], srcPointIds, destField["values"]);
}
}
}

// Reorder the elements unless it was turned off.
std::vector<conduit::index_t> old2NewPoint;
if(reorder)
Expand Down
3 changes: 1 addition & 2 deletions src/libs/blueprint/conduit_blueprint_mpi_mesh_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ MatchQuery::execute()
m_comm);

// Look up a rank that owns a domain.
auto domain_to_rank = [&ntuple_values](const std::vector<int> &allqueries, int d) -> int
auto domain_to_rank = [=](const std::vector<int> &allqueries, int d) -> int
{
for(size_t i = 0; i < allqueries.size(); i += ntuple_values)
{
Expand Down Expand Up @@ -683,7 +683,6 @@ adjset::compare_pointwise(conduit::Node &mesh, const std::string &adjsetName, MP
for(auto dom_ptr : domains)
{
Node &domain = *dom_ptr;
auto domainId = bputils::find_domain_id(domain);

// If the domain has the adjset, make a point mesh of its points
// that we can send to the neighbor.
Expand Down

0 comments on commit d012d0c

Please sign in to comment.