adamantine
experimental_data_utils.cc
Go to the documentation of this file.
1 /* SPDX-FileCopyrightText: Copyright (c) 2021 - 2024, the adamantine authors.
2  * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
3  */
4 
6 #include <utils.hh>
7 
8 #include <deal.II/arborx/distributed_tree.h>
9 #include <deal.II/dofs/dof_handler.h>
10 #include <deal.II/fe/mapping_q1.h>
11 #include <deal.II/grid/filtered_iterator.h>
12 #include <deal.II/hp/fe_values.h>
13 
14 #include <boost/algorithm/string.hpp>
15 
16 #include <fstream>
17 #include <unordered_set>
18 
19 namespace adamantine
20 {
21 template <int dim>
22 std::pair<std::vector<dealii::types::global_dof_index>,
23  std::vector<dealii::Point<dim>>>
24 get_dof_to_support_mapping(dealii::DoFHandler<dim> const &dof_handler)
25 {
26  std::vector<dealii::types::global_dof_index> dof_indices;
27  std::vector<dealii::Point<dim>> support_points;
28  std::unordered_set<dealii::types::global_dof_index> visited_dof_indices;
29 
30  // Manually do what dealii::DoFTools::map_dofs_to_support_points does, since
31  // that doesn't currently work with FE_Nothing. The issue has been fixed in
32  // deal.II 9.7
33  const dealii::FiniteElement<dim> &fe = dof_handler.get_fe(0);
34 
35  dealii::FEValues<dim, dim> fe_values(fe, fe.get_unit_support_points(),
36  dealii::update_quadrature_points);
37 
38  std::vector<dealii::types::global_dof_index> local_dof_indices(
39  fe.n_dofs_per_cell());
40  auto locally_owned_dofs = dof_handler.locally_owned_dofs();
41 
42  for (auto const &cell :
43  dealii::filter_iterators(dof_handler.active_cell_iterators(),
44  dealii::IteratorFilters::ActiveFEIndexEqualTo(
45  0, /* locally owned */ true)))
46  {
47  fe_values.reinit(cell);
48  cell->get_dof_indices(local_dof_indices);
49  const std::vector<dealii::Point<dim>> &points =
50  fe_values.get_quadrature_points();
51  for (unsigned int i = 0; i < fe.n_dofs_per_cell(); ++i)
52  {
53  // Skip duplicate points like vertices and indices that correspond to
54  // ghosted elements
55  if ((visited_dof_indices.count(local_dof_indices[i]) == 0) &&
56  (locally_owned_dofs.is_element(local_dof_indices[i])))
57  {
58  dof_indices.push_back(local_dof_indices[i]);
59  support_points.push_back(points[i]);
60  visited_dof_indices.insert(local_dof_indices[i]);
61  }
62  }
63  }
64 
65  return {dof_indices, support_points};
66 }
67 
68 template <int dim>
69 std::pair<std::vector<int>, std::vector<int>>
71  dealii::DoFHandler<dim> const &dof_handler)
72 {
73  auto [dof_indices, support_points] = get_dof_to_support_mapping(dof_handler);
74 
75 #if DEAL_II_VERSION_GTE(9, 7, 0)
76  auto communicator = dof_handler.get_mpi_communicator();
77 #else
78  auto communicator = dof_handler.get_communicator();
79 #endif
80  int my_rank = dealii::Utilities::MPI::this_mpi_process(communicator);
81 
82  // Perform the search
83  dealii::ArborXWrappers::DistributedTree distributed_tree(communicator,
84  support_points);
85  dealii::ArborXWrappers::PointNearestPredicate pt_nearest(points_values.points,
86  1);
87  auto [indices_ranks, offset] = distributed_tree.query(pt_nearest);
88 
89  // Convert the indices and offsets to a pair that maps experimental indices to
90  // dof indices
91  std::vector<int> obs_indices;
92  std::vector<int> global_indices;
93  obs_indices.resize(indices_ranks.size());
94  global_indices.resize(indices_ranks.size());
95  unsigned int const n_queries = points_values.points.size();
96  for (unsigned int i = 0; i < n_queries; ++i)
97  {
98  for (int j = offset[i]; j < offset[i + 1]; ++j)
99  {
100  obs_indices[j] = i;
101  global_indices[j] = indices_ranks[j].second == my_rank
102  ? dof_indices[indices_ranks[j].first]
103  : -1;
104  }
105  }
106 
107  dealii::Utilities::MPI::max(global_indices, communicator, global_indices);
108 
109  return std::make_pair(obs_indices, global_indices);
110 }
111 
112 template <int dim>
114  MPI_Comm const &communicator, PointsValues<dim> const &points_values,
115  std::pair<std::vector<int>, std::vector<int>> &expt_to_dof_mapping,
116  dealii::LinearAlgebra::distributed::Vector<double> &temperature,
117  bool verbose_output)
118 {
119  unsigned int rank = dealii::Utilities::MPI::this_mpi_process(communicator);
120  if ((rank == 0) && verbose_output)
121  {
122  std::cout << "Number of unique experimental points is "
123  << std::set<double>(expt_to_dof_mapping.second.begin(),
124  expt_to_dof_mapping.second.end())
125  .size()
126  << std::endl;
127  }
128 
129  auto locally_owned_dofs = temperature.locally_owned_elements();
130  for (unsigned int i = 0; i < points_values.values.size(); ++i)
131  {
132  // Only add locally owned elements
133  if (locally_owned_dofs.is_element(expt_to_dof_mapping.second[i]))
134  temperature[expt_to_dof_mapping.second[i]] = points_values.values[i];
135  }
136 
137  temperature.compress(dealii::VectorOperation::insert);
138 }
139 
140 std::vector<std::vector<double>>
141 read_frame_timestamps(boost::property_tree::ptree const &experiment_database)
142 {
143  // PropertyTreeInput experiment.log_filename
144  std::string log_filename =
145  experiment_database.get<std::string>("log_filename");
146 
147  wait_for_file(log_filename, "Waiting for frame time stamps: " + log_filename);
148 
149  // PropertyTreeInput experiment.first_frame_temporal_offset
150  double first_frame_offset =
151  experiment_database.get("first_frame_temporal_offset", 0.0);
152 
153  // PropertyTreeInput experiment.first_frame
154  unsigned int first_frame =
155  experiment_database.get<unsigned int>("first_frame", 0);
156  // PropertyTreeInput experiment.last_frame
157  unsigned int last_frame = experiment_database.get<unsigned int>("last_frame");
158 
159  // PropertyTreeInput experiment.first_camera_id
160  unsigned int first_camera_id =
161  experiment_database.get<unsigned int>("first_camera_id");
162  // PropertyTreeInput experiment.last_camera_id
163  unsigned int last_camera_id =
164  experiment_database.get<unsigned int>("last_camera_id");
165 
166  unsigned int num_cameras = last_camera_id - first_camera_id + 1;
167  std::vector<std::vector<double>> time_stamps(num_cameras);
168 
169  // Read and parse the file
170  std::ifstream file;
171  file.open(log_filename);
172  std::string line;
173  while (std::getline(file, line))
174  {
175  unsigned int entry_index = 0;
176  std::stringstream s_stream(line);
177  bool frame_of_interest = false;
178  unsigned int frame = std::numeric_limits<unsigned int>::max();
179  while (s_stream.good())
180  {
181  std::string substring;
182  std::getline(s_stream, substring, ',');
183  boost::trim(substring);
184 
185  if (entry_index == 0)
186  {
187  std::string error_message = "The file " + log_filename +
188  " does not have consecutive frame indices.";
189  ASSERT_THROW(std::stoi(substring) - frame == 1 ||
190  frame == std::numeric_limits<unsigned int>::max(),
191  error_message.c_str());
192  frame = std::stoi(substring);
193  if (frame >= first_frame && frame <= last_frame)
194  frame_of_interest = true;
195  }
196  else
197  {
198  if (frame_of_interest && substring.size() > 0)
199  time_stamps[entry_index - 1].push_back(std::stod(substring) +
200  first_frame_offset);
201  }
202  entry_index++;
203  }
204  }
205  return time_stamps;
206 }
207 
208 } // namespace adamantine
209 
210 //-------------------- Explicit Instantiations --------------------//
211 namespace adamantine
212 {
214  MPI_Comm const &communicator, PointsValues<2> const &points_values,
215  std::pair<std::vector<int>, std::vector<int>> &expt_to_dof_mapping,
216  dealii::LinearAlgebra::distributed::Vector<double> &temperature,
217  bool verbose_output);
219  MPI_Comm const &communicator, PointsValues<3> const &points_values,
220  std::pair<std::vector<int>, std::vector<int>> &expt_to_dof_mapping,
221  dealii::LinearAlgebra::distributed::Vector<double> &temperature,
222  bool verbose_output);
223 template std::pair<std::vector<int>, std::vector<int>>
225  dealii::DoFHandler<2> const &dof_handler);
226 template std::pair<std::vector<int>, std::vector<int>>
228  dealii::DoFHandler<3> const &dof_handler);
229 template std::pair<std::vector<dealii::types::global_dof_index>,
230  std::vector<dealii::Point<2>>>
231 get_dof_to_support_mapping(dealii::DoFHandler<2> const &dof_handler);
232 template std::pair<std::vector<dealii::types::global_dof_index>,
233  std::vector<dealii::Point<3>>>
234 get_dof_to_support_mapping(dealii::DoFHandler<3> const &dof_handler);
235 } // namespace adamantine
std::vector< dealii::types::global_dof_index > local_dof_indices
std::pair< std::vector< dealii::types::global_dof_index >, std::vector< dealii::Point< dim > > > get_dof_to_support_mapping(dealii::DoFHandler< dim > const &dof_handler)
std::pair< std::vector< int >, std::vector< int > > get_expt_to_dof_mapping(PointsValues< dim > const &points_values, dealii::DoFHandler< dim > const &dof_handler)
void wait_for_file(std::string const &filename, std::string const &message)
Definition: utils.hh:24
void ASSERT_THROW(bool cond, std::string const &message)
Definition: utils.hh:70
void set_with_experimental_data(MPI_Comm const &communicator, PointsValues< dim > const &points_values, std::pair< std::vector< int >, std::vector< int >> &expt_to_dof_mapping, dealii::LinearAlgebra::distributed::Vector< double > &temperature, bool verbose_output)
std::vector< std::vector< double > > read_frame_timestamps(boost::property_tree::ptree const &experiment_database)
std::vector< dealii::Point< dim > > points