Line data Source code
1 : //* This file is part of the MOOSE framework
2 : //* https://mooseframework.inl.gov
3 : //*
4 : //* All rights reserved, see COPYRIGHT for full restrictions
5 : //* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6 : //*
7 : //* Licensed under LGPL 2.1, please see LICENSE for details
8 : //* https://www.gnu.org/licenses/lgpl-2.1.html
9 :
10 : // MOOSE includes
11 : #include "TopResidualDebugOutput.h"
12 : #include "FEProblem.h"
13 : #include "MooseApp.h"
14 : #include "Material.h"
15 : #include "Console.h"
16 : #include "Action.h"
17 : #include "MooseMesh.h"
18 : #include "NonlinearSystemBase.h"
19 :
20 : #include "libmesh/transient_system.h"
21 : #include "libmesh/fe_type.h"
22 :
23 : registerMooseObject("MooseApp", TopResidualDebugOutput);
24 :
25 : InputParameters
26 14361 : TopResidualDebugOutput::validParams()
27 : {
28 14361 : InputParameters params = PetscOutput::validParams();
29 14361 : params.addClassDescription("Debug output object for displaying the top contributing residuals.");
30 :
31 : // Create parameters for allowing debug outputter to be defined within the [Outputs] block
32 43083 : params.addParam<unsigned int>(
33 28722 : "num_residuals", 0, "The number of top residuals to print out (0 = no output)");
34 :
35 : // By default operate on both nonlinear and linear residuals
36 57444 : params.set<ExecFlagEnum>("execute_on", true) = {EXEC_LINEAR, EXEC_NONLINEAR, EXEC_TIMESTEP_END};
37 14361 : params.addParam<NonlinearSystemName>(
38 : "nl_sys", "nl0", "The nonlinear system that we should output information for.");
39 14361 : return params;
40 14361 : }
41 :
42 48 : TopResidualDebugOutput::TopResidualDebugOutput(const InputParameters & parameters)
43 : : PetscOutput(parameters),
44 48 : _num_residuals(getParam<unsigned int>("num_residuals")),
45 48 : _nl(_problem_ptr->getNonlinearSystemBase(
46 48 : _problem_ptr->nlSysNum(getParam<NonlinearSystemName>("nl_sys")))),
47 96 : _sys(_nl.system())
48 : {
49 48 : }
50 :
51 : void
52 103 : TopResidualDebugOutput::output()
53 : {
54 : // Display the top residuals
55 103 : if (_num_residuals > 0)
56 103 : printTopResiduals(_nl.RHS(), _num_residuals);
57 103 : }
58 :
59 : void
60 103 : TopResidualDebugOutput::printTopResiduals(const NumericVector<Number> & residual, unsigned int n)
61 : {
62 103 : MooseMesh & mesh = _problem_ptr->mesh();
63 :
64 103 : std::vector<TopResidualDebugOutputTopResidualData> vec;
65 103 : vec.resize(residual.local_size());
66 :
67 103 : unsigned int j = 0;
68 :
69 : // Loop over all nodal variables
70 12717 : for (const auto & node : as_range(mesh.localNodesBegin(), mesh.localNodesEnd()))
71 : {
72 6307 : dof_id_type nd = node->id();
73 :
74 12866 : for (unsigned int var = 0; var < node->n_vars(_sys.number()); ++var)
75 : // check that variable exists on node
76 6559 : if (node->n_dofs(_sys.number(), var) > 0)
77 : {
78 4613 : const auto & subdomain_ids = mesh.getNodeBlockIds(*node);
79 4613 : dof_id_type dof_idx = node->dof_number(_sys.number(), var, 0);
80 9226 : vec[j] = TopResidualDebugOutputTopResidualData(
81 9226 : var, subdomain_ids, nd, *node, residual(dof_idx), false, true);
82 4613 : j++;
83 : }
84 103 : }
85 :
86 : // Loop over all elemental variables
87 10239 : for (const auto & elem : as_range(mesh.activeLocalElementsBegin(), mesh.activeLocalElementsEnd()))
88 : {
89 5068 : dof_id_type elem_id = elem->id();
90 5068 : const SubdomainID subdomain_id = elem->subdomain_id();
91 :
92 10248 : for (unsigned int var = 0; var < elem->n_vars(_sys.number()); ++var)
93 : // check that variable exists on element
94 5180 : if (elem->n_dofs(_sys.number(), var) > 0)
95 : {
96 56 : dof_id_type dof_idx = elem->dof_number(_sys.number(), var, 0);
97 112 : vec[j] = TopResidualDebugOutputTopResidualData(
98 112 : var, {subdomain_id}, elem_id, elem->vertex_average(), residual(dof_idx), false, false);
99 56 : j++;
100 : }
101 103 : }
102 :
103 : // Loop over all scalar variables
104 103 : std::vector<unsigned int> var_nums;
105 103 : _sys.get_all_variable_numbers(var_nums);
106 103 : const DofMap & dof_map = _sys.get_dof_map();
107 234 : for (const auto & var_num : var_nums)
108 131 : if (_sys.variable_type(var_num).family == SCALAR)
109 : {
110 28 : std::vector<dof_id_type> dof_indices;
111 28 : dof_map.SCALAR_dof_indices(dof_indices, var_num);
112 :
113 56 : for (const auto & dof : dof_indices)
114 28 : if (dof >= dof_map.first_dof() && dof < dof_map.end_dof())
115 : {
116 28 : vec[j] =
117 56 : TopResidualDebugOutputTopResidualData(var_num, {}, 0, Point(), residual(dof), true);
118 28 : j++;
119 : }
120 28 : }
121 :
122 : // Sort vec by residuals
123 103 : std::sort(vec.begin(), vec.end(), sortTopResidualData);
124 :
125 : // Display the residuals
126 103 : Moose::err << "[DBG][" << processor_id() << "] Max " << n << " residuals";
127 103 : if (j < n)
128 : {
129 12 : n = j;
130 12 : Moose::err << " (Only " << n << " available)";
131 : }
132 103 : Moose::err << std::endl;
133 :
134 468 : for (unsigned int i = 0; i < n; ++i)
135 : {
136 365 : Moose::err << "[DBG][" << processor_id() << "] " << std::setprecision(15) << vec[i]._residual
137 365 : << " '" << _sys.variable_name(vec[i]._var).c_str() << "' ";
138 365 : if (vec[i]._is_scalar)
139 21 : Moose::err << "(SCALAR)\n";
140 : else
141 : {
142 : // Create subdomain list string for node
143 344 : const unsigned int n_subdomains = vec[i]._subdomain_ids.size();
144 344 : std::vector<SubdomainName> subdomain_names(n_subdomains);
145 344 : unsigned int i_block = 0;
146 688 : for (const auto & subdomain_id : vec[i]._subdomain_ids)
147 : {
148 344 : subdomain_names[i_block] = mesh.getSubdomainName(subdomain_id);
149 344 : i_block++;
150 : }
151 344 : const std::string subdomains_string = Moose::stringify(subdomain_names, ", ", "'", true);
152 :
153 344 : const std::string elem_or_node_string = vec[i]._is_nodal ? "node" : "element";
154 :
155 344 : Moose::err << "in subdomain(s) " << subdomains_string << " at " << elem_or_node_string << " "
156 344 : << vec[i]._id << ": " << vec[i]._point << '\n';
157 344 : }
158 : }
159 :
160 103 : Moose::err << std::flush;
161 103 : }
|