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 deallog << "Read VTK file: " << par.reduced_grid_name
107 << ", properties norm: " << serial_properties.l2_norm() << std::endl;
108
109 // Preprocess the serial triangulation
111
112 // Then make sure the partitioner is what the user wants
114
115 // Once the triangulation is created, copy it to the distributed
116 // triangulation
117 triangulation.copy_triangulation(serial_tria);
118
119 if (triangulation.n_locally_owned_active_cells() == 0)
121 << " has no locally owned cells." << std::endl;
122
123 properties_dh.distribute_dofs(serial_properties_dh.get_fe());
124
125 properties.reinit(properties_dh.locally_owned_dofs(),
128
129 if (serial_properties_dh.n_dofs() == properties_dh.n_dofs())
130 {
131 VTKUtils::serial_vector_to_distributed_vector(serial_properties_dh,
133 serial_properties,
134 properties);
135 }
136 else
137 {
138 // TODO: transfer from coarse serial grid to fine distributed grid
139 deallog << "PROPERTIES ARE ZERO. DO NOT REFINE INPUT GRID" << std::endl;
140 }
141
142 // Make sure we have ghost values
143 properties.update_ghost_values();
144
145 const auto &properties_fe = properties_dh.get_fe();
146 const auto block_indices = VTKUtils::get_block_indices(properties_fe);
147
148 for (unsigned int i = 0; i < block_indices.size(); ++i)
149 {
150 const auto &name = properties_names[i];
151 deallog << "Property name: " << name << ", block index: " << i
152 << ", block size: " << block_indices.block_size(i)
153 << ", block start: " << block_indices.block_start(i) << std::endl;
154 }
155 deallog << "Properties norm: " << properties.l2_norm() << std::endl;
156 deallog << "Serial properties norm: " << serial_properties.l2_norm()
157 << std::endl;
158 AssertDimension(block_indices.total_size(), properties_fe.n_components());
159 AssertDimension(block_indices.size(), properties_names.size());
160};
161
162template <int reduced_dim, int dim, int spacedim, int n_components>
169
176template <int reduced_dim, int dim, int spacedim, int n_components>
177const std::vector<Point<spacedim>> &
180{
181 const int n_local_qpoints = all_qpoints.size();
182 const int global_qpoints =
183 Utilities::MPI::sum(n_local_qpoints, mpi_communicator);
184
186 global_qpoints > 0,
187 ExcMessage(
188 "No quadrature points exist across all MPI ranks. You must call compute_points_and_weights() first"));
189 return all_qpoints;
190}
191
192template <int reduced_dim, int dim, int spacedim, int n_components>
193const std::vector<std::vector<double>> &
197 const int n_local_weights = all_weights.size();
198 const int global_weights =
199 Utilities::MPI::sum(n_local_weights, mpi_communicator);
200 AssertThrow(global_weights > 0,
201 ExcMessage("No weights exist across all MPI ranks. You must call"
202 " compute_points_and_weights() first"));
203 return all_weights;
205
206template <int reduced_dim, int dim, int spacedim, int n_components>
207const std::vector<Point<spacedim>> &
210{
211 const int n_local_reduced_qpoints = reduced_qpoints.size();
212 const int global_reduced_qpoints =
213 Utilities::MPI::sum(n_local_reduced_qpoints, mpi_communicator);
215 global_reduced_qpoints > 0,
216 ExcMessage(
217 "No reduced quadrature points exist across all MPI ranks. You must call"
218 " compute_points_and_weights() first"));
220}
221
222template <int reduced_dim, int dim, int spacedim, int n_components>
223const std::vector<std::vector<double>> &
226{
227 const int n_local_reduced_weights = reduced_weights.size();
228 const int global_reduced_weights =
229 Utilities::MPI::sum(n_local_reduced_weights, mpi_communicator);
230 AssertThrow(global_reduced_weights > 0,
231 ExcMessage(
232 "No reduced weights exist across all MPI ranks. You must call"
233 " compute_points_and_weights() first"));
234 return reduced_weights;
235}
236
237
238template <int reduced_dim, int dim, int spacedim, int n_components>
239void
242 const std::map<unsigned int, IndexSet> &remote_q_point_indices)
243{
244 auto global_cell_indices =
246 std::map<
247 unsigned int,
248 std::map<types::global_cell_index, std::vector<types::global_dof_index>>>
249 global_dof_indices;
250
251 for (const auto &[proc, cell_indices] : global_cell_indices)
252 for (const auto &id : cell_indices)
253 global_dof_indices[proc][id] = global_cell_to_dof_indices[id];
254
255 // Exchange the data with participating processors
256 auto local_dof_indices =
258 // update global_cell_to_dof_indices
259 for (const auto &[proc, cell_indices] : local_dof_indices)
260 {
261 global_cell_to_dof_indices.insert(cell_indices.begin(),
262 cell_indices.end());
263 }
264}
265
266template <int reduced_dim, int dim, int spacedim, int n_components>
267const std::vector<types::global_dof_index> &
270{
273 ExcMessage("Cell index not found in global cell to dof indices."));
275}
276
278
279template <int reduced_dim, int dim, int spacedim, int n_components>
280std::tuple<unsigned int, unsigned int, unsigned int>
282 particle_id_to_cell_and_qpoint_indices(const unsigned int particle_id) const
283{
284 AssertIndexRange(particle_id,
285 triangulation.n_global_active_cells() *
286 quadrature_formula.size() *
287 reference_cross_section.n_quadrature_points());
288 const unsigned int cell_index =
289 particle_id /
290 (quadrature_formula.size() * reference_cross_section.n_quadrature_points());
291 const unsigned int qpoint_index_in_cell =
292 (particle_id / reference_cross_section.n_quadrature_points()) %
293 quadrature_formula.size();
294 const unsigned int qpoint_index_in_section =
295 particle_id % reference_cross_section.n_quadrature_points();
296
297 AssertIndexRange(cell_index, triangulation.n_global_active_cells());
298 AssertIndexRange(qpoint_index_in_cell, quadrature_formula.size());
299 AssertIndexRange(qpoint_index_in_section,
300 reference_cross_section.n_quadrature_points());
301 return std::make_tuple(cell_index,
302 qpoint_index_in_cell,
303 qpoint_index_in_section);
304}
305
307template <int reduced_dim, int dim, int spacedim, int n_components>
308std::map<unsigned int, IndexSet>
311 const std::map<unsigned int, IndexSet> &remote_q_point_indices) const
312{
313 std::map<unsigned int, IndexSet> cell_indices;
314 const IndexSet &owned_cells =
315 triangulation.global_active_cell_index_partitioner()
316 .lock()
317 ->locally_owned_range();
318
319 auto local_q_point_indices =
320 Utilities::MPI::some_to_some(mpi_communicator, remote_q_point_indices);
321
322 for (const auto &[proc, qpoint_indices] : local_q_point_indices)
323 {
324 IndexSet cell_indices_for_proc(triangulation.n_global_active_cells());
325 for (const auto &qpoint_index : qpoint_indices)
327 const auto [cell_index, q_index, i] =
329 cell_indices_for_proc.add_index(
330 owned_cells.nth_index_in_set(cell_index));
331 }
332 cell_indices_for_proc.compress();
333 cell_indices[proc] = cell_indices_for_proc;
334 }
335 return cell_indices;
336}
337
338
339// Setup degrees of freedom for the tensor product space
340template <int reduced_dim, int dim, int spacedim, int n_components>
341void
343{
344 dof_handler.distribute_dofs(fe);
345 // Additional setup can be done here if needed
346 for (const auto &cell : dof_handler.active_cell_iterators())
347 if (cell->is_locally_owned())
348 {
349 std::vector<types::global_dof_index> dof_indices(fe.n_dofs_per_cell());
350 cell->get_dof_indices(dof_indices);
351 global_cell_to_dof_indices[cell->global_active_cell_index()] =
352 dof_indices;
353 }
354}
355
356template <int reduced_dim, int dim, int spacedim, int n_components>
360{
361 IndexSet locally_owned_cell_set =
362 triangulation.global_active_cell_index_partitioner()
363 .lock()
364 ->locally_owned_range();
365
366 // Now make a tensor product of the local indices with the total number of
367 // quadrature points, and the number of quadrature points in the
368 // cross-section
369 const unsigned int n_qpoints_per_cell =
370 reference_cross_section.n_quadrature_points() * quadrature_formula.size();
371
372 IndexSet locally_owned_qpoints_set = locally_owned_cell_set.tensor_product(
373 complete_index_set(n_qpoints_per_cell));
374
375 return locally_owned_qpoints_set;
376}
377
378template <int reduced_dim, int dim, int spacedim, int n_components>
382{
383 IndexSet indices = triangulation.global_active_cell_index_partitioner()
384 .lock()
385 ->locally_owned_range();
386 for (const auto &[cell_id, local_indices] : global_cell_to_dof_indices)
387 indices.add_index(cell_id);
388 indices.compress();
389 return indices;
390}
391
392template <int reduced_dim, int dim, int spacedim, int n_components>
393auto
399
400template <int reduced_dim, int dim, int spacedim, int n_components>
401void
404{
405 all_qpoints.reserve(triangulation.n_active_cells() *
406 quadrature_formula.size() *
407 reference_cross_section.n_quadrature_points());
408 all_weights.reserve(triangulation.n_active_cells() *
409 quadrature_formula.size() *
410 reference_cross_section.n_quadrature_points());
411
412 reduced_qpoints.reserve(triangulation.n_active_cells() *
413 quadrature_formula.size());
414 reduced_weights.reserve(triangulation.n_active_cells() *
415 quadrature_formula.size());
416
417 UpdateFlags flags =
418 reduced_dim == 1 ?
421
423
424
425
426 const auto &properties_fe = properties_dh.get_fe();
427 FEValues<reduced_dim, spacedim> properties_fe_values(properties_fe,
430
431 // Find the index of the thickness field in the properties
432 const unsigned int thickness_field_index =
433 std::distance(properties_names.begin(),
434 std::find(properties_names.begin(),
435 properties_names.end(),
436 par.thickness_field_name));
437
438 const auto thickness_start =
439 thickness_field_index >= properties_names.size() ?
441 VTKUtils::get_block_indices(properties_fe)
442 .block_start(thickness_field_index);
443
444 FEValuesExtractors::Scalar thickness(thickness_start);
445
446 // Initialize the thickness values with the constant thickness
447 std::vector<double> thickness_values(get_quadrature().size(), par.thickness);
448
449 for (const auto &cell : triangulation.active_cell_iterators())
450 if (cell->is_locally_owned())
451 {
452 fev.reinit(cell);
453 const auto &qpoints = fev.get_quadrature_points();
454 const auto &JxW = fev.get_JxW_values();
455
456
457 if (thickness_start != numbers::invalid_unsigned_int)
458 {
459 properties_fe_values.reinit(
460 cell->as_dof_handler_iterator(this->properties_dh));
461 properties_fe_values[thickness].get_function_values(
462 properties, thickness_values);
463 }
464
465 reduced_qpoints.insert(reduced_qpoints.end(),
466 qpoints.begin(),
467 qpoints.end());
468 for (const auto &w : JxW)
469 reduced_weights.emplace_back(std::vector<double>(1, w));
470
471 Tensor<1, spacedim> new_vertical;
472 if constexpr (reduced_dim == 1)
473 new_vertical = cell->vertex(1) - cell->vertex(0);
474
475 for (const auto &q : fev.quadrature_point_indices())
476 {
477 const auto &qpoint = qpoints[q];
478 if constexpr (reduced_dim == 2)
479 new_vertical = fev.normal_vector(q);
480 // [TODO] Make radius a function of the cell
481 auto cross_section_qpoints =
482 reference_cross_section.get_transformed_quadrature(
483 qpoint, new_vertical, thickness_values[q]);
484
485 all_qpoints.insert(all_qpoints.end(),
486 cross_section_qpoints.get_points().begin(),
487 cross_section_qpoints.get_points().end());
488
489 for (const auto &w : cross_section_qpoints.get_weights())
490 all_weights.emplace_back(std::vector<double>(1, w * fev.JxW(q)));
491 }
492 }
493};
494
495template <int reduced_dim, int dim, int spacedim, int n_components>
502
503template <int reduced_dim, int dim, int spacedim, int n_components>
504double
506 const unsigned int) const
507{
508 return std::pow(par.thickness, -((dim - reduced_dim) / 2.0));
509}
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>
534
535template <int reduced_dim, int dim, int spacedim, int n_components>
536const std::vector<std::string> &
542
543template <int reduced_dim, int dim, int spacedim, int n_components>
544std::vector<std::string> &
550
551
552
557
562
563template class TensorProductSpace<1, 2, 2, 1>;
564template class TensorProductSpace<1, 2, 3, 1>;
565template class TensorProductSpace<1, 3, 3, 1>;
566template class TensorProductSpace<2, 3, 3, 1>;
567
568template class TensorProductSpace<1, 2, 2, 2>;
569template class TensorProductSpace<1, 2, 3, 3>;
570template class TensorProductSpace<1, 3, 3, 3>;
571template 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< Point< spacedim > > reduced_qpoints
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::function< void(Triangulation< reduced_dim, spacedim > &)> preprocess_serial_triangulation
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)
LogStream deallog
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.