@@ -37,7 +37,9 @@ namespace aspect
3737 {
3838
3939
40-
40+ /* *
41+ * Produce graphical output defined in points provided by the user.
42+ */
4143 template <int dim, int spacedim = dim>
4244 class PointDataOut : public dealii ::DataOutInterface<0 , spacedim>
4345 {
@@ -72,14 +74,21 @@ namespace aspect
7274 DataComponentInterpretation::DataComponentInterpretation>
7375 &data_component_interpretations_ = {})
7476 {
75- Assert (
76- data_component_names.size () == data_component_interpretations_.size (),
77- ExcMessage (
78- " When calling Particles::DataOut::build_patches with data component "
79- " names and interpretations you need to provide as many data component "
80- " names as interpretations. Provide the same name for components that "
81- " belong to a single vector or tensor." ));
82-
77+ Assert (data_component_names.size () == data_component_interpretations_.size (),
78+ ExcMessage (
79+ " When calling PointDataOut::build_patches() with data component "
80+ " names and interpretations you need to provide as many data component "
81+ " names as interpretations. Provide the same name for components that "
82+ " belong to a single vector or tensor." ));
83+
84+ Assert (data.size () == 0 || locations.size (),
85+ ExcMessage (" You need to either provide no data or data for each point." ));
86+ for (const auto &datum : data)
87+ Assert (datum.size () == data_component_names.size (),
88+ ExcMessage (" The data provided in each point needs to have the same number "
89+ " of components as names were provided." ));
90+
91+ // Prepend the "id" to the data fields provided by the user:
8392 dataset_names.clear ();
8493 dataset_names.emplace_back (" id" );
8594 dataset_names.insert (dataset_names.end (),
@@ -104,26 +113,17 @@ namespace aspect
104113 patches[i].vertices [0 ] = locations[i];
105114 patches[i].patch_index = i;
106115
107- // We have one more data components than dataset_names ( the particle id)
116+ // Store id and properties given by the user:
108117 patches[i].data .reinit (n_data_components, 1 );
109-
110- patches[i].data (0 , 0 ) = i; // id
111-
112- if (n_data_components > 1 )
113- {
114- for (unsigned int property_index = 0 ;
115- property_index < n_property_components;
116- ++property_index)
117- patches[i].data (property_index + 1 , 0 ) =
118- data[i][property_index];
119- }
118+ patches[i].data (0 , 0 ) = i; // store id
119+ for (unsigned int property_index = 0 ; property_index < n_property_components; ++property_index)
120+ patches[i].data (property_index + 1 , 0 ) = data[i][property_index];
120121 }
121122 }
122123
123124 protected:
124125 /* *
125- * Returns the patches built by the data_out class which was previously
126- * built using a particle handler
126+ * Returns the patches previously built by the build_patches() function.
127127 */
128128 virtual const std::vector<DataOutBase::Patch<0 , spacedim>> &
129129 get_patches () const override
@@ -318,7 +318,7 @@ namespace aspect
318318 = compute_updated_velocities_at_points (aspect_surface_velocities);
319319
320320 const LinearAlgebra::Vector v_interpolated
321- = interpolate_velocities_to_surface_points (external_surface_velocities);
321+ = interpolate_external_velocities_to_surface_support_points (external_surface_velocities);
322322
323323 // TODO: need ghost values of v_interpolated?
324324
@@ -363,10 +363,12 @@ namespace aspect
363363 // for later function calls describe the same number of points.
364364 this ->evaluation_points = evaluation_points;
365365
366- // Set up RemotePointEvaluation with a Mapping of the undeformed mesh:
367- remote_point_evaluator = std::make_unique<Utilities::MPI::RemotePointEvaluation<dim, dim>>();
368- // TODO: does this need to be a higher order mapping for spherical problems?
366+ // Set up RemotePointEvaluation. The evaluation points are given in reference coordinates,
367+ // so we need to use a simple mapping instead of the one stored in the Simulator. The latter
368+ // would produce the deformed mesh. We currently always use a Q1 mapping when mesh deformation
369+ // is enabled, so a Q1 mapping is the right choice.
369370 static MappingQ<dim> mapping (1 );
371+ remote_point_evaluator = std::make_unique<Utilities::MPI::RemotePointEvaluation<dim, dim>>();
370372 remote_point_evaluator->reinit (this ->evaluation_points , this ->get_triangulation (), mapping);
371373
372374 // Finally, also ensure that upon mesh refinement, all of the
@@ -401,13 +403,13 @@ namespace aspect
401403 // to put directly into deal.II...
402404 for (unsigned int c=0 ; c<n_components; ++c)
403405 {
404- std::vector<double > values = VectorTools::point_values<1 >(*this ->remote_point_evaluator ,
405- this ->get_dof_handler (),
406- this ->get_solution (),
407- dealii::VectorTools::EvaluationFlags::avg,
408- c);
406+ const std::vector<double > values = VectorTools::point_values<1 >(*this ->remote_point_evaluator ,
407+ this ->get_dof_handler (),
408+ this ->get_solution (),
409+ dealii::VectorTools::EvaluationFlags::avg,
410+ c);
409411 for (unsigned int i=0 ; i<evaluation_points.size (); ++i)
410- solution_at_points[i][c]= values[i];
412+ solution_at_points[i][c] = values[i];
411413 }
412414
413415 return solution_at_points;
@@ -418,7 +420,7 @@ namespace aspect
418420 template <int dim>
419421 LinearAlgebra::Vector
420422 ExternalToolInterface<dim>::
421- interpolate_velocities_to_surface_points (const std::vector<Tensor<1 ,dim>> &velocities) const
423+ interpolate_external_velocities_to_surface_support_points (const std::vector<Tensor<1 ,dim>> &velocities) const
422424 {
423425 Assert (remote_point_evaluator != nullptr ,
424426 ExcMessage (" You can only call this function if you have previously "
@@ -458,16 +460,24 @@ namespace aspect
458460 const DoFHandler<dim> &mesh_dof_handler = this ->get_mesh_deformation_handler ().get_mesh_deformation_dof_handler ();
459461 LinearAlgebra::Vector vector_with_surface_velocities (mesh_dof_handler.locally_owned_dofs (),
460462 this ->get_mpi_communicator ());
463+
464+ // The remote_point_evaluator will gives us the velocities in all evaluation points that are within one of our locally
465+ // owned cells. The lambda defined below receives a list of points and their velocities for each cell. The coordinates
466+ // are given in coordinates of the unit cell.
467+ // For each support point of the velocity DoFHandler, we will set the velocity from the closest evaluation point. We
468+ // do this by keeping track of 1/distance of the closest evaluation point checked so far. The initial value of 0.0
469+ // denotes an infinite distance.
461470 LinearAlgebra::Vector one_over_distance_vec (mesh_dof_handler.locally_owned_dofs (),
462471 this ->get_mpi_communicator ());
463472
464-
465473 const unsigned int dofs_per_cell = mesh_dof_handler.get_fe ().dofs_per_cell ;
466- std::vector<types::global_dof_index> cell_dof_indices (dofs_per_cell);
467474
475+ // Note: We assume that process_and_evaluate() does not call our lambda concurrently, otherwise we would have write
476+ // conflicts when updating vector_with_surface_velocities and one_over_distance_vec.
468477 const auto eval_func = [&](const ArrayView< const Tensor<1 ,dim>> &values,
469478 const typename Utilities::MPI::RemotePointEvaluation<dim>::CellData &cell_data)
470479 {
480+ std::vector<types::global_dof_index> cell_dof_indices (dofs_per_cell);
471481 for (const auto cell_index : cell_data.cell_indices ())
472482 {
473483 const auto cell_dofs =
@@ -478,6 +488,9 @@ namespace aspect
478488 const auto local_values = cell_data.get_data_view (cell_index, values);
479489
480490 cell_dofs->get_dof_indices (cell_dof_indices);
491+
492+ // Note: This search is a nested loop with the inner part executed #evaluation_point_in_this_cell * #dofs_per_cell
493+ // times. We could precompute this information as the point locations and do not change (outside of mesh refinement).
481494 const std::vector< Point< dim >> &support_points = mesh_dof_handler.get_fe ().get_unit_support_points ();
482495 for (unsigned int i=0 ; i<unit_points.size (); ++i)
483496 {
@@ -486,18 +499,18 @@ namespace aspect
486499 const double one_over_distance = 1.0 /(unit_points[i].distance (support_points[j])+1e-10 );
487500 if (one_over_distance > one_over_distance_vec (cell_dof_indices[j]))
488501 {
502+ // The point i is closer to support point j than anything we have seen so far. Keep track
503+ // of the distance and write the correct velocity component into the result:
489504 one_over_distance_vec (cell_dof_indices[j]) = one_over_distance;
490- const unsigned int c = mesh_dof_handler.get_fe ().system_to_component_index (j).first ;
491- vector_with_surface_velocities (cell_dof_indices[j]) = local_values[i][c ];
505+ const unsigned int component = mesh_dof_handler.get_fe ().system_to_component_index (j).first ;
506+ vector_with_surface_velocities (cell_dof_indices[j]) = local_values[i][component ];
492507 }
493508 }
494509 }
495510 }
496511 };
497512
498513 this ->remote_point_evaluator ->template process_and_evaluate <Tensor<1 ,dim>,1 >(velocities, eval_func, /* sort_data*/ true );
499-
500- one_over_distance_vec.compress (VectorOperation::insert);
501514 vector_with_surface_velocities.compress (VectorOperation::insert);
502515
503516 return vector_with_surface_velocities;
0 commit comments