Skip to content

Vertex integrals #3726

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

Open
wants to merge 43 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
fa17cb9
sketch out
schnellerhase May 9, 2025
0a36e2d
Working rank 0 assembly
schnellerhase May 10, 2025
71d2ebf
Move urls into environment file -> fork support
schnellerhase May 10, 2025
78e310c
Switch ffcx reference branch
schnellerhase May 10, 2025
6124269
Missed one
schnellerhase May 10, 2025
25ebace
Loop over forms
schnellerhase May 10, 2025
5d5329e
Domain marker support
schnellerhase May 10, 2025
a2d78c8
Missed forms.py
schnellerhase May 10, 2025
b72fa07
Remove python match
schnellerhase May 10, 2025
dffa202
Tidy compute_integration_domains
schnellerhase May 10, 2025
105fdab
Debug partitioned domain
schnellerhase May 10, 2025
5210a13
Format
schnellerhase May 10, 2025
64353e0
Simplify test
schnellerhase May 10, 2025
1e34560
Try with new line in .env
schnellerhase May 10, 2025
57ced5d
Vector assembly
schnellerhase May 10, 2025
cfcdecf
Fix sign
schnellerhase May 11, 2025
575fbb5
Explicit clone in oneapi
schnellerhase May 11, 2025
01eff1a
ANother
schnellerhase May 11, 2025
dbc7e0e
Tidy up
schnellerhase May 11, 2025
b5aa433
Coefficient packing
schnellerhase May 11, 2025
51365b5
deactivate c interface install
schnellerhase May 11, 2025
eca4568
Debug oneapi
schnellerhase May 11, 2025
d602ee0
Merge branch 'main' into point_source
schnellerhase May 11, 2025
6ce1f1b
Fix assertions and add non constant coefficient test
schnellerhase May 12, 2025
368fdfa
Merge branch 'main' into point_source
schnellerhase May 16, 2025
aee26a7
Central extract kernel
schnellerhase May 16, 2025
1507fa5
Use has_complex_ufcx_kernels instead of macro
schnellerhase May 16, 2025
ddd3004
Tidy casting
schnellerhase May 16, 2025
3b93b69
Env: repo + ref
schnellerhase May 16, 2025
263fff5
CI done?
schnellerhase May 16, 2025
27f02a5
Add docs
schnellerhase May 16, 2025
0cd5444
Add space
schnellerhase May 16, 2025
fbb595d
Tidy up packing code duplication
schnellerhase May 16, 2025
42273ef
kern_t template types
schnellerhase May 16, 2025
1cd3d37
format
schnellerhase May 16, 2025
10ddac2
capture
schnellerhase May 16, 2025
944b5b6
Apply suggestions from code review
schnellerhase May 16, 2025
8c4e7be
Ruff
schnellerhase May 16, 2025
f61acce
Parametrize over dtype
schnellerhase May 16, 2025
a539295
Debug: test without rank 1
schnellerhase May 17, 2025
dc3c8c7
Fix tolerances
schnellerhase May 17, 2025
e91624a
Reactivate rank1
schnellerhase May 17, 2025
eec970d
Merge branch 'main' into point_source
schnellerhase May 27, 2025
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
37 changes: 18 additions & 19 deletions .github/workflows/ccpp.yml
Original file line number Diff line number Diff line change
Expand Up @@ -111,15 +111,15 @@ jobs:
- name: Install FEniCS Python components (default branches/tags)
if: github.event_name != 'workflow_dispatch'
run: |
pip install git+https://github.com/fenics/ufl.git@${{ env.ufl_ref }}
pip install git+https://github.com/fenics/basix.git@${{ env.basix_ref }}
pip install git+https://github.com/fenics/ffcx.git@${{ env.ffcx_ref }}
pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}
- name: Install FEniCS Python components
if: github.event_name == 'workflow_dispatch'
run: |
pip install git+https://github.com/FEniCS/ufl.git@${{ env.ufl_ref }}
pip install git+https://github.com/FEniCS/basix.git@${{ env.basix_ref }}
pip install git+https://github.com/FEniCS/ffcx.git@${{ env.ffcx_ref }}
pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}

- name: Configure and install C++
run: |
Expand Down Expand Up @@ -184,16 +184,15 @@ jobs:
- name: Install FEniCS Python components (default branches/tags)
if: github.event_name != 'workflow_dispatch'
run: |
pip install git+https://github.com/FEniCS/ufl.git@${{ env.ufl_ref }}
pip install git+https://github.com/FEniCS/basix.git@${{ env.basix_ref }}
pip install git+https://github.com/FEniCS/ffcx.git@${{ env.ffcx_ref }}

pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}
- name: Install FEniCS Python components
if: github.event_name == 'workflow_dispatch'
run: |
pip install git+https://github.com/FEniCS/ufl.git@${{ env.ufl_ref }}
pip install git+https://github.com/FEniCS/basix.git@${{ env.basix_ref }}
pip install git+https://github.com/FEniCS/ffcx.git@${{ env.ffcx_ref }}
pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}

- name: Configure, build and install C++ library
run: |
Expand Down Expand Up @@ -266,15 +265,15 @@ jobs:
- name: Install FEniCS Python components (default branches/tags)
if: github.event_name != 'workflow_dispatch'
run: |
pip install git+https://github.com/FEniCS/ufl.git@${{ env.ufl_ref }}
pip install git+https://github.com/FEniCS/basix.git@${{ env.basix_ref }}
pip install git+https://github.com/FEniCS/ffcx.git@${{ env.ffcx_ref }}
pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}
- name: Install FEniCS Python components
if: github.event_name == 'workflow_dispatch'
run: |
pip install git+https://github.com/FEniCS/ufl.git@${{ env.ufl_ref }}
pip install git+https://github.com/FEniCS/basix.git@${{ env.basix_ref }}
pip install git+https://github.com/FEniCS/ffcx.git@${{ env.ffcx_ref }}
pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}

- name: Configure C++
run: |
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/fenicsx-refs.env
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
basix_repository=FEniCS/basix
basix_ref=main
ufl_repository=FEniCS/ufl
ufl_ref=main
ffcx_ref=main
ffcx_repository=schnellerhase/fenics-ffcx
ffcx_ref=point_measure
6 changes: 3 additions & 3 deletions .github/workflows/macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ jobs:

- name: Install FEniCSx dependencies
run: |
python -m pip install git+https://github.com/fenics/ufl.git@${{ env.ufl_ref }}
python -m pip install git+https://github.com/fenics/basix.git@${{ env.basix_ref }}
python -m pip install git+https://github.com/fenics/ffcx.git@${{ env.ffcx_ref }}
python -m pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
python -m pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
python -m pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}

- name: Build and install DOLFINx C++ library
run: |
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/oneapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@ jobs:
conda list

- name: Install Basix
run: uv pip install --no-build-isolation git+https://github.com/FEniCS/basix.git@${{ env.basix_ref }}
run: uv pip install --no-build-isolation git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}

- name: Clone FFCx
uses: actions/checkout@v4
with:
path: ./ffcx
repository: FEniCS/ffcx
repository: ${{ env.ffcx_repository }}
ref: ${{ env.ffcx_ref }}

- name: Install UFCx C interface
Expand All @@ -82,7 +82,7 @@ jobs:

- name: Install UFL and FFCx modules
run: |
uv pip install --no-build-isolation git+https://github.com/FEniCS/ufl.git@${{ env.ufl_ref }}
uv pip install --no-build-isolation git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
uv pip install --no-build-isolation ffcx/

- name: Build and run DOLFINx C++ unit tests (serial and MPI)
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/pyvista.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ jobs:

- name: Install FEniCS Python components
run: |
python -m pip install git+https://github.com/fenics/ufl.git@${{ env.ufl_ref }}
python -m pip install git+https://github.com/fenics/basix.git@${{ env.basix_ref }}
python -m pip install git+https://github.com/fenics/ffcx.git@${{ env.ffcx_ref }}
pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}
apt-get update
apt-get install -y --no-install-recommends libgl1-mesa-dev xvfb # pyvista
apt-get install -y --no-install-recommends libqt5gui5t64 libgl1 # pyvistaqt
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/redhat.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ jobs:

- name: Install FEniCS Python components
run: |
python3 -m pip install git+https://github.com/fenics/ufl.git@${{ env.ufl_ref }}
python3 -m pip install git+https://github.com/fenics/basix.git@${{ env.basix_ref }}
python3 -m pip install git+https://github.com/fenics/ffcx.git@${{ env.ffcx_ref }}
pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}

- name: Configure C++
run: cmake -G Ninja -DCMAKE_BUILD_TYPE=Developer -B build -S cpp/
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ jobs:
echo "$HOME/.sonar/build-wrapper-linux-x86" >> $GITHUB_PATH
- name: Install FEniCS Python components
run: |
python -m pip install git+https://github.com/fenics/ufl.git@${{ env.ufl_ref }}
python -m pip install git+https://github.com/fenics/basix.git@${{ env.basix_ref }}
python -m pip install git+https://github.com/fenics/ffcx.git@${{ env.ffcx_ref }}
pip install git+https://github.com/${{ env.ufl_repository }}.git@${{ env.ufl_ref }}
pip install git+https://github.com/${{ env.basix_repository }}.git@${{ env.basix_ref }}
pip install git+https://github.com/${{ env.ffcx_repository }}.git@${{ env.ffcx_ref }}
- name: Run build-wrapper
run: |
mkdir build
Expand Down
58 changes: 57 additions & 1 deletion cpp/dolfinx/fem/assemble_scalar_impl.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2019-2025 Garth N. Wells
// Copyright (C) 2019-2025 Garth N. Wells and Paul T. Kühner
//
// This file is part of DOLFINx (https://www.fenicsproject.org)
//
Expand Down Expand Up @@ -150,6 +150,43 @@ T assemble_interior_facets(
return value;
}

/// Assemble functional over vertices
template <dolfinx::scalar T>
T assemble_vertices(mdspan2_t x_dofmap,
md::mdspan<const scalar_value_t<T>,
md::extents<std::size_t, md::dynamic_extent, 3>>
x,
md::mdspan<const std::int32_t,
md::extents<std::size_t, md::dynamic_extent, 2>>
vertices,
FEkernel<T> auto fn, std::span<const T> constants,
md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs)
{
T value(0);
if (vertices.empty())
return value;

// Create data structures used in assembly
std::vector<scalar_value_t<T>> cdofs(3 * x_dofmap.extent(1));

// Iterate over all cells
for (std::size_t index = 0; index < vertices.extent(0); ++index)
{
std::int32_t cell = vertices(index, 0);
std::int32_t local_vertex_index = vertices(index, 1);

// Get cell coordinates/geometry
auto x_dofs = md::submdspan(x_dofmap, cell, md::full_extent);
for (std::size_t i = 0; i < x_dofs.size(); ++i)
std::copy_n(&x(x_dofs[i], 0), 3, std::next(cdofs.begin(), 3 * i));

fn(&value, &coeffs(index, 0), constants.data(), cdofs.data(),
&local_vertex_index, nullptr, nullptr);
}

return value;
}

/// Assemble functional into an scalar with provided mesh geometry.
template <dolfinx::scalar T, std::floating_point U>
T assemble_scalar(
Expand Down Expand Up @@ -228,6 +265,25 @@ T assemble_scalar(
perms);
}

for (int i : M.integral_ids(IntegralType::vertex))
{
auto fn = M.kernel(IntegralType::vertex, i, 0);
assert(fn);

auto& [coeffs, cstride] = coefficients.at({IntegralType::vertex, i});

std::span<const std::int32_t> data = M.domain(IntegralType::vertex, i, 0);
assert(data.size() * cstride == coeffs.size());

md::mdspan<const std::int32_t,
md::extents<std::size_t, md::dynamic_extent, 2>>
cell_and_vertex(data.data(), data.size() / 2, 2);

value += impl::assemble_vertices(
x_dofmap, x, cell_and_vertex, fn, constants,
md::mdspan(coeffs.data(), data.size() / 2, cstride));
}

return value;
}

Expand Down
117 changes: 116 additions & 1 deletion cpp/dolfinx/fem/assemble_vector_impl.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2018-2021 Garth N. Wells
// Copyright (C) 2018-2025 Garth N. Wells and Paul T. Kühner
//
// This file is part of DOLFINx (https://www.fenicsproject.org)
//
Expand Down Expand Up @@ -907,6 +907,95 @@ void assemble_interior_facets(
}
}

/// @brief Execute kernel over a set of vertices and accumulate result in
/// vector.
///
/// @tparam T Scalar type
/// @tparam _bs Block size of the form test function dof map. If less
/// than zero the block size is determined at runtime. If `_bs` is
/// positive the block size is used as a compile-time constant, which
/// has performance benefits.
/// @param[in] P0 Function that applies transformation `P0.b` in-place
/// to `b` to transform test degrees-of-freedom.
/// @param[in,out] b Array to accumulate into.
/// @param[in] x_dofmap Dofmap for the mesh geometry.
/// @param[in] x Mesh geometry (coordinates).
/// @param[in] vertices Vertex indices `(vertices.size(), 2)` - first entry
/// holds the cell index over which the vertex is to evaluated, and the second
/// stores the local index of the vertex within the cell.
/// @param[in] dofmap Test function (row) degree-of-freedom data holding
/// the (0) dofmap, (1) dofmap block size and (2) dofmap cell indices.
/// @param[in] kernel Kernel function to execute over each cell.
/// @param[in] constants Constant coefficient data in the kernel.
/// @param[in] coeffs Coefficient data in the kernel. It has shape
/// `(vertices.size(), num_cell_coeffs)`. `coeffs(i, j)` is the `j`th
/// coefficient for cell `i`.
/// @param[in] cell_info0 Cell permutation information for the test
/// function mesh.
template <dolfinx::scalar T, int _bs = -1>
void assemble_vertices(
fem::DofTransformKernel<T> auto P0, std::span<T> b, mdspan2_t x_dofmap,
md::mdspan<const scalar_value_t<T>,
md::extents<std::size_t, md::dynamic_extent, 3>>
x,
md::mdspan<const std::int32_t,
md::extents<std::size_t, md::dynamic_extent, 2>>
vertices,
std::tuple<mdspan2_t, int,
md::mdspan<const std::int32_t,
md::extents<std::size_t, md::dynamic_extent, 2>>>
dofmap,
FEkernel<T> auto kernel, std::span<const T> constants,
md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
std::span<const std::uint32_t> cell_info0)
{
if (vertices.empty())
return;

const auto [dmap, bs, vertices0] = dofmap;
assert(_bs < 0 or _bs == bs);

// Create data structures used in assembly
std::vector<scalar_value_t<T>> cdofs(3 * x_dofmap.extent(1));
std::vector<T> be(bs * dmap.extent(1));
std::span<T> _be(be);

// Iterate over active cells
for (std::size_t index = 0; index < vertices.extent(0); ++index)
{
// Integration domain cell, local index, and test function cell
std::int32_t cell = vertices(index, 0);
std::int32_t local_index = vertices(index, 1);
std::int32_t c0 = vertices0(index, 0);

// Get cell coordinates/geometry
auto x_dofs = md::submdspan(x_dofmap, cell, md::full_extent);
for (std::size_t i = 0; i < x_dofs.size(); ++i)
std::copy_n(&x(x_dofs[i], 0), 3, std::next(cdofs.begin(), 3 * i));

// Tabulate vector for cell
std::ranges::fill(be, 0);
kernel(be.data(), &coeffs(index, 0), constants.data(), cdofs.data(),
&local_index, nullptr, nullptr);
P0(_be, cell_info0, c0, 1);

// Scatter cell vector to 'global' vector array
auto dofs = md::submdspan(dmap, c0, md::full_extent);
if constexpr (_bs > 0)
{
for (std::size_t i = 0; i < dofs.size(); ++i)
for (int k = 0; k < _bs; ++k)
b[_bs * dofs[i] + k] += be[_bs * i + k];
}
else
{
for (std::size_t i = 0; i < dofs.size(); ++i)
for (int k = 0; k < bs; ++k)
b[bs * dofs[i] + k] += be[bs * i + k];
}
}
}

/// Modify RHS vector to account for boundary condition such that:
///
/// b <- b - alpha * A.(x_bc - x0)
Expand Down Expand Up @@ -1340,6 +1429,32 @@ void assemble_vector(
cell_info0, perms);
}
}

for (int i : L.integral_ids(IntegralType::vertex))
{
auto fn = L.kernel(IntegralType::vertex, i, 0);
assert(fn);

std::span vertices = L.domain(IntegralType::vertex, i, cell_type_idx);
std::span vertices0
= L.domain_arg(IntegralType::vertex, 0, i, cell_type_idx);

auto& [coeffs, cstride] = coefficients.at({IntegralType::vertex, i});

assert(vertices.size() * cstride == coeffs.size());

impl::assemble_vertices<T>(
P0, b, x_dofmap, x,
md::mdspan<const std::int32_t,
md::extents<std::size_t, md::dynamic_extent, 2>>(
vertices.data(), vertices.size() / 2, 2),
{dofs, bs,
md::mdspan<const std::int32_t,
md::extents<std::size_t, md::dynamic_extent, 2>>(
vertices0.data(), vertices0.size() / 2, 2)},
fn, constants,
md::mdspan(coeffs.data(), vertices.size() / 2, cstride), cell_info0);
}
}
}

Expand Down
Loading
Loading