diff_system.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 #include "libmesh/diff_solver.h"
20 #include "libmesh/diff_system.h"
21 #include "libmesh/time_solver.h"
24 #include "libmesh/dof_map.h"
25 #include "libmesh/zero_function.h"
26 
27 #include <utility> // std::swap
28 
29 namespace libMesh
30 {
31 
32 
33 
35  const std::string & name_in,
36  const unsigned int number_in) :
37  Parent (es, name_in, number_in),
38  time_solver (),
39  deltat(1.),
40  print_solution_norms(false),
41  print_solutions(false),
42  print_residual_norms(false),
43  print_residuals(false),
44  print_jacobian_norms(false),
45  print_jacobians(false),
46  print_element_solutions(false),
47  print_element_residuals(false),
48  print_element_jacobians(false),
49  _diff_physics(this),
50  diff_qoi(this)
51 {
52 }
53 
54 
55 
57 {
58  // If we had an attached Physics object, delete it.
59  if (this->_diff_physics != this)
60  delete this->_diff_physics;
61 
62  // If we had an attached QoI object, delete it.
63  if (this->diff_qoi != this)
64  delete this->diff_qoi;
65 }
66 
67 
68 
70 {
71  // If we had an attached Physics object, delete it.
72  if (this->_diff_physics != this)
73  {
74  delete this->_diff_physics;
75  this->_diff_physics = this;
76  }
77  // If we had no attached Physics object, clear our own Physics data
78  else
79  this->clear_physics();
80 
81  // If we had an attached QoI object, delete it.
82  if (this->diff_qoi != this)
83  {
84  delete this->diff_qoi;
85  this->diff_qoi = this;
86  }
87  // If we had no attached QoI object, clear our own QoI data
88  else
89  this->clear_qoi();
90 
91  use_fixed_solution = false;
92 }
93 
94 
95 
97 {
99 
100  libmesh_assert(time_solver.get());
101  libmesh_assert_equal_to (&(time_solver->system()), this);
102 
103  time_solver->reinit();
104 }
105 
106 
107 
109 {
110  // If it isn't a separate initialized-upon-attachment object, do any
111  // initialization our physics needs.
112  if (this->_diff_physics == this)
113  this->init_physics(*this);
114 
115  // Do any initialization our solvers need
116  libmesh_assert(time_solver.get());
117  libmesh_assert_equal_to (&(time_solver->system()), this);
118 
119  // Now check for second order variables and add their velocities to the System.
120  if (!time_solver->is_steady())
121  {
122  const UnsteadySolver & unsteady_solver =
123  cast_ref<const UnsteadySolver &>(*(time_solver.get()));
124 
125  if (unsteady_solver.time_order() == 1)
127  }
128 
129  time_solver->init();
130 
131  // Next initialize ImplicitSystem data
133 
134  time_solver->init_data();
135 }
136 
137 std::unique_ptr<DiffContext> DifferentiableSystem::build_context ()
138 {
139  DiffContext * context = new DiffContext(*this);
140  context->set_deltat_pointer( &this->deltat );
141  return std::unique_ptr<DiffContext>(context);
142 }
143 
144 
146 {
147  this->assembly(true, true);
148 }
149 
150 
151 
153 {
154  // Get the time solver object associated with the system, and tell it that
155  // we are not solving the adjoint problem
156  this->get_time_solver().set_is_adjoint(false);
157 
158  libmesh_assert_equal_to (&(time_solver->system()), this);
159  time_solver->solve();
160 }
161 
162 
163 
164 std::pair<unsigned int, Real> DifferentiableSystem::adjoint_solve (const QoISet & qoi_indices)
165 {
166  // Get the time solver object associated with the system, and tell it that
167  // we are solving the adjoint problem
168  this->get_time_solver().set_is_adjoint(true);
169 
170  return this->ImplicitSystem::adjoint_solve(qoi_indices);
171 }
172 
173 
174 
176 {
177  libmesh_assert(time_solver.get());
178  libmesh_assert_equal_to (&(time_solver->system()), this);
179  return this->time_solver->linear_solver().get();
180 }
181 
182 
183 
184 std::pair<unsigned int, Real> DifferentiableSystem::get_linear_solve_parameters() const
185 {
186  libmesh_assert(time_solver.get());
187  libmesh_assert_equal_to (&(time_solver->system()), this);
188  return std::make_pair(this->time_solver->diff_solver()->max_linear_iterations,
189  this->time_solver->diff_solver()->relative_residual_tolerance);
190 }
191 
192 
193 
195 {
196 }
197 
199 {
200  const std::set<unsigned int> & second_order_vars = this->get_second_order_vars();
201  if (!second_order_vars.empty())
202  {
203  for (const auto & var_id : second_order_vars)
204  {
205  const Variable & var = this->variable(var_id);
206  std::string new_var_name = std::string("dot_")+var.name();
207 
208  unsigned int v_var_idx;
209 
210  if (var.active_subdomains().empty())
211  v_var_idx = this->add_variable( new_var_name, var.type() );
212  else
213  v_var_idx = this->add_variable( new_var_name, var.type(), &var.active_subdomains() );
214 
215  _second_order_dot_vars.insert(std::pair<unsigned int, unsigned int>(var_id, v_var_idx));
216 
217  // The new velocities are time evolving variables of first order
218  this->time_evolving( v_var_idx, 1 );
219 
220  // And if there are any boundary conditions set on the second order
221  // variable, we also need to set it on its velocity variable.
222  this->add_dot_var_dirichlet_bcs(var_id, v_var_idx);
223  }
224  }
225 }
226 
228  unsigned int dot_var_idx )
229 {
230  // We're assuming that there could be a lot more variables than
231  // boundary conditions, so we search each of the boundary conditions
232  // for this variable rather than looping over boundary conditions
233  // in a separate loop and searching through all the variables.
234  const DirichletBoundaries * all_dbcs =
236 
237  if (all_dbcs)
238  {
239  // We need to cache the DBCs to be added so that we add them
240  // after looping over the existing DBCs. Otherwise, we're polluting
241  // the thing we're looping over.
242  std::vector<DirichletBoundary *> new_dbcs;
243 
244  for (const auto & dbc : *all_dbcs)
245  {
246  libmesh_assert(dbc);
247 
248  // Look for second order variable in the current
249  // DirichletBoundary object
250  std::vector<unsigned int>::const_iterator dbc_var_it =
251  std::find( dbc->variables.begin(), dbc->variables.end(), var_idx );
252 
253  // If we found it, then we also need to add it's corresponding
254  // "dot" variable to a DirichletBoundary
255  std::vector<unsigned int> vars_to_add;
256  if (dbc_var_it != dbc->variables.end())
257  vars_to_add.push_back(dot_var_idx);
258 
259  if (!vars_to_add.empty())
260  {
261  // We need to check if the boundary condition is time-dependent.
262  // Currently, we cannot automatically differentiate w.r.t. time
263  // so if the user supplies a time-dependent Dirichlet BC, then
264  // we can't automatically support the Dirichlet BC for the
265  // "velocity" boundary condition, so we error. Otherwise,
266  // the "velocity boundary condition will just be zero.
267  bool is_time_evolving_bc = false;
268  if (dbc->f)
269  is_time_evolving_bc = dbc->f->is_time_dependent();
270  else if (dbc->f_fem)
271  // We it's a FEMFunctionBase object, it will be implicitly
272  // time-dependent since it is assumed to depend on the solution.
273  is_time_evolving_bc = true;
274  else
275  libmesh_error_msg("Could not find valid boundary function!");
276 
277  if (is_time_evolving_bc)
278  libmesh_error_msg("Cannot currently support time-dependent Dirichlet BC for dot variables!");
279 
280 
281  DirichletBoundary * new_dbc;
282 
283  if (dbc->f)
284  {
286 
287  new_dbc = new DirichletBoundary(dbc->b, vars_to_add, zf);
288  }
289  else
290  libmesh_error();
291 
292  new_dbcs.push_back(new_dbc);
293  }
294  }
295 
296  // Let the DofMap make its own deep copy of the DirichletBC objects and delete our copy.
297  for (const auto & dbc : new_dbcs)
298  {
299  this->get_dof_map().add_dirichlet_boundary(*dbc);
300  delete dbc;
301  }
302 
303  } // if (all_dbcs)
304 }
305 
306 unsigned int DifferentiableSystem::get_second_order_dot_var( unsigned int var ) const
307 {
308  // For SteadySolver or SecondOrderUnsteadySolvers, we just give back var
309  unsigned int dot_var = var;
310 
311  if (!time_solver->is_steady())
312  {
313  const UnsteadySolver & unsteady_solver =
314  cast_ref<const UnsteadySolver &>(*(time_solver.get()));
315 
316  if (unsteady_solver.time_order() == 1)
317  dot_var = this->_second_order_dot_vars.find(var)->second;
318  }
319 
320  return dot_var;
321 }
322 
324 {
325  bool have_first_order_scalar_vars = false;
326 
327  if (this->have_first_order_vars())
328  for (const auto & var : this->get_first_order_vars())
329  if (this->variable(var).type().family == SCALAR)
331 
333 }
334 
336 {
337  bool have_second_order_scalar_vars = false;
338 
339  if (this->have_second_order_vars())
340  for (const auto & var : this->get_second_order_vars())
341  if (this->variable(var).type().family == SCALAR)
343 
345 }
346 
347 
348 
350 {
351  std::swap(this->_diff_physics, swap_physics);
352 }
353 
354 
355 } // namespace libMesh
virtual void init_data() override
Manages multiples systems of equations.
virtual void assemble() override
Definition: diff_system.C:145
const Variable & variable(unsigned int var) const
Definition: system.h:2133
ConstFunction that simply returns 0.
Definition: zero_function.h:36
virtual void assembly(bool get_residual, bool get_jacobian, bool apply_heterogeneous_constraints=false, bool apply_no_constraints=false) override=0
Used to specify quantities of interest in a simulation.
Definition: qoi_set.h:45
virtual void reinit() override
std::unique_ptr< TimeSolver > time_solver
Definition: diff_system.h:234
Class for specifying Dirichlet boundary conditions as constraints.
void add_dot_var_dirichlet_bcs(unsigned int var_idx, unsigned int dot_var_idx)
Definition: diff_system.C:227
virtual std::pair< unsigned int, Real > adjoint_solve(const QoISet &qoi_indices=QoISet()) override
virtual std::unique_ptr< DiffContext > build_context()
Definition: diff_system.C:137
std::map< unsigned int, unsigned int > _second_order_dot_vars
Definition: diff_physics.h:571
DifferentiableQoI * diff_qoi
Definition: diff_system.h:378
virtual void reinit() override
Definition: diff_system.C:96
void swap_physics(DifferentiablePhysics *&swap_physics)
Definition: diff_system.C:349
DifferentiablePhysics * _diff_physics
Definition: diff_system.h:371
void set_is_adjoint(bool _is_adjoint_value)
Definition: time_solver.h:240
virtual unsigned int time_order() const =0
const std::set< unsigned int > & get_second_order_vars() const
Definition: diff_physics.h:530
A variable which is solved for in a System of equations.
Definition: variable.h:49
const std::set< subdomain_id_type > & active_subdomains() const
Definition: variable.h:150
unsigned int get_second_order_dot_var(unsigned int var) const
Definition: diff_system.C:306
const std::set< unsigned int > & get_first_order_vars() const
Definition: diff_physics.h:517
bool use_fixed_solution
Definition: system.h:1493
virtual void clear_qoi()
Definition: diff_qoi.h:75
virtual void time_evolving(unsigned int var)
Definition: diff_physics.h:249
const DirichletBoundaries * get_dirichlet_boundaries() const
Definition: dof_map.h:1223
bool have_second_order_scalar_vars() const
Definition: diff_system.C:335
DifferentiableSystem(EquationSystems &es, const std::string &name, const unsigned int number)
Definition: diff_system.C:34
virtual void init_data() override
Definition: diff_system.C:108
virtual LinearSolver< Number > * get_linear_solver() const override
Definition: diff_system.C:175
virtual std::pair< unsigned int, Real > get_linear_solve_parameters() const override
Definition: diff_system.C:184
void swap(Iterator &lhs, Iterator &rhs)
void add_dirichlet_boundary(const DirichletBoundary &dirichlet_boundary)
void set_deltat_pointer(Real *dt)
Definition: diff_context.C:103
virtual void init_physics(const System &sys)
virtual void solve() override
Definition: diff_system.C:152
virtual void clear() override
Definition: diff_system.C:69
const std::string & name() const
Definition: variable.h:100
virtual void release_linear_solver(LinearSolver< Number > *) const override
Definition: diff_system.C:194
bool have_first_order_scalar_vars() const
Definition: diff_system.C:323
unsigned int add_variable(const std::string &var, const FEType &type, const std::set< subdomain_id_type > *const active_subdomains=nullptr)
Definition: system.C:1081
const DofMap & get_dof_map() const
Definition: system.h:2049
virtual std::pair< unsigned int, Real > adjoint_solve(const QoISet &qoi_indices=QoISet()) override
Definition: diff_system.C:164
TimeSolver & get_time_solver()
Definition: diff_system.h:415
const FEType & type() const
Definition: variable.h:119
Manages consistently variables, degrees of freedom, coefficient vectors, and matrices for implicit sy...