@@ -131,28 +131,33 @@ class MGTwoLevelTransferBase : public EnableObserverPointer
131131 MemorySpace::Default>>,
132132 " This class is currently only implemented for vectors of "
133133 " type LinearAlgebra::distributed::Vector." );
134+ /* *
135+ * Partitioner needed by the intermediate vector.
136+ */
137+ std::shared_ptr<const Utilities::MPI::Partitioner> partitioner_coarse;
134138
135139 /* *
136- * The scalar type used by the vector-type template argument .
140+ * Partitioner needed by the intermediate vector .
137141 */
138- using Number = typename VectorType::value_type ;
142+ std::shared_ptr< const Utilities::MPI::Partitioner> partitioner_fine ;
139143
140144 /* *
141145 * Default constructor.
142146 */
143- MGTwoLevelTransferBase ();
147+ MGTwoLevelTransferBase ()
148+ {}
144149
145150 /* *
146151 * Perform prolongation on a solution vector.
147152 */
148- void
149- prolongate_and_add (VectorType &dst, const VectorType &src) const ;
153+ virtual void
154+ prolongate_and_add (VectorType &dst, const VectorType &src) const = 0 ;
150155
151156 /* *
152157 * Perform restriction on a residual vector.
153158 */
154- void
155- restrict_and_add (VectorType &dst, const VectorType &src) const ;
159+ virtual void
160+ restrict_and_add (VectorType &dst, const VectorType &src) const = 0 ;
156161
157162 /* *
158163 * Perform interpolation of a solution vector from the fine level to the
@@ -181,6 +186,51 @@ class MGTwoLevelTransferBase : public EnableObserverPointer
181186 */
182187 virtual std::size_t
183188 memory_consumption () const = 0 ;
189+ };
190+
191+
192+
193+ /* *
194+ * A class which provides extra functionality used by several MGTwoLevelTransfer
195+ * schemes.
196+ */
197+ template <typename VectorType>
198+ class MGTwoLevelTransferCore : public MGTwoLevelTransferBase <VectorType>
199+ {
200+ public:
201+ static_assert (
202+ std::is_same_v<
203+ VectorType,
204+ LinearAlgebra::distributed::Vector<typename VectorType::value_type,
205+ MemorySpace::Host>> ||
206+ std::is_same_v<
207+ VectorType,
208+ LinearAlgebra::distributed::Vector<typename VectorType::value_type,
209+ MemorySpace::Default>>,
210+ " This class is currently only implemented for vectors of "
211+ " type LinearAlgebra::distributed::Vector." );
212+
213+ /* *
214+ * The scalar type used by the vector-type template argument.
215+ */
216+ using Number = typename VectorType::value_type;
217+
218+ /* *
219+ * Default constructor.
220+ */
221+ MGTwoLevelTransferCore ();
222+
223+ /* *
224+ * @copydoc MGTwoLevelTransferBase::prolongate_and_add
225+ */
226+ void
227+ prolongate_and_add (VectorType &dst, const VectorType &src) const override ;
228+
229+ /* *
230+ * @copydoc MGTwoLevelTransferBase::restrict_and_add
231+ */
232+ void
233+ restrict_and_add (VectorType &dst, const VectorType &src) const override ;
184234
185235protected:
186236 /* *
@@ -242,17 +292,6 @@ class MGTwoLevelTransferBase : public EnableObserverPointer
242292 */
243293 bool fine_element_is_continuous;
244294
245- public:
246- /* *
247- * Partitioner needed by the intermediate vector.
248- */
249- std::shared_ptr<const Utilities::MPI::Partitioner> partitioner_coarse;
250-
251- /* *
252- * Partitioner needed by the intermediate vector.
253- */
254- std::shared_ptr<const Utilities::MPI::Partitioner> partitioner_fine;
255-
256295protected:
257296 /* *
258297 * Internal vector on which the actual prolongation/restriction is performed.
@@ -327,7 +366,7 @@ class MGTwoLevelTransferBase : public EnableObserverPointer
327366 * point, and we fall back to the first option in such a case.
328367 */
329368template <int dim, typename VectorType>
330- class MGTwoLevelTransfer : public MGTwoLevelTransferBase <VectorType>
369+ class MGTwoLevelTransfer : public MGTwoLevelTransferCore <VectorType>
331370{
332371public:
333372 static_assert (
@@ -627,6 +666,250 @@ class MGTwoLevelTransfer : public MGTwoLevelTransferBase<VectorType>
627666
628667 friend class internal ::MGTwoLevelTransferImplementation;
629668
669+ friend class MGTransferMatrixFree <dim, Number, MemorySpace::Host>;
670+
671+ friend class MGTransferMatrixFree <dim, Number, MemorySpace::Default>;
672+ };
673+
674+
675+ /* *
676+ * A transfer class supporting device vectors via copying them to the host and
677+ * using an internal trasfer of type MGTwoLevelTransfer defined on the
678+ * host.
679+ */
680+ template <int dim, typename VectorType>
681+ class MGTwoLevelTransferCopyToHost : public MGTwoLevelTransferBase <VectorType>
682+ {
683+ public:
684+ static_assert (
685+ std::is_same_v<
686+ VectorType,
687+ LinearAlgebra::distributed::Vector<typename VectorType::value_type,
688+ MemorySpace::Host>> ||
689+ std::is_same_v<
690+ VectorType,
691+ LinearAlgebra::distributed::Vector<typename VectorType::value_type,
692+ MemorySpace::Default>>,
693+ " This class is currently only implemented for vectors of "
694+ " type LinearAlgebra::distributed::Vector." );
695+
696+
697+ /* *
698+ * The scalar type used by the vector-type template argument.
699+ */
700+ using Number = typename VectorType::value_type;
701+
702+ using VectorTypeHost = LinearAlgebra::distributed::Vector<Number>;
703+ /* *
704+ * Default constructor.
705+ */
706+ MGTwoLevelTransferCopyToHost ()
707+ : host_transfer()
708+ {}
709+
710+ /* *
711+ * @copydoc MGTwoLevelTransfer::reinit_geometric_transfer
712+ */
713+ void
714+ reinit_geometric_transfer (
715+ const DoFHandler<dim> &dof_handler_fine,
716+ const DoFHandler<dim> &dof_handler_coarse,
717+ const AffineConstraints<Number> &constraint_fine =
718+ AffineConstraints<Number>(),
719+ const AffineConstraints<Number> &constraint_coarse =
720+ AffineConstraints<Number>(),
721+ const unsigned int mg_level_fine = numbers::invalid_unsigned_int,
722+ const unsigned int mg_level_coarse = numbers::invalid_unsigned_int)
723+ {
724+ host_transfer.reinit_geometric_transfer (dof_handler_fine,
725+ dof_handler_coarse,
726+ constraint_fine,
727+ constraint_coarse,
728+ mg_level_fine,
729+ mg_level_coarse);
730+ }
731+
732+ /* *
733+ * @copydoc MGTwoLevelTransfer::reinit_polynomial_transfer
734+ */
735+ void
736+ reinit_polynomial_transfer (
737+ const DoFHandler<dim> &dof_handler_fine,
738+ const DoFHandler<dim> &dof_handler_coarse,
739+ const AffineConstraints<Number> &constraint_fine =
740+ AffineConstraints<Number>(),
741+ const AffineConstraints<Number> &constraint_coarse =
742+ AffineConstraints<Number>(),
743+ const unsigned int mg_level_fine = numbers::invalid_unsigned_int,
744+ const unsigned int mg_level_coarse = numbers::invalid_unsigned_int)
745+ {
746+ host_transfer.reinit_polynomial_transfer (dof_handler_fine,
747+ dof_handler_coarse,
748+ constraint_fine,
749+ constraint_coarse,
750+ mg_level_fine,
751+ mg_level_coarse);
752+ }
753+
754+ /* *
755+ * @copydoc MGTwoLevelTransfer::reinit(const DoFHandler<dim>, const DoFHandler<dim>, const AffineConstraints<Number>, const AffineConstraints<Number>, const unsigned int, const unsigned int)
756+ */
757+ void
758+ reinit (const DoFHandler<dim> &dof_handler_fine,
759+ const DoFHandler<dim> &dof_handler_coarse,
760+ const AffineConstraints<Number> &constraint_fine =
761+ AffineConstraints<Number>(),
762+ const AffineConstraints<Number> &constraint_coarse =
763+ AffineConstraints<Number>(),
764+ const unsigned int mg_level_fine = numbers::invalid_unsigned_int,
765+ const unsigned int mg_level_coarse = numbers::invalid_unsigned_int)
766+ {
767+ host_transfer.reinit (dof_handler_fine,
768+ dof_handler_coarse,
769+ constraint_fine,
770+ constraint_coarse,
771+ mg_level_fine,
772+ mg_level_coarse);
773+ }
774+
775+ /* *
776+ * @copydoc MGTwoLevelTransfer::reinit(const MatrixFree<dim, Number>, const unsigned int, const MatrixFree<dim, Number>, const unsigned int)
777+ */
778+ void
779+ reinit (const MatrixFree<dim, Number> &matrix_free_fine,
780+ const unsigned int dof_no_fine,
781+ const MatrixFree<dim, Number> &matrix_free_coarse,
782+ const unsigned int dof_no_coarse)
783+ {
784+ host_transfer.reinit (matrix_free_fine,
785+ dof_no_fine,
786+ matrix_free_coarse,
787+ dof_no_coarse);
788+ }
789+
790+ /* *
791+ * @copydoc MGTwoLevelTransfer::fast_polynomial_transfer_supported
792+ */
793+ bool
794+ fast_polynomial_transfer_supported (const unsigned int fe_degree_fine,
795+ const unsigned int fe_degree_coarse)
796+ {
797+ return host_transfer.fast_polynomial_transfer_supported (fe_degree_fine,
798+ fe_degree_coarse);
799+ }
800+
801+ /* *
802+ * @copydoc MGTwoLevelTransfer::prolongate_and_add
803+ */
804+ void
805+ prolongate_and_add (VectorType &dst, const VectorType &src) const override
806+ {
807+ VectorTypeHost dst_host;
808+ VectorTypeHost src_host;
809+
810+ dst_host.reinit (dst.get_partitioner ());
811+ copy_to_host (src_host, src);
812+
813+ host_transfer.prolongate_and_add (dst_host, src_host);
814+
815+ copy_from_host (dst, dst_host);
816+ }
817+
818+ /* *
819+ * @copydoc MGTwoLevelTransfer::restrict_and_add
820+ */
821+ void
822+ restrict_and_add (VectorType &dst, const VectorType &src) const override
823+ {
824+ VectorTypeHost dst_host;
825+ VectorTypeHost src_host;
826+
827+ copy_to_host (dst_host, dst);
828+ copy_to_host (src_host, src);
829+
830+ host_transfer.restrict_and_add (dst_host, src_host);
831+
832+ copy_from_host (dst, dst_host);
833+ }
834+
835+ /* *
836+ * @copydoc MGTwoLevelTransfer::interpolate
837+ */
838+ void
839+ interpolate (VectorType &dst, const VectorType &src) const override
840+ {
841+ VectorTypeHost dst_host;
842+ VectorTypeHost src_host;
843+
844+ copy_to_host (dst_host, dst);
845+ copy_to_host (src_host, src);
846+
847+ host_transfer.interpolate (dst_host, src_host);
848+
849+ copy_from_host (dst, dst_host);
850+ }
851+
852+ /* *
853+ * @copydoc MGTwoLevelTransfer::enable_inplace_operations_if_possible
854+ */
855+ std::pair<bool , bool >
856+ enable_inplace_operations_if_possible (
857+ const std::shared_ptr<const Utilities::MPI::Partitioner>
858+ &partitioner_coarse,
859+ const std::shared_ptr<const Utilities::MPI::Partitioner> &partitioner_fine)
860+ override
861+ {
862+ return host_transfer.enable_inplace_operations_if_possible (
863+ partitioner_coarse, partitioner_fine);
864+ }
865+
866+ /* *
867+ * @copydoc MGTwoLevelTransfer::memory_consumption
868+ */
869+ std::size_t
870+ memory_consumption () const override
871+ {
872+ return host_transfer.memory_consumption ();
873+ }
874+
875+ private:
876+ /* *
877+ * The internal transfer defined on the host which handles all operations.
878+ */
879+ MGTwoLevelTransfer<dim, VectorTypeHost> host_transfer;
880+
881+
882+ /* *
883+ * Copies a device vector to a host vector.
884+ */
885+ void
886+ copy_to_host (VectorTypeHost &dst, const VectorType &src) const
887+ {
888+ LinearAlgebra::ReadWriteVector<Number> rw_vector (
889+ src.get_partitioner ()->locally_owned_range ());
890+ rw_vector.import_elements (src, VectorOperation::insert);
891+
892+ dst.reinit (src.get_partitioner ());
893+ dst.import_elements (rw_vector, VectorOperation::insert);
894+ }
895+
896+ /* *
897+ * Copies a host vector to a device vector.
898+ */
899+ void
900+ copy_from_host (VectorType &dst, const VectorTypeHost &src) const
901+ {
902+ LinearAlgebra::ReadWriteVector<Number> rw_vector (
903+ src.get_partitioner ()->locally_owned_range ());
904+ rw_vector.import_elements (src, VectorOperation::insert);
905+
906+ if (dst.size () == 0 )
907+ dst.reinit (src.get_partitioner ());
908+ dst.import_elements (rw_vector, VectorOperation::insert);
909+ }
910+
911+ friend class internal ::MGTwoLevelTransferImplementation;
912+
630913 friend class MGTransferMatrixFree <dim,
631914 Number,
632915 typename VectorType::memory_space>;
@@ -638,7 +921,7 @@ class MGTwoLevelTransfer : public MGTwoLevelTransferBase<VectorType>
638921 * Class for transfer between two non-nested multigrid levels.
639922 */
640923template <int dim, typename VectorType>
641- class MGTwoLevelTransferNonNested : public MGTwoLevelTransferBase <VectorType>
924+ class MGTwoLevelTransferNonNested : public MGTwoLevelTransferCore <VectorType>
642925{
643926private:
644927 static_assert (
0 commit comments