Reduced Lagrange Multipliers
 
Loading...
Searching...
No Matches
tensor_product_space.cc
Go to the documentation of this file.
1// ---------------------------------------------------------------------
2//
3// Copyright (C) 2024 by Luca Heltai
4//
5// This file is part of the reduced_lagrange_multipliers application, based on
6// the deal.II library.
7//
8// The reduced_lagrange_multipliers application is free software; you can use
9// it, redistribute it, and/or modify it under the terms of the Apache-2.0
10// License WITH LLVM-exception as published by the Free Software Foundation;
11// either version 3.0 of the License, or (at your option) any later version. The
12// full text of the license can be found in the file LICENSE.md at the top level
13// of the reduced_lagrange_multipliers distribution.
14//
15// ---------------------------------------------------------------------
16
18
19#include <deal.II/fe/fe_q.h>
21
25
28
30#include "vtk_utils.h"
31
32template <int reduced_dim, int dim, int spacedim, int n_components>
35 : ParameterAcceptor("Representative domain")
36{
37 add_parameter("Finite element degree", fe_degree);
38 add_parameter("Number of quadrature points", n_q_points);
39 add_parameter("Thickness", thickness);
40 add_parameter("Thickness field name", thickness_field_name);
41 add_parameter("Reduced grid name", reduced_grid_name);
42}
43
44// Constructor for TensorProductSpace
45template <int reduced_dim, int dim, int spacedim, int n_components>
62
63// Initialize the tensor product space
64template <int reduced_dim, int dim, int spacedim, int n_components>
65void
67{
68 // Create the reduced grid and perform setup only if the triangulation is
69 // empty
70 if (triangulation.n_active_cells() == 0)
71 {
72 reference_cross_section.initialize();
73
75
76 // Setup degrees of freedom
77 setup_dofs();
78
79 // Setup quadrature formulas
81 }
82}
83
84template <int reduced_dim, int dim, int spacedim, int n_components>
85const ReferenceCrossSection<dim - reduced_dim, spacedim, n_components> &
91
92template <int reduced_dim, int dim, int spacedim, int n_components>
93void
96{
97 // First create a serial triangulation with the VTK file
99 DoFHandler<reduced_dim, spacedim> serial_properties_dh(serial_tria);
100 Vector<double> serial_properties;
101 VTKUtils::read_vtk(par.reduced_grid_name,
102 serial_properties_dh,
103 serial_properties,
105
106 std::cout << "Read VTK file: " << par.reduced_grid_name
107 << ", properties norm: " << serial_properties.l2_norm()
108 << std::endl;
109
110 // Then make sure the partitioner is what the user wants
112
113 // Once the triangulation is created, copy it to the distributed
114 // triangulation
115 triangulation.copy_triangulation(serial_tria);
116
117 if (triangulation.n_locally_owned_active_cells() == 0)
118 std::cout << "Process "
120 << " has no locally owned cells." << std::endl;
121
122 properties_dh.distribute_dofs(serial_properties_dh.get_fe());
123
124 AssertDimension(serial_properties_dh.n_dofs(), properties_dh.n_dofs());
125
126 properties.reinit(properties_dh.locally_owned_dofs(),
129 VTKUtils::serial_vector_to_distributed_vector(serial_properties_dh,
131 serial_properties,
132 properties);
133 // Make sure we have ghost values
134 properties.update_ghost_values();
135
136 const auto &properties_fe = properties_dh.get_fe();
137 const auto block_indices = VTKUtils::get_block_indices(properties_fe);
138
139 for (unsigned int i = 0; i < block_indices.size(); ++i)
140 {
141 const auto &name = properties_names[i];
142 std::cout << "Property name: " << name << ", block index: " << i
143 << ", block size: " << block_indices.block_size(i)
144 << ", block start: " << block_indices.block_start(i)
145 << std::endl;
146 }
147 std::cout << "Properties norm: " << properties.l2_norm() << std::endl;
148 std::cout << "Serial properties norm: " << serial_properties.l2_norm()
149 << std::endl;
150 AssertDimension(block_indices.total_size(), properties_fe.n_components());
151 AssertDimension(block_indices.size(), properties_names.size());
152};
153
154template <int reduced_dim, int dim, int spacedim, int n_components>
157 const
158{
159 return dof_handler;
160}
161
168template <int reduced_dim, int dim, int spacedim, int n_components>
169const std::vector<Point<spacedim>> &
172{
173 const int n_local_qpoints = all_qpoints.size();
174 const int global_qpoints =
175 Utilities::MPI::sum(n_local_qpoints, mpi_communicator);
176
178 global_qpoints > 0,
179 ExcMessage(
180 "No quadrature points exist across all MPI ranks. You must call compute_points_and_weights() first"));
181 return all_qpoints;
182}
183
184template <int reduced_dim, int dim, int spacedim, int n_components>
185const std::vector<std::vector<double>> &
188{
189 const int n_local_weights = all_weights.size();
190 const int global_weights =
191 Utilities::MPI::sum(n_local_weights, mpi_communicator);
192 AssertThrow(global_weights > 0,
193 ExcMessage("No weights exist across all MPI ranks. You must call"
194 " compute_points_and_weights() first"));
195 return all_weights;
196}
197
198template <int reduced_dim, int dim, int spacedim, int n_components>
199const std::vector<Point<spacedim>> &
203 const int n_local_reduced_qpoints = reduced_qpoints.size();
204 const int global_reduced_qpoints =
205 Utilities::MPI::sum(n_local_reduced_qpoints, mpi_communicator);
207 global_reduced_qpoints > 0,
208 ExcMessage(
209 "No reduced quadrature points exist across all MPI ranks. You must call"
210 " compute_points_and_weights() first"));
211 return reduced_qpoints;
212}
214template <int reduced_dim, int dim, int spacedim, int n_components>
215const std::vector<std::vector<double>> &
218{
219 const int n_local_reduced_weights = reduced_weights.size();
220 const int global_reduced_weights =
221 Utilities::MPI::sum(n_local_reduced_weights, mpi_communicator);
222 AssertThrow(global_reduced_weights > 0,
223 ExcMessage(
224 "No reduced weights exist across all MPI ranks. You must call"
225 " compute_points_and_weights() first"));
226 return reduced_weights;
227}
228
229
230template <int reduced_dim, int dim, int spacedim, int n_components>
231void
234 const std::map<unsigned int, IndexSet> &remote_q_point_indices)
235{
236 auto global_cell_indices =
237 local_q_point_indices_to_global_cell_indices(remote_q_point_indices);
238 std::map<
239 unsigned int,
240 std::map<types::global_cell_index, std::vector<types::global_dof_index>>>
241 global_dof_indices;
242
243 for (const auto &[proc, cell_indices] : global_cell_indices)
244 for (const auto &id : cell_indices)
245 global_dof_indices[proc][id] = global_cell_to_dof_indices[id];
246
247 // Exchange the data with participating processors
248 auto local_dof_indices =
250 // update global_cell_to_dof_indices
251 for (const auto &[proc, cell_indices] : local_dof_indices)
252 {
253 global_cell_to_dof_indices.insert(cell_indices.begin(),
254 cell_indices.end());
255 }
256}
257
258template <int reduced_dim, int dim, int spacedim, int n_components>
259const std::vector<types::global_dof_index> &
262{
265 ExcMessage("Cell index not found in global cell to dof indices."));
267}
268
269
270
271template <int reduced_dim, int dim, int spacedim, int n_components>
272std::tuple<unsigned int, unsigned int, unsigned int>
274 particle_id_to_cell_and_qpoint_indices(const unsigned int particle_id) const
275{
276 AssertIndexRange(particle_id,
277 triangulation.n_global_active_cells() *
278 quadrature_formula.size() *
279 reference_cross_section.n_quadrature_points());
280 const unsigned int cell_index =
281 particle_id /
282 (quadrature_formula.size() * reference_cross_section.n_quadrature_points());
283 const unsigned int qpoint_index_in_cell =
284 (particle_id / reference_cross_section.n_quadrature_points()) %
286 const unsigned int qpoint_index_in_section =
287 particle_id % reference_cross_section.n_quadrature_points();
289 AssertIndexRange(cell_index, triangulation.n_global_active_cells());
290 AssertIndexRange(qpoint_index_in_cell, quadrature_formula.size());
291 AssertIndexRange(qpoint_index_in_section,
292 reference_cross_section.n_quadrature_points());
293 return std::make_tuple(cell_index,
294 qpoint_index_in_cell,
295 qpoint_index_in_section);
296}
298
299template <int reduced_dim, int dim, int spacedim, int n_components>
300std::map<unsigned int, IndexSet>
303 const std::map<unsigned int, IndexSet> &remote_q_point_indices) const
304{
305 std::map<unsigned int, IndexSet> cell_indices;
306 const IndexSet &owned_cells =
307 triangulation.global_active_cell_index_partitioner()
308 .lock()
309 ->locally_owned_range();
310
311 auto local_q_point_indices =
312 Utilities::MPI::some_to_some(mpi_communicator, remote_q_point_indices);
314 for (const auto &[proc, qpoint_indices] : local_q_point_indices)
315 {
316 IndexSet cell_indices_for_proc(triangulation.n_global_active_cells());
317 for (const auto &qpoint_index : qpoint_indices)
318 {
319 const auto [cell_index, q_index, i] =
321 cell_indices_for_proc.add_index(
322 owned_cells.nth_index_in_set(cell_index));
323 }
324 cell_indices_for_proc.compress();
325 cell_indices[proc] = cell_indices_for_proc;
326 }
327 return cell_indices;
328}
329
330
331// Setup degrees of freedom for the tensor product space
332template <int reduced_dim, int dim, int spacedim, int n_components>
333void
335{
336 dof_handler.distribute_dofs(fe);
337 // Additional setup can be done here if needed
338 for (const auto &cell : dof_handler.active_cell_iterators())
339 if (cell->is_locally_owned())
340 {
341 std::vector<types::global_dof_index> dof_indices(fe.n_dofs_per_cell());
342 cell->get_dof_indices(dof_indices);
343 global_cell_to_dof_indices[cell->global_active_cell_index()] =
344 dof_indices;
345 }
346}
347
348template <int reduced_dim, int dim, int spacedim, int n_components>
352{
353 IndexSet locally_owned_cell_set =
354 triangulation.global_active_cell_index_partitioner()
355 .lock()
356 ->locally_owned_range();
357
358 // Now make a tensor product of the local indices with the total number of
359 // quadrature points, and the number of quadrature points in the
360 // cross-section
361 const unsigned int n_qpoints_per_cell =
362 reference_cross_section.n_quadrature_points() * quadrature_formula.size();
363
364 IndexSet locally_owned_qpoints_set = locally_owned_cell_set.tensor_product(
365 complete_index_set(n_qpoints_per_cell));
366
367 return locally_owned_qpoints_set;
368}
369
370template <int reduced_dim, int dim, int spacedim, int n_components>
374{
375 IndexSet indices = triangulation.global_active_cell_index_partitioner()
376 .lock()
377 ->locally_owned_range();
378 for (const auto &[cell_id, local_indices] : global_cell_to_dof_indices)
379 indices.add_index(cell_id);
380 indices.compress();
381 return indices;
382}
383
384template <int reduced_dim, int dim, int spacedim, int n_components>
385auto
391
392template <int reduced_dim, int dim, int spacedim, int n_components>
393void
396{
397 all_qpoints.reserve(triangulation.n_active_cells() *
398 quadrature_formula.size() *
399 reference_cross_section.n_quadrature_points());
400 all_weights.reserve(triangulation.n_active_cells() *
401 quadrature_formula.size() *
402 reference_cross_section.n_quadrature_points());
403
404 reduced_qpoints.reserve(triangulation.n_active_cells() *
405 quadrature_formula.size());
406 reduced_weights.reserve(triangulation.n_active_cells() *
407 quadrature_formula.size());
408
409 UpdateFlags flags =
410 reduced_dim == 1 ?
413
415
416
417
418 const auto &properties_fe = properties_dh.get_fe();
419 FEValues<reduced_dim, spacedim> properties_fe_values(properties_fe,
422
423 // Find the index of the thickness field in the properties
424 const unsigned int thickness_field_index =
425 std::distance(properties_names.begin(),
426 std::find(properties_names.begin(),
427 properties_names.end(),
428 par.thickness_field_name));
429
430 const auto thickness_start =
431 thickness_field_index >= properties_names.size() ?
433 VTKUtils::get_block_indices(properties_fe)
434 .block_start(thickness_field_index);
435
436 FEValuesExtractors::Scalar thickness(thickness_start);
437
438 // Initialize the thickness values with the constant thickness
439 std::vector<double> thickness_values(get_quadrature().size(), par.thickness);
440
441 for (const auto &cell : triangulation.active_cell_iterators())
442 if (cell->is_locally_owned())
443 {
444 fev.reinit(cell);
445 const auto &qpoints = fev.get_quadrature_points();
446 const auto &JxW = fev.get_JxW_values();
447
448
449 if (thickness_start != numbers::invalid_unsigned_int)
450 {
451 properties_fe_values.reinit(
452 cell->as_dof_handler_iterator(this->properties_dh));
453 properties_fe_values[thickness].get_function_values(
454 properties, thickness_values);
455 }
456
457 reduced_qpoints.insert(reduced_qpoints.end(),
458 qpoints.begin(),
459 qpoints.end());
460 for (const auto &w : JxW)
461 reduced_weights.emplace_back(std::vector<double>(1, w));
462
463 Tensor<1, spacedim> new_vertical;
464 if constexpr (reduced_dim == 1)
465 new_vertical = cell->vertex(1) - cell->vertex(0);
466
467 for (const auto &q : fev.quadrature_point_indices())
468 {
469 const auto &qpoint = qpoints[q];
470 if constexpr (reduced_dim == 2)
471 new_vertical = fev.normal_vector(q);
472 // [TODO] Make radius a function of the cell
473 auto cross_section_qpoints =
474 reference_cross_section.get_transformed_quadrature(
475 qpoint, new_vertical, thickness_values[q]);
476
477 all_qpoints.insert(all_qpoints.end(),
478 cross_section_qpoints.get_points().begin(),
479 cross_section_qpoints.get_points().end());
480
481 for (const auto &w : cross_section_qpoints.get_weights())
482 all_weights.emplace_back(std::vector<double>(1, w * fev.JxW(q)));
483 }
484 }
485};
486
487template <int reduced_dim, int dim, int spacedim, int n_components>
494
495template <int reduced_dim, int dim, int spacedim, int n_components>
496double
498 const unsigned int) const
499{
500 return std::pow(par.thickness, -((dim - reduced_dim) / 2.0));
501}
502
503template <int reduced_dim, int dim, int spacedim, int n_components>
510
511template <int reduced_dim, int dim, int spacedim, int n_components>
518
519template <int reduced_dim, int dim, int spacedim, int n_components>
526
527template <int reduced_dim, int dim, int spacedim, int n_components>
528const std::vector<std::string> &
534
535template <int reduced_dim, int dim, int spacedim, int n_components>
536std::vector<std::string> &
542
543
544
549
554
555template class TensorProductSpace<1, 2, 2, 1>;
556template class TensorProductSpace<1, 2, 3, 1>;
557template class TensorProductSpace<1, 3, 3, 1>;
558template class TensorProductSpace<2, 3, 3, 1>;
559
560template class TensorProductSpace<1, 2, 2, 2>;
561template class TensorProductSpace<1, 2, 3, 3>;
562template class TensorProductSpace<1, 3, 3, 3>;
563template class TensorProductSpace<2, 3, 3, 3>;
const FiniteElement< dim, spacedim > & get_fe(const types::fe_index index=0) const
types::global_dof_index n_dofs() const
const std::vector< double > & get_JxW_values() const
void get_function_values(const ReadVector< Number > &fe_function, std::vector< Number > &values) const
const std::vector< Point< spacedim > > & get_quadrature_points() const
const Tensor< 1, spacedim > & normal_vector(const unsigned int q_point) const
std_cxx20::ranges::iota_view< unsigned int, unsigned int > quadrature_point_indices() const
double JxW(const unsigned int q_point) const
void reinit(const TriaIterator< DoFCellAccessor< dim, spacedim, level_dof_access > > &cell)
IndexSet tensor_product(const IndexSet &other) const
void add_index(const size_type index)
size_type nth_index_in_set(const size_type local_index) const
void compress() const
ParameterAcceptor(const std::string &section_name="")
void add_parameter(const std::string &entry, ParameterType &parameter, const std::string &documentation="", ParameterHandler &prm_=prm, const Patterns::PatternBase &pattern=*Patterns::Tools::Convert< ParameterType >::to_pattern())
real_type l2_norm() const
Handles the construction and management of a reference inclusion geometry and its basis.
parallel::fullydistributed::Triangulation< reduced_dim, spacedim > triangulation
std::vector< std::vector< double > > reduced_weights
const LinearAlgebra::distributed::Vector< double > & get_properties() const
const parallel::fullydistributed::Triangulation< reduced_dim, spacedim > & get_triangulation() const
std::vector< std::vector< double > > all_weights
const std::vector< Point< spacedim > > & get_locally_owned_qpoints() const
TensorProductSpace(const TensorProductSpaceParameters< reduced_dim, dim, spacedim, n_components > &par, MPI_Comm mpi_communicator=MPI_COMM_WORLD)
DoFHandler< reduced_dim, spacedim > properties_dh
double get_scaling(const unsigned int) const
const ReferenceCrossSection< dim - reduced_dim, spacedim, n_components > & get_reference_cross_section() const
auto get_quadrature() const -> const QGauss< reduced_dim > &
std::vector< Point< spacedim > > all_qpoints
std::function< void(parallel::fullydistributed::Triangulation< reduced_dim, spacedim > &)> set_partitioner
std::map< types::global_cell_index, std::vector< types::global_dof_index > > global_cell_to_dof_indices
const DoFHandler< reduced_dim, spacedim > & get_dof_handler() const
void update_local_dof_indices(const std::map< unsigned int, IndexSet > &remote_q_point_indices)
const std::vector< types::global_dof_index > & get_dof_indices(const types::global_cell_index cell_index) const
const DoFHandler< reduced_dim, spacedim > & get_properties_dh() const
const std::vector< std::vector< double > > & get_locally_owned_reduced_weights() const
IndexSet locally_relevant_indices() const
std::vector< std::string > properties_names
IndexSet locally_owned_qpoints() const
std::tuple< unsigned int, unsigned int, unsigned int > particle_id_to_cell_and_qpoint_indices(const unsigned int qpoint_index) const
DoFHandler< reduced_dim, spacedim > dof_handler
const std::vector< std::string > & get_properties_names() const
const std::vector< Point< spacedim > > & get_locally_owned_reduced_qpoints() const
LinearAlgebra::distributed::Vector< double > properties
QGauss< reduced_dim > quadrature_formula
const TensorProductSpaceParameters< reduced_dim, dim, spacedim, n_components > & par
std::map< unsigned int, IndexSet > local_q_point_indices_to_global_cell_indices(const std::map< unsigned int, IndexSet > &local_q_point_indices) const
const std::vector< std::vector< double > > & get_locally_owned_weights() const
ReferenceCrossSection< cross_section_dim, spacedim, n_components > reference_cross_section
FESystem< reduced_dim, spacedim > fe
unsigned int cell_index
#define Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
#define AssertThrow(cond, exc)
UpdateFlags
update_values
update_normal_vectors
update_JxW_values
update_quadrature_points
IndexSet complete_index_set(const IndexSet::size_type N)
std::size_t size
IndexSet extract_locally_relevant_dofs(const DoFHandler< dim, spacedim > &dof_handler)
Tensor< 2, dim, Number > w(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
T sum(const T &t, const MPI_Comm mpi_communicator)
std::map< unsigned int, T > some_to_some(const MPI_Comm comm, const std::map< unsigned int, T > &objects_to_send)
unsigned int this_mpi_process(const MPI_Comm mpi_communicator)
constexpr unsigned int invalid_unsigned_int
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
unsigned int global_cell_index
std::string reduced_grid_name
Name of the grid to read from a file.