libMesh
Loading...
Searching...
No Matches
kokkos_vector_ops.h
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18#ifndef LIBMESH_KOKKOS_VECTOR_OPS_H
19#define LIBMESH_KOKKOS_VECTOR_OPS_H
20
21// libMesh Kokkos generic vector operations.
22//
23// These free functions build vector algebra on top of the primitive
24// access/materialization layer in kokkos_linalg_base.h. They are written
25// against vector-like inputs so both libMesh owning types and storage-backed
26// refs can participate in the same math.
27//
28// The header is organized as:
29//
30// - construction/materialization helpers (copy_vector),
31// - detail:: componentwise kernels shared by everything below,
32// - reductions, geometry helpers, and libMesh-like wrappers, and
33// - the out-of-line vector_ref definitions and the operator overloads.
34//
35// The operator overloads are constrained (via is_vector_ref_v) to
36// require at least one storage-backed ref operand: expressions between
37// two owning vectors keep using the operators those types already
38// define, while vector-only expressions involving a ref resolve here
39// (mixed vector/tensor products live in kokkos_tensor_ops.h).
40//
41// Functions taking an optional ResultVector template parameter return
42// the input's semantic type (e.g. TypeVector) by default, but a caller
43// can request a different owning type explicitly, e.g.
44// vector_cross<Point>(a, b).
45
46#include "libmesh/kokkos_linalg_base.h"
47
48#include "libmesh/tensor_tools.h"
49
50#include <cmath>
51
52namespace libMesh::Kokkos
53{
54
55// Construction and materialization
56
63template <typename ResultVector = void, typename VectorLike>
64LIBMESH_DEVICE_INLINE
65auto copy_vector(const VectorLike & v)
66 -> std::conditional_t<std::is_void<ResultVector>::value,
68 ResultVector>
69{
70 using output_type = std::conditional_t<std::is_void<ResultVector>::value,
72 ResultVector>;
73 return materialize_vector<output_type>(v);
74}
75
76namespace detail
77{
78
79// These helpers are shared by the public functions and ref operators so
80// Kokkos-backed refs use direct component access without extra materialization.
81
85template <typename LeftVector, typename RightVector>
86LIBMESH_DEVICE_INLINE
87void assign_vector_components(LeftVector & left, const RightVector & right)
88{
89 for (unsigned int component = 0; component < LIBMESH_DIM; ++component)
90 left(component) = right(component);
91}
92
96template <typename VectorLike, typename Scalar>
97LIBMESH_DEVICE_INLINE
98void fill_vector_components(VectorLike & v, const Scalar & value)
99{
100 for (unsigned int component = 0; component < LIBMESH_DIM; ++component)
101 v(component) = value;
102}
103
107template <typename LeftVector, typename RightVector, typename Scalar>
108LIBMESH_DEVICE_INLINE
109void update_vector_components(LeftVector & left, const RightVector & right, const Scalar & factor)
110{
111 for (unsigned int component = 0; component < LIBMESH_DIM; ++component)
112 left(component) = left(component) + factor * right(component);
113}
114
119template <typename OutputVector, typename InputVector, typename TransformOp>
120LIBMESH_DEVICE_INLINE
121void transform_vector_components(OutputVector & out, const InputVector & in, const TransformOp & op)
122{
123 for (unsigned int component = 0; component < LIBMESH_DIM; ++component)
124 out(component) = op(in(component));
125}
126
130template <typename ResultVector, typename VectorLike, typename TransformOp>
131LIBMESH_DEVICE_INLINE
132ResultVector transformed_vector(const VectorLike & v, const TransformOp & op)
133{
134 ResultVector out;
135 out.zero();
137 return out;
138}
139
144template <typename LeftVector, typename RightVector>
145LIBMESH_DEVICE_INLINE
146bool vector_equal_impl(const LeftVector & left, const RightVector & right)
147{
148 for (unsigned int component = 0; component < LIBMESH_DIM; ++component)
149 if (left(component) != right(component))
150 return false;
151
152 return true;
153}
154
162template <typename ValueType>
164{
165 LIBMESH_DEVICE_INLINE
166 auto operator()(const ValueType & value) const
167 {
168 return -value;
169 }
170};
171
172template <typename Scalar>
174{
175 const Scalar & alpha;
176
177 LIBMESH_DEVICE_INLINE
178 auto operator()(const Scalar & value) const -> decltype(value * alpha)
179 {
180 return value * alpha;
181 }
182
183 template <typename ValueType>
184 LIBMESH_DEVICE_INLINE
185 auto operator()(const ValueType & value) const -> decltype(value * alpha)
186 {
187 return value * alpha;
188 }
189};
190
191template <typename Scalar>
193{
194 const Scalar & alpha;
195
196 LIBMESH_DEVICE_INLINE
197 auto operator()(const Scalar & value) const -> decltype(value / alpha)
198 {
199 return value / alpha;
200 }
201
202 template <typename ValueType>
203 LIBMESH_DEVICE_INLINE
204 auto operator()(const ValueType & value) const -> decltype(value / alpha)
205 {
206 return value / alpha;
207 }
208};
209
210} // namespace detail
211
212// Reductions and normalization
213
218template <typename LeftVector, typename RightVector>
219LIBMESH_DEVICE_INLINE
220auto vector_dot(const LeftVector & left, const RightVector & right)
221{
222 static_assert(is_vector_like_v<LeftVector>, "vector_dot() requires a vector-like left input");
223 static_assert(is_vector_like_v<RightVector>, "vector_dot() requires a vector-like right input");
224
225 using sum_type =
226 detail::remove_cvref_t<decltype(left(0) * right(0))>;
227
228 sum_type sum = sum_type(0);
229 for (unsigned int component = 0; component < LIBMESH_DIM; ++component)
230 sum += left(component) * right(component);
231
232 return sum;
233}
234
235
240template <typename ResultVector = void, typename VectorLike>
241LIBMESH_DEVICE_INLINE
242auto vector_unit(const VectorLike & v)
243 -> std::conditional_t<std::is_void<ResultVector>::value,
245 ResultVector>
246{
247 const auto length = v.norm();
248 libmesh_assert_not_equal_to(length, static_cast<Real>(0.));
249 using output_type = std::conditional_t<std::is_void<ResultVector>::value,
251 ResultVector>;
252 return detail::transformed_vector<output_type>(v, detail::divide_value<decltype(length)>{length});
253}
254
255// Geometry
256
265template <typename ResultVector = void, typename LeftVector, typename RightVector>
266LIBMESH_DEVICE_INLINE
267auto vector_cross(const LeftVector & left, const RightVector & right)
268 -> std::conditional_t<std::is_void<ResultVector>::value,
270 ResultVector>
271{
272 using output_type = std::conditional_t<std::is_void<ResultVector>::value,
274 ResultVector>;
275 output_type out;
276 out.zero();
277
278#if LIBMESH_DIM == 3
279 out(0) = left(1) * right(2) - left(2) * right(1);
280 out(1) = -left(0) * right(2) + left(2) * right(0);
281 out(2) = left(0) * right(1) - left(1) * right(0);
282#else
283 libmesh_ignore(left);
284 libmesh_ignore(right);
285#endif
286
287 return out;
288}
289
295template <typename LeftVector, typename MiddleVector, typename RightVector>
296LIBMESH_DEVICE_INLINE
297auto vector_triple_product(const LeftVector & left,
298 const MiddleVector & middle,
299 const RightVector & right)
300{
301#if LIBMESH_DIM == 3
302 return left(0) * (middle(1) * right(2) - middle(2) * right(1)) -
303 left(1) * (middle(0) * right(2) - middle(2) * right(0)) +
304 left(2) * (middle(0) * right(1) - middle(1) * right(0));
305#else
306 libmesh_ignore(left, middle, right);
307 using value_type =
308 detail::remove_cvref_t<decltype(left(0) * middle(0))>;
309 return value_type(0);
310#endif
311}
312
318template <typename LeftVector, typename RightVector>
319LIBMESH_DEVICE_INLINE
320auto vector_cross_norm_sq(const LeftVector & left, const RightVector & right)
321{
322 const auto z = left(0) * right(1) - left(1) * right(0);
323
324#if LIBMESH_DIM == 3
325 const auto x = left(1) * right(2) - left(2) * right(1);
326 const auto y = left(0) * right(2) - left(2) * right(0);
327 return x * x + y * y + z * z;
328#else
329 return z * z;
330#endif
331}
332
340template <typename VectorA, typename VectorB, typename VectorC>
341LIBMESH_DEVICE_INLINE
342auto vector_solid_angle(const VectorA & v01, const VectorB & v02, const VectorC & v03)
343{
344 using std::atan;
345
346 const auto norm01 = v01.norm();
347 const auto norm02 = v02.norm();
348 const auto norm03 = v03.norm();
349 const auto tan_half_angle =
350 vector_triple_product(v01, v02, v03) /
351 (vector_dot(v01, v02) * norm03 +
352 vector_dot(v01, v03) * norm02 +
353 vector_dot(v02, v03) * norm01 +
354 norm01 * norm02 * norm03);
355
356 return Real(2) * atan(tan_half_angle);
357}
358
359// libMesh-like convenience wrappers
360
365template <typename LeftVector,
366 typename RightVector,
367 typename std::enable_if<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector>,
368 int>::type = 0>
369LIBMESH_DEVICE_INLINE
370auto contract(const LeftVector & left, const RightVector & right)
371{
372 return vector_dot(left, right);
373}
374
375
376// Forward declarations of the compound assignment operators, which the
377// vector_ref member definitions below delegate to.
378
379template <typename LeftVector, typename RightVector>
380LIBMESH_DEVICE_INLINE
381auto operator+=(LeftVector & left, const RightVector & right)
382 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector> &&
383 (is_vector_ref_v<LeftVector> || is_vector_ref_v<RightVector>),
384 LeftVector &>;
385
386template <typename LeftVector, typename RightVector>
387LIBMESH_DEVICE_INLINE
388auto operator-=(LeftVector & left, const RightVector & right)
389 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector> &&
390 (is_vector_ref_v<LeftVector> || is_vector_ref_v<RightVector>),
391 LeftVector &>;
392
393// Out-of-line vector_ref member definitions. Several delegate to the
394// generic operations above or the operators below, so the whole group
395// lives here rather than in kokkos_linalg_base.h; see the class
396// definition for their documentation.
397
398template <typename ViewType>
399template <typename RightVector>
400LIBMESH_DEVICE_INLINE
401void vector_ref<ViewType>::assign(const RightVector & right)
402{
404}
405
406template <typename ViewType>
407template <typename RightVector>
408LIBMESH_DEVICE_INLINE
409void vector_ref<ViewType>::add(const RightVector & right)
410{
411 libMesh::Kokkos::operator+=(*this, right);
412}
413
414template <typename ViewType>
415template <typename RightVector>
416LIBMESH_DEVICE_INLINE
417void vector_ref<ViewType>::add_scaled(const RightVector & right, const value_type & factor)
418{
419 detail::update_vector_components(*this, right, factor);
420}
421
422template <typename ViewType>
423template <typename RightVector>
424LIBMESH_DEVICE_INLINE
425void vector_ref<ViewType>::subtract(const RightVector & right)
426{
427 libMesh::Kokkos::operator-=(*this, right);
428}
429
430template <typename ViewType>
431template <typename RightVector>
432LIBMESH_DEVICE_INLINE
433void vector_ref<ViewType>::subtract_scaled(const RightVector & right, const value_type & factor)
434{
435 detail::update_vector_components(*this, right, -factor);
436}
437
438template <typename ViewType>
439LIBMESH_DEVICE_INLINE
444
445template <typename ViewType>
446template <typename RightVector>
447LIBMESH_DEVICE_INLINE
448auto vector_ref<ViewType>::contract(const RightVector & right) const
449{
450 return libMesh::Kokkos::contract(*this, right);
451}
452
453template <typename ViewType>
454LIBMESH_DEVICE_INLINE
456{
457 using std::sqrt;
458 return sqrt(this->norm_sq());
459}
460
461template <typename ViewType>
462LIBMESH_DEVICE_INLINE
464{
465 // TensorTools::norm_sq handles complex-valued components correctly.
466 using norm_type = detail::remove_cvref_t<decltype(libMesh::TensorTools::norm_sq((*this)(0)))>;
467
468 norm_type sum = norm_type(0);
469 for (unsigned int component = 0; component < LIBMESH_DIM; ++component)
470 sum += libMesh::TensorTools::norm_sq((*this)(component));
471
472 return sum;
473}
474
475template <typename ViewType>
476LIBMESH_DEVICE_INLINE
478{
479 using std::abs;
480 using norm_type = detail::remove_cvref_t<decltype(abs((*this)(0)))>;
481
482 norm_type sum = norm_type(0);
483 for (unsigned int component = 0; component < LIBMESH_DIM; ++component)
484 sum += abs((*this)(component));
485
486 return sum;
487}
488
489template <typename ViewType>
490LIBMESH_DEVICE_INLINE
492{
493 for (unsigned int component = 0; component < LIBMESH_DIM; ++component)
494 if ((*this)(component) != value_type(0))
495 return false;
496
497 return true;
498}
499
500template <typename ViewType>
501LIBMESH_DEVICE_INLINE
503{
504 return vector_unit(*this);
505}
506
507template <typename ViewType>
508template <typename RightVector>
509LIBMESH_DEVICE_INLINE
510auto vector_ref<ViewType>::cross(const RightVector & right) const
511{
512 return vector_cross(*this, right);
513}
514
515// Operator-compatible wrappers for storage-backed refs and mixed ref/owning math.
516//
517// Every overload requires at least one vector_ref operand (via
518// is_vector_ref_v), so these never compete with the operators the
519// owning types define for themselves. Vector-valued results are
520// returned as owning values (sums and differences use the left
521// operand's semantic type); compound assignments update the left
522// operand in place, writing through to storage when it is a ref.
523
527template <typename VectorLike>
528LIBMESH_DEVICE_INLINE
529auto operator-(const VectorLike & v)
530 -> std::enable_if_t<is_vector_like_v<VectorLike> && is_vector_ref_v<VectorLike>,
532{
533 return detail::transformed_vector<vector_semantic_type_t<VectorLike>>(
534 v,
536}
537
541template <typename LeftVector, typename RightVector>
542LIBMESH_DEVICE_INLINE
543auto operator+(const LeftVector & left, const RightVector & right)
544 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector> &&
545 (is_vector_ref_v<LeftVector> || is_vector_ref_v<RightVector>),
547{
548 auto out = copy_vector<vector_semantic_type_t<LeftVector>>(left);
549 out += right;
550 return out;
551}
552
556template <typename LeftVector, typename RightVector>
557LIBMESH_DEVICE_INLINE
558auto operator-(const LeftVector & left, const RightVector & right)
559 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector> &&
560 (is_vector_ref_v<LeftVector> || is_vector_ref_v<RightVector>),
562{
563 auto out = copy_vector<vector_semantic_type_t<LeftVector>>(left);
564 out -= right;
565 return out;
566}
567
572template <typename LeftVector,
573 typename RightVector,
574 typename std::enable_if<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector> &&
575 (is_vector_ref_v<LeftVector> || is_vector_ref_v<RightVector>),
576 int>::type = 0>
577LIBMESH_DEVICE_INLINE
578auto operator*(const LeftVector & left, const RightVector & right)
579{
580 return vector_dot(left, right);
581}
582
587template <typename Scalar,
588 typename VectorLike,
589 typename std::enable_if<!is_vector_like_v<Scalar> && !is_tensor_like_v<Scalar> &&
590 is_vector_like_v<VectorLike> && is_vector_ref_v<VectorLike>,
591 int>::type = 0>
592LIBMESH_DEVICE_INLINE
593auto operator*(const Scalar & alpha, const VectorLike & v)
594{
595 return v * alpha;
596}
597
598template <typename VectorLike,
599 typename Scalar,
600 typename std::enable_if<is_vector_like_v<VectorLike> && is_vector_ref_v<VectorLike> &&
601 !is_vector_like_v<Scalar> && !is_tensor_like_v<Scalar>,
602 int>::type = 0>
603LIBMESH_DEVICE_INLINE
604auto operator*(const VectorLike & v, const Scalar & alpha)
605{
606 return detail::transformed_vector<vector_semantic_type_t<VectorLike>>(
607 v,
609}
610
615template <typename VectorLike,
616 typename Scalar,
617 typename std::enable_if<is_vector_like_v<VectorLike> && is_vector_ref_v<VectorLike> &&
618 !is_vector_like_v<Scalar> && !is_tensor_like_v<Scalar>,
619 int>::type = 0>
620LIBMESH_DEVICE_INLINE
621auto operator/(const VectorLike & v, const Scalar & alpha)
622{
623 return detail::transformed_vector<vector_semantic_type_t<VectorLike>>(
624 v,
626}
627
634template <typename LeftVector, typename RightVector>
635LIBMESH_DEVICE_INLINE
636auto operator==(const LeftVector & left, const RightVector & right)
637 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector> &&
638 (is_vector_ref_v<LeftVector> || is_vector_ref_v<RightVector>),
639 bool>
640{
641 return detail::vector_equal_impl(left, right);
642}
643
648template <typename LeftVector, typename RightVector>
649LIBMESH_DEVICE_INLINE
650auto operator!=(const LeftVector & left, const RightVector & right)
651 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector> &&
652 (is_vector_ref_v<LeftVector> || is_vector_ref_v<RightVector>),
653 bool>
654{
655 return !(left == right);
656}
657
662template <typename LeftVector, typename RightVector>
663LIBMESH_DEVICE_INLINE
664auto operator+=(LeftVector & left, const RightVector & right)
665 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector> &&
666 (is_vector_ref_v<LeftVector> || is_vector_ref_v<RightVector>),
667 LeftVector &>
668{
669 detail::update_vector_components(left, right, 1);
670 return left;
671}
672
676template <typename LeftVector, typename RightVector>
677LIBMESH_DEVICE_INLINE
678auto operator-=(LeftVector & left, const RightVector & right)
679 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_like_v<RightVector> &&
680 (is_vector_ref_v<LeftVector> || is_vector_ref_v<RightVector>),
681 LeftVector &>
682{
683 detail::update_vector_components(left, right, -1);
684 return left;
685}
686
690template <typename LeftVector, typename Scalar>
691LIBMESH_DEVICE_INLINE
692auto operator*=(LeftVector & left, const Scalar & alpha)
693 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_ref_v<LeftVector> &&
694 !is_vector_like_v<Scalar> && !is_tensor_like_v<Scalar>,
695 LeftVector &>
696{
698 return left;
699}
700
704template <typename LeftVector, typename Scalar>
705LIBMESH_DEVICE_INLINE
706auto operator/=(LeftVector & left, const Scalar & alpha)
707 -> std::enable_if_t<is_vector_like_v<LeftVector> && is_vector_ref_v<LeftVector> &&
708 !is_vector_like_v<Scalar> && !is_tensor_like_v<Scalar>,
709 LeftVector &>
710{
712 return left;
713}
714
715} // namespace libMesh::Kokkos
716
717#endif // LIBMESH_KOKKOS_VECTOR_OPS_H
LIBMESH_DEVICE_INLINE auto l1_norm() const
LIBMESH_DEVICE_INLINE auto norm() const
LIBMESH_DEVICE_INLINE auto cross(const RightVector &right) const
LIBMESH_DEVICE_INLINE void zero()
Sets every component of the referenced entry to zero.
LIBMESH_DEVICE_INLINE void add_scaled(const RightVector &right, const value_type &factor)
Adds factor times right to the referenced entry, in place.
LIBMESH_DEVICE_INLINE void add(const RightVector &right)
Adds right to the referenced entry, in place.
detail::vector_view_value_t< ViewType > value_type
LIBMESH_DEVICE_INLINE void subtract(const RightVector &right)
Subtracts right from the referenced entry, in place.
LIBMESH_DEVICE_INLINE void subtract_scaled(const RightVector &right, const value_type &factor)
Subtracts factor times right from the referenced entry, in place.
LIBMESH_DEVICE_INLINE auto norm_sq() const
LIBMESH_DEVICE_INLINE auto contract(const RightVector &right) const
LIBMESH_DEVICE_INLINE void assign(const RightVector &right)
Assigns right 's components to the referenced entry.
LIBMESH_DEVICE_INLINE auto unit() const
LIBMESH_DEVICE_INLINE bool is_zero() const
LIBMESH_DEVICE_INLINE void update_vector_components(LeftVector &left, const RightVector &right, const Scalar &factor)
Componentwise axpy-style update: left += factor * right.
LIBMESH_DEVICE_INLINE void assign_vector_components(LeftVector &left, const RightVector &right)
Componentwise copy: left = right.
LIBMESH_DEVICE_INLINE ResultVector transformed_vector(const VectorLike &v, const TransformOp &op)
typename std::remove_cv< typename std::remove_reference< T >::type >::type remove_cvref_t
Strips reference and const/volatile qualifiers from T, turning e.g.
LIBMESH_DEVICE_INLINE void fill_vector_components(VectorLike &v, const Scalar &value)
Sets every component of v to value.
LIBMESH_DEVICE_INLINE void transform_vector_components(OutputVector &out, const InputVector &in, const TransformOp &op)
Componentwise transform: out(i) = op(in(i)).
LIBMESH_DEVICE_INLINE bool vector_equal_impl(const LeftVector &left, const RightVector &right)
LIBMESH_DEVICE_INLINE auto operator*(const Scalar &alpha, const TensorLike &T_in)
LIBMESH_DEVICE_INLINE auto vector_triple_product(const LeftVector &left, const MiddleVector &middle, const RightVector &right)
LIBMESH_DEVICE_INLINE auto vector_unit(const VectorLike &v) -> std::conditional_t< std::is_void< ResultVector >::value, vector_semantic_type_t< VectorLike >, ResultVector >
LIBMESH_DEVICE_INLINE auto vector_dot(const LeftVector &left, const RightVector &right)
LIBMESH_DEVICE_INLINE auto operator/=(LeftTensor &left, const Scalar &alpha) -> std::enable_if_t< is_tensor_like_v< LeftTensor > &&is_tensor_ref_v< LeftTensor > &&!is_vector_like_v< Scalar > &&!is_tensor_like_v< Scalar >, LeftTensor & >
Divides left by alpha in place.
typename vector_traits< detail::remove_cvref_t< T > >::semantic_type vector_semantic_type_t
The owning libMesh type a vector-like T materializes to, with any cv/reference qualification on T str...
LIBMESH_DEVICE_INLINE auto operator+(const LeftTensor &left, const RightTensor &right) -> std::enable_if_t< is_tensor_like_v< LeftTensor > &&is_tensor_like_v< RightTensor > &&(is_tensor_ref_v< LeftTensor >||is_tensor_ref_v< RightTensor >), tensor_semantic_type_t< LeftTensor > >
LIBMESH_DEVICE_INLINE auto contract(const LeftTensor &left, const RightTensor &right)
LIBMESH_DEVICE_INLINE auto operator==(const LeftTensor &left, const RightTensor &right) -> std::enable_if_t< is_tensor_like_v< LeftTensor > &&is_tensor_like_v< RightTensor > &&(is_tensor_ref_v< LeftTensor >||is_tensor_ref_v< RightTensor >), bool >
LIBMESH_DEVICE_INLINE auto operator-(const TensorLike &T_in) -> std::enable_if_t< is_tensor_like_v< TensorLike > &&is_tensor_ref_v< TensorLike >, tensor_semantic_type_t< TensorLike > >
LIBMESH_DEVICE_INLINE auto operator!=(const LeftTensor &left, const RightTensor &right) -> std::enable_if_t< is_tensor_like_v< LeftTensor > &&is_tensor_like_v< RightTensor > &&(is_tensor_ref_v< LeftTensor >||is_tensor_ref_v< RightTensor >), bool >
LIBMESH_DEVICE_INLINE auto vector_cross(const LeftVector &left, const RightVector &right) -> std::conditional_t< std::is_void< ResultVector >::value, vector_semantic_type_t< LeftVector >, ResultVector >
LIBMESH_DEVICE_INLINE auto copy_vector(const VectorLike &v) -> std::conditional_t< std::is_void< ResultVector >::value, vector_semantic_type_t< VectorLike >, ResultVector >
LIBMESH_DEVICE_INLINE auto vector_solid_angle(const VectorA &v01, const VectorB &v02, const VectorC &v03)
LIBMESH_DEVICE_INLINE auto operator-=(LeftTensor &left, const RightTensor &right) -> std::enable_if_t< is_tensor_like_v< LeftTensor > &&is_tensor_like_v< RightTensor > &&(is_tensor_ref_v< LeftTensor >||is_tensor_ref_v< RightTensor >), LeftTensor & >
Subtracts right from left in place.
LIBMESH_DEVICE_INLINE auto operator/(const TensorLike &T_in, const Scalar &alpha) -> std::enable_if_t< is_tensor_like_v< TensorLike > &&is_tensor_ref_v< TensorLike > &&!is_vector_like_v< Scalar > &&!is_tensor_like_v< Scalar >, tensor_semantic_type_t< TensorLike > >
LIBMESH_DEVICE_INLINE auto operator+=(LeftTensor &left, const RightTensor &right) -> std::enable_if_t< is_tensor_like_v< LeftTensor > &&is_tensor_like_v< RightTensor > &&(is_tensor_ref_v< LeftTensor >||is_tensor_ref_v< RightTensor >), LeftTensor & >
Adds right to left in place; when left is a ref, the update writes through to the underlying storage.
LIBMESH_DEVICE_INLINE auto operator*=(LeftTensor &left, const Scalar &alpha) -> std::enable_if_t< is_tensor_like_v< LeftTensor > &&is_tensor_ref_v< LeftTensor > &&!is_vector_like_v< Scalar > &&!is_tensor_like_v< Scalar >, LeftTensor & >
Scales left by alpha in place.
LIBMESH_DEVICE_INLINE auto vector_cross_norm_sq(const LeftVector &left, const RightVector &right)
LIBMESH_DEVICE_INLINE auto norm_sq(const T &a)
void libmesh_ignore(const Args &...)
OStreamProxy out
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
LIBMESH_DEVICE_INLINE auto operator()(const ValueType &value) const -> decltype(value/alpha)
LIBMESH_DEVICE_INLINE auto operator()(const Scalar &value) const -> decltype(value/alpha)
Componentwise transform functors, shared by the vector helpers here and the tensor helpers in kokkos_...
LIBMESH_DEVICE_INLINE auto operator()(const ValueType &value) const
LIBMESH_DEVICE_INLINE auto operator()(const Scalar &value) const -> decltype(value *alpha)
LIBMESH_DEVICE_INLINE auto operator()(const ValueType &value) const -> decltype(value *alpha)
static const bool value
Definition xdr_io.C:55