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

Let integration entities be specified manually #2269

Merged
merged 160 commits into from
Mar 13, 2023
Merged
Show file tree
Hide file tree
Changes from 142 commits
Commits
Show all changes
160 commits
Select commit Hold shift + click to select a range
f62eecd
Start work
jpdean Jul 12, 2022
29cd3b1
Pass integration entities
jpdean Jul 12, 2022
d3f0369
Change Form constructor
jpdean Jul 12, 2022
06377dc
Restructure integral data
jpdean Jul 12, 2022
ac41b90
Set domains
jpdean Jul 12, 2022
e6d308d
Same for ext and int facets
jpdean Jul 12, 2022
7973ebc
Rename new integral data
jpdean Jul 12, 2022
88024a9
Set default domains
jpdean Jul 13, 2022
5f2b1ef
Start work on converting meshtags
jpdean Jul 13, 2022
be209e8
Fix for parallel
jpdean Jul 13, 2022
d55f0fb
Start work on ext facets
jpdean Jul 13, 2022
f4f0035
Move function
jpdean Jul 13, 2022
63bb4e0
Get ext facets working
jpdean Jul 13, 2022
bcbf256
Same for int facets
jpdean Jul 13, 2022
1a7ec76
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Jul 13, 2022
42e4054
Add comment
jpdean Jul 13, 2022
11ffe8a
Add docs
jpdean Jul 13, 2022
9189bbe
Fix docs
jpdean Jul 13, 2022
2684c93
Remove old code
jpdean Jul 13, 2022
b9b2d6c
Add test
jpdean Jul 13, 2022
a04da11
Fix for parallel
jpdean Jul 13, 2022
b34e33d
Remove cout
jpdean Jul 13, 2022
0b803e9
Add fix for measures without subdomain data
jpdean Jul 13, 2022
c08a044
Flake8
jpdean Jul 13, 2022
30893b0
Bind Form constructor
jpdean Jul 14, 2022
e4ee75b
Bind Form constructor
jpdean Jul 14, 2022
a4f124d
Make const
jpdean Jul 14, 2022
69aa67a
Fix and simplify
jpdean Jul 14, 2022
b406878
Make const reference
jpdean Jul 14, 2022
9ee7f81
Flake8
jpdean Jul 14, 2022
3f25107
Fix consts
jpdean Jul 14, 2022
bbda851
Update test
jpdean Jul 14, 2022
14ea680
Add FIXMEs
jpdean Jul 14, 2022
36806dc
Format
jpdean Jul 14, 2022
09c84e4
Remove commented code
jpdean Jul 14, 2022
93579d0
Remove old code
jpdean Jul 14, 2022
85a048d
Add to test
jpdean Jul 14, 2022
6305ec2
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Jul 14, 2022
090e8b6
Remove duplicate code
jpdean Jul 15, 2022
ab5ffe9
Simplify
jpdean Jul 15, 2022
2dd89a9
Improve test
jpdean Jul 15, 2022
ed23634
Update error message
jpdean Jul 15, 2022
264132d
Remove TODO
jpdean Jul 15, 2022
9d4646d
FIXMEs
jpdean Jul 15, 2022
b53423c
Add NOTE
jpdean Jul 15, 2022
f0bbd89
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Jul 15, 2022
7b6e5b3
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Jul 20, 2022
99e3047
Update docs
jpdean Jul 20, 2022
df6074b
Simplify
jpdean Jul 20, 2022
573bd71
Docs
jpdean Jul 20, 2022
2181476
Docs
jpdean Jul 20, 2022
52d87c8
Specify type explicitly
jpdean Jul 20, 2022
075643e
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Jul 22, 2022
7c9e6e5
Use exterior_facet_indices
jpdean Jul 22, 2022
545628a
Reduce number of map lookups
jpdean Jul 22, 2022
186bcc7
Improve docs
jpdean Jul 22, 2022
52007e1
fix typo
jpdean Jul 22, 2022
67a5ec5
Don't use isinstance
jpdean Jul 22, 2022
bf63ea0
Don't use isinstance
jpdean Jul 22, 2022
bd40d01
Move subdomain data check to dolfinx
jpdean Jul 22, 2022
e817549
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Jul 25, 2022
75662aa
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Aug 7, 2022
5ecf02a
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Aug 8, 2022
5119278
Flake8
jpdean Aug 8, 2022
3769ff8
Flake8
jpdean Aug 8, 2022
014a701
Flake8
jpdean Aug 8, 2022
1212dbb
Mypy
jpdean Aug 8, 2022
0679c47
Use UFL branch
jpdean Aug 8, 2022
8885904
Merge branch 'main' into jpdean/manual_integration_domains_2
jorgensd Sep 6, 2022
0452ee3
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Sep 6, 2022
015a79b
Put on single line
jpdean Sep 6, 2022
c72284f
Merge branch 'jpdean/manual_integration_domains_2' of github.com:FEni…
jpdean Sep 6, 2022
e645f72
Workaround for strange issue
jpdean Sep 6, 2022
a451dad
Flake8
jpdean Sep 6, 2022
fc90a58
Add TODOs
jpdean Sep 7, 2022
48edeae
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Sep 8, 2022
b6c0d71
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Sep 12, 2022
fb27110
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Sep 14, 2022
d46b8a0
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Sep 14, 2022
43bfaf9
Check all subdomain data is the same
jpdean Sep 16, 2022
9fce163
Use UFL branch
jpdean Sep 16, 2022
5c4500e
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Sep 26, 2022
6cb0294
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Sep 29, 2022
908ce88
Pass partitioner
jpdean Oct 6, 2022
cb834c7
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Oct 7, 2022
9626c0b
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Oct 17, 2022
3b214e2
Fix typo
jpdean Oct 17, 2022
e4c60d2
Merge branch 'main' into jpdean/multiple_subdomain_data
jpdean Oct 17, 2022
550ecc2
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Oct 21, 2022
1bee2ab
Merge branch 'main' into jpdean/multiple_subdomain_data
chrisrichardson Oct 21, 2022
d92bff4
Try to use sd.get(domain)
chrisrichardson Oct 21, 2022
aa95e56
Merge branch 'main' into jpdean/multiple_subdomain_data
jpdean Oct 31, 2022
b92737e
Change UFL branch
jpdean Oct 31, 2022
f880cf8
Merge branch 'main' into jpdean/multiple_subdomain_data
chrisrichardson Oct 31, 2022
9e2588a
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Oct 31, 2022
ec221d9
Change UFL branch
jpdean Oct 31, 2022
bc1b8ff
Merge branch 'jpdean/multiple_subdomain_data' into jpdean/manual_inte…
jpdean Oct 31, 2022
c519174
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Oct 31, 2022
d79c677
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Nov 4, 2022
aff551f
Use std::size_t
jpdean Nov 4, 2022
2c347c3
Fix bug
jpdean Nov 4, 2022
2664d63
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Nov 17, 2022
9b36c4a
Some fixes
jpdean Nov 17, 2022
c7508ec
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Nov 23, 2022
e6c1f17
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Nov 24, 2022
a5061de
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Nov 28, 2022
1ebc04d
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Dec 6, 2022
17568c9
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Dec 20, 2022
32ad526
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Dec 23, 2022
c3e51a5
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Dec 29, 2022
f05f947
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Jan 10, 2023
6e1c3cf
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Feb 2, 2023
79b4c6f
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Feb 11, 2023
a576179
Move meshtag to entity code
jpdean Feb 12, 2023
6882ad2
Fix bug
jpdean Feb 12, 2023
20f8e8a
Fix for parallel
jpdean Feb 12, 2023
8574db4
Fix bug where ghost entites were being added to integration domains b…
jpdean Feb 12, 2023
1a058b7
Simplify
jpdean Feb 12, 2023
841acf5
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Feb 12, 2023
43fc676
Merge branch 'main' into jpdean/manual_integration_domains_2
jpdean Feb 27, 2023
7a25d1b
Remove TODO
jpdean Mar 3, 2023
1954109
Remove unused function
jpdean Mar 3, 2023
cabb3e1
Avoid map lookup in tight loop
jpdean Mar 3, 2023
8ce9e00
Rename
jpdean Mar 5, 2023
49417cc
Same for facet integrals
jpdean Mar 5, 2023
6dfbc8e
Merge branch 'main' into jpdean/manual_integration_domains_2_refactoring
jpdean Mar 6, 2023
d8cad21
Remove unnecessary sort
jpdean Mar 6, 2023
33b1822
Remove function
jpdean Mar 6, 2023
b67dc16
Remove function
jpdean Mar 6, 2023
e5e2467
Tidy
jpdean Mar 6, 2023
b0fca68
Remove second map
jpdean Mar 6, 2023
57e8b05
Change type
jpdean Mar 6, 2023
690971c
Update test
jpdean Mar 6, 2023
e00d53f
Tidy
jpdean Mar 6, 2023
0c51fce
Update type
jpdean Mar 6, 2023
f4ef663
Tidy
jpdean Mar 6, 2023
caccd2c
Fix seg fault
jpdean Mar 6, 2023
1baae06
Tidy
jpdean Mar 6, 2023
269c93a
Simplify
jpdean Mar 6, 2023
3a3dfa9
Simplify
jpdean Mar 6, 2023
eb14d81
Small style fixes
garth-wells Mar 7, 2023
788f71f
Readability improvement.
garth-wells Mar 7, 2023
728f125
Merge branch 'main' into jpdean/manual_integration_domains_2
garth-wells Mar 12, 2023
1f1daeb
Improve pybind11 wrapping
garth-wells Mar 12, 2023
8582233
Merge branch 'jpdean/manual_integration_domains_2' of github.com:FEni…
garth-wells Mar 12, 2023
b341781
Avoid copies
garth-wells Mar 12, 2023
7a316fa
Simplifications
garth-wells Mar 12, 2023
dcd66d5
Small fix
garth-wells Mar 12, 2023
d21bd3e
Revert some changes
garth-wells Mar 12, 2023
6fa9f29
Interface fix
garth-wells Mar 12, 2023
5075832
Work on doc
garth-wells Mar 12, 2023
54600f3
Avoid costly allocations
garth-wells Mar 12, 2023
0c8e7b3
Cleanup
garth-wells Mar 12, 2023
c13724f
Use stable sort
garth-wells Mar 12, 2023
7637f5f
Merge branch 'main' into jpdean/manual_integration_domains_2
garth-wells Mar 12, 2023
98bc806
Simplificstions
garth-wells Mar 12, 2023
377876b
Small naming improvements
garth-wells Mar 13, 2023
c6a6e32
Bug fix
garth-wells Mar 13, 2023
f8b6c71
Another fix
garth-wells Mar 13, 2023
088f2d3
Tidy up
garth-wells Mar 13, 2023
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
5 changes: 1 addition & 4 deletions cpp/dolfinx/fem/Form.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,8 @@ class Form
throw std::runtime_error("No mesh could be associated with the Form.");

// Store kernels, looping over integrals by domain type (dimension)
for (auto& integral_type : integrals)
for (auto& [type, kernels] : integrals)
{
const IntegralType type = integral_type.first;
auto& kernels = integral_type.second;

// Loop over integrals kernels and set domains
switch (type)
{
Expand Down
116 changes: 116 additions & 0 deletions cpp/dolfinx/fem/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -266,3 +266,119 @@ fem::FunctionSpace fem::create_functionspace(
mesh->comm(), layout, mesh->topology(), reorder_fn, *element)));
}
//-----------------------------------------------------------------------------
std::vector<std::pair<int, std::vector<std::int32_t>>>
fem::compute_integration_domains(const fem::IntegralType integral_type,
const mesh::MeshTags<int>& meshtags)
{
std::shared_ptr<const mesh::Mesh> mesh = meshtags.mesh();
assert(mesh);
const mesh::Topology& topology = mesh->topology();
const int tdim = topology.dim();
int dim = integral_type == IntegralType::cell ? tdim : tdim - 1;
if (dim != meshtags.dim())
{
throw std::runtime_error("Invalid MeshTags dimension: "
+ std::to_string(meshtags.dim()));
}

std::span<const std::int32_t> entities = meshtags.indices();
std::span<const int> values = meshtags.values();
assert(topology.index_map(dim));
auto it0 = entities.begin();
auto it1 = std::lower_bound(it0, entities.end(),
topology.index_map(dim)->size_local());
entities = entities.first(std::distance(it0, it1));
values = values.first(std::distance(it0, it1));

// Structure to store (meshtag value, entity) pairs
std::vector<std::pair<int, std::vector<std::int32_t>>> value_entity_pairs;
switch (integral_type)
{
// TODO: Sort pairs or use std::iota
case fem::IntegralType::cell:
for (std::size_t i = 0; i < values.size(); ++i)
value_entity_pairs.push_back({values[i], {entities[i]}});
break;
default:
mesh->topology_mutable().create_connectivity(dim, tdim);
mesh->topology_mutable().create_connectivity(tdim, dim);
auto f_to_c = topology.connectivity(tdim - 1, tdim);
assert(f_to_c);
auto c_to_f = topology.connectivity(tdim, tdim - 1);
assert(c_to_f);
switch (integral_type)
{
case IntegralType::exterior_facet:
{
// Create list of tagged boundary facets
const std::vector bfacets = mesh::exterior_facet_indices(topology);
std::vector<std::int32_t> facets;
std::set_intersection(entities.begin(), entities.end(), bfacets.begin(),
bfacets.end(), std::back_inserter(facets));
for (auto f : facets)
{
auto index_it = std::lower_bound(entities.begin(), entities.end(), f);
assert(index_it != entities.end() and *index_it == f);
std::size_t pos = std::distance(entities.begin(), index_it);
auto facet
= impl::get_cell_facet_pairs<1>(f, f_to_c->links(f), *c_to_f);
value_entity_pairs.push_back(
{values[pos], std::vector(facet.begin(), facet.end())});
}
}
break;
case IntegralType::interior_facet:
{
for (std::size_t j = 0; j < entities.size(); ++j)
{
const std::int32_t f = entities[j];
if (f_to_c->num_links(f) == 2)
{
// Get the facet as a pair of (cell, local facet) pairs, one
// for each cell
auto facets
= impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);

value_entity_pairs.push_back(
{values[j], std::vector(facets.begin(), facets.end())});
}
}
}
break;
default:
throw std::runtime_error(
"Cannot compute integration domains. Integral type not supported.");
}
}

// Sort pairs by meshtag value so that entities can be grouped
std::sort(value_entity_pairs.begin(), value_entity_pairs.end());

std::vector<std::pair<int, std::vector<std::int32_t>>> integrals;
// Iterator to mark the start of the group
auto group_start_it = value_entity_pairs.begin();
while (group_start_it != value_entity_pairs.end())
{
// Get iterator pointing to end of group
auto val = group_start_it->first;
auto group_end_it = std::lower_bound(
value_entity_pairs.begin(), value_entity_pairs.end(), val,
[](auto& pair, auto val) { return pair.first <= val; });

// Meshtag value for this group
const int id = group_start_it->first;
// List to store entities in this group
std::vector<std::int32_t> group_entities;
// Loop through entities in this group and add
for (auto it = group_start_it; it != group_end_it; ++it)
{
const auto entity = it->second;
group_entities.insert(group_entities.end(), entity.begin(), entity.end());
}
integrals.push_back({id, std::move(group_entities)});
group_start_it = group_end_it;
}

return integrals;
}
//-----------------------------------------------------------------------------
117 changes: 55 additions & 62 deletions cpp/dolfinx/fem/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,20 @@ using scalar_value_type_t = typename scalar_value_type<T>::value_type;

} // namespace impl

/// @brief Given an integral type and MeshTags compute
/// the entities that should be integrated over.
///
/// I.e., local cell indices for cell integrals, local facets on the
/// boundary as (cell, local facet index) pairs for exterior facet
/// integrals etc.)
///
/// @param[in] integral_type The integral type
/// @param[in] meshtags The meshtags
/// @return A list of (integral id, entities) pairs
std::vector<std::pair<int, std::vector<std::int32_t>>>
compute_integration_domains(const IntegralType integral_type,
const mesh::MeshTags<int>& meshtags);

/// @brief Finite element cell kernel concept.
///
/// Kernel functions that can be passed to an assembler for execution
Expand Down Expand Up @@ -262,14 +276,18 @@ std::vector<std::string> get_constant_names(const ufcx_form& ufcx_form);
/// @param[in] coefficients Coefficient fields in the form
/// @param[in] constants Spatial constants in the form
/// @param[in] subdomains Subdomain markers
/// @pre Each value in `subdomains` must be sorted by domain id
/// @param[in] mesh The mesh of the domain
template <typename T>
Form<T> create_form(
const ufcx_form& ufcx_form,
const std::vector<std::shared_ptr<const FunctionSpace>>& spaces,
const std::vector<std::shared_ptr<const Function<T>>>& coefficients,
const std::vector<std::shared_ptr<const Constant<T>>>& constants,
const std::map<IntegralType, const mesh::MeshTags<int>*>& subdomains,
const std::map<
IntegralType,
std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>&
subdomains,
std::shared_ptr<const mesh::Mesh> mesh = nullptr)
{
if (ufcx_form.rank != (int)spaces.size())
Expand Down Expand Up @@ -370,29 +388,25 @@ Form<T> create_form(
assert(k);

// Build list of entities to assembler over
std::vector<std::int32_t> e;
if (id == -1)
{
// Default kernel, operates on all (owned) cells
assert(topology.index_map(tdim));
std::vector<std::int32_t> e;
e.resize(topology.index_map(tdim)->size_local(), 0);
std::iota(e.begin(), e.end(), 0);
itg.first->second.emplace_back(id, k, std::move(e));
}
else if (sd != subdomains.end() and sd->second)
else if (sd != subdomains.end())
{
assert(topology.index_map(tdim));
std::span<const std::int32_t> entities = sd->second->indices();
std::span<const int> values = sd->second->values();
auto it0 = entities.begin();
auto it1 = std::lower_bound(it0, entities.end(),
topology.index_map(tdim)->size_local());
entities = entities.first(std::distance(it0, it1));
for (std::size_t j = 0; j < entities.size(); ++j)
if (values[j] == id)
e.push_back(entities[j]);
// NOTE: This requires that pairs are sorted
auto it = std::lower_bound(sd->second.begin(), sd->second.end(), id,
[](auto& pair, auto val)
{ return pair.first < val; });
if (it != sd->second.end() && (*it).first == id)
itg.first->second.emplace_back(id, k, (*it).second);
}

itg.first->second.emplace_back(id, k, std::move(e));
if (integral->needs_facet_permutations)
needs_facet_permutations = true;
}
Expand Down Expand Up @@ -432,7 +446,6 @@ Form<T> create_form(
assert(k);

// Build list of entities to assembler over
std::vector<std::int32_t> e;
const std::vector bfacets = mesh::exterior_facet_indices(topology);
auto f_to_c = topology.connectivity(tdim - 1, tdim);
assert(f_to_c);
Expand All @@ -441,6 +454,7 @@ Form<T> create_form(
if (id == -1)
{
// Default kernel, operates on all (owned) exterior facets
std::vector<std::int32_t> e;
e.reserve(2 * bfacets.size());
for (std::int32_t f : bfacets)
{
Expand All @@ -449,34 +463,18 @@ Form<T> create_form(
= impl::get_cell_facet_pairs<1>(f, f_to_c->links(f), *c_to_f);
e.insert(e.end(), pair.begin(), pair.end());
}
itg.first->second.emplace_back(id, k, std::move(e));
}
else if (sd != subdomains.end() and sd->second)
else if (sd != subdomains.end())
{
// Create list of tagged boundary facets
std::span<const std::int32_t> entities = sd->second->indices();
auto it0 = entities.begin();
auto it1 = std::lower_bound(it0, entities.end(),
topology.index_map(tdim - 1)->size_local());
entities = entities.first(std::distance(it0, it1));
std::span<const int> values = sd->second->values();
std::vector<std::int32_t> facets;
std::set_intersection(entities.begin(), entities.end(), bfacets.begin(),
bfacets.end(), std::back_inserter(facets));
for (auto f : facets)
{
auto index_it = std::lower_bound(entities.begin(), entities.end(), f);
assert(index_it != entities.end() and *index_it == f);
std::size_t pos = std::distance(entities.begin(), index_it);
if (values[pos] == id)
{
auto facet
= impl::get_cell_facet_pairs<1>(f, f_to_c->links(f), *c_to_f);
e.insert(e.end(), facet.begin(), facet.end());
}
}
// NOTE: This requires that pairs are sorted
auto it = std::lower_bound(sd->second.begin(), sd->second.end(), id,
[](auto& pair, auto val)
{ return pair.first < val; });
if (it != sd->second.end() && (*it).first == id)
itg.first->second.emplace_back(id, k, (*it).second);
}

itg.first->second.emplace_back(id, k, std::move(e));
if (integral->needs_facet_permutations)
needs_facet_permutations = true;
}
Expand Down Expand Up @@ -516,14 +514,14 @@ Form<T> create_form(
assert(k);

// Build list of entities to assembler over
std::vector<std::int32_t> e;
auto f_to_c = topology.connectivity(tdim - 1, tdim);
assert(f_to_c);
auto c_to_f = topology.connectivity(tdim, tdim - 1);
assert(c_to_f);
if (id == -1)
{
// Default kernel, operates on all (owned) interior facets
std::vector<std::int32_t> e;
assert(topology.index_map(tdim - 1));
std::int32_t num_facets = topology.index_map(tdim - 1)->size_local();
e.reserve(4 * num_facets);
Expand All @@ -536,30 +534,17 @@ Form<T> create_form(
e.insert(e.end(), pairs.begin(), pairs.end());
}
}
itg.first->second.emplace_back(id, k, std::move(e));
}
else if (sd != subdomains.end() and sd->second)
else if (sd != subdomains.end())
{
std::span<const std::int32_t> entities = sd->second->indices();
auto it0 = entities.begin();
auto it1 = std::lower_bound(it0, entities.end(),
topology.index_map(tdim - 1)->size_local());
entities = entities.first(std::distance(it0, it1));
std::span<const int> values = sd->second->values();
for (std::size_t j = 0; j < entities.size(); ++j)
{
const std::int32_t f = entities[j];
if (f_to_c->num_links(f) == 2 and values[j] == id)
{
// Get the facet as a pair of (cell, local facet) pairs, one
// for each cell
auto facets
= impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
e.insert(e.end(), facets.begin(), facets.end());
}
}
auto it = std::lower_bound(sd->second.begin(), sd->second.end(), id,
[](auto& pair, auto val)
{ return pair.first < val; });
if (it != sd->second.end() && (*it).first == id)
itg.first->second.emplace_back(id, k, (*it).second);
}

itg.first->second.emplace_back(id, k, std::move(e));
if (integral->needs_facet_permutations)
needs_facet_permutations = true;
}
Expand All @@ -575,6 +560,7 @@ Form<T> create_form(
/// @param[in] coefficients Coefficient fields in the form (by name)
/// @param[in] constants Spatial constants in the form (by name)
/// @param[in] subdomains Subdomain makers
/// @pre Each value in `subdomains` must be sorted by domain id
/// @param[in] mesh The mesh of the domain. This is required if the form
/// has no arguments, e.g. a functional
/// @return A Form
Expand All @@ -585,7 +571,10 @@ Form<T> create_form(
const std::map<std::string, std::shared_ptr<const Function<T>>>&
coefficients,
const std::map<std::string, std::shared_ptr<const Constant<T>>>& constants,
const std::map<IntegralType, const mesh::MeshTags<int>*>& subdomains,
const std::map<
IntegralType,
std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>&
subdomains,
std::shared_ptr<const mesh::Mesh> mesh = nullptr)
{
// Place coefficients in appropriate order
Expand Down Expand Up @@ -622,6 +611,7 @@ Form<T> create_form(
/// @param[in] coefficients Coefficient fields in the form (by name)
/// @param[in] constants Spatial constants in the form (by name)
/// @param[in] subdomains Subdomain markers
/// @pre Each value in `subdomains` must be sorted by domain id
/// @param[in] mesh The mesh of the domain. This is required if the form
/// has no arguments, e.g. a functional.
/// @return A Form
Expand All @@ -632,7 +622,10 @@ Form<T> create_form(
const std::map<std::string, std::shared_ptr<const Function<T>>>&
coefficients,
const std::map<std::string, std::shared_ptr<const Constant<T>>>& constants,
const std::map<IntegralType, const mesh::MeshTags<int>*>& subdomains,
const std::map<
IntegralType,
std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>&
subdomains,
std::shared_ptr<const mesh::Mesh> mesh = nullptr)
{
ufcx_form* form = fptr();
Expand Down
Loading