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 DispatcherRegistry::hasUserMethod<typename Object::MatrixLoop>(
430 objectname, hasLinearFVMatrixContribution<Object>());
431 }
432}
433
434} // namespace Moose::Kokkos
435
436// Kernel, NodalKernel, BC
437
438namespace Moose::Kokkos
439{
440
441template <typename Object>
442bool
444{
445 if constexpr (Object::use_precompute_hooks)
446 return &Object::template precomputeQpJacobian<Object> !=
447 Object::template defaultJacobian<Object>();
448 else
449 return &Object::template computeQpJacobian<Object> !=
450 Object::template defaultJacobian<Object>();
451}
452
453template <typename Object>
454bool
456{
457 if constexpr (Object::use_precompute_hooks)
458 return &Object::template precomputeQpOffDiagJacobian<Object> !=
459 Object::template defaultOffDiagJacobian<Object>();
460 else
461 return &Object::template computeQpOffDiagJacobian<Object> !=
462 Object::template defaultOffDiagJacobian<Object>();
463}
464
465} // namespace Moose::Kokkos
466
467#define callRegisterKokkosResidualObjectFunction(classname, objectname) \
468 static char registerKokkosResidualObject##classname() \
469 { \
470 using namespace Moose::Kokkos; \
471 \
472 DispatcherRegistry::addDispatcher<classname::ResidualLoop, classname>(objectname); \
473 DispatcherRegistry::addDispatcher<classname::JacobianLoop, classname>(objectname); \
474 DispatcherRegistry::addDispatcher<classname::OffDiagJacobianLoop, classname>(objectname); \
475 DispatcherRegistry::hasUserMethod<classname::JacobianLoop>(objectname, \
476 hasUserJacobianHook<classname>()); \
477 DispatcherRegistry::hasUserMethod<classname::OffDiagJacobianLoop>( \
478 objectname, hasUserOffDiagJacobianHook<classname>()); \
479 \
480 return 0; \
481 } \
482 \
483 [[maybe_unused]] static char combineNames(kokkos_dispatcher_residual_object_##classname, \
484 __COUNTER__) = \
485 registerKokkosResidualObject##classname()
486
487#define registerKokkosResidualObject(app, classname) \
488 registerMooseObject(app, classname); \
489 callRegisterKokkosResidualObjectFunction(classname, #classname)
490
491#define registerKokkosResidualObjectAliased(app, classname, alias) \
492 registerMooseObjectAliased(app, classname, alias); \
493 callRegisterKokkosResidualObjectFunction(classname, alias)
494
495// AD Kernel, NodalKernel, BC
496
497#define callRegisterKokkosADResidualObjectFunction(classname, objectname) \
498 static char registerKokkosADResidualObject##classname() \
499 { \
500 using namespace Moose::Kokkos; \
501 \
502 DispatcherRegistry::addDispatcher<classname::ResidualLoop, classname>(objectname); \
503 \
504 return 0; \
505 } \
506 \
507 [[maybe_unused]] static char combineNames(kokkos_dispatcher_ad_residual_object_##classname, \
508 __COUNTER__) = \
509 registerKokkosADResidualObject##classname()
510
511#define registerKokkosADResidualObject(app, classname) \
512 registerMooseObject(app, classname); \
513 callRegisterKokkosADResidualObjectFunction(classname, #classname)
514
515#define registerKokkosADResidualObjectAliased(app, classname, alias) \
516 registerMooseObjectAliased(app, classname, alias); \
517 callRegisterKokkosADResidualObjectFunction(classname, alias)
518
519#define callRegisterKokkosLinearFVKernelFunction(classname, objectname) \
520 static char registerKokkosLinearFVKernel##classname() \
521 { \
522 using namespace Moose::Kokkos; \
523 \
524 registerLinearFVKernelDispatchers<classname>(objectname); \
525 \
526 return 0; \
527 } \
528 \
529 static char combineNames(kokkos_dispatcher_linear_fv_kernel_##classname, __COUNTER__) = \
530 registerKokkosLinearFVKernel##classname()
531
532#define registerKokkosLinearFVKernel(app, classname) \
533 registerMooseObject(app, classname); \
534 callRegisterKokkosLinearFVKernelFunction(classname, #classname)
535
536#define registerKokkosLinearFVKernelAliased(app, classname, alias) \
537 registerMooseObjectAliased(app, classname, alias); \
538 callRegisterKokkosLinearFVKernelFunction(classname, alias)
539
540#define callRegisterKokkosLinearFVBoundaryConditionFunction(classname, objectname) \
541 static char registerKokkosLinearFVBoundaryCondition##classname() \
542 { \
543 using namespace Moose::Kokkos; \
544 \
545 DispatcherRegistry::addDispatcher<classname::BoundaryValueLoop, classname>(objectname); \
546 DispatcherRegistry::addDispatcher<classname::BoundaryNormalGradientLoop, classname>( \
547 objectname); \
548 DispatcherRegistry::hasUserMethod<classname::BoundaryValueLoop>( \
549 objectname, \
550 &classname::computeBoundaryValue<classname> != \
551 classname::defaultBoundaryValue<classname>()); \
552 DispatcherRegistry::hasUserMethod<classname::BoundaryNormalGradientLoop>( \
553 objectname, \
554 &classname::computeBoundaryNormalGradient<classname> != \
555 classname::defaultBoundaryNormalGradient<classname>()); \
556 \
557 return 0; \
558 } \
559 \
560 static char combineNames(kokkos_dispatcher_linear_fv_boundary_condition_##classname, \
561 __COUNTER__) = registerKokkosLinearFVBoundaryCondition##classname()
562
563#define registerKokkosLinearFVBoundaryCondition(app, classname) \
564 registerMooseObject(app, classname); \
565 callRegisterKokkosLinearFVBoundaryConditionFunction(classname, #classname)
566
567#define registerKokkosLinearFVBoundaryConditionAliased(app, classname, alias) \
568 registerMooseObjectAliased(app, classname, alias); \
569 callRegisterKokkosLinearFVBoundaryConditionFunction(classname, alias)
570
571// Material
572
573#define callRegisterKokkosMaterialFunction(classname, objectname) \
574 static char registerKokkosMaterial##classname() \
575 { \
576 using namespace Moose::Kokkos; \
577 \
578 DispatcherRegistry::addDispatcher<classname::ElementInit, classname>(objectname); \
579 DispatcherRegistry::addDispatcher<classname::SideInit, classname>(objectname); \
580 DispatcherRegistry::addDispatcher<classname::NeighborInit, classname>(objectname); \
581 DispatcherRegistry::addDispatcher<classname::ElementCompute, classname>(objectname); \
582 DispatcherRegistry::addDispatcher<classname::SideCompute, classname>(objectname); \
583 DispatcherRegistry::addDispatcher<classname::NeighborCompute, classname>(objectname); \
584 DispatcherRegistry::hasUserMethod<classname::ElementInit>( \
585 objectname, \
586 &classname::initQpStatefulProperties<classname> != \
587 classname::defaultInitStateful<classname>()); \
588 DispatcherRegistry::hasUserMethod<classname::SideInit>( \
589 objectname, \
590 &classname::initQpStatefulProperties<classname> != \
591 classname::defaultInitStateful<classname>()); \
592 DispatcherRegistry::hasUserMethod<classname::NeighborInit>( \
593 objectname, \
594 &classname::initQpStatefulProperties<classname> != \
595 classname::defaultInitStateful<classname>()); \
596 \
597 return 0; \
598 } \
599 \
600 [[maybe_unused]] static char combineNames(kokkos_dispatcher_material_##classname, __COUNTER__) = \
601 registerKokkosMaterial##classname()
602
603#define registerKokkosMaterial(app, classname) \
604 registerMooseObject(app, classname); \
605 callRegisterKokkosMaterialFunction(classname, #classname)
606
607#define registerKokkosMaterialAliased(app, classname, alias) \
608 registerMooseObjectAliased(app, classname, alias); \
609 callRegisterKokkosMaterialFunction(classname, alias)
610
611// AuxKernel
612
613#define callRegisterKokkosAuxKernelFunction(classname, objectname) \
614 static char registerKokkosAuxKernel##classname() \
615 { \
616 using namespace Moose::Kokkos; \
617 \
618 DispatcherRegistry::addDispatcher<classname::ElementLoop, classname>(objectname); \
619 DispatcherRegistry::addDispatcher<classname::NodeLoop, classname>(objectname); \
620 \
621 return 0; \
622 } \
623 \
624 [[maybe_unused]] static char combineNames(kokkos_dispatcher_auxkernel_##classname, \
625 __COUNTER__) = registerKokkosAuxKernel##classname()
626
627#define registerKokkosAuxKernel(app, classname) \
628 registerMooseObject(app, classname); \
629 callRegisterKokkosAuxKernelFunction(classname, #classname)
630
631#define registerKokkosAuxKernelAliased(app, classname, alias) \
632 registerMooseObjectAliased(app, classname, alias); \
633 callRegisterKokkosAuxKernelFunction(classname, alias)
634
635// UserObject
636
637#define callRegisterKokkosUserObjectFunction(classname, objectname) \
638 static char registerKokkosUserObject##classname() \
639 { \
640 using namespace Moose::Kokkos; \
641 \
642 DispatcherRegistry::addDispatcher<classname::DefaultLoop, classname>(objectname); \
643 DispatcherRegistry::addReducer<classname::ReducerLoop, classname>(objectname); \
644 DispatcherRegistry::hasUserMethod<classname::DefaultLoop>( \
645 objectname, &classname::execute<classname> != classname::defaultExecute<classname>()); \
646 DispatcherRegistry::hasUserMethod<classname::ReducerLoop>( \
647 objectname, &classname::reduce<classname> != classname::defaultReduce<classname>()); \
648 \
649 return 0; \
650 } \
651 \
652 [[maybe_unused]] static char combineNames(kokkos_dispatcher_userobject_##classname, \
653 __COUNTER__) = registerKokkosUserObject##classname()
654
655#define registerKokkosUserObject(app, classname) \
656 registerMooseObject(app, classname); \
657 callRegisterKokkosUserObjectFunction(classname, #classname)
658
659#define registerKokkosUserObjectAliased(app, classname, alias) \
660 registerMooseObjectAliased(app, classname, alias); \
661 callRegisterKokkosUserObjectFunction(classname, alias)
662
663// User-defined parallel operation registry
664
665#define registerKokkosAdditionalOperation(classname, operation) \
666 static char registerKokkos##classname##operation() \
667 { \
668 using namespace Moose::Kokkos; \
669 \
670 DispatcherRegistry::addDispatcher<classname::operation, classname>(#classname); \
671 \
672 return 0; \
673 } \
674 \
675 [[maybe_unused]] static char combineNames(kokkos_##classname##_##operation, __COUNTER__) = \
676 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.
bool hasUserOffDiagJacobianHook()
bool hasBoundaryLinearFVFluxMatrixContribution()
::Kokkos::RangePolicy< ExecSpace, ::Kokkos::IndexType< ThreadID > > Policy
bool hasLinearFVMatrixContribution()
bool hasInternalLinearFVFluxMatrixContribution()
MOOSE_KOKKOS_INDEX_TYPE ThreadID
void registerLinearFVKernelDispatchers(const std::string &objectname)