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 "PetscOutput.h" 12 : #include "FEProblem.h" 13 : #include "NonlinearSystem.h" 14 : #include "CommonOutputAction.h" 15 : 16 : #include "libmesh/libmesh_common.h" 17 : #include "libmesh/petsc_nonlinear_solver.h" 18 : 19 155247 : PetscOutputInterface::PetscOutputInterface(PetscOutput * obj) : _petsc_output(obj) 20 : { 21 : // register petsc output interface 22 155247 : obj->getMooseApp().registerInterfaceObject(*this); 23 155247 : } 24 : 25 : PetscErrorCode 26 747884 : PetscOutputInterface::petscNonlinearOutput(SNES, PetscInt its, PetscReal norm, void * void_ptr) 27 : { 28 : // Get the primary outputter object 29 747884 : PetscOutput * primary_ptr = static_cast<PetscOutput *>(void_ptr); 30 : 31 : // loop over all interface objects 32 2808357 : for (const auto poi_ptr : primary_ptr->getMooseApp().getInterfaceObjects<PetscOutputInterface>()) 33 : { 34 2060473 : auto ptr = poi_ptr->_petsc_output; 35 : 36 : // check time 37 2060473 : if (!ptr->inNonlinearTimeWindow()) 38 864 : continue; 39 : 40 : // Update the pseudo times 41 2059609 : ptr->_nonlinear_time += ptr->_nonlinear_dt; 42 2059609 : ptr->_linear_time = ptr->_nonlinear_time; 43 : 44 : // Set the current norm and iteration number 45 2059609 : ptr->_norm = norm; 46 2059609 : ptr->_nonlinear_iter = its; 47 : 48 : // Set the flag indicating that output is occurring on the non-linear residual 49 2059609 : ptr->_on_nonlinear_residual = true; 50 : 51 : // Perform the output 52 2059609 : ptr->outputStep(EXEC_NONLINEAR); 53 : 54 : /** 55 : * This is one of three locations where we explicitly flush the output buffers during a 56 : * simulation: 57 : * PetscOutput::petscNonlinearOutput() 58 : * PetscOutput::petscLinearOutput() 59 : * OutputWarehouse::outputStep() 60 : * 61 : * All other Console output _should_ be using newlines to avoid covering buffer errors 62 : * and to avoid excessive I/O. This call is necessary. In the PETSc callback the 63 : * context bypasses the OutputWarehouse. 64 : */ 65 2059609 : ptr->_app.getOutputWarehouse().flushConsoleBuffer(); 66 : 67 : // Reset the non-linear output flag and the simulation time 68 2059609 : ptr->_on_nonlinear_residual = false; 69 : } 70 : 71 : // Done 72 747884 : return (PetscErrorCode)0; 73 : } 74 : 75 : PetscErrorCode 76 2409182 : PetscOutputInterface::petscLinearOutput(KSP, PetscInt its, PetscReal norm, void * void_ptr) 77 : { 78 : // Get the primary outputter object 79 2409182 : PetscOutput * primary_ptr = static_cast<PetscOutput *>(void_ptr); 80 : 81 : // loop over all interface objects 82 9051098 : for (const auto poi_ptr : primary_ptr->getMooseApp().getInterfaceObjects<PetscOutputInterface>()) 83 : { 84 6641916 : auto ptr = poi_ptr->_petsc_output; 85 : 86 : // check time 87 6641916 : if (!ptr->inLinearTimeWindow()) 88 2304 : continue; 89 : 90 : // Update the pseudo time 91 6639612 : ptr->_linear_time += ptr->_linear_dt; 92 : 93 : // Set the current norm and iteration number 94 6639612 : ptr->_norm = norm; 95 6639612 : ptr->_linear_iter = its; 96 : 97 : // Set the flag indicating that output is occurring on the non-linear residual 98 6639612 : ptr->_on_linear_residual = true; 99 : 100 : // Perform the output 101 6639612 : ptr->outputStep(EXEC_LINEAR); 102 : 103 : /** 104 : * This is one of three locations where we explicitly flush the output buffers during a 105 : * simulation: 106 : * PetscOutput::petscNonlinearOutput() 107 : * PetscOutput::petscLinearOutput() 108 : * OutputWarehouse::outputStep() 109 : * 110 : * All other Console output _should_ be using newlines to avoid covering buffer errors 111 : * and to avoid excessive I/O. This call is necessary. In the PETSc callback the 112 : * context bypasses the OutputWarehouse. 113 : */ 114 6639612 : ptr->_app.getOutputWarehouse().flushConsoleBuffer(); 115 : 116 : // Reset the linear output flag and the simulation time 117 6639612 : ptr->_on_linear_residual = false; 118 : } 119 : 120 : // Done 121 2409182 : return (PetscErrorCode)0; 122 : } 123 : 124 : InputParameters 125 626501 : PetscOutput::validParams() 126 : { 127 626501 : InputParameters params = Output::validParams(); 128 : 129 : // Toggled for outputting nonlinear and linear residuals, only if we have PETSc 130 1879503 : params.addParam<bool>("output_linear", 131 1253002 : false, 132 : "Specifies whether output occurs on each PETSc linear residual evaluation"); 133 1879503 : params.addParam<bool>( 134 : "output_nonlinear", 135 1253002 : false, 136 : "Specifies whether output occurs on each PETSc nonlinear residual evaluation"); 137 626501 : params.addParamNamesToGroup("output_linear output_nonlinear", "Execution scheduling"); 138 : 139 : // Pseudo time step divisors 140 1879503 : params.addParam<Real>( 141 : "nonlinear_residual_dt_divisor", 142 1253002 : 1000, 143 : "Number of divisions applied to time step when outputting non-linear residuals"); 144 1879503 : params.addParam<Real>( 145 : "linear_residual_dt_divisor", 146 1253002 : 1000, 147 : "Number of divisions applied to time step when outputting linear residuals"); 148 : 149 : // Start times for residual output 150 626501 : params.addParam<Real>( 151 : "linear_residual_start_time", 152 : "Specifies a start time to begin output on each linear residual evaluation"); 153 626501 : params.addParam<Real>( 154 : "nonlinear_residual_start_time", 155 : "Specifies a start time to begin output on each nonlinear residual evaluation"); 156 : 157 : // End time for residual output 158 : /* Note, No default is given here so that in Peacock giant numbers do not show up by default, the 159 : * defaults are set in the initialization list */ 160 626501 : params.addParam<Real>("linear_residual_end_time", 161 : "Specifies an end time to begin output on each linear residual evaluation"); 162 626501 : params.addParam<Real>( 163 : "nonlinear_residual_end_time", 164 : "Specifies an end time to begin output on each nonlinear residual evaluation"); 165 : 166 626501 : params.addParamNamesToGroup("linear_residual_start_time " 167 : "nonlinear_residual_start_time linear_residual_end_time " 168 : "nonlinear_residual_end_time nonlinear_residual_dt_divisor " 169 : "linear_residual_dt_divisor", 170 : "PETSc linear/nonlinear output"); 171 626501 : return params; 172 0 : } 173 : 174 155255 : PetscOutput::PetscOutput(const InputParameters & parameters) 175 : : Output(parameters), 176 : PetscOutputInterface(this), 177 155247 : _nonlinear_iter(0), 178 155247 : _linear_iter(0), 179 155247 : _on_linear_residual(false), 180 155247 : _on_nonlinear_residual(false), 181 155247 : _nonlinear_dt_divisor(getParam<Real>("nonlinear_residual_dt_divisor")), 182 155247 : _linear_dt_divisor(getParam<Real>("linear_residual_dt_divisor")), 183 155247 : _nonlinear_start_time(-std::numeric_limits<Real>::max()), 184 155247 : _linear_start_time(-std::numeric_limits<Real>::max()), 185 155247 : _nonlinear_end_time(std::numeric_limits<Real>::max()), 186 310502 : _linear_end_time(std::numeric_limits<Real>::max()) 187 : { 188 : // Output toggle support 189 155247 : if (getParam<bool>("output_linear")) 190 12 : _execute_on.setAdditionalValue("linear"); 191 155247 : if (getParam<bool>("output_nonlinear")) 192 0 : _execute_on.setAdditionalValue("nonlinear"); 193 : 194 : // Nonlinear residual start-time supplied by user 195 155247 : if (isParamValid("nonlinear_residual_start_time")) 196 : { 197 18 : _nonlinear_start_time = getParam<Real>("nonlinear_residual_start_time"); 198 18 : _execute_on.setAdditionalValue("nonlinear"); 199 : } 200 : 201 : // Nonlinear residual end-time supplied by user 202 155247 : if (isParamValid("nonlinear_residual_end_time")) 203 9 : _nonlinear_end_time = getParam<Real>("nonlinear_residual_end_time"); 204 : 205 : // Linear residual start-time supplied by user 206 155247 : if (isParamValid("linear_residual_start_time")) 207 : { 208 18 : _linear_start_time = getParam<Real>("linear_residual_start_time"); 209 18 : _execute_on.setAdditionalValue("linear"); 210 : } 211 : 212 : // Linear residual end-time supplied by user 213 155247 : if (isParamValid("linear_residual_end_time")) 214 9 : _linear_end_time = getParam<Real>("linear_residual_end_time"); 215 155247 : } 216 : 217 : void 218 911670 : PetscOutput::solveSetup() 219 : { 220 : // Update the pseudo times 221 911670 : _nonlinear_time = _time_old; // non-linear time starts with the previous time step 222 911670 : if (_dt != 0) 223 : // set the pseudo non-linear timestep as fraction 224 : // of real timestep for transient executioners 225 814007 : _nonlinear_dt = _dt / _nonlinear_dt_divisor; 226 : else 227 : // set the pseudo non-linear timestep for steady 228 : // executioners (here _dt==0) 229 97663 : _nonlinear_dt = 1. / _nonlinear_dt_divisor; 230 : 231 911670 : _linear_dt = _nonlinear_dt / _linear_dt_divisor; // set the pseudo linear timestep 232 : 233 : // only the first PetscOutput object registers a DM monitor for linear and nonlinear 234 : // all other PetscOutput objects are dispatched from that one monitor (per app). 235 911670 : if (_app.getInterfaceObjects<PetscOutputInterface>()[0] != this) 236 577444 : return; 237 : 238 334226 : ActionWarehouse & awh = _app.actionWarehouse(); 239 334226 : const auto actions = awh.getActions<CommonOutputAction>(); 240 : mooseAssert(actions.size() <= 1, "Should not be more than one CommonOutputAction"); 241 334226 : const Action * common = actions.empty() ? nullptr : *actions.begin(); 242 : 243 : // Extract the non-linear and linear solvers from PETSc 244 334226 : NonlinearSystemBase & nl = _problem_ptr->currentNonlinearSystem(); 245 334226 : SNES snes = nl.getSNES(); 246 : KSP ksp; 247 334226 : LibmeshPetscCallA(_communicator.get(), SNESGetKSP(snes, &ksp)); 248 : 249 : // Set the PETSc monitor functions (register the nonlinear callback so that linear outputs 250 : // get an updated nonlinear iteration number) 251 : // Not every Output should register its own DM monitor! Just register one each of nonlinear 252 : // and linear and dispatch all Outputs from there! 253 334226 : if (common && common->getParam<bool>("print_nonlinear_residuals")) 254 329646 : LibmeshPetscCallA(_communicator.get(), 255 : SNESMonitorSet(snes, petscNonlinearOutput, this, LIBMESH_PETSC_NULLPTR)); 256 334226 : if (common && common->getParam<bool>("print_linear_residuals")) 257 328261 : LibmeshPetscCallA(_communicator.get(), 258 : KSPMonitorSet(ksp, petscLinearOutput, this, LIBMESH_PETSC_NULLPTR)); 259 334226 : } 260 : 261 : Real 262 1123717 : PetscOutput::time() 263 : { 264 1123717 : if (_on_nonlinear_residual) 265 21028 : return _nonlinear_time; 266 1102689 : else if (_on_linear_residual) 267 520 : return _linear_time; 268 : else 269 1102169 : return Output::time(); 270 : } 271 : 272 : Real 273 1123393 : PetscOutput::getOutputTime() 274 : { 275 1123393 : return time(); 276 : }