DataTransferKit - Multiphysics Solution Transfer Services  2.0
DTK_ConsistentInterpolationOperator.cpp
1 //---------------------------------------------------------------------------//
2 /*
3  Copyright (c) 2012, Stuart R. Slattery
4  All rights reserved.
5 
6  Redistribution and use in source and binary forms, with or without
7  modification, are permitted provided that the following conditions are
8  met:
9 
10  *: Redistributions of source code must retain the above copyright
11  notice, this list of conditions and the following disclaimer.
12 
13  *: Redistributions in binary form must reproduce the above copyright
14  notice, this list of conditions and the following disclaimer in the
15  documentation and/or other materials provided with the distribution.
16 
17  *: Neither the name of the University of Wisconsin - Madison nor the
18  names of its contributors may be used to endorse or promote products
19  derived from this software without specific prior written permission.
20 
21  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33 //---------------------------------------------------------------------------//
39 //---------------------------------------------------------------------------//
40 
41 #include <algorithm>
42 #include <unordered_map>
43 
44 #include "DTK_BasicEntityPredicates.hpp"
45 #include "DTK_ConsistentInterpolationOperator.hpp"
46 #include "DTK_DBC.hpp"
47 #include "DTK_ParallelSearch.hpp"
48 #include "DTK_PredicateComposition.hpp"
49 
50 #include <Teuchos_OrdinalTraits.hpp>
51 
52 #include <Tpetra_Distributor.hpp>
53 #include <Tpetra_Map.hpp>
54 
55 namespace DataTransferKit
56 {
57 //---------------------------------------------------------------------------//
58 // Constructor.
60  const Teuchos::RCP<const TpetraMap> &domain_map,
61  const Teuchos::RCP<const TpetraMap> &range_map,
62  const Teuchos::ParameterList &parameters )
63  : Base( domain_map, range_map )
64  , d_range_entity_dim( 0 )
65  , d_keep_missed_sol( false )
66  , d_missed_range_entity_ids( 0 )
67 {
68  // Get the topological dimension of the range entities.
69  Teuchos::ParameterList map_list =
70  parameters.sublist( "Consistent Interpolation" );
71  if ( map_list.isParameter( "Range Entity Dimension" ) )
72  {
73  d_range_entity_dim = map_list.get<int>( "Range Entity Dimension" );
74  }
75 
76  // Get the search list.
77  d_search_list = parameters.sublist( "Search" );
78 
79  // If we want to keep the range data when we miss entities instead of
80  // zeros, turn this on.
81  if ( map_list.isParameter( "Keep Missed Range Data" ) )
82  {
83  d_keep_missed_sol = map_list.get<bool>( "Keep Missed Range Data" );
84  if ( d_keep_missed_sol )
85  {
86  d_search_list.set( "Track Missed Range Entities", true );
87  }
88  }
89 }
90 
91 //---------------------------------------------------------------------------//
92 // Setup the map operator.
93 void ConsistentInterpolationOperator::setupImpl(
94  const Teuchos::RCP<FunctionSpace> &domain_space,
95  const Teuchos::RCP<FunctionSpace> &range_space )
96 {
97  DTK_REQUIRE( Teuchos::nonnull( domain_space ) );
98  DTK_REQUIRE( Teuchos::nonnull( range_space ) );
99 
100  // Extract the Support maps.
101  const Teuchos::RCP<const typename Base::TpetraMap> domain_map =
102  this->getDomainMap();
103  const Teuchos::RCP<const typename Base::TpetraMap> range_map =
104  this->getRangeMap();
105 
106  // Get the parallel communicator.
107  Teuchos::RCP<const Teuchos::Comm<int>> comm = domain_map->getComm();
108 
109  // Determine if we have range and domain data on this process.
110  bool nonnull_domain = Teuchos::nonnull( domain_space->entitySet() );
111  bool nonnull_range = Teuchos::nonnull( range_space->entitySet() );
112 
113  // Get the physical dimension.
114  int physical_dimension = 0;
115  if ( nonnull_domain )
116  {
117  physical_dimension = domain_space->entitySet()->physicalDimension();
118  }
119  else if ( nonnull_range )
120  {
121  physical_dimension = range_space->entitySet()->physicalDimension();
122  }
123 
124  // Get an iterator over the domain entities.
125  EntityIterator domain_iterator;
126  if ( nonnull_domain )
127  {
128  LocalEntityPredicate local_predicate(
129  domain_space->entitySet()->communicator()->getRank() );
130  PredicateFunction domain_predicate = PredicateComposition::And(
131  domain_space->selectFunction(), local_predicate.getFunction() );
132  domain_iterator = domain_space->entitySet()->entityIterator(
133  domain_space->entitySet()->physicalDimension(), domain_predicate );
134  }
135 
136  // Build a parallel search over the domain.
137  ParallelSearch psearch( comm, physical_dimension, domain_iterator,
138  domain_space->localMap(), d_search_list );
139 
140  // Get an iterator over the range entities.
141  EntityIterator range_iterator;
142  if ( nonnull_range )
143  {
144  LocalEntityPredicate local_predicate(
145  range_space->entitySet()->communicator()->getRank() );
146  PredicateFunction range_predicate = PredicateComposition::And(
147  range_space->selectFunction(), local_predicate.getFunction() );
148  range_iterator = range_space->entitySet()->entityIterator(
149  d_range_entity_dim, range_predicate );
150  }
151 
152  // Search the domain with the range.
153  psearch.search( range_iterator, range_space->localMap(), d_search_list );
154 
155  // If we are keeping track of range entities that were not mapped, extract
156  // them.
157  d_missed_range_entity_ids =
158  Teuchos::Array<EntityId>( psearch.getMissedRangeEntityIds() );
159 
160  // Determine the Support ids for the range entities found in the local
161  // domain
162  // on this process and the number of domain entities they were found in
163  // globally for averaging.
164  std::unordered_map<EntityId, GO> range_support_id_map;
165  Teuchos::RCP<Tpetra::Vector<double, int, SupportId>> scale_vector =
166  Tpetra::createVector<double, int, SupportId>( range_map );
167  {
168  // Extract the set of local range entities that were found in domain
169  // entities.
170  Teuchos::Array<int> export_ranks;
171  Teuchos::Array<GO> export_data;
172  Teuchos::Array<EntityId> domain_ids;
173  Teuchos::Array<EntityId>::const_iterator domain_id_it;
174  Teuchos::Array<GO> range_support_ids;
175  EntityIterator range_it;
176  EntityIterator range_begin = range_iterator.begin();
177  EntityIterator range_end = range_iterator.end();
178  for ( range_it = range_begin; range_it != range_end; ++range_it )
179  {
180  // Get the support id for the range entity.
181  range_space->shapeFunction()->entitySupportIds( *range_it,
182  range_support_ids );
183  DTK_CHECK( 1 == range_support_ids.size() );
184 
185  // Get the domain entities in which the range entity was found.
186  psearch.getDomainEntitiesFromRange( range_it->id(), domain_ids );
187 
188  // Add a scale factor for this range entity to the scaling vector.
189  DTK_CHECK( range_map->isNodeGlobalElement( range_support_ids[0] ) );
190  scale_vector->replaceGlobalValue( range_support_ids[0],
191  1.0 / domain_ids.size() );
192 
193  // For each supporting domain entity, pair the range entity id and
194  // its support id.
195  for ( domain_id_it = domain_ids.begin();
196  domain_id_it != domain_ids.end(); ++domain_id_it )
197  {
198  export_ranks.push_back(
199  psearch.domainEntityOwnerRank( *domain_id_it ) );
200 
201  export_data.push_back( range_support_ids[0] );
202  export_data.push_back( Teuchos::as<GO>( range_it->id() ) );
203  }
204  }
205 
206  // Communicate the range entity Support data back to the domain parallel
207  // decomposition.
208  Tpetra::Distributor range_to_domain_dist( comm );
209  int num_import = range_to_domain_dist.createFromSends( export_ranks() );
210  Teuchos::Array<GO> import_data( 2 * num_import );
211  Teuchos::ArrayView<const GO> export_data_view = export_data();
212  range_to_domain_dist.doPostsAndWaits( export_data_view, 2,
213  import_data() );
214 
215  // Map the range entities to their support ids.
216  for ( int i = 0; i < num_import; ++i )
217  {
218  range_support_id_map.emplace(
219  Teuchos::as<EntityId>( import_data[2 * i + 1] ),
220  import_data[2 * i] );
221  }
222  }
223 
224  // Allocate the coupling matrix.
225  d_coupling_matrix = Tpetra::createCrsMatrix<double, LO, GO>( range_map );
226 
227  // Construct the entries of the coupling matrix.
228  Teuchos::Array<EntityId> range_entity_ids;
229  Teuchos::Array<EntityId>::const_iterator range_entity_id_it;
230  Teuchos::ArrayView<const double> range_parametric_coords;
231  Teuchos::Array<double> domain_shape_values;
232  Teuchos::Array<double>::iterator domain_shape_it;
233  Teuchos::Array<GO> domain_support_ids;
234  EntityIterator domain_it;
235  EntityIterator domain_begin = domain_iterator.begin();
236  EntityIterator domain_end = domain_iterator.end();
237  for ( domain_it = domain_begin; domain_it != domain_end; ++domain_it )
238  {
239  // Get the domain Support ids supporting the domain entity.
240  domain_space->shapeFunction()->entitySupportIds( *domain_it,
241  domain_support_ids );
242 
243  // Get the range entities that mapped into this domain entity.
244  psearch.getRangeEntitiesFromDomain( domain_it->id(), range_entity_ids );
245 
246  // Sum into the global coupling matrix row for each domain.
247  for ( range_entity_id_it = range_entity_ids.begin();
248  range_entity_id_it != range_entity_ids.end();
249  ++range_entity_id_it )
250  {
251  // Get the parametric coordinates of the range entity in the
252  // domain entity.
253  psearch.rangeParametricCoordinatesInDomain(
254  domain_it->id(), *range_entity_id_it, range_parametric_coords );
255 
256  // Evaluate the shape function at the coordinates.
257  domain_space->shapeFunction()->evaluateValue(
258  *domain_it, range_parametric_coords, domain_shape_values );
259  DTK_CHECK( domain_shape_values.size() ==
260  domain_support_ids.size() );
261 
262  // Consistent interpolation requires one support location per
263  // range entity. Load the row for this range support location into
264  // the matrix.
265  DTK_CHECK( range_support_id_map.count( *range_entity_id_it ) );
266  d_coupling_matrix->insertGlobalValues(
267  range_support_id_map.find( *range_entity_id_it )->second,
268  domain_support_ids(), domain_shape_values() );
269  }
270  }
271 
272  // Finalize the coupling matrix.
273  d_coupling_matrix->fillComplete( domain_map, range_map );
274 
275  // Left-scale the matrix with the number of domain entities in which each
276  // range entity was found.
277  d_coupling_matrix->leftScale( *scale_vector );
278 
279  // If we want to keep the range data when we miss points, create the
280  // scaling vector.
281  if ( d_keep_missed_sol )
282  {
283  d_keep_range_vec = Tpetra::createVector<double, LO, GO>( range_map );
284  for ( auto &m : d_missed_range_entity_ids )
285  {
286  d_keep_range_vec->replaceGlobalValue( m, 1.0 );
287  }
288  }
289 }
290 
291 //---------------------------------------------------------------------------//
292 // Apply the operator.
293 void ConsistentInterpolationOperator::applyImpl( const TpetraMultiVector &X,
294  TpetraMultiVector &Y,
295  Teuchos::ETransp mode,
296  double alpha,
297  double beta ) const
298 {
299  // If we want to keep the range data when we miss points, make a work vec
300  // and get the parts we will zero out. Beta must be zero or the interface
301  // is violated.
302  Teuchos::RCP<Tpetra::Vector<Scalar, LO, GO>> work_vec;
303  if ( d_keep_missed_sol )
304  {
305  DTK_REQUIRE( 0.0 == beta );
306  DTK_REQUIRE( Teuchos::nonnull( d_keep_range_vec ) );
307  work_vec = Tpetra::createVector<double, LO, GO>( this->getRangeMap() );
308  work_vec->elementWiseMultiply( 1.0, *d_keep_range_vec, Y, 0.0 );
309  }
310 
311  // Apply the coupling matrix.
312  d_coupling_matrix->apply( X, Y, mode, alpha, beta );
313 
314  // If we want to keep the range data when we miss points, add back in the
315  // components that got zeroed out.
316  if ( d_keep_missed_sol )
317  {
318  Y.update( 1.0, *work_vec, 1.0 );
319  }
320 }
321 
322 //---------------------------------------------------------------------------//
323 // Transpose apply option.
324 bool ConsistentInterpolationOperator::hasTransposeApplyImpl() const
325 {
326  return true;
327 }
328 
329 //---------------------------------------------------------------------------//
330 // Return the ids of the range entities that were not mapped during the last
331 // setup phase (i.e. those that are guaranteed to not receive data from the
332 // transfer).
333 Teuchos::ArrayView<const EntityId>
335 {
336  return d_missed_range_entity_ids();
337 }
338 
339 //---------------------------------------------------------------------------//
340 
341 } // end namespace DataTransferKit
342 
343 //---------------------------------------------------------------------------//
344 // end DTK_ConsistentInterpolationOperator.cpp
345 //---------------------------------------------------------------------------//
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.
ConsistentInterpolationOperator(const Teuchos::RCP< const TpetraMap > &domain_map, const Teuchos::RCP< const TpetraMap > &range_map, const Teuchos::ParameterList &parameters)
Constructor.
Entity iterator interface.
Assertions and Design-by-Contract for error handling.
std::function< bool(Entity)> PredicateFunction
Predicate function typedef.
Definition: DTK_Types.hpp:64
Teuchos::ArrayView< const EntityId > getMissedRangeEntityIds() const
Return the ids of the range entities that were not mapped during the last setup phase (i...
DTK_BasicEntitySet.cpp.
EntityId id() const
Client interface.
Definition: DTK_Entity.cpp:82