Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify displacement BC interface #1274

Merged
merged 71 commits into from
Dec 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
8e62e9f
Add a method for setting EBCs that takes a Domain, but still with mfe…
btalamini Nov 7, 2024
f757a15
Get the Domain versino of dirichlet bcs working, format still not wha…
btalamini Nov 7, 2024
fecd194
Make new displacement BC function take tensor-valued functor like oth…
btalamini Nov 7, 2024
f409231
Implement applied displacement component using domain
btalamini Nov 7, 2024
60565e0
Remove some of the boundary condition methods (breaks code, will fix)
btalamini Nov 14, 2024
365654a
Change singel component version to use a vector-valued function
btalamini Nov 14, 2024
c9d7cf9
Slim down to 2 domain-based versions, with no repeated code
btalamini Nov 15, 2024
b3c82d7
Updated a few files with new displacement BCs to test drive new methods
btalamini Nov 15, 2024
5b54f60
Fix bug in domains created by Entire{Domain,Boundary} functions
btalamini Nov 17, 2024
a5a1d49
Get the new boundary condition method working
btalamini Nov 17, 2024
b189aec
Update patch test with new BC function and verify it passes
btalamini Nov 17, 2024
4ea9ad1
Update pressure patch tests
btalamini Nov 17, 2024
5adef4a
Merge branch 'develop' into talamini/feature/ebcs_with_domain
btalamini Nov 29, 2024
8a383ff
Update ironing example with new BC methods
btalamini Nov 30, 2024
4f0427c
Undo local changes to Domain class in favor of updates to develop branch
btalamini Nov 30, 2024
ead31ce
Revert local changes to functional in favor of develop updates
btalamini Nov 30, 2024
bad5950
Revert changes to solid mechanics module due to fixes applied to doma…
btalamini Nov 30, 2024
1c83a90
Update tests and examples
btalamini Nov 30, 2024
acd9a47
Clean up one of the earlier tests I updated now that I've learned a f…
btalamini Dec 4, 2024
aa97e94
Remove dead code from unsuccessful attempt at higher-order patch test…
btalamini Dec 4, 2024
cd5b76f
Add convenience method for setting one component to zero
btalamini Dec 5, 2024
a140477
Update examples/tests with new function
btalamini Dec 5, 2024
b7e1a48
Make it possible ot make a domain out of several attributes at once
btalamini Dec 7, 2024
124e625
Make convenience function an overload, so that you can use a single i…
btalamini Dec 7, 2024
0ce1642
Update tests with new way to create domains by sets of attributes
btalamini Dec 7, 2024
f25e4cf
Fix bug in adding of edge elements to domain
btalamini Dec 7, 2024
5bb34b2
Resolve ambiguity between overloaded method to add boundary conditions
btalamini Dec 7, 2024
9e5f8de
Allow multiple components of BC to be set with one call
btalamini Dec 8, 2024
e417a6b
Put in default value to constrain all components if no components arg…
btalamini Dec 8, 2024
3a53d51
Update tests and examples
btalamini Dec 8, 2024
849553a
Provide usage examples in doxygen string
btalamini Dec 8, 2024
07a93d7
Make a couple examples cleaner, but was already correct
btalamini Dec 8, 2024
4a3e293
Remove uses of BCs by dof list since I removed this function
btalamini Dec 8, 2024
820c616
Merge branch 'develop' into talamini/feature/ebcs_with_domain
btalamini Dec 8, 2024
01e9c03
Fix bugs introduced by merge
btalamini Dec 8, 2024
c98b664
Remove unused variable
btalamini Dec 8, 2024
18151c3
Make style
btalamini Dec 8, 2024
f3d9a79
Fix and add docstrings
btalamini Dec 9, 2024
7a38efc
Make style
btalamini Dec 9, 2024
0969851
Fix shadowed variable warning on gcc
btalamini Dec 9, 2024
404c671
Remove obsolete boundary condition method and shift test to use the n…
btalamini Dec 9, 2024
7b35ae6
Fix docstring
btalamini Dec 9, 2024
8fc6809
Fix compilation error in benchmark problem
btalamini Dec 9, 2024
4170c23
Make type-safe component class to replace bitmask
btalamini Dec 12, 2024
44c3368
Update tests/examples
btalamini Dec 13, 2024
0f4e3d7
Update docstrings
btalamini Dec 14, 2024
6caadf9
Make style
btalamini Dec 14, 2024
79ffc88
Fix logical error using domains that are out of scope
btalamini Dec 14, 2024
f1ba34a
Fix comments and commented code that were outdated
btalamini Dec 14, 2024
aab69bd
Fix weird gcc shadowed variable warning that's probably a compiler bug
btalamini Dec 14, 2024
c2c0c80
Fix compilation error
btalamini Dec 14, 2024
0f482f4
Write missing doxygen
btalamini Dec 14, 2024
84e56e1
Make style
btalamini Dec 14, 2024
57381be
Merge branch 'develop' into talamini/feature/ebcs_with_domain
btalamini Dec 14, 2024
d948438
Update cmake files with new header for components class
btalamini Dec 15, 2024
7252f0b
Fix typo in boundary attributes in a test
btalamini Dec 21, 2024
7c595cd
Fix parallel bug in boundary condition dof identification
btalamini Dec 22, 2024
774b458
Merge branch 'develop' into talamini/feature/ebcs_with_domain
btalamini Dec 22, 2024
11dfc6c
Make style
btalamini Dec 22, 2024
bfb1e9b
Remove const qualifier from Domain argument so that temporary objects…
btalamini Dec 22, 2024
3a17a32
Update code that is commented to illustrate a point
btalamini Dec 22, 2024
e5526fe
Make style
btalamini Dec 22, 2024
b23414e
Move parallel correction to Domain class where it really belongs
btalamini Dec 23, 2024
e903009
Move transformation of local dof indices to true dofs to the boundary…
btalamini Dec 23, 2024
d660523
Put back the spatial query boundary condition method, but deprecate it
btalamini Dec 24, 2024
deee454
Make style
btalamini Dec 24, 2024
944f87c
Update test of bc manager, since it takes ldofs instead of tdofs now
btalamini Dec 24, 2024
5ef1c00
Add doxygen keywords to internal function
btalamini Dec 24, 2024
517e52c
Fix indexing bug in spatial search bc method
btalamini Dec 27, 2024
694b99a
Remove test of deprecated function to prevent warning during library …
btalamini Dec 27, 2024
29a1a82
Merge branch 'develop' into talamini/feature/ebcs_with_domain
btalamini Dec 31, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 24 additions & 23 deletions examples/buckling/cylinder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@

#include "mfem.hpp"

#include "serac/numerics/functional/domain.hpp"
#include "serac/physics/boundary_conditions/components.hpp"
#include "serac/physics/solid_mechanics_contact.hpp"
#include "serac/infrastructure/terminator.hpp"
#include "serac/mesh/mesh_utils.hpp"
Expand Down Expand Up @@ -123,15 +125,18 @@ int main(int argc, char* argv[])
serac::StateManager::initialize(datastore, name + "_data");

// Create and refine mesh
std::string filename = SERAC_REPO_DIR "/data/meshes/hollow-cylinder.mesh";
auto mesh = mesh::refineAndDistribute(serac::buildMeshFromFile(filename), serial_refinement, parallel_refinement);
auto& pmesh = serac::StateManager::setMesh(std::move(mesh), mesh_tag);

// Surface attributes for boundary conditions
std::set<int> xneg{2};
std::set<int> xpos{3};
std::set<int> bottom{1};
std::set<int> top{4};
std::string filename = SERAC_REPO_DIR "/data/meshes/hollow-cylinder.mesh";
auto mesh = serac::buildMeshFromFile(filename);
auto refined_mesh = mesh::refineAndDistribute(std::move(mesh), serial_refinement, parallel_refinement);
auto& pmesh = serac::StateManager::setMesh(std::move(refined_mesh), mesh_tag);

// Surfaces for boundary conditions
constexpr int xneg_attr{2};
constexpr int xpos_attr{3};
auto xneg = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(xneg_attr));
auto xpos = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(xpos_attr));
auto bottom = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(1));
auto top = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(4));

// Create solver, either with or without contact
std::unique_ptr<SolidMechanics<p, dim>> solid_solver;
Expand All @@ -145,14 +150,12 @@ int main(int argc, char* argv[])
.type = serac::ContactType::Frictionless,
.penalty = penalty};
auto contact_interaction_id = 0;
solid_contact_solver->addContactInteraction(contact_interaction_id, xpos, xneg, contact_options);
solid_contact_solver->addContactInteraction(contact_interaction_id, {xpos_attr}, {xneg_attr}, contact_options);
solid_solver = std::move(solid_contact_solver);
} else {
solid_solver = std::make_unique<serac::SolidMechanics<p, dim>>(
nonlinear_options, linear_options, serac::solid_mechanics::default_quasistatic_options, name, mesh_tag);
auto domain = serac::Domain::ofBoundaryElements(
StateManager::mesh(mesh_tag), [&](std::vector<vec3>, int attr) { return xpos.find(attr) != xpos.end(); });
solid_solver->setPressure([&](auto&, double t) { return 0.01 * t; }, domain);
solid_solver->setPressure([&](auto&, double t) { return 0.01 * t; }, xpos);
}

// Define a Neo-Hookean material
Expand All @@ -164,19 +167,17 @@ int main(int argc, char* argv[])

// Set up essential boundary conditions
// Bottom of cylinder is fixed
auto clamp = [](const mfem::Vector&, mfem::Vector& u) {
u.SetSize(dim);
u = 0.0;
};
solid_solver->setDisplacementBCs(bottom, clamp);
solid_solver->setFixedBCs(bottom);

// Top of cylinder has prescribed displacement of magnitude in x-z direction
auto compress = [&](const mfem::Vector&, double t, mfem::Vector& u) {
u.SetSize(dim);
u = 0.0;
u(0) = u(2) = -1.5 / std::sqrt(2.0) * t;
auto compress = [&](const serac::tensor<double, dim>, double t) {
serac::tensor<double, dim> u{};
u[0] = u[2] = -1.5 / std::sqrt(2.0) * t;
return u;
};
solid_solver->setDisplacementBCs(top, compress);
solid_solver->setDisplacementBCs(compress, top, Component::X + Component::Z);
solid_solver->setDisplacementBCs(compress, top,
Component::Y); // BT: Would it be better to leave this component free?

// Finalize the data structures
solid_solver->completeSetup();
Expand Down
20 changes: 12 additions & 8 deletions examples/contact/beam_bending.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ int main(int argc, char* argv[])
auto mesh = serac::mesh::refineAndDistribute(serac::buildMeshFromFile(filename), 2, 0);
auto& pmesh = serac::StateManager::setMesh(std::move(mesh), "beam_mesh");

// create boundary domains for boundary conditions
auto support = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(1));
auto applied_displacement_surface = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(6));

serac::LinearSolverOptions linear_options{.linear_solver = serac::LinearSolver::Strumpack, .print_level = 1};
#ifndef MFEM_USE_STRUMPACK
SLIC_INFO_ROOT("Contact requires MFEM built with strumpack.");
Expand Down Expand Up @@ -82,15 +86,15 @@ int main(int argc, char* argv[])
solid_solver.setMaterial(serac::DependsOn<0, 1>{}, mat, whole_mesh);

// Pass the BC information to the solver object
solid_solver.setDisplacementBCs({1}, [](const mfem::Vector&, mfem::Vector& u) {
u.SetSize(dim);
u = 0.0;
});
solid_solver.setDisplacementBCs({6}, [](const mfem::Vector&, double t, mfem::Vector& u) {
u.SetSize(dim);
u = 0.0;
solid_solver.setFixedBCs(support);

auto applied_displacement = [](serac::tensor<double, dim>, double t) {
serac::tensor<double, dim> u{};
u[2] = -0.05 * t;
});
return u;
};

solid_solver.setDisplacementBCs(applied_displacement, applied_displacement_surface);

// Add the contact interaction
auto contact_interaction_id = 0;
Expand Down
20 changes: 11 additions & 9 deletions examples/contact/ironing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "serac/physics/solid_mechanics_contact.hpp"
#include "serac/infrastructure/terminator.hpp"
#include "serac/mesh/mesh_utils.hpp"
#include "serac/numerics/functional/domain.hpp"
#include "serac/physics/state/state_manager.hpp"
#include "serac/physics/materials/parameterized_solid_material.hpp"
#include "serac/serac_config.hpp"
Expand Down Expand Up @@ -83,21 +84,22 @@ int main(int argc, char* argv[])
solid_solver.setMaterial(serac::DependsOn<0, 1>{}, mat, whole_mesh);

// Pass the BC information to the solver object
solid_solver.setDisplacementBCs({5}, [](const mfem::Vector&, mfem::Vector& u) {
u.SetSize(dim);
u = 0.0;
});
solid_solver.setDisplacementBCs({12}, [](const mfem::Vector&, double t, mfem::Vector& u) {
constexpr double init_steps = 2.0;
u.SetSize(dim);
u = 0.0;
serac::Domain bottom_of_substrate = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(5));
solid_solver.setFixedBCs(bottom_of_substrate);

serac::Domain top_of_indenter = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(12));
auto applied_displacement = [](serac::tensor<double, dim>, double t) {
constexpr double init_steps = 2.0;
serac::tensor<double, dim> u{};
if (t <= init_steps + 1.0e-12) {
u[2] = -t * 0.3 / init_steps;
} else {
u[0] = -(t - init_steps) * 0.25;
u[2] = -0.3;
}
});
return u;
};
solid_solver.setDisplacementBCs(applied_displacement, top_of_indenter);

// Add the contact interaction
auto contact_interaction_id = 0;
Expand Down
20 changes: 12 additions & 8 deletions examples/contact/sphere.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "mfem.hpp"

#include "serac/numerics/functional/domain.hpp"
#include "serac/physics/solid_mechanics_contact.hpp"
#include "serac/infrastructure/terminator.hpp"
#include "serac/mesh/mesh_utils.hpp"
Expand Down Expand Up @@ -54,6 +55,9 @@ int main(int argc, char* argv[])
auto mesh = serac::mesh::refineAndDistribute(mfem::Mesh(mesh_ptrs.data(), static_cast<int>(mesh_ptrs.size())), 0, 0);
auto& pmesh = serac::StateManager::setMesh(std::move(mesh), "sphere_mesh");

auto fixed_boundary = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(3));
auto driven_surface = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(12));

serac::LinearSolverOptions linear_options{.linear_solver = serac::LinearSolver::Strumpack, .print_level = 1};
#ifndef MFEM_USE_STRUMPACK
SLIC_INFO_ROOT("Contact requires MFEM built with strumpack.");
Expand All @@ -79,13 +83,10 @@ int main(int argc, char* argv[])
solid_solver.setMaterial(mat, whole_mesh);

// Pass the BC information to the solver object
solid_solver.setDisplacementBCs({3}, [](const mfem::Vector&, mfem::Vector& u) {
u.SetSize(dim);
u = 0.0;
});
solid_solver.setDisplacementBCs({12}, [](const mfem::Vector& x, double t, mfem::Vector& u) {
u.SetSize(dim);
u = 0.0;
solid_solver.setFixedBCs(fixed_boundary);

auto applied_displacement = [](serac::tensor<double, dim> x, double t) {
serac::tensor<double, dim> u{};
if (t <= 3.0 + 1.0e-12) {
u[2] = -t * 0.02;
} else {
Expand All @@ -95,7 +96,10 @@ int main(int argc, char* argv[])
std::sin(M_PI / 40.0 * (t - 3.0)) * (x[0] - 0.5) + (std::cos(M_PI / 40.0 * (t - 3.0)) - 1.0) * (x[1] - 0.5);
u[2] = -0.06;
}
});
return u;
};

solid_solver.setDisplacementBCs(applied_displacement, driven_surface);

// Add the contact interaction
auto contact_interaction_id = 0;
Expand Down
20 changes: 12 additions & 8 deletions examples/contact/twist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "mfem.hpp"

#include "serac/numerics/functional/domain.hpp"
#include "serac/physics/solid_mechanics_contact.hpp"
#include "serac/infrastructure/terminator.hpp"
#include "serac/mesh/mesh_utils.hpp"
Expand Down Expand Up @@ -40,6 +41,9 @@ int main(int argc, char* argv[])
auto mesh = serac::mesh::refineAndDistribute(serac::buildMeshFromFile(filename), 3, 0);
auto& pmesh = serac::StateManager::setMesh(std::move(mesh), "twist_mesh");

auto fixed_surface = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(3));
auto driven_surface = serac::Domain::ofBoundaryElements(pmesh, serac::by_attr<dim>(6));

serac::LinearSolverOptions linear_options{.linear_solver = serac::LinearSolver::Strumpack, .print_level = 1};
#ifndef MFEM_USE_STRUMPACK
SLIC_INFO_ROOT("Contact requires MFEM built with strumpack.");
Expand All @@ -65,13 +69,10 @@ int main(int argc, char* argv[])
solid_solver.setMaterial(mat, whole_mesh);

// Pass the BC information to the solver object
solid_solver.setDisplacementBCs({3}, [](const mfem::Vector&, mfem::Vector& u) {
u.SetSize(dim);
u = 0.0;
});
solid_solver.setDisplacementBCs({6}, [](const mfem::Vector& x, double t, mfem::Vector& u) {
u.SetSize(dim);
u = 0.0;
solid_solver.setFixedBCs(fixed_surface);

auto applied_displacement = [](serac::tensor<double, dim> x, double t) {
serac::tensor<double, dim> u{};
if (t <= 3.0 + 1.0e-12) {
u[2] = -t * 0.02;
} else {
Expand All @@ -81,7 +82,10 @@ int main(int argc, char* argv[])
std::sin(M_PI / 40.0 * (t - 3.0)) * (x[0] - 0.5) + (std::cos(M_PI / 40.0 * (t - 3.0)) - 1.0) * (x[1] - 0.5);
u[2] = -0.06;
}
});
return u;
};

solid_solver.setDisplacementBCs(applied_displacement, driven_surface);

// Add the contact interaction
auto contact_interaction_id = 0;
Expand Down
92 changes: 91 additions & 1 deletion src/serac/numerics/functional/domain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ static Domain domain_of_edges(const mesh_t& mesh, std::function<T> predicate)

if constexpr (d == 2) {
int bdr_id = edge_id_to_bdr_id[i];
int attr = (bdr_id > 0) ? mesh.GetBdrAttribute(bdr_id) : -1;
int attr = (bdr_id >= 0) ? mesh.GetBdrAttribute(bdr_id) : -1;
if (predicate(x, attr)) {
output.addElement(i, i, mfem::Geometry::SEGMENT);
}
Expand Down Expand Up @@ -367,6 +367,94 @@ Domain Domain::ofBoundaryElements(const mesh_t& mesh, std::function<bool(std::ve
return domain_of_boundary_elems<3>(mesh, func);
}

/**
* @brief Get local dofs that are part of a domain, but are owned by a neighboring MPI rank
*
* This is necessary for situations like this:
* Mesh before parallel partition:
* 3 *--------* 2
* | /|
* | / |
* | / |
* | / | <-- Edge we want in Domain
* | / |
* | / |
* | / |
* |/ |
* Node 0 *--------* 1
*
* Possible mesh after partition into two ranks:
*
* RANK 0 RANK 1
*
* 3 *--------* 2 2 o
* | / /|
* | / / |
* | / / |
* | / / | <-- Edge we want in Domain
* | / / |
* | / / |
* | / / |
* |/ / |
* 0 * 0 o--------* 1
*
* *: locally owned node
* o: node owned by a neighbor rank
*
* We create a domain containing the right vertical edge, and then ask for its local dofs.
* The dof list returned for Rank 1 will be correct, containing the local indices for nodes
* 1 and 2. However, the dof list on rank 0 will not be correct without parallel communication.
* It will see that it doesn't own the edge in question, so when it then goes to fetch the
* local dofs on the domain, it will be an empty list.
*
* This function corrects for that, flagging the dofs we want on the domain on each rank
* (using the local_dof_ids list), and then exchanging this info with
* neighboring ranks, so that rank 0 will be told that its local dof for node 2 should be
* added to the list of dofs on the domain.
*
* Before findDomainDofsOnNeighborRanks():
* dof list on Rank 0: {}
* dof list on Rank 1: {1, 2}
*
* After:
* dof list on Rank 0: {2}
* dof list on Rank 1: {1, 2}
*
* Note: the sets will actually contain the ldof indices corresponding to the global (tdof)
* indices in the sets above.
*
* This function operates on the local_dof_ids data in place.
*/
void findDomainDofsOnNeighborRanks(const serac::fes_t* fes, mfem::Array<int>& local_dof_ids)
{
auto par_fes = dynamic_cast<const mfem::ParFiniteElementSpace*>(fes);
// There's no work to do unless the finite element space really is parallel
if (par_fes) {
// As far as I can tell, the parallel communication in mfem only works with
// vector field dof indexing. So we need to get the parallel-correct scalar
// dof ids, we do the following:
// (1) transform scalar ldof ids to vector ldof ids,
// (2) transform the vector ldof ids into a boolean "marker" ldof field
// (3) do our parallel sync, which applies an OR logic operator to the
// boolean fields from all ranks at each dof
// (4) get the ldof indices of the TRUE values of the parallel-correct
// boolean ldof field
// (5) transform the parallel-correct vector ldof ids back to scalar dof ids.
fes->DofsToVDofs(0, local_dof_ids);

mfem::Array<int> local_dof_markers;
mfem::FiniteElementSpace::ListToMarker(local_dof_ids, par_fes->GetVSize(), local_dof_markers, 1);

par_fes->Synchronize(local_dof_markers);

mfem::FiniteElementSpace::MarkerToList(local_dof_markers, local_dof_ids);

for (int i = 0; i < local_dof_ids.Size(); i++) {
local_dof_ids[i] = par_fes->VDofToDof(local_dof_ids[i]);
}
}
}

mfem::Array<int> Domain::dof_list(const serac::fes_t* fes) const
{
std::set<int> dof_ids;
Expand Down Expand Up @@ -432,6 +520,8 @@ mfem::Array<int> Domain::dof_list(const serac::fes_t* fes) const
uniq_dof_ids[i++] = id;
}

findDomainDofsOnNeighborRanks(fes, uniq_dof_ids);

return uniq_dof_ids;
}

Expand Down
11 changes: 9 additions & 2 deletions src/serac/numerics/functional/domain.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,14 @@ Domain operator-(const Domain& a, const Domain& b);
template <int dim>
inline auto by_attr(int value)
{
return [value](std::vector<tensor<double, dim> >, int attr) { return attr == value; };
return [value](std::vector<tensor<double, dim>>, int attr) { return value == attr; };
}

/// @brief convenience predicate for creating domains by a set of attributes
template <int dim>
inline auto by_attr(std::set<int> values)
{
return [values](std::vector<tensor<double, dim>>, int attr) { return values.find(attr) != values.end(); };
}

/**
Expand All @@ -292,7 +299,7 @@ inline std::array<uint32_t, mfem::Geometry::NUM_GEOMETRIES> geometry_counts(cons
* @brief convenience function for computing the arithmetic mean of some list of vectors
*/
template <int dim>
inline tensor<double, dim> average(std::vector<tensor<double, dim> >& positions)
inline tensor<double, dim> average(std::vector<tensor<double, dim>>& positions)
{
tensor<double, dim> total{};
for (auto x : positions) {
Expand Down
1 change: 1 addition & 0 deletions src/serac/numerics/functional/tests/domain_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ TEST(domain, of_edges)

// check that by_attr compiles
Domain d4 = Domain::ofEdges(mesh, by_attr<dim>(3));
EXPECT_EQ(d4.mfem_edge_ids_.size(), 16);

Domain d5 = Domain::ofBoundaryElements(mesh, [](std::vector<vec2>, int) { return true; });
EXPECT_EQ(d5.edge_ids_.size(), 18); // 1x8 row of quads has 18 boundary edges
Expand Down
Loading