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