https://mooseframework.inl.gov
Loading...
Searching...
No Matches
KokkosDispatcher.h
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://www.mooseframework.org
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#pragma once
11
12#include "KokkosHeader.h"
13#include "KokkosThread.h"
14
15#include <typeindex>
16#include <type_traits>
17
18namespace Moose::Kokkos
19{
20
21using Policy = ::Kokkos::RangePolicy<ExecSpace, ::Kokkos::IndexType<ThreadID>>;
22
29{
30public:
31 virtual ~DispatcherBase() {}
36 virtual void parallelFor(const Policy & /* policy */)
37 {
38 mooseError("parallelFor() called for an instance that is not a dispatcher.");
39 }
46 virtual void parallelReduce(const Policy & /* policy */,
47 ::Kokkos::View<Real *, ::Kokkos::HostSpace> & /* result */)
48 {
49 mooseError("parallelReduce() called for an instance that is not a reducer.");
50 }
51};
52
59template <typename Operation, typename Object>
61{
62public:
69 Dispatcher(const void * object)
70 : _functor_host(*static_cast<const Object *>(object)), _functor_device(_functor_host)
71 {
72 }
76 Dispatcher(const Dispatcher & functor)
78 {
79 }
80
81 void parallelFor(const Policy & policy) override final
82 {
83 ::Kokkos::parallel_for(policy, *this);
84 ::Kokkos::fence();
85 }
86
90 KOKKOS_FUNCTION void operator()(const ThreadID tid) const
91 {
92 _functor_device(Operation{}, tid, _functor_device);
93 }
94
95private:
99 const Object & _functor_host;
103 const Object _functor_device;
104};
105
112template <typename Operation, typename Object>
114{
115public:
122 Reducer(const void * object)
123 : _functor_host(*static_cast<const Object *>(object)), _functor_device(_functor_host)
124 {
125 }
129 Reducer(const Reducer & functor)
130 : value_count(functor.value_count),
133 {
134 }
135
136 void parallelReduce(const Policy & policy,
137 ::Kokkos::View<Real *, ::Kokkos::HostSpace> & result) override final
138 {
139 value_count = result.size();
140
141 ::Kokkos::parallel_reduce(policy, *this, result);
142 ::Kokkos::fence();
143 }
144
145 using value_type = Real[];
146 using size_type = ::Kokkos::View<Real *>::size_type;
147
149
153 KOKKOS_FUNCTION void operator()(const ThreadID tid, value_type result) const
154 {
155 _functor_device(Operation{}, tid, _functor_device, result);
156 }
157
162 KOKKOS_FUNCTION void join(value_type result, const value_type source) const
163 {
164 _functor_device.template join<Object>(result, source);
165 }
166 KOKKOS_FUNCTION void init(value_type result) const
167 {
168 _functor_device.template init<Object>(result);
169 }
171
172private:
176 const Object & _functor_host;
180 const Object _functor_device;
181};
182
189{
190public:
192
197 virtual std::unique_ptr<DispatcherBase> build(const void * object) const = 0;
198
203 void hasUserMethod(bool flag) { _has_user_method = flag; }
208 bool hasUserMethod() const { return _has_user_method; }
209
210private:
214 bool _has_user_method = false;
215};
216
227template <typename Operation, typename Object>
229{
230public:
231 std::unique_ptr<DispatcherBase> build(const void * object) const override final
232 {
233 return std::make_unique<Dispatcher<Operation, Object>>(object);
234 }
235};
236
237template <typename Operation, typename Object>
239{
240public:
241 std::unique_ptr<DispatcherBase> build(const void * object) const override final
242 {
243 return std::make_unique<Reducer<Operation, Object>>(object);
244 }
245};
247
252{
253public:
255
258
261
268 template <typename Operation, typename Object>
269 static void addDispatcher(const std::string & name)
270 {
271 auto operation = std::type_index(typeid(Operation));
272
273 getRegistry()._dispatchers[std::make_pair(operation, name)] =
274 std::make_unique<DispatcherRegistryEntry<Operation, Object>>();
275 }
276
283 template <typename Operation, typename Object>
284 static void addReducer(const std::string & name)
285 {
286 auto operation = std::type_index(typeid(Operation));
287
288 getRegistry()._dispatchers[std::make_pair(operation, name)] =
289 std::make_unique<ReducerRegistryEntry<Operation, Object>>();
290 }
291
298 template <typename Operation>
299 static void hasUserMethod(const std::string & name, const bool flag)
300 {
301 getDispatcher<Operation>(name)->hasUserMethod(flag);
302 }
303
310 template <typename Operation>
311 static bool hasUserMethod(const std::string & name)
312 {
313 return getDispatcher<Operation>(name)->hasUserMethod();
314 }
315
323 template <typename Operation>
324 static std::unique_ptr<DispatcherBase> build(const void * object, const std::string & name)
325 {
326 return getDispatcher<Operation>(name)->build(object);
327 }
328
329private:
335
342 template <typename Operation>
343 static auto & getDispatcher(const std::string & name)
344 {
345 auto operation = std::type_index(typeid(Operation));
346
347 auto it = getRegistry()._dispatchers.find(std::make_pair(operation, name));
348 if (it == getRegistry()._dispatchers.end())
349 mooseError("Kokkos functor dispatcher not registered for object type '",
350 name,
351 "'. Double check that you used Kokkos-specific registration macro.");
352
353 return it->second;
354 }
355
360 std::map<std::pair<std::type_index, std::string>, std::unique_ptr<DispatcherRegistryEntryBase>>
362};
363
364template <typename T, typename = void>
366{
367};
368
369template <typename T>
371 std::void_t<typename T::InternalRightHandSideLoop,
372 typename T::BoundaryRightHandSideLoop,
373 typename T::InternalMatrixLoop,
374 typename T::BoundaryMatrixLoop>>
375 : std::true_type
376{
377};
378
379template <typename Object>
380bool
382{
383 return &Object::template computeMatrixContribution<Object> !=
384 Object::template defaultMatrixContribution<Object>() ||
385 &Object::template computeNeighborMatrixContribution<Object> !=
386 Object::template defaultNeighborMatrixContribution<Object>();
387}
388
389template <typename Object>
390bool
392{
393 return &Object::template computeInternalMatrixContribution<Object> !=
394 Object::template defaultInternalMatrixContribution<Object>() ||
395 &Object::template computeInternalNeighborMatrixContribution<Object> !=
396 Object::template defaultInternalNeighborMatrixContribution<Object>();
397}
398
399template <typename Object>
400bool
402{
403 return &Object::template computeBoundaryMatrixContribution<Object> !=
404 Object::template defaultBoundaryMatrixContribution<Object>();
405}
406
407template <typename Object>
408void
409registerLinearFVKernelDispatchers(const std::string & objectname)
410{
412 {
413 DispatcherRegistry::addDispatcher<typename Object::InternalRightHandSideLoop, Object>(
414 objectname);
415 DispatcherRegistry::addDispatcher<typename Object::BoundaryRightHandSideLoop, Object>(
416 objectname);
417 DispatcherRegistry::addDispatcher<typename Object::InternalMatrixLoop, Object>(objectname);
418 DispatcherRegistry::addDispatcher<typename Object::BoundaryMatrixLoop, Object>(objectname);
419
420 DispatcherRegistry::hasUserMethod<typename Object::InternalMatrixLoop>(
421 objectname, hasInternalLinearFVFluxMatrixContribution<Object>());
422 DispatcherRegistry::hasUserMethod<typename Object::BoundaryMatrixLoop>(
423 objectname, hasBoundaryLinearFVFluxMatrixContribution<Object>());
424 }
425 else
426 {
427 DispatcherRegistry::addDispatcher<typename Object::RightHandSideLoop, Object>(objectname);
428 DispatcherRegistry::addDispatcher<typename Object::MatrixLoop, Object>(objectname);
429
430 DispatcherRegistry::hasUserMethod<typename Object::MatrixLoop>(
431 objectname, hasLinearFVMatrixContribution<Object>());
432 }
433}
434
435} // namespace Moose::Kokkos
436
437// Kernel, NodalKernel, BC
438
439namespace Moose::Kokkos
440{
441
442template <typename Object>
443void
444registerResidualObjectDispatchers(const std::string & objectname)
445{
446 using namespace Moose::Kokkos;
447
448 DispatcherRegistry::addDispatcher<typename Object::ResidualLoop, Object>(objectname);
449 DispatcherRegistry::addDispatcher<typename Object::JacobianLoop, Object>(objectname);
450 DispatcherRegistry::addDispatcher<typename Object::OffDiagJacobianLoop, Object>(objectname);
451
452 if constexpr (Object::uses_precompute_hooks)
453 {
454 DispatcherRegistry::hasUserMethod<typename Object::JacobianLoop>(
455 objectname,
456 &Object::template precomputeQpJacobian<Object> !=
457 Object::template defaultJacobian<Object>());
458 DispatcherRegistry::hasUserMethod<typename Object::OffDiagJacobianLoop>(
459 objectname,
460 &Object::template precomputeQpOffDiagJacobian<Object> !=
461 Object::template defaultOffDiagJacobian<Object>());
462 }
463 else
464 {
465 DispatcherRegistry::hasUserMethod<typename Object::JacobianLoop>(
466 objectname,
467 &Object::template computeQpJacobian<Object> != Object::template defaultJacobian<Object>());
468 DispatcherRegistry::hasUserMethod<typename Object::OffDiagJacobianLoop>(
469 objectname,
470 &Object::template computeQpOffDiagJacobian<Object> !=
471 Object::template defaultOffDiagJacobian<Object>());
472 }
473
474 if constexpr (Object::supports_scalar_jacobian)
475 {
476 DispatcherRegistry::addDispatcher<typename Object::OffDiagJacobianScalarLoop, Object>(
477 objectname);
478 DispatcherRegistry::hasUserMethod<typename Object::OffDiagJacobianScalarLoop>(
479 objectname,
480 &Object::template computeQpOffDiagJacobianScalar<Object> !=
481 Object::template defaultOffDiagJacobianScalar<Object>());
482 }
483}
484
485} // namespace Moose::Kokkos
486
487#define callRegisterKokkosResidualObjectFunction(classname, objectname) \
488 static char registerKokkosResidualObject##classname() \
489 { \
490 using namespace Moose::Kokkos; \
491 \
492 registerResidualObjectDispatchers<classname>(objectname); \
493 \
494 return 0; \
495 } \
496 \
497 [[maybe_unused]] static char combineNames(kokkos_dispatcher_residual_object_##classname, \
498 __COUNTER__) = \
499 registerKokkosResidualObject##classname()
500
501#define registerKokkosResidualObject(app, classname) \
502 registerMooseObject(app, classname); \
503 callRegisterKokkosResidualObjectFunction(classname, #classname)
504
505#define registerKokkosResidualObjectAliased(app, classname, alias) \
506 registerMooseObjectAliased(app, classname, alias); \
507 callRegisterKokkosResidualObjectFunction(classname, alias)
508
509// AD Kernel, NodalKernel, BC
510
511#define callRegisterKokkosADResidualObjectFunction(classname, objectname) \
512 static char registerKokkosADResidualObject##classname() \
513 { \
514 using namespace Moose::Kokkos; \
515 \
516 DispatcherRegistry::addDispatcher<classname::ResidualLoop, classname>(objectname); \
517 \
518 return 0; \
519 } \
520 \
521 [[maybe_unused]] static char combineNames(kokkos_dispatcher_ad_residual_object_##classname, \
522 __COUNTER__) = \
523 registerKokkosADResidualObject##classname()
524
525#define registerKokkosADResidualObject(app, classname) \
526 registerMooseObject(app, classname); \
527 callRegisterKokkosADResidualObjectFunction(classname, #classname)
528
529#define registerKokkosADResidualObjectAliased(app, classname, alias) \
530 registerMooseObjectAliased(app, classname, alias); \
531 callRegisterKokkosADResidualObjectFunction(classname, alias)
532
533#define callRegisterKokkosLinearFVKernelFunction(classname, objectname) \
534 static char registerKokkosLinearFVKernel##classname() \
535 { \
536 using namespace Moose::Kokkos; \
537 \
538 registerLinearFVKernelDispatchers<classname>(objectname); \
539 \
540 return 0; \
541 } \
542 \
543 static char combineNames(kokkos_dispatcher_linear_fv_kernel_##classname, __COUNTER__) = \
544 registerKokkosLinearFVKernel##classname()
545
546#define registerKokkosLinearFVKernel(app, classname) \
547 registerMooseObject(app, classname); \
548 callRegisterKokkosLinearFVKernelFunction(classname, #classname)
549
550#define registerKokkosLinearFVKernelAliased(app, classname, alias) \
551 registerMooseObjectAliased(app, classname, alias); \
552 callRegisterKokkosLinearFVKernelFunction(classname, alias)
553
554#define callRegisterKokkosLinearFVBoundaryConditionFunction(classname, objectname) \
555 static char registerKokkosLinearFVBoundaryCondition##classname() \
556 { \
557 using namespace Moose::Kokkos; \
558 \
559 DispatcherRegistry::addDispatcher<classname::BoundaryValueLoop, classname>(objectname); \
560 DispatcherRegistry::addDispatcher<classname::BoundaryNormalGradientLoop, classname>( \
561 \
562 objectname); \
563 DispatcherRegistry::hasUserMethod<classname::BoundaryValueLoop>( \
564 objectname, \
565 &classname::computeBoundaryValue<classname> != \
566 classname::defaultBoundaryValue<classname>()); \
567 DispatcherRegistry::hasUserMethod<classname::BoundaryNormalGradientLoop>( \
568 objectname, \
569 &classname::computeBoundaryNormalGradient<classname> != \
570 classname::defaultBoundaryNormalGradient<classname>()); \
571 \
572 return 0; \
573 } \
574 \
575 static char combineNames(kokkos_dispatcher_linear_fv_boundary_condition_##classname, \
576 __COUNTER__) = registerKokkosLinearFVBoundaryCondition##classname()
577
578#define registerKokkosLinearFVBoundaryCondition(app, classname) \
579 registerMooseObject(app, classname); \
580 callRegisterKokkosLinearFVBoundaryConditionFunction(classname, #classname)
581
582#define registerKokkosLinearFVBoundaryConditionAliased(app, classname, alias) \
583 registerMooseObjectAliased(app, classname, alias); \
584 callRegisterKokkosLinearFVBoundaryConditionFunction(classname, alias)
585
586// Material
587
588#define callRegisterKokkosMaterialFunction(classname, objectname) \
589 static char registerKokkosMaterial##classname() \
590 { \
591 using namespace Moose::Kokkos; \
592 \
593 DispatcherRegistry::addDispatcher<classname::ElementInit, classname>(objectname); \
594 DispatcherRegistry::addDispatcher<classname::SideInit, classname>(objectname); \
595 DispatcherRegistry::addDispatcher<classname::NeighborInit, classname>(objectname); \
596 DispatcherRegistry::addDispatcher<classname::ElementCompute, classname>(objectname); \
597 DispatcherRegistry::addDispatcher<classname::SideCompute, classname>(objectname); \
598 DispatcherRegistry::addDispatcher<classname::NeighborCompute, classname>(objectname); \
599 \
600 DispatcherRegistry::hasUserMethod<classname::ElementInit>( \
601 objectname, \
602 &classname::initQpStatefulProperties<classname> != \
603 classname::defaultInitStateful<classname>()); \
604 DispatcherRegistry::hasUserMethod<classname::SideInit>( \
605 objectname, \
606 &classname::initQpStatefulProperties<classname> != \
607 classname::defaultInitStateful<classname>()); \
608 DispatcherRegistry::hasUserMethod<classname::NeighborInit>( \
609 objectname, \
610 &classname::initQpStatefulProperties<classname> != \
611 classname::defaultInitStateful<classname>()); \
612 \
613 return 0; \
614 } \
615 \
616 [[maybe_unused]] static char combineNames(kokkos_dispatcher_material_##classname, __COUNTER__) = \
617 registerKokkosMaterial##classname()
618
619#define registerKokkosMaterial(app, classname) \
620 registerMooseObject(app, classname); \
621 callRegisterKokkosMaterialFunction(classname, #classname)
622
623#define registerKokkosMaterialAliased(app, classname, alias) \
624 registerMooseObjectAliased(app, classname, alias); \
625 callRegisterKokkosMaterialFunction(classname, alias)
626
627// AuxKernel
628
629#define callRegisterKokkosAuxKernelFunction(classname, objectname) \
630 static char registerKokkosAuxKernel##classname() \
631 { \
632 using namespace Moose::Kokkos; \
633 \
634 DispatcherRegistry::addDispatcher<classname::ElementLoop, classname>(objectname); \
635 DispatcherRegistry::addDispatcher<classname::NodeLoop, classname>(objectname); \
636 \
637 return 0; \
638 } \
639 \
640 [[maybe_unused]] static char combineNames(kokkos_dispatcher_auxkernel_##classname, \
641 __COUNTER__) = registerKokkosAuxKernel##classname()
642
643#define registerKokkosAuxKernel(app, classname) \
644 registerMooseObject(app, classname); \
645 callRegisterKokkosAuxKernelFunction(classname, #classname)
646
647#define registerKokkosAuxKernelAliased(app, classname, alias) \
648 registerMooseObjectAliased(app, classname, alias); \
649 callRegisterKokkosAuxKernelFunction(classname, alias)
650
651// UserObject
652
653#define callRegisterKokkosUserObjectFunction(classname, objectname) \
654 static char registerKokkosUserObject##classname() \
655 { \
656 using namespace Moose::Kokkos; \
657 \
658 DispatcherRegistry::addDispatcher<classname::DefaultLoop, classname>(objectname); \
659 DispatcherRegistry::addReducer<classname::ReducerLoop, classname>(objectname); \
660 \
661 DispatcherRegistry::hasUserMethod<classname::DefaultLoop>( \
662 objectname, &classname::execute<classname> != classname::defaultExecute<classname>()); \
663 DispatcherRegistry::hasUserMethod<classname::ReducerLoop>( \
664 objectname, &classname::reduce<classname> != classname::defaultReduce<classname>()); \
665 \
666 return 0; \
667 } \
668 \
669 [[maybe_unused]] static char combineNames(kokkos_dispatcher_userobject_##classname, \
670 __COUNTER__) = registerKokkosUserObject##classname()
671
672#define registerKokkosUserObject(app, classname) \
673 registerMooseObject(app, classname); \
674 callRegisterKokkosUserObjectFunction(classname, #classname)
675
676#define registerKokkosUserObjectAliased(app, classname, alias) \
677 registerMooseObjectAliased(app, classname, alias); \
678 callRegisterKokkosUserObjectFunction(classname, alias)
679
680// User-defined parallel operation registry
681
682#define registerKokkosAdditionalOperation(classname, operation) \
683 static char registerKokkos##classname##operation() \
684 { \
685 using namespace Moose::Kokkos; \
686 \
687 DispatcherRegistry::addDispatcher<classname::operation, classname>(#classname); \
688 \
689 return 0; \
690 } \
691 \
692 [[maybe_unused]] static char combineNames(kokkos_##classname##_##operation, __COUNTER__) = \
693 registerKokkos##classname##operation()
void mooseError(Args &&... args)
Emit an error message with the given stringified, concatenated args and terminate the application.
Definition MooseError.h:311
Base class for Kokkos functor dispatcher.
virtual void parallelFor(const Policy &)
Dispatch this functor with Kokkos parallel_for() given a Kokkos execution policy.
virtual void parallelReduce(const Policy &, ::Kokkos::View< Real *, ::Kokkos::HostSpace > &)
Dispatch this functor with Kokkos parallel_reduce() given a Kokkos execution policy and result buffer...
Base class for dispatcher registry entry.
bool hasUserMethod() const
Get whether the user has overriden the hook method associated with this operation.
bool _has_user_method
Flag whether the user has overriden the hook method associated with this operation.
void hasUserMethod(bool flag)
Set whether the user has overriden the hook method associated with this operation.
virtual std::unique_ptr< DispatcherBase > build(const void *object) const =0
Build a dispatcher for this operation and functor.
Class that stores the information of a dispatcher and builds it.
std::unique_ptr< DispatcherBase > build(const void *object) const override final
Build a dispatcher for this operation and functor.
Class that registers dispatchers of all Kokkos functors.
std::map< std::pair< std::type_index, std::string >, std::unique_ptr< DispatcherRegistryEntryBase > > _dispatchers
Map containing the dispatcher shells with the key being the pair of function tag type index and regis...
static auto & getDispatcher(const std::string &name)
Get the dispatcher shell of an operation of a functor.
DispatcherRegistry & operator=(DispatcherRegistry const &)=delete
DispatcherRegistry(DispatcherRegistry &&)=delete
static void hasUserMethod(const std::string &name, const bool flag)
Set whether the user has overriden the hook method associated with an operation of a functor.
static std::unique_ptr< DispatcherBase > build(const void *object, const std::string &name)
Build and get a dispatcher of an operation of a functor.
DispatcherRegistry(DispatcherRegistry const &)=delete
DispatcherRegistry & operator=(DispatcherRegistry &&)=delete
static bool hasUserMethod(const std::string &name)
Get whether the user has overriden the hook method associated with an operation of a functor.
static void addDispatcher(const std::string &name)
Register a dispatcher of an operation of a functor.
static DispatcherRegistry & getRegistry()
Get the registry singleton.
static void addReducer(const std::string &name)
Register a reducer of an operation of a functor.
Class that dispatches a parallel loop operation of a Kokkos functor.
Dispatcher(const void *object)
Constructor.
const Object _functor_device
Copy of the functor on device.
KOKKOS_FUNCTION void operator()(const ThreadID tid) const
The parallel computation entry function called by Kokkos::parallel_for.
const Object & _functor_host
Reference of the functor on host.
void parallelFor(const Policy &policy) override final
Dispatch this functor with Kokkos parallel_for() given a Kokkos execution policy.
Dispatcher(const Dispatcher &functor)
Copy constructor for parallel dispatch.
std::unique_ptr< DispatcherBase > build(const void *object) const override final
Build a dispatcher for this operation and functor.
Class that dispatches a parallel reduction operation of a Kokkos functor.
const Object & _functor_host
Reference of the functor on host.
KOKKOS_FUNCTION void init(value_type result) const
KOKKOS_FUNCTION void join(value_type result, const value_type source) const
Functions required by the reducer concept of Kokkos.
Reducer(const void *object)
Constructor.
const Object _functor_device
Copy of the functor on device.
Reducer(const Reducer &functor)
Copy constructor for parallel dispatch.
void parallelReduce(const Policy &policy, ::Kokkos::View< Real *, ::Kokkos::HostSpace > &result) override final
Dispatch this functor with Kokkos parallel_reduce() given a Kokkos execution policy and result buffer...
::Kokkos::View< Real * >::size_type size_type
KOKKOS_FUNCTION void operator()(const ThreadID tid, value_type result) const
The parallel computation entry function called by Kokkos::parallel_reduce.
void registerResidualObjectDispatchers(const std::string &objectname)
bool hasBoundaryLinearFVFluxMatrixContribution()
::Kokkos::RangePolicy< ExecSpace, ::Kokkos::IndexType< ThreadID > > Policy
bool hasLinearFVMatrixContribution()
bool hasInternalLinearFVFluxMatrixContribution()
MOOSE_KOKKOS_INDEX_TYPE ThreadID
void registerLinearFVKernelDispatchers(const std::string &objectname)