deal.II version GIT relicensing-2173-gae8fc9d14b 2024-11-24 06:40:00+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
information_based_mesh_refinement.h
Go to the documentation of this file.
1
136 *  
137 *   #include <deal.II/base/numbers.h>
138 *   #include <deal.II/base/thread_management.h>
139 *   #include <deal.II/grid/tria.h>
140 *   #include <deal.II/dofs/dof_handler.h>
141 *   #include <deal.II/grid/grid_generator.h>
142 *   #include <deal.II/grid/tria_accessor.h>
143 *   #include <deal.II/grid/tria_iterator.h>
144 *   #include <deal.II/dofs/dof_accessor.h>
145 *   #include <deal.II/dofs/dof_renumbering.h>
146 *   #include <deal.II/fe/fe_q.h>
147 *   #include <deal.II/fe/fe_dgq.h>
148 *   #include <deal.II/fe/fe_system.h>
149 *   #include <deal.II/dofs/dof_tools.h>
150 *   #include <deal.II/fe/fe_values.h>
151 *   #include <deal.II/base/quadrature_lib.h>
152 *   #include <deal.II/base/function.h>
153 *   #include <deal.II/numerics/vector_tools.h>
154 *   #include <deal.II/numerics/matrix_tools.h>
155 *   #include <deal.II/numerics/derivative_approximation.h>
156 *   #include <deal.II/lac/block_vector.h>
157 *   #include <deal.II/lac/full_matrix.h>
158 *   #include <deal.II/lac/block_sparse_matrix.h>
159 *   #include <deal.II/lac/block_sparsity_pattern.h>
160 *   #include <deal.II/lac/sparse_direct.h>
161 *   #include <deal.II/particles/particle_handler.h>
162 *   #include <deal.II/particles/data_out.h>
163 *  
164 *   #include <deal.II/numerics/data_out.h>
165 *   #include <fstream>
166 *   #include <iostream>
167 *  
168 *   #include <deal.II/base/logstream.h>
169 *   #include <deal.II/grid/grid_refinement.h>
170 *  
171 *   using namespace dealii;
172 *  
173 *  
174 * @endcode
175 *
176 * The following is the main class. It resembles a variation of the @ref step_6 "step-6"
177 * principal class, with the addition of information-specific stuff. It also
178 * has to deal with solving a vector-valued problem for (c,lambda,f) as
179 * primal variable, dual variable, and right hand side, as explained
180 * in the paper.
181 *
182 * @code
183 *   template <int dim>
184 *   class InformationDensityMeshRefinement
185 *   {
186 *   public:
187 *   InformationDensityMeshRefinement ();
188 *   void run ();
189 *  
190 *   private:
191 *   void compute_synthetic_measurements();
192 *   void bounce_measurement_points_to_cell_centers ();
193 *   void setup_system();
194 *   void assemble_system ();
195 *   void solve ();
196 *   void compute_information_content ();
197 *   void output_results (const unsigned int cycle) const;
198 *   void refine_grid ();
199 *  
200 *   const Point<dim> source_location;
201 *   const double source_radius;
202 *  
203 *   std::vector<Point<dim>> detector_locations;
204 *  
205 *   const double regularization_parameter;
206 *   Tensor<1,dim> velocity;
207 *  
209 *   FESystem<dim> fe;
210 *   DoFHandler<dim> dof_handler;
211 *  
212 *   AffineConstraints<double> hanging_node_constraints;
213 *  
214 *   BlockSparsityPattern sparsity_pattern;
215 *   BlockSparseMatrix<double> system_matrix;
216 *  
217 *   BlockVector<double> solution;
218 *   BlockVector<double> system_rhs;
219 *  
220 *   Vector<double> information_content;
221 *  
222 *   std::vector<Point<dim>> detector_locations_on_mesh;
223 *   std::vector<double> measurement_values;
224 *   std::vector<double> noise_level;
225 *   };
226 *  
227 *  
228 *  
229 *  
230 *   template <int dim>
231 *   InformationDensityMeshRefinement<dim>::InformationDensityMeshRefinement ()
232 *   :
233 *   source_location (Point<dim>(-0.25,0)),
234 *   source_radius (0.2),
235 *   regularization_parameter (10000),
236 *   fe (FE_Q<dim>(3), 1, // c
237 *   FE_Q<dim>(3), 1, // lambda
238 *   FE_DGQ<dim>(0), 1), // f
239 *   dof_handler (triangulation)
240 *   {
241 *   velocity[0] = 100;
242 *  
243 * @endcode
244 *
245 * We have 50 detector points on an outer ring...
246 *
247 * @code
248 *   for (unsigned int i=0; i<50; ++i)
249 *   {
250 *   const Point<dim> p (0.6 * std::sin(2*numbers::PI * i/50),
251 *   0.6 * std::cos(2*numbers::PI * i/50));
252 *   detector_locations.push_back (p);
253 *   }
254 *  
255 * @endcode
256 *
257 * ...and another 50 detector points on an innner ring:
258 *
259 * @code
260 *   for (unsigned int i=0; i<50; ++i)
261 *   {
262 *   const Point<dim> p (0.2 * std::sin(2*numbers::PI * i/50),
263 *   0.2 * std::cos(2*numbers::PI * i/50));
264 *   detector_locations.push_back (p);
265 *   }
266 *  
267 * @endcode
268 *
269 * Generate the grid we will work on:
270 *
271 * @code
273 *   triangulation.refine_global (4);
274 *  
275 * @endcode
276 *
277 * The detector locations are static, so we can already here
278 * generate a file that contains their locations. We use the
279 * particle framework to do this, using detector locations as
280 * particle locations.
281 *
282 * @code
283 *   {
286 *   for (const auto &loc : detector_locations)
287 *   {
288 *   Particles::Particle<dim> new_particle;
289 *   new_particle.set_location(loc);
290 * @endcode
291 *
292 * Insert the particle. It is a lie that the particle is in
293 * the first cell, but nothing we do actually cares about the
294 * cell a particle is in.
295 *
296 * @code
297 *   particle_handler.insert_particle(new_particle,
298 *   triangulation.begin_active());
299 *   }
300 *  
301 *   Particles::DataOut<dim> particle_out;
302 *   particle_out.build_patches(particle_handler);
303 *   std::ofstream output("detector_locations.vtu");
304 *   particle_out.write_vtu(output);
305 *   }
306 *  
307 * @endcode
308 *
309 * While we're generating output, also output the source location. Do this
310 * by outputting many (1000) points that indicate the perimeter of the source
311 *
312 * @code
313 *   {
314 *   Particles::ParticleHandler<dim> particle_handler(triangulation,
315 *   StaticMappingQ1<dim>::mapping);
316 *  
317 *   const unsigned int n_points = 1000;
318 *   for (unsigned int i=0; i<n_points; ++i)
319 *   {
320 *   Point<dim> loc = source_location;
321 *   loc[0] += source_radius * std::cos(2*numbers::PI*i/n_points);
322 *   loc[1] += source_radius * std::sin(2*numbers::PI*i/n_points);
323 *  
324 *   Particles::Particle<dim> new_particle;
325 *   new_particle.set_location(loc);
326 *   particle_handler.insert_particle(new_particle,
327 *   triangulation.begin_active());
328 *   }
329 *  
330 *   Particles::DataOut<dim> particle_out;
331 *   particle_out.build_patches(particle_handler);
332 *   std::ofstream output("source_locations.vtu");
333 *   particle_out.write_vtu(output);
334 *   }
335 *   }
336 *  
337 *  
338 *  
339 * @endcode
340 *
341 * The following function solves a forward problem on a twice
342 * refined mesh to compute "synthetic data". Refining the mesh
343 * beyond the mesh used for the inverse problem avoids an
344 * inverse crime.
345 *
346 * @code
347 *   template <int dim>
348 *   void InformationDensityMeshRefinement<dim>::compute_synthetic_measurements ()
349 *   {
350 *   std::cout << "Computing synthetic data by solving the forward problem..."
351 *   << std::flush;
352 *  
353 * @endcode
354 *
355 * Create a triangulation and DoFHandler that corresponds to a
356 * twice-refined mesh so that we obtain the synthetic data with
357 * higher accuracy than we do on the regular mesh used for all other
358 * computations.
359 *
360 * @code
361 *   Triangulation<dim> forward_triangulation;
362 *   forward_triangulation.copy_triangulation (triangulation);
363 *   forward_triangulation.refine_global (2);
364 *  
365 *   const FE_Q<dim> forward_fe (fe.base_element(0).degree);
366 *   DoFHandler<dim> forward_dof_handler (forward_triangulation);
367 *   forward_dof_handler.distribute_dofs (forward_fe);
368 *  
369 *   AffineConstraints<double> constraints;
370 *   DoFTools::make_hanging_node_constraints(forward_dof_handler, constraints);
371 *   constraints.close();
372 *  
373 *   SparsityPattern sparsity (forward_dof_handler.n_dofs(),
374 *   forward_dof_handler.max_couplings_between_dofs());
375 *   DoFTools::make_sparsity_pattern (forward_dof_handler, sparsity);
376 *   constraints.condense (sparsity);
377 *   sparsity.compress ();
378 *  
379 *   SparseMatrix<double> system_matrix (sparsity);
380 *   Vector<double> system_rhs (forward_dof_handler.n_dofs());
381 *  
382 *   QGauss<dim> quadrature_formula(3);
383 *   FEValues<dim> fe_values (forward_fe, quadrature_formula,
384 *   update_values | update_gradients |
385 *   update_quadrature_points | update_JxW_values);
386 *  
387 *   const unsigned int dofs_per_cell = forward_fe.dofs_per_cell;
388 *   const unsigned int n_q_points = quadrature_formula.size();
389 *  
390 * @endcode
391 *
392 * First assemble the system matrix and right hand side for the forward
393 * problem:
394 *
395 * @code
396 *   {
397 *   FullMatrix<double> cell_matrix (dofs_per_cell, dofs_per_cell);
398 *   Vector<double> cell_rhs (dofs_per_cell);
399 *   std::vector<unsigned int> local_dof_indices (dofs_per_cell);
400 *  
401 *   for (const auto &cell : forward_dof_handler.active_cell_iterators())
402 *   {
403 *   fe_values.reinit (cell);
404 *   cell_matrix = 0;
405 *   cell_rhs = 0;
406 *  
407 *   for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
408 *   for (unsigned int i=0; i<dofs_per_cell; ++i)
409 *   for (unsigned int j=0; j<dofs_per_cell; ++j)
410 *   cell_matrix(i,j) += (fe_values.shape_grad(i,q_point) *
411 *   fe_values.shape_grad(j,q_point)
412 *   +
413 *   fe_values.shape_value(i,q_point) *
414 *   (velocity * fe_values.shape_grad(j,q_point))
415 *   )
416 *   *
417 *   fe_values.JxW(q_point);
418 *   for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
419 *   if (fe_values.quadrature_point(q_point).distance (source_location)
420 *   < source_radius)
421 *   for (unsigned int i=0; i<dofs_per_cell; ++i)
422 *   cell_rhs(i) +=
423 *   1.0 *
424 *   fe_values.shape_value (i, q_point) *
425 *   fe_values.JxW(q_point);
426 *  
427 *   cell->get_dof_indices (local_dof_indices);
428 *   constraints.distribute_local_to_global (cell_matrix,
429 *   cell_rhs,
430 *   local_dof_indices,
431 *   system_matrix,
432 *   system_rhs);
433 *   }
434 *  
435 *   std::map<unsigned int, double> boundary_values;
436 *   VectorTools::interpolate_boundary_values (forward_dof_handler,
437 *   0,
438 *   Functions::ZeroFunction<dim>(),
439 *   boundary_values);
440 *   Vector<double> tmp (forward_dof_handler.n_dofs());
441 *   MatrixTools::apply_boundary_values (boundary_values,
442 *   system_matrix,
443 *   tmp,
444 *   system_rhs);
445 *   }
446 *  
447 * @endcode
448 *
449 * Solve the forward problem and output it into its own VTU file :
450 *
451 * @code
452 *   SparseDirectUMFPACK A_inverse;
453 *   Vector<double> forward_solution (forward_dof_handler.n_dofs());
454 *   forward_solution = system_rhs;
455 *   A_inverse.solve(system_matrix, forward_solution);
456 *  
457 *   const double max_forward_solution = forward_solution.linfty_norm();
458 *  
459 *   {
460 *   DataOut<dim> data_out;
461 *   data_out.attach_dof_handler (forward_dof_handler);
462 *   data_out.add_data_vector (forward_solution, "c");
463 *   data_out.build_patches (4);
464 *  
465 *   std::ofstream out ("forward-solution.vtu");
466 *   data_out.write_vtu (out);
467 *   }
468 *  
469 * @endcode
470 *
471 * Now evaluate the forward solution at the measurement points:
472 *
473 * @code
474 *   for (const auto &p : detector_locations)
475 *   {
476 * @endcode
477 *
478 * same 10% noise level for all points
479 *
480 * @code
481 *   noise_level.push_back (0.1 * max_forward_solution);
482 *  
483 *   const double z_n = VectorTools::point_value(forward_dof_handler, forward_solution, p);
484 *   const double eps_n = Utilities::generate_normal_random_number(0, noise_level.back());
485 *  
486 *   measurement_values.push_back (z_n + eps_n);
487 *   }
488 *  
489 *   std::cout << std::endl;
490 *   }
491 *  
492 *  
493 * @endcode
494 *
495 * It will make our lives easier if we can always assume that detector
496 * locations are at cell centers, because then we can evaluate the
497 * solution there using a quadrature formula whose sole quadrature
498 * point lies at the center of a cell. That's of course not where the
499 * "real" detector locations are, but it does not introduce a large
500 * error to do this.
501 *
502 * @code
503 *   template <int dim>
504 *   void InformationDensityMeshRefinement<dim>::bounce_measurement_points_to_cell_centers ()
505 *   {
506 *   detector_locations_on_mesh = detector_locations;
507 *   for (auto &p : detector_locations_on_mesh)
508 *   {
509 *   for (const auto &cell : triangulation.active_cell_iterators())
510 *   if (cell->point_inside (p))
511 *   {
512 *   p = cell->center();
513 *   break;
514 *   }
515 *   }
516 *   }
517 *  
518 *  
519 * @endcode
520 *
521 * The following functions are all quite standard by what we have
522 * shown in @ref step_4 "step-4", @ref step_6 "step-6", and @ref step_22 "step-22" (to name just a few of the
523 * more typical programs):
524 *
525 * @code
526 *   template <int dim>
527 *   void InformationDensityMeshRefinement<dim>::setup_system ()
528 *   {
529 *   std::cout << "Setting up the linear system for the inverse problem..."
530 *   << std::endl;
531 *  
532 *   dof_handler.distribute_dofs (fe);
533 *   DoFRenumbering::component_wise (dof_handler);
534 *  
535 *   hanging_node_constraints.clear ();
537 *   hanging_node_constraints);
538 *   hanging_node_constraints.close();
539 *  
540 *   std::cout << " Number of active cells: "
541 *   << triangulation.n_active_cells()
542 *   << std::endl;
543 *   std::cout << " Number of degrees of freedom: "
544 *   << dof_handler.n_dofs()
545 *   << std::endl;
546 *  
547 *   const std::vector<types::global_dof_index> dofs_per_component =
549 *   BlockDynamicSparsityPattern c_sparsity(dofs_per_component,dofs_per_component);
550 *   DoFTools::make_sparsity_pattern (dof_handler, c_sparsity);
551 *   hanging_node_constraints.condense(c_sparsity);
552 *   sparsity_pattern.copy_from(c_sparsity);
553 *  
554 *   system_matrix.reinit (sparsity_pattern);
555 *  
556 *   solution.reinit (dofs_per_component);
557 *   system_rhs.reinit (dofs_per_component);
558 *   }
559 *  
560 *  
561 *  
562 *   template <int dim>
563 *   void InformationDensityMeshRefinement<dim>::assemble_system ()
564 *   {
565 *   std::cout << "Assembling the linear system for the inverse problem..."
566 *   << std::flush;
567 *  
568 *   QGauss<dim> quadrature_formula(3);
569 *  
570 *   FEValues<dim> fe_values (fe, quadrature_formula,
573 *  
574 *   const unsigned int dofs_per_cell = fe.dofs_per_cell;
575 *   const unsigned int n_q_points = quadrature_formula.size();
576 *  
577 *   FullMatrix<double> cell_matrix (dofs_per_cell, dofs_per_cell);
578 *   Vector<double> cell_rhs (dofs_per_cell);
579 *  
580 *   std::vector<unsigned int> local_dof_indices (dofs_per_cell);
581 *  
582 *   const FEValuesExtractors::Scalar c(0), lambda(1), f(2);
583 *  
584 *   for (const auto &cell : dof_handler.active_cell_iterators())
585 *   {
586 *   fe_values.reinit (cell);
587 *   cell_matrix = 0;
588 *   cell_rhs = 0;
589 *  
590 *   for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
591 *   for (unsigned int i=0; i<dofs_per_cell; ++i)
592 *   {
593 *   const Tensor<1,dim> grad_phi_i = fe_values[c].gradient (i,q_point);
594 *   const Tensor<1,dim> grad_psi_i = fe_values[lambda].gradient (i,q_point);
595 *  
596 *   const double phi_i = fe_values[c].value (i,q_point);
597 *   const double psi_i = fe_values[lambda].value (i,q_point);
598 *   const double chi_i = fe_values[f].value (i,q_point);
599 *  
600 *   for (unsigned int j=0; j<dofs_per_cell; ++j)
601 *   {
602 *   const Tensor<1,dim> grad_phi_j = fe_values[c].gradient (j,q_point);
603 *   const Tensor<1,dim> grad_psi_j = fe_values[lambda].gradient (j,q_point);
604 *  
605 *   const double phi_j = fe_values[c].value (j,q_point);
606 *   const double psi_j= fe_values[lambda].value (j,q_point);
607 *   const double chi_j = fe_values[f].value (j,q_point);
608 *  
609 *   cell_matrix(i,j) +=
610 *   ((grad_phi_i * grad_phi_j
611 *   +
612 *   phi_i * (velocity * grad_phi_j)
613 *   -
614 *   phi_i * chi_j
615 *   +
616 *   grad_psi_i * grad_psi_j
617 *   -
618 *   psi_i * (velocity * grad_psi_j)
619 *   -
620 *   chi_i * psi_j
621 *   +
622 *   regularization_parameter * chi_i * chi_j
623 *   ) *
624 *   fe_values.JxW (q_point));
625 *  
626 *   for (unsigned int n=0; n< detector_locations_on_mesh.size(); ++n)
627 *   if (fe_values.quadrature_point(q_point).distance (detector_locations_on_mesh[n]) < 1e-12)
628 *   {
629 *   cell_matrix(i,j) += psi_i * phi_j / noise_level[n] / noise_level[n];
630 *   }
631 *   }
632 *  
633 *   for (unsigned int n=0; n< detector_locations_on_mesh.size(); ++n)
634 *   if (fe_values.quadrature_point(q_point).distance (detector_locations_on_mesh[n]) < 1e-12)
635 *   cell_rhs(i) += psi_i * measurement_values[n] / noise_level[n] / noise_level[n];
636 *   }
637 *  
638 *   cell->get_dof_indices (local_dof_indices);
639 *   for (unsigned int i=0; i<dofs_per_cell; ++i)
640 *   {
641 *   for (unsigned int j=0; j<dofs_per_cell; ++j)
642 *   system_matrix.add (local_dof_indices[i],
643 *   local_dof_indices[j],
644 *   cell_matrix(i,j));
645 *  
646 *   system_rhs(local_dof_indices[i]) += cell_rhs(i);
647 *   }
648 *   }
649 *  
650 *   hanging_node_constraints.condense (system_matrix);
651 *   hanging_node_constraints.condense (system_rhs);
652 *  
653 *   std::map<unsigned int,double> boundary_values;
654 *   std::vector<bool> component_mask (3);
655 *   component_mask[0] = component_mask[1] = true;
656 *   component_mask[2] = false;
658 *   0,
660 *   boundary_values,
661 *   component_mask);
662 *   MatrixTools::apply_boundary_values (boundary_values,
663 *   system_matrix,
664 *   solution,
665 *   system_rhs);
666 *  
667 *   std::cout << std::endl;
668 *   }
669 *  
670 *  
671 *  
672 *   template <int dim>
673 *   void InformationDensityMeshRefinement<dim>::solve ()
674 *   {
675 *   std::cout << "Solving the linear system for the inverse problem..."
676 *   << std::flush;
677 *  
678 *   SparseDirectUMFPACK A_direct;
679 *   solution = system_rhs;
680 *   A_direct.solve(system_matrix, solution);
681 *  
682 *   hanging_node_constraints.distribute (solution);
683 *  
684 *   std::cout << std::endl;
685 *   }
686 *  
687 *  
688 *  
689 * @endcode
690 *
691 * This is really the only interesting function of this program. It
692 * computes the functions @f$h_K = A^{-1} s_K@f$ for each source function
693 * (corresponding to each cell of the mesh). To do so, it first
694 * computes the forward matrix @f$A@f$ and uses the SparseDirectUMFPACK
695 * class to build an LU decomposition for this matrix. Then it loops
696 * over all cells @f$K@f$ and computes the corresponding @f$h_K@f$ by applying
697 * the LU decomposition to a right hand side vector for each @f$s_K@f$.
698 *
699
700 *
701 * The actual information content is then computed by evaluating these
702 * functions @f$h_K@f$ at measurement locations.
703 *
704 * @code
705 *   template <int dim>
706 *   void InformationDensityMeshRefinement<dim>::compute_information_content ()
707 *   {
708 *   std::cout << "Computing the information content..."
709 *   << std::flush;
710 *  
711 *   information_content.reinit (triangulation.n_active_cells());
712 *  
713 *   const FE_Q<dim> information_fe (fe.base_element(0).degree);
714 *   DoFHandler<dim> information_dof_handler (triangulation);
715 *   information_dof_handler.distribute_dofs (information_fe);
716 *  
717 *   AffineConstraints<double> constraints;
718 *   DoFTools::make_hanging_node_constraints(information_dof_handler, constraints);
719 *   constraints.close();
720 *  
721 *   SparsityPattern sparsity (information_dof_handler.n_dofs(),
722 *   information_dof_handler.max_couplings_between_dofs());
723 *   DoFTools::make_sparsity_pattern (information_dof_handler, sparsity);
724 *   constraints.condense (sparsity);
725 *   sparsity.compress ();
726 *  
727 *   SparseMatrix<double> system_matrix (sparsity);
728 *  
729 *   QGauss<dim> quadrature_formula(3);
730 *  
731 *   const unsigned int dofs_per_cell = information_fe.dofs_per_cell;
732 *   const unsigned int n_q_points = quadrature_formula.size();
733 *  
734 * @endcode
735 *
736 * First build the forward operator
737 *
738 * @code
739 *   {
740 *   FEValues<dim> fe_values (information_fe, quadrature_formula,
743 *  
744 *   FullMatrix<double> cell_matrix (dofs_per_cell, dofs_per_cell);
745 *   std::vector<unsigned int> local_dof_indices (dofs_per_cell);
746 *  
747 *   for (const auto &cell : information_dof_handler.active_cell_iterators())
748 *   {
749 *   fe_values.reinit (cell);
750 *   cell_matrix = 0;
751 *  
752 *   for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
753 *   for (unsigned int i=0; i<dofs_per_cell; ++i)
754 *   for (unsigned int j=0; j<dofs_per_cell; ++j)
755 *   cell_matrix(i,j) += (fe_values.shape_grad (i,q_point) *
756 *   fe_values.shape_grad(j,q_point)
757 *   +
758 *   fe_values.shape_value(i,q_point) *
759 *   (velocity * fe_values.shape_grad(j,q_point))) *
760 *   fe_values.JxW(q_point);
761 *  
762 *   cell->distribute_local_to_global (cell_matrix,
763 *   system_matrix);
764 *   }
765 *  
766 *   constraints.condense (system_matrix);
767 *  
768 *   std::map<unsigned int, double> boundary_values;
769 *   VectorTools::interpolate_boundary_values (information_dof_handler,
770 *   0,
772 *   boundary_values);
773 *   Vector<double> tmp (information_dof_handler.n_dofs());
774 *   MatrixTools::apply_boundary_values (boundary_values,
775 *   system_matrix,
776 *   tmp,
777 *   tmp);
778 *   }
779 *  
780 * @endcode
781 *
782 * Then factorize
783 *
784 * @code
785 *   SparseDirectUMFPACK A_inverse;
786 *   A_inverse.factorize(system_matrix);
787 *  
788 * @endcode
789 *
790 * Now compute the solutions corresponding to the possible
791 * sources. Each source is active on exactly one cell.
792 *
793
794 *
795 * As mentioned in the paper, this is a trivially parallel job, so
796 * we send the computations for each of these cells onto a separate
797 * task and let the OS schedule them onto individual processor
798 * cores.
799 *
800 * @code
801 *   Threads::TaskGroup<void> tasks;
802 *   for (unsigned int K=0; K<triangulation.n_active_cells(); ++K)
803 *   tasks +=
804 *   Threads::new_task([&,K]()
805 *   {
806 *   Vector<double> rhs (information_dof_handler.n_dofs());
807 *   Vector<double> cell_rhs (dofs_per_cell);
808 *   std::vector<unsigned int> local_dof_indices (dofs_per_cell);
809 *  
811 *   cell = information_dof_handler.begin_active();
812 *   std::advance (cell, K);
813 *  
814 *   FEValues<dim> fe_values (information_fe, quadrature_formula,
815 *   update_values |
817 *  
818 *   fe_values.reinit (cell);
819 *   cell_rhs = 0;
820 *  
821 *   for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
822 *   for (unsigned int i=0; i<dofs_per_cell; ++i)
823 *   cell_rhs(i) += fe_values.shape_value (i,q_point) *
824 *   fe_values.JxW(q_point);
825 *  
826 *   cell->distribute_local_to_global (cell_rhs,
827 *   rhs);
828 *  
829 *   constraints.condense (rhs);
830 *  
831 *   A_inverse.solve(rhs);
832 *  
833 *   constraints.distribute (rhs);
834 *  
835 * @endcode
836 *
837 * Having computed the forward solutions
838 * corresponding to this source term, evaluate its
839 * contribution to the information content on all
840 * cells of the mesh by taking into account the
841 * detector locations. We add these into global
842 * objects, so we have to guard access to the
843 * global object:
844 *
845 * @code
846 *   static std::mutex m;
847 *   std::lock_guard<std::mutex> g(m);
848 *  
849 *  
850 *   information_content(K) = regularization_parameter * cell->measure() * cell->measure();
851 *   std::vector<double> local_h_K_values (n_q_points);
852 *   for (const auto &cell : information_dof_handler.active_cell_iterators())
853 *   {
854 *   fe_values.reinit (cell);
855 *   fe_values.get_function_values (rhs, local_h_K_values);
856 *  
857 *   for (unsigned int q_point=0; q_point<n_q_points; ++q_point)
858 *   for (unsigned int n=0; n< detector_locations_on_mesh.size(); ++n)
859 *   if (fe_values.quadrature_point(q_point).distance (detector_locations_on_mesh[n]) < 1e-12)
860 *   information_content(K) += local_h_K_values[q_point]
861 *   * local_h_K_values[q_point]
862 *   / noise_level[n] / noise_level[n];
863 *   }
864 *   }
865 *   );
866 *  
867 * @endcode
868 *
869 * And wait:
870 *
871 * @code
872 *   tasks.join_all();
873 *  
874 *   std::cout << std::endl;
875 *   }
876 *  
877 *  
878 *  
879 * @endcode
880 *
881 * Create graphical output for all of the principal variables of the
882 * problem (c,lambda,f) as well as for the information content and
883 * density. Then also output the various blocks of the matrix so we
884 * can compute the eigenvalues of the H matrix mentioned in the paper.
885 *
886 * @code
887 *   template <int dim>
888 *   void InformationDensityMeshRefinement<dim>::output_results (const unsigned int cycle) const
889 *   {
890 *   std::cout << "Outputting solutions..." << std::flush;
891 *  
892 *   DataOut<dim> data_out;
893 *  
894 *   std::vector<std::string> names;
895 *   names.push_back ("forward_solution");
896 *   names.push_back ("adjoint_solution");
897 *   names.push_back ("recovered_parameter");
898 *  
899 *   data_out.attach_dof_handler (dof_handler);
900 *   data_out.add_data_vector (solution, names);
901 *   data_out.add_data_vector (information_content, "information_content");
902 *  
903 *   Vector<double> information_density (triangulation.n_active_cells());
904 *   for (const auto &cell : triangulation.active_cell_iterators())
905 *   information_density(cell->active_cell_index())
906 *   = std::sqrt(information_content(cell->active_cell_index())) / cell->measure();
907 *   data_out.add_data_vector (information_density, "information_density");
908 *  
909 *   data_out.build_patches ();
910 *  
911 *   std::string filename = "solution-";
912 *   filename += ('0'+cycle);
913 *   filename += ".vtu";
914 *  
915 *   std::ofstream output (filename.c_str());
916 *   data_out.write_vtu (output);
917 *  
918 *  
919 * @endcode
920 *
921 * Now output the individual blocks of the matrix into files.
922 *
923 * @code
924 *   auto write_block = [&](const unsigned int block_i,
925 *   const unsigned int block_j,
926 *   const std::string &filename)
927 *   {
928 *   std::ofstream o(filename);
929 *   system_matrix.block(block_i,block_j).print (o);
930 *   };
931 *   write_block(0,0, "matrix-" + std::to_string(cycle) + "-A.txt");
932 *   write_block(0,2, "matrix-" + std::to_string(cycle) + "-B.txt");
933 *   write_block(1,0, "matrix-" + std::to_string(cycle) + "-C.txt");
934 *   write_block(2,2, "matrix-" + std::to_string(cycle) + "-M.txt");
935 *  
936 *   std::cout << std::endl;
937 *   }
938 *  
939 *  
940 *  
941 * @endcode
942 *
943 * The following is then a function that refines the mesh based on the
944 * refinement criteria described in the paper. Which criterion to use
945 * is determined by which value the `refinement_criterion` variable
946 * is set to.
947 *
948 * @code
949 *   template <int dim>
950 *   void InformationDensityMeshRefinement<dim>::refine_grid ()
951 *   {
952 *   std::cout << "Refining the mesh..." << std::endl;
953 *  
954 *   enum RefinementCriterion
955 *   {
956 *   global,
957 *   information_content,
958 *   indicator,
959 *   smoothness
960 *   };
961 *   const RefinementCriterion refinement_criterion = information_content;
962 *  
963 *   switch (refinement_criterion)
964 *   {
965 *   case global:
966 *   {
967 *   triangulation.refine_global();
968 *   break;
969 *   }
970 *  
971 *   case information_content:
972 *   {
974 *   this->information_content,
975 *   0.2, 0.05);
976 *   triangulation.execute_coarsening_and_refinement ();
977 *   break;
978 *   }
979 *  
980 *   case indicator:
981 *   {
982 *   Vector<double> refinement_indicators (triangulation.n_active_cells());
983 *  
984 *   QGauss<dim> quadrature(3);
985 *   FEValues<dim> fe_values (fe, quadrature, update_values | update_JxW_values);
986 *  
987 *   const FEValuesExtractors::Scalar lambda(1), f(2);
988 *  
989 *   std::vector<double> lambda_values (quadrature.size());
990 *   std::vector<double> f_values (quadrature.size());
991 *  
992 *   for (const auto &cell : dof_handler.active_cell_iterators())
993 *   {
994 *   fe_values.reinit (cell);
995 *   fe_values[lambda].get_function_values (solution, lambda_values);
996 *   fe_values[f].get_function_values (solution, f_values);
997 *  
998 *   for (unsigned int q=0; q<quadrature.size(); ++q)
999 *   refinement_indicators(cell->active_cell_index())
1000 *   += (std::fabs (regularization_parameter * f_values[q]
1001 *   -
1002 *   lambda_values[q])
1003 *   * fe_values.JxW(q));
1004 *   }
1005 *  
1007 *   refinement_indicators,
1008 *   0.2, 0.05);
1009 *   triangulation.execute_coarsening_and_refinement ();
1010 *   break;
1011 *   }
1012 *  
1013 *  
1014 *   case smoothness:
1015 *   {
1016 *   Vector<float> refinement_indicators (triangulation.n_active_cells());
1017 *  
1019 *   solution,
1020 *   refinement_indicators,
1021 *   /*component=*/2);
1022 * @endcode
1023 *
1024 * and scale it to obtain an error indicator.
1025 *
1026 * @code
1027 *   for (const auto &cell : triangulation.active_cell_iterators())
1028 *   refinement_indicators[cell->active_cell_index()] *=
1029 *   std::pow(cell->diameter(), 1 + 1.0 * dim / 2);
1030 *  
1031 *  
1033 *   refinement_indicators,
1034 *   0.2, 0.05);
1035 *   triangulation.execute_coarsening_and_refinement ();
1036 *   break;
1037 *   }
1038 *  
1039 *   default:
1040 *   Assert (false, ExcInternalError());
1041 *   }
1042 *  
1043 *   bounce_measurement_points_to_cell_centers ();
1044 *  
1045 *  
1046 *   std::cout << std::endl;
1047 *   }
1048 *  
1049 *  
1050 *  
1051 *  
1052 *   template <int dim>
1053 *   void InformationDensityMeshRefinement<dim>::run ()
1054 *   {
1055 *   std::cout << "Solving problem in " << dim << " space dimensions." << std::endl;
1056 *  
1057 *   compute_synthetic_measurements ();
1058 *   bounce_measurement_points_to_cell_centers ();
1059 *  
1060 *   for (unsigned int cycle=0; cycle<7; ++cycle)
1061 *   {
1062 *   std::cout << "---------- Cycle " << cycle << " ------------" << std::endl;
1063 *  
1064 *   setup_system ();
1065 *   assemble_system ();
1066 *   solve ();
1067 *   compute_information_content ();
1068 *   output_results (cycle);
1069 *   refine_grid ();
1070 *   }
1071 *   }
1072 *  
1073 *  
1074 *  
1075 *   int main ()
1076 *   {
1077 *   try
1078 *   {
1079 *   deallog.depth_console (0);
1080 *  
1081 *   InformationDensityMeshRefinement<2> information_density_mesh_refinement;
1082 *   information_density_mesh_refinement.run ();
1083 *   }
1084 *   catch (std::exception &exc)
1085 *   {
1086 *   std::cerr << std::endl << std::endl
1087 *   << "----------------------------------------------------"
1088 *   << std::endl;
1089 *   std::cerr << "Exception on processing: " << std::endl
1090 *   << exc.what() << std::endl
1091 *   << "Aborting!" << std::endl
1092 *   << "----------------------------------------------------"
1093 *   << std::endl;
1094 *  
1095 *   return 1;
1096 *   }
1097 *   catch (...)
1098 *   {
1099 *   std::cerr << std::endl << std::endl
1100 *   << "----------------------------------------------------"
1101 *   << std::endl;
1102 *   std::cerr << "Unknown exception!" << std::endl
1103 *   << "Aborting!" << std::endl
1104 *   << "----------------------------------------------------"
1105 *   << std::endl;
1106 *   return 1;
1107 *   }
1108 *  
1109 *   return 0;
1110 *   }
1111 * @endcode
1112
1113
1114*/
void attach_dof_handler(const DoFHandler< dim, spacedim > &)
Definition fe_q.h:554
unsigned int depth_console(const unsigned int n)
Definition logstream.cc:349
void build_patches(const Particles::ParticleHandler< dim, spacedim > &particles, const std::vector< std::string > &data_component_names={}, const std::vector< DataComponentInterpretation::DataComponentInterpretation > &data_component_interpretations={})
Definition data_out.cc:27
Definition point.h:111
void solve(Vector< double > &rhs_and_solution, const bool transpose=false) const
void factorize(const Matrix &matrix)
Point< 2 > first
Definition grid_out.cc:4623
#define Assert(cond, exc)
typename ActiveSelector::active_cell_iterator active_cell_iterator
void make_hanging_node_constraints(const DoFHandler< dim, spacedim > &dof_handler, AffineConstraints< number > &constraints)
void make_sparsity_pattern(const DoFHandler< dim, spacedim > &dof_handler, SparsityPatternBase &sparsity_pattern, const AffineConstraints< number > &constraints={}, const bool keep_constrained_dofs=true, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id)
@ update_values
Shape function values.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
Task< RT > new_task(const std::function< RT()> &function)
LogStream deallog
Definition logstream.cc:36
CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt K
void approximate_gradient(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const InputVector &solution, Vector< float > &derivative_norm, const unsigned int component=0)
void component_wise(DoFHandler< dim, spacedim > &dof_handler, const std::vector< unsigned int > &target_component=std::vector< unsigned int >())
std::vector< types::global_dof_index > count_dofs_per_fe_component(const DoFHandler< dim, spacedim > &dof_handler, const bool vector_valued_once=false, const std::vector< unsigned int > &target_component={})
void hyper_cube(Triangulation< dim, spacedim > &tria, const double left=0., const double right=1., const bool colorize=false)
void refine_and_coarsen_fixed_number(Triangulation< dim, spacedim > &triangulation, const Vector< Number > &criteria, const double top_fraction_of_cells, const double bottom_fraction_of_cells, const unsigned int max_n_cells=std::numeric_limits< unsigned int >::max())
void scale(const double scaling_factor, Triangulation< dim, spacedim > &triangulation)
double diameter(const Triangulation< dim, spacedim > &tria)
@ matrix
Contents is actually a matrix.
void cell_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const FEValuesBase< dim > &fetest, const ArrayView< const std::vector< double > > &velocity, const double factor=1.)
Definition advection.h:74
void apply_boundary_values(const std::map< types::global_dof_index, number > &boundary_values, SparseMatrix< number > &matrix, Vector< number > &solution, Vector< number > &right_hand_side, const bool eliminate_columns=true)
void interpolate_boundary_values(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const std::map< types::boundary_id, const Function< spacedim, number > * > &function_map, std::map< types::global_dof_index, number > &boundary_values, const ComponentMask &component_mask={})
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
int(&) functions(const void *v1, const void *v2)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
static constexpr double PI
Definition numbers.h:254
STL namespace.
::VectorizedArray< Number, width > cos(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sin(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation
std::array< Number, 1 > eigenvalues(const SymmetricTensor< 2, 1, Number > &T)