44 #include "DTK_BasicEntityPredicates.hpp" 46 #include "DTK_IntegrationPoint.hpp" 47 #include "DTK_L2ProjectionOperator.hpp" 48 #include "DTK_ParallelSearch.hpp" 49 #include "DTK_PredicateComposition.hpp" 51 #include <Teuchos_OrdinalTraits.hpp> 53 #include <Teuchos_XMLParameterListCoreHelpers.hpp> 55 #include <Tpetra_Distributor.hpp> 57 #include <BelosPseudoBlockCGSolMgr.hpp> 59 #include <Thyra_DefaultMultipliedLinearOp.hpp> 60 #include <Thyra_LinearOpWithSolveFactoryHelpers.hpp> 61 #include <Thyra_TpetraThyraWrappers.hpp> 63 #include <Stratimikos_DefaultLinearSolverBuilder.hpp> 70 const Teuchos::RCP<const TpetraMap> &domain_map,
71 const Teuchos::RCP<const TpetraMap> &range_map,
72 const Teuchos::ParameterList ¶meters )
73 :
Base( domain_map, range_map )
76 const Teuchos::ParameterList &l2_list =
77 parameters.sublist(
"L2 Projection" );
78 DTK_REQUIRE( l2_list.isParameter(
"Integration Order" ) );
79 d_int_order = l2_list.get<
int>(
"Integration Order" );
82 d_search_list = parameters.sublist(
"Search" );
87 void L2ProjectionOperator::setupImpl(
88 const Teuchos::RCP<FunctionSpace> &domain_space,
89 const Teuchos::RCP<FunctionSpace> &range_space )
91 DTK_REQUIRE( Teuchos::nonnull( domain_space ) );
92 DTK_REQUIRE( Teuchos::nonnull( range_space ) );
95 Teuchos::RCP<const Teuchos::Comm<int>> comm =
96 this->getDomainMap()->getComm();
99 bool nonnull_domain = Teuchos::nonnull( domain_space->entitySet() );
100 bool nonnull_range = Teuchos::nonnull( range_space->entitySet() );
104 if ( nonnull_domain )
106 LocalEntityPredicate local_predicate(
107 domain_space->entitySet()->communicator()->getRank() );
109 domain_space->selectFunction(), local_predicate.getFunction() );
110 domain_iterator = domain_space->entitySet()->entityIterator(
111 domain_space->entitySet()->physicalDimension(), domain_predicate );
118 LocalEntityPredicate local_predicate(
119 range_space->entitySet()->communicator()->getRank() );
121 range_space->selectFunction(), local_predicate.getFunction() );
122 range_iterator = range_space->entitySet()->entityIterator(
123 range_space->entitySet()->physicalDimension(), range_predicate );
127 Teuchos::RCP<Tpetra::CrsMatrix<Scalar, LO, GO>> mass_matrix;
128 Teuchos::RCP<IntegrationPointSet> range_ip_set;
129 assembleMassMatrix( range_space, range_iterator, mass_matrix,
133 Teuchos::RCP<Tpetra::CrsMatrix<Scalar, LO, GO>> coupling_matrix;
134 assembleCouplingMatrix( domain_space, domain_iterator, range_ip_set,
138 Teuchos::RCP<const Thyra::VectorSpaceBase<double>>
139 thyra_range_vector_space_M =
140 Thyra::createVectorSpace<double>( mass_matrix->getRangeMap() );
141 Teuchos::RCP<const Thyra::VectorSpaceBase<double>>
142 thyra_domain_vector_space_M =
143 Thyra::createVectorSpace<double>( mass_matrix->getDomainMap() );
144 Teuchos::RCP<const Thyra::TpetraLinearOp<Scalar, LO, GO>> thyra_M =
145 Teuchos::rcp(
new Thyra::TpetraLinearOp<Scalar, LO, GO>() );
146 Teuchos::rcp_const_cast<Thyra::TpetraLinearOp<Scalar, LO, GO>>( thyra_M )
147 ->constInitialize( thyra_range_vector_space_M,
148 thyra_domain_vector_space_M, mass_matrix );
151 Teuchos::RCP<const Thyra::VectorSpaceBase<double>>
152 thyra_range_vector_space_A =
153 Thyra::createVectorSpace<double>( coupling_matrix->getRangeMap() );
154 Teuchos::RCP<const Thyra::VectorSpaceBase<double>>
155 thyra_domain_vector_space_A =
156 Thyra::createVectorSpace<double>( coupling_matrix->getDomainMap() );
157 Teuchos::RCP<const Thyra::TpetraLinearOp<Scalar, LO, GO>> thyra_A =
158 Teuchos::rcp(
new Thyra::TpetraLinearOp<Scalar, LO, GO>() );
159 Teuchos::rcp_const_cast<Thyra::TpetraLinearOp<Scalar, LO, GO>>( thyra_A )
160 ->constInitialize( thyra_range_vector_space_A,
161 thyra_domain_vector_space_A, coupling_matrix );
165 Teuchos::RCP<Teuchos::ParameterList> builder_params =
166 Teuchos::parameterList(
"Stratimikos" );
168 builder_params->set(
"Linear Solver Type",
"Belos" );
169 builder_params->set(
"Preconditioner Type",
"None" );
171 auto &linear_solver_types_list =
172 builder_params->sublist(
"Linear Solver Types" );
173 auto &belos_list = linear_solver_types_list.sublist(
"Belos" );
174 belos_list.set(
"Solver Type",
"Pseudo Block CG" );
175 auto &solver_types_list = belos_list.sublist(
"Solver Types" );
176 auto &cg_list = solver_types_list.sublist(
"Pseudo Block CG" );
177 cg_list.set(
"Convergence Tolerance", 1.0e-10 );
178 cg_list.set(
"Verbosity", Belos::Errors + Belos::Warnings +
179 Belos::TimingDetails + Belos::FinalSummary +
180 Belos::StatusTestDetails );
181 cg_list.set(
"Output Frequency", 1 );
183 Stratimikos::DefaultLinearSolverBuilder builder;
184 builder.setParameterList( builder_params );
185 Teuchos::RCP<Thyra::LinearOpWithSolveFactoryBase<double>> factory =
186 Thyra::createLinearSolveStrategy( builder );
187 Teuchos::RCP<const Thyra::LinearOpBase<double>> thyra_M_inv =
188 Thyra::inverse<double>( *factory, thyra_M );
191 d_l2_operator = Thyra::multiply<double>( thyra_M_inv, thyra_A );
192 DTK_ENSURE( Teuchos::nonnull( d_l2_operator ) );
198 TpetraMultiVector &Y,
199 Teuchos::ETransp mode,
double alpha,
202 DTK_REQUIRE( Teuchos::NO_TRANS == mode );
203 Teuchos::RCP<const Thyra::MultiVectorBase<double>> thyra_X =
204 Thyra::createConstMultiVector<double>( Teuchos::rcpFromRef( X ) );
205 Teuchos::RCP<Thyra::MultiVectorBase<double>> thyra_Y =
206 Thyra::createMultiVector<double>( Teuchos::rcpFromRef( Y ) );
207 d_l2_operator->apply( Thyra::NOTRANS, *thyra_X, thyra_Y.ptr(), alpha,
213 bool L2ProjectionOperator::hasTransposeApplyImpl()
const {
return false; }
217 void L2ProjectionOperator::assembleMassMatrix(
218 const Teuchos::RCP<FunctionSpace> &range_space,
220 Teuchos::RCP<Tpetra::CrsMatrix<Scalar, LO, GO>> &mass_matrix,
221 Teuchos::RCP<IntegrationPointSet> &range_ip_set )
224 Teuchos::RCP<const Teuchos::Comm<int>> range_comm =
225 range_space->entitySet()->communicator();
227 Tpetra::createCrsMatrix<Scalar, LO, GO>( this->getRangeMap() );
228 range_ip_set = Teuchos::rcp(
new IntegrationPointSet( range_comm ) );
231 Teuchos::RCP<EntityLocalMap> range_local_map = range_space->localMap();
232 Teuchos::RCP<EntityShapeFunction> range_shape_function =
233 range_space->shapeFunction();
234 Teuchos::RCP<EntityIntegrationRule> range_integration_rule =
235 range_space->integrationRule();
238 double range_entity_measure = 0.0;
239 IntegrationPoint range_ip;
240 range_ip.d_physical_coordinates.resize(
241 range_space->entitySet()->physicalDimension() );
242 Teuchos::Array<Teuchos::Array<double>> int_points;
243 Teuchos::Array<double> int_weights;
244 Teuchos::Array<Teuchos::Array<double>> shape_evals;
245 Teuchos::Array<SupportId> range_support_ids;
246 Teuchos::Array<double> mm_values;
247 int range_cardinality = 0;
255 for ( range_it = range_begin; range_it != range_end; ++range_it )
258 range_shape_function->entitySupportIds( *range_it, range_support_ids );
261 range_entity_measure = range_local_map->measure( *range_it );
264 range_integration_rule->getIntegrationRule( *range_it, d_int_order,
265 int_points, int_weights );
268 num_ip = int_weights.size();
269 shape_evals.resize( num_ip );
270 for (
int p = 0; p < num_ip; ++p )
273 range_ip.d_owner_measure = range_entity_measure;
274 range_ip.d_owner_support_ids = range_support_ids;
275 range_ip.d_integration_weight = int_weights[p];
278 range_shape_function->evaluateValue( *range_it, int_points[p](),
280 range_ip.d_owner_shape_evals = shape_evals[p];
284 range_local_map->mapToPhysicalFrame(
285 *range_it, int_points[p](), range_ip.d_physical_coordinates() );
288 range_ip_set->addPoint( range_ip );
292 range_cardinality = range_support_ids.size();
293 for (
int ni = 0; ni < range_cardinality; ++ni )
295 mm_values.assign( range_cardinality, 0.0 );
296 for (
int p = 0; p < num_ip; ++p )
299 range_entity_measure * int_weights[p] * shape_evals[p][ni];
300 for (
int nj = 0; nj < range_cardinality; ++nj )
302 mm_values[nj] += temp * shape_evals[p][nj];
305 mass_matrix->insertGlobalValues( range_support_ids[ni],
306 range_support_ids(), mm_values() );
311 mass_matrix->fillComplete( this->getRangeMap(), this->getRangeMap() );
312 DTK_CHECK( mass_matrix->isFillComplete() );
315 range_ip_set->finalize();
319 void L2ProjectionOperator::assembleCouplingMatrix(
320 const Teuchos::RCP<FunctionSpace> &domain_space,
322 const Teuchos::RCP<IntegrationPointSet> &range_ip_set,
323 Teuchos::RCP<Tpetra::CrsMatrix<Scalar, LO, GO>> &coupling_matrix )
326 Teuchos::RCP<const Teuchos::Comm<int>> comm =
327 domain_space->entitySet()->communicator();
330 int physical_dimension = domain_space->entitySet()->physicalDimension();
333 ParallelSearch psearch( comm, physical_dimension, domain_iterator,
334 domain_space->localMap(), d_search_list );
338 psearch.search( ip_iterator, range_ip_set, d_search_list );
342 int global_max_support = range_ip_set->globalMaxSupportSize();
343 int ip_stride = global_max_support + 1;
344 Teuchos::Array<int> export_ranks;
345 Teuchos::Array<EntityId> export_ip_domain_ids;
346 Teuchos::Array<double> export_measures_weights;
347 Teuchos::Array<double> export_shape_evals;
348 Teuchos::Array<SupportId> export_support_ids;
349 Teuchos::Array<EntityId> domain_ids;
350 Teuchos::Array<EntityId>::const_iterator domain_id_it;
355 for ( ip_it = ip_begin; ip_it != ip_end; ++ip_it )
358 psearch.getDomainEntitiesFromRange( ip_it->
id(), domain_ids );
361 const IntegrationPoint ¤t_ip =
362 range_ip_set->getPoint( ip_it->
id() );
366 for ( domain_id_it = domain_ids.begin();
367 domain_id_it != domain_ids.end(); ++domain_id_it )
370 export_ranks.push_back(
371 psearch.domainEntityOwnerRank( *domain_id_it ) );
374 export_ip_domain_ids.push_back( ip_it->
id() );
375 export_ip_domain_ids.push_back( *domain_id_it );
379 export_measures_weights.push_back( current_ip.d_owner_measure *
380 current_ip.d_integration_weight /
384 num_support = current_ip.d_owner_support_ids.size();
385 export_shape_evals.push_back( num_support );
386 export_support_ids.push_back( num_support );
387 for (
int i = 0; i < num_support; ++i )
389 export_shape_evals.push_back(
390 current_ip.d_owner_shape_evals[i] );
391 export_support_ids.push_back(
392 current_ip.d_owner_support_ids[i] );
394 for (
int i = num_support; i < global_max_support; ++i )
396 export_shape_evals.push_back( 0.0 );
397 export_support_ids.push_back( 0 );
404 Tpetra::Distributor range_to_domain_dist( comm );
405 int num_import = range_to_domain_dist.createFromSends( export_ranks() );
406 Teuchos::Array<EntityId> import_ip_domain_ids( 2 * num_import );
407 range_to_domain_dist.doPostsAndWaits( export_ip_domain_ids().getConst(), 2,
408 import_ip_domain_ids() );
409 Teuchos::Array<double> import_measures_weights( num_import );
410 range_to_domain_dist.doPostsAndWaits( export_measures_weights().getConst(),
411 1, import_measures_weights() );
412 Teuchos::Array<double> import_shape_evals( ip_stride * num_import );
413 range_to_domain_dist.doPostsAndWaits( export_shape_evals().getConst(),
414 ip_stride, import_shape_evals() );
415 Teuchos::Array<SupportId> import_support_ids( ip_stride * num_import );
416 range_to_domain_dist.doPostsAndWaits( export_support_ids().getConst(),
417 ip_stride, import_support_ids() );
420 std::map<std::pair<EntityId, EntityId>,
int> ip_domain_lid_map;
421 std::pair<EntityId, EntityId> lid_pair;
422 for (
int n = 0; n < num_import; ++n )
424 lid_pair.first = import_ip_domain_ids[2 * n];
425 lid_pair.second = import_ip_domain_ids[2 * n + 1];
426 ip_domain_lid_map[lid_pair] = n;
430 import_ip_domain_ids.clear();
431 export_ranks.clear();
432 export_ip_domain_ids.clear();
433 export_measures_weights.clear();
434 export_shape_evals.clear();
435 export_support_ids.clear();
439 Tpetra::createCrsMatrix<Scalar, LO, GO>( this->getRangeMap() );
442 Teuchos::Array<EntityId> ip_entity_ids;
443 Teuchos::Array<EntityId>::const_iterator ip_entity_id_it;
444 Teuchos::ArrayView<const double> ip_parametric_coords;
445 Teuchos::Array<double> domain_shape_values;
446 Teuchos::Array<double> cm_values;
447 Teuchos::Array<double>::iterator domain_shape_it;
448 Teuchos::Array<GO> domain_support_ids;
453 int range_cardinality = 0;
454 int domain_cardinality = 0;
457 for ( domain_it = domain_begin; domain_it != domain_end; ++domain_it )
460 domain_space->shapeFunction()->entitySupportIds( *domain_it,
461 domain_support_ids );
464 psearch.getRangeEntitiesFromDomain( domain_it->
id(), ip_entity_ids );
467 for ( ip_entity_id_it = ip_entity_ids.begin();
468 ip_entity_id_it != ip_entity_ids.end(); ++ip_entity_id_it )
471 lid_pair.first = *ip_entity_id_it;
472 lid_pair.second = domain_it->
id();
473 DTK_CHECK( ip_domain_lid_map.count( lid_pair ) );
474 local_id = ip_domain_lid_map.find( lid_pair )->second;
478 psearch.rangeParametricCoordinatesInDomain(
479 domain_it->
id(), *ip_entity_id_it, ip_parametric_coords );
483 domain_space->shapeFunction()->evaluateValue(
484 *domain_it, ip_parametric_coords, domain_shape_values );
485 DTK_CHECK( domain_shape_values.size() ==
486 domain_support_ids.size() );
489 range_cardinality = import_shape_evals[ip_stride * local_id];
490 domain_cardinality = domain_shape_values.size();
491 cm_values.assign( domain_cardinality, 0.0 );
492 for (
int i = 0; i < range_cardinality; ++i )
494 ip_index = ip_stride * local_id + i + 1;
495 temp = import_measures_weights[local_id] *
496 import_shape_evals[ip_index];
497 for (
int j = 0; j < domain_cardinality; ++j )
499 cm_values[j] = temp * domain_shape_values[j];
501 coupling_matrix->insertGlobalValues(
502 import_support_ids[ip_index], domain_support_ids(),
509 coupling_matrix->fillComplete( this->getDomainMap(), this->getRangeMap() );
Entity iterator interface.
Assertions and Design-by-Contract for error handling.
MapOperator Base
Root class tyepdef.
std::function< bool(Entity)> PredicateFunction
Predicate function typedef.
L2ProjectionOperator(const Teuchos::RCP< const TpetraMap > &domain_map, const Teuchos::RCP< const TpetraMap > &range_map, const Teuchos::ParameterList ¶meters)
Constructor.
void applyImpl(const TpetraMultiVector &X, TpetraMultiVector &Y, Teuchos::ETransp mode=Teuchos::NO_TRANS, double alpha=Teuchos::ScalarTraits< double >::one(), double beta=Teuchos::ScalarTraits< double >::zero()) const override
Apply the operator.
EntityId id() const
Client interface.