13#include <dolfinx/common/IndexMap.h>
14#include <dolfinx/common/Scatterer.h>
15#include <dolfinx/common/types.h>
26template <
class F,
class Container,
class ScatterContainer>
28 f(idx.cbegin(), idx.cend(), x.cbegin(), x.begin());
32template <
class GetPtr,
class U,
class T>
34 { f(x) } -> std::same_as<T*>;
35} and
requires(GetPtr f,
const U x) {
36 { f(x) } -> std::same_as<const T*>;
47template <
typename T,
typename Container = std::vector<T>,
48 typename ScatterContainer = std::vector<std::
int32_t>>
51 static_assert(std::is_same_v<typename Container::value_type, T>);
53 template <
typename,
typename,
typename>
63 return [](
typename ScatterContainer::const_iterator idx_first,
64 typename ScatterContainer::const_iterator idx_last,
65 const auto in_first,
auto out_first)
68 std::transform(idx_first, idx_last, out_first,
69 [in_first](
auto p) {
return *std::next(in_first, p); });
79 return [](
typename ScatterContainer::const_iterator idx_first,
80 typename ScatterContainer::const_iterator idx_last,
81 const auto in_first,
auto out_first)
84 for (
typename ScatterContainer::const_iterator idx = idx_first;
85 idx != idx_last; ++idx)
87 std::size_t d = std::distance(idx_first, idx);
88 *std::next(out_first, *idx) = *std::next(in_first, d);
98 template <
typename BinaryOp>
99 auto get_unpack_op(BinaryOp op)
101 return [op](
typename ScatterContainer::const_iterator idx_first,
102 typename ScatterContainer::const_iterator idx_last,
103 const auto in_first,
auto out_first)
106 for (
typename ScatterContainer::const_iterator idx = idx_first;
107 idx != idx_last; ++idx)
109 std::size_t d = std::distance(idx_first, idx);
110 auto& out = *std::next(out_first, *idx);
111 out = op(out, *std::next(in_first, d));
123 static_assert(std::is_same_v<value_type, typename container_type::value_type>,
124 "Scalar type and container value type must be the same.");
131 Vector(std::shared_ptr<const common::IndexMap> map,
int bs)
132 : _map(map), _bs(
bs), _x(
bs * (map->size_local() + map->num_ghosts())),
134 std::make_shared<
common::Scatterer<ScatterContainer>>(*_map,
bs)),
135 _buffer_local(_scatterer->local_indices().size()),
136 _buffer_remote(_scatterer->remote_indices().size())
156 std::shared_ptr<const common::Scatterer<ScatterContainer>>
157 scatter_ptr(
auto sc)
const
159 using SC =
typename std::remove_cv<
160 typename decltype(sc)::element_type>::type::container_type;
161 if constexpr (std::is_same_v<ScatterContainer, SC>)
164 return std::make_shared<common::Scatterer<ScatterContainer>>(*sc);
180 template <
typename T0,
typename Container0,
typename ScatterContainer0>
181 explicit Vector(
const Vector<T0, Container0, ScatterContainer0>& x)
182 : _map(x.
index_map()), _bs(x.
bs()), _x(x._x.begin(), x._x.end()),
183 _scatterer(scatter_ptr(x._scatterer)), _request(MPI_REQUEST_NULL),
184 _buffer_local(_scatterer->local_indices().size()),
185 _buffer_remote(_scatterer->remote_indices().size())
199 [[deprecated(
"Use std::ranges::fill(u.array(), v) instead.")]]
void
202 std::ranges::fill(_x, v);
219 template <
typename U,
typename GetPtr>
224 pack(_scatterer->local_indices().begin(), _scatterer->local_indices().end(),
225 _x.begin(), _buffer_local.begin());
226 _scatterer->scatter_fwd_begin(get_ptr(_buffer_local),
227 get_ptr(_buffer_remote), _request);
239 requires requires(Container c) {
240 { c.data() } -> std::same_as<T*>;
257 template <
typename U>
258 requires VectorPackKernel<U, container_type, ScatterContainer>
261 _scatterer->scatter_end(_request);
262 unpack(_scatterer->remote_indices().begin(),
263 _scatterer->remote_indices().end(), _buffer_remote.begin(),
264 std::next(_x.begin(), _bs * _map->size_local()));
276 requires requires(Container c) {
277 { c.data() } -> std::same_as<T*>;
293 requires requires(Container c) {
294 { c.data() } -> std::same_as<T*>;
314 template <
typename U,
typename GetPtr>
315 requires VectorPackKernel<U, container_type, ScatterContainer>
316 and GetPtrConcept<GetPtr, Container, T>
319 std::int32_t local_size = _bs * _map->size_local();
320 pack(_scatterer->remote_indices().begin(),
321 _scatterer->remote_indices().end(), std::next(_x.begin(), local_size),
322 _buffer_remote.begin());
323 _scatterer->scatter_rev_begin(get_ptr(_buffer_remote),
324 get_ptr(_buffer_local), _request);
336 requires requires(Container c) {
337 { c.data() } -> std::same_as<T*>;
350 template <
typename U>
351 requires VectorPackKernel<U, container_type, ScatterContainer>
354 _scatterer->scatter_end(_request);
355 unpack(_scatterer->local_indices().begin(),
356 _scatterer->local_indices().end(), _buffer_local.begin(),
371 template <
class BinaryOperation>
372 requires requires(Container c) {
373 { c.data() } -> std::same_as<T*>;
382 std::shared_ptr<const common::IndexMap>
index_map()
const {
return _map; }
385 constexpr int bs()
const {
return _bs; }
406 std::shared_ptr<const common::IndexMap> _map;
415 std::shared_ptr<const common::Scatterer<ScatterContainer>> _scatterer;
418 MPI_Request _request = MPI_REQUEST_NULL;
437 using T =
typename V::value_type;
438 const std::int32_t local_size = a.bs() * a.index_map()->size_local();
439 if (local_size != b.bs() * b.index_map()->size_local())
440 throw std::runtime_error(
"Incompatible vector sizes");
442 const T local = std::transform_reduce(
443 a.array().begin(), std::next(a.array().begin(), local_size),
444 b.array().begin(),
static_cast<T
>(0), std::plus{},
447 if constexpr (std::is_same<T, std::complex<double>>::value
448 or std::is_same<T, std::complex<float>>::value)
450 return std::conj(a) * b;
458 a.index_map()->comm());
468 using T =
typename V::value_type;
470 return std::real(result);
482 using T =
typename V::value_type;
487 std::int32_t size_local = x.bs() * x.index_map()->size_local();
488 using U =
typename dolfinx::scalar_value_t<T>;
489 U local_l1 = std::accumulate(
490 x.array().begin(), std::next(x.array().begin(), size_local), U(0),
491 [](
auto norm,
auto x) {
return norm + std::abs(x); });
494 x.index_map()->comm());
501 std::int32_t size_local = x.bs() * x.index_map()->size_local();
502 auto max_pos = std::max_element(
503 x.array().begin(), std::next(x.array().begin(), size_local),
504 [](T a, T b) { return std::norm(a) < std::norm(b); });
505 auto local_linf = std::abs(*max_pos);
506 decltype(local_linf) linf = 0;
507 MPI_Allreduce(&local_linf, &linf, 1,
MPI::mpi_t<
decltype(linf)>, MPI_MAX,
508 x.index_map()->comm());
512 throw std::runtime_error(
"Norm type not supported");
525 using T =
typename V::value_type;
526 using U =
typename dolfinx::scalar_value_t<T>;
529 for (std::size_t i = 0; i < basis.size(); ++i)
533 V& bi = basis[i].get();
534 for (std::size_t j = 0; j < i; ++j)
536 const V& bj = basis[j].get();
540 std::ranges::transform(bj.array(), bi.array(), bi.array().begin(),
541 [dot_ij](
auto xj,
auto xi)
542 { return xi - dot_ij * xj; });
547 if (
norm *
norm < std::numeric_limits<U>::epsilon())
549 throw std::runtime_error(
550 "Linear dependency detected. Cannot orthogonalize.");
552 std::ranges::transform(bi.array(), bi.array().begin(),
553 [
norm](
auto x) { return x / norm; });
567 std::vector<std::reference_wrapper<const V>> basis,
568 dolfinx::scalar_value_t<typename V::value_type> eps = std::numeric_limits<
569 dolfinx::scalar_value_t<typename V::value_type>>::epsilon())
571 using T =
typename V::value_type;
572 for (std::size_t i = 0; i < basis.size(); i++)
574 for (std::size_t j = i; j < basis.size(); ++j)
576 T delta_ij = (i == j) ? T(1) : T(0);
578 if (std::norm(delta_ij - dot_ij) > eps)
A vector that can be distributed across processes.
Definition Vector.h:50
container_type & mutable_array()
Get local part of the vector.
Definition Vector.h:399
container_type & array()
Get the process-local part of the vector.
Definition Vector.h:390
container_type::value_type value_type
Scalar type.
Definition Vector.h:121
const container_type & array() const
Get the process-local part of the vector (const version).
Definition Vector.h:395
void scatter_rev_begin(U pack, GetPtr get_ptr)
Start scatter (send) of ghost entry data to the owning process of an index.
Definition Vector.h:317
Vector(const Vector< T0, Container0, ScatterContainer0 > &x)
Copy-convert vector, possibly using to different container types.
Definition Vector.h:181
constexpr int bs() const
Get block size.
Definition Vector.h:385
Vector(std::shared_ptr< const common::IndexMap > map, int bs)
Create a distributed vector.
Definition Vector.h:131
void scatter_rev(BinaryOperation op)
Scatter (send) of ghost data values to the owning process and assign/accumulate into the owned data e...
Definition Vector.h:375
void scatter_fwd_end(U unpack)
End scatter (send) of local data values that are ghosted on other processes.
Definition Vector.h:259
void scatter_rev_end(U unpack)
End scatter of ghost data to owner and update owned entries.
Definition Vector.h:352
Vector & operator=(Vector &&x)=default
Move assignment operator.
std::shared_ptr< const common::IndexMap > index_map() const
Get IndexMap.
Definition Vector.h:382
void scatter_fwd_end()
End scatter (send) of local data values that are ghosted on other processes (simplified CPU version).
Definition Vector.h:275
void scatter_fwd()
Scatter (send) of local data values that are ghosted on other processes and update ghost entry values...
Definition Vector.h:292
Container container_type
Container type.
Definition Vector.h:118
void scatter_fwd_begin(U pack, GetPtr get_ptr)
Begin scatter (send) of local data that is ghosted on other processes.
Definition Vector.h:222
void set(value_type v)
Set all entries (including ghosts).
Definition Vector.h:200
Vector(Vector &&x)=default
Move constructor.
void scatter_fwd_begin()
Begin scatter (send) of local data that is ghosted on other processes (simplified CPU version).
Definition Vector.h:238
Vector(const Vector &x)=default
Copy constructor.
void scatter_rev_begin()
Start scatter (send) of ghost entry data to the owning process of an index (simplified CPU version).
Definition Vector.h:335
Access to pointer function concept.
Definition Vector.h:33
la::Vector scatter pack/unpack function concept.
Definition Vector.h:27
MPI_Datatype mpi_t
Retrieves the MPI data type associated to the provided type.
Definition MPI.h:257
Miscellaneous classes, functions and types.
Definition dolfinx_common.h:8
Linear algebra interface.
Definition dolfinx_la.h:7
void orthonormalize(std::vector< std::reference_wrapper< V > > basis)
Orthonormalize a set of vectors.
Definition Vector.h:523
auto squared_norm(const V &a)
Compute the squared L2 norm of vector.
Definition Vector.h:466
auto norm(const V &x, Norm type=Norm::l2)
Compute the norm of the vector.
Definition Vector.h:480
auto inner_product(const V &a, const V &b)
Compute the inner product of two vectors.
Definition Vector.h:435
bool is_orthonormal(std::vector< std::reference_wrapper< const V > > basis, dolfinx::scalar_value_t< typename V::value_type > eps=std::numeric_limits< dolfinx::scalar_value_t< typename V::value_type > >::epsilon())
Test if basis is orthonormal.
Definition Vector.h:566
Norm
Norm types.
Definition utils.h:17