PISM, A Parallel Ice Sheet Model  stable v2.1.1 committed by Constantine Khrulev on 2024-12-04 13:36:58 -0900
IP_SSAHardavForwardProblem.cc
Go to the documentation of this file.
1 // Copyright (C) 2013, 2014, 2015, 2016, 2017, 2018, 2020, 2021, 2022, 2023 David Maxwell and Constantine Khroulev
2 //
3 // This file is part of PISM.
4 //
5 // PISM is free software; you can redistribute it and/or modify it under the
6 // terms of the GNU General Public License as published by the Free Software
7 // Foundation; either version 3 of the License, or (at your option) any later
8 // version.
9 //
10 // PISM is distributed in the hope that it will be useful, but WITHOUT ANY
11 // WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 // FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
13 // details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with PISM; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 
19 #include "pism/inverse/IP_SSAHardavForwardProblem.hh"
20 #include "pism/basalstrength/basal_resistance.hh"
21 #include "pism/util/Grid.hh"
22 #include "pism/util/Mask.hh"
23 #include "pism/util/ConfigInterface.hh"
24 #include "pism/util/Vars.hh"
25 #include "pism/util/error_handling.hh"
26 #include "pism/util/pism_utilities.hh"
27 #include "pism/rheology/FlowLaw.hh"
28 #include "pism/geometry/Geometry.hh"
29 #include "pism/stressbalance/StressBalance.hh"
30 #include "pism/util/petscwrappers/DM.hh"
31 #include "pism/util/petscwrappers/Vec.hh"
32 
33 namespace pism {
34 namespace inverse {
35 
38  : SSAFEM(g),
39  m_stencil_width(1),
40  m_zeta(NULL),
41  m_dzeta_local(m_grid, "d_zeta_local"),
42  m_fixed_design_locations(NULL),
43  m_design_param(tp),
44  m_du_global(m_grid, "linearization work vector (sans ghosts)"),
45  m_du_local(m_grid, "linearization work vector (with ghosts)"),
46  m_hardav(m_grid, "hardav"),
47  m_element_index(*m_grid),
48  m_element(*m_grid, fem::Q1Quadrature4()),
49  m_rebuild_J_state(true)
50 {
51 
52  PetscErrorCode ierr;
53 
54  m_velocity_shared.reset(new array::Vector(m_grid, "dummy"));
55  m_velocity_shared->metadata(0) = m_velocity.metadata(0);
56  m_velocity_shared->metadata(1) = m_velocity.metadata(1);
57 
58  ierr = DMSetMatType(*m_da, MATBAIJ);
59  PISM_CHK(ierr, "DMSetMatType");
60 
61  ierr = DMCreateMatrix(*m_da, m_J_state.rawptr());
62  PISM_CHK(ierr, "DMCreateMatrix");
63 
64  ierr = KSPCreate(m_grid->com, m_ksp.rawptr());
65  PISM_CHK(ierr, "KSPCreate");
66 
67  double ksp_rtol = 1e-12;
68  ierr = KSPSetTolerances(m_ksp, ksp_rtol, PETSC_DEFAULT, PETSC_DEFAULT, PETSC_DEFAULT);
69  PISM_CHK(ierr, "KSPSetTolerances");
70 
71  PC pc;
72  ierr = KSPGetPC(m_ksp, &pc);
73  PISM_CHK(ierr, "KSPGetPC");
74 
75  ierr = PCSetType(pc, PCBJACOBI);
76  PISM_CHK(ierr, "PCSetType");
77 
78  ierr = KSPSetFromOptions(m_ksp);
79  PISM_CHK(ierr, "KSPSetFromOptions");
80 }
81 
83 
84  SSAFEM::init();
85 
86  // Get most of the inputs from Grid::variables() and fake the rest.
87  //
88  // I will need to fix this at some point.
89  {
90  Geometry geometry(m_grid);
91  geometry.ice_thickness.copy_from(*m_grid->variables().get_2d_scalar("land_ice_thickness"));
92  geometry.bed_elevation.copy_from(*m_grid->variables().get_2d_scalar("bedrock_altitude"));
93  geometry.sea_level_elevation.set(0.0); // FIXME: this should be an input
94  geometry.ice_area_specific_volume.set(0.0);
95 
96  geometry.ensure_consistency(m_config->get_number("stress_balance.ice_free_thickness_standard"));
97 
98  stressbalance::Inputs inputs;
99 
100  inputs.geometry = &geometry;
101  inputs.basal_melt_rate = NULL;
102  inputs.basal_yield_stress = m_grid->variables().get_2d_scalar("tauc");
103  inputs.enthalpy = m_grid->variables().get_3d_scalar("enthalpy");
104  inputs.age = NULL;
105  inputs.bc_mask = m_grid->variables().get_2d_mask("vel_bc_mask");
106  inputs.bc_values = m_grid->variables().get_2d_vector("vel_bc");
107 
108  inputs.water_column_pressure = NULL;
109 
110  cache_inputs(inputs);
111  }
112 }
113 
114 //! Sets the current value of of the design paramter \f$\zeta\f$.
115 /*! This method sets \f$\zeta\f$ but does not solve the %SSA.
116 It it intended for inverse methods that simultaneously compute
117 the pair \f$u\f$ and \f$\zeta\f$ without ever solving the %SSA
118 directly. Use this method in conjuction with
119 \ref assemble_jacobian_state and \ref apply_jacobian_design and their friends.
120 The vector \f$\zeta\f$ is not copied; a reference to the array::Array is
121 kept.
122 */
124 
125  m_zeta = &new_zeta;
126 
127  // Convert zeta to hardav.
129 
130  // Cache hardav at the quadrature points.
132 
133  for (auto p = m_grid->points(1); p; p.next()) {
134  const int i = p.i(), j = p.j();
135  m_coefficients(i, j).hardness = m_hardav(i, j);
136  }
137 
138  // Flag the state jacobian as needing rebuilding.
139  m_rebuild_J_state = true;
140 }
141 
142 //! Sets the current value of the design variable \f$\zeta\f$ and solves the %SSA to find the associated \f$u_{\rm SSA}\f$.
143 /* Use this method for inverse methods employing the reduced gradient. Use this method
144 in conjuction with apply_linearization and apply_linearization_transpose.*/
145 std::shared_ptr<TerminationReason> IP_SSAHardavForwardProblem::linearize_at(array::Scalar &zeta) {
146  this->set_design(zeta);
147  return this->solve_nocache();
148 }
149 
150 //! Computes the residual function \f$\mathcal{R}(u, \zeta)\f$ as defined in the class-level documentation.
151 /* The value of \f$\zeta\f$ is set prior to this call via set_design or linearize_at. The value
152 of the residual is returned in \a RHS.*/
154 
155  array::AccessScope l{&u, &RHS};
156 
157  this->compute_local_function(u.array(), RHS.array());
158 }
159 
160 //! Computes the residual function \f$\mathcal{R}(u, \zeta)\f$ defined in the class-level documentation.
161 /* The return value is specified via a Vec for the benefit of certain TAO routines. Otherwise,
162 the method is identical to the assemble_residual returning values as a StateVec (an array::Vector).*/
164 
165  array::AccessScope l{&u};
166 
167  petsc::DMDAVecArray rhs_a(m_da, RHS);
168 
169  this->compute_local_function(u.array(), (Vector2d**)rhs_a.get());
170 }
171 
172 //! Assembles the state Jacobian matrix.
173 /* The matrix depends on the current value of the design variable \f$\zeta\f$ and the current
174 value of the state variable \f$u\f$. The specification of \f$\zeta\f$ is done earlier
175 with set_design or linearize_at. The value of \f$u\f$ is specified explicitly as an argument
176 to this method.
177  @param[in] u Current state variable value.
178  @param[out] J computed state Jacobian.
179 */
181  array::AccessScope l{&u};
182 
183  this->compute_local_jacobian(u.array(), Jac);
184 }
185 
186 //! Applies the design Jacobian matrix to a perturbation of the design variable.
187 /*! The return value uses a DesignVector (array::Vector), which can be ghostless. Ghosts (if present) are updated.
188 \overload
189 */
191  array::Scalar &dzeta,
192  array::Vector &du) {
193  array::AccessScope l{&du};
194 
195  this->apply_jacobian_design(u, dzeta, du.array());
196 }
197 
198 //! Applies the design Jacobian matrix to a perturbation of the design variable.
199 /*! The return value is a Vec for the benefit of TAO. It is assumed to be ghostless; no communication is done.
200 \overload
201 */
203  array::Scalar &dzeta,
204  Vec du) {
205  petsc::DMDAVecArray du_a(m_da, du);
206  this->apply_jacobian_design(u, dzeta, (Vector2d**)du_a.get());
207 }
208 
209 //! @brief Applies the design Jacobian matrix to a perturbation of the
210 //! design variable.
211 
212 /*! The matrix depends on the current value of the design variable
213  \f$\zeta\f$ and the current value of the state variable \f$u\f$.
214  The specification of \f$\zeta\f$ is done earlier with set_design
215  or linearize_at. The value of \f$u\f$ is specified explicitly as
216  an argument to this method.
217 
218  @param[in] u Current state variable value.
219 
220  @param[in] dzeta Perturbation of the design variable. Prefers
221  vectors with ghosts; will copy to a ghosted vector
222  if needed.
223 
224  @param[out] du_a Computed corresponding perturbation of the state
225  variable. The array \a du_a should be extracted
226  first from a Vec or an array::Array.
227 
228  Typically this method is called via one of its overloads.
229 */
231  array::Scalar &dzeta,
232  Vector2d **du_a) {
233 
234  const unsigned int Nk = fem::q1::n_chi;
235  const unsigned int Nq = m_element.n_pts();
236  const unsigned int Nq_max = fem::MAX_QUADRATURE_SIZE;
237 
239 
240  array::Scalar *dzeta_local;
241  if (dzeta.stencil_width() > 0) {
242  dzeta_local = &dzeta;
243  } else {
244  m_dzeta_local.copy_from(dzeta);
245  dzeta_local = &m_dzeta_local;
246  }
247  list.add(*dzeta_local);
248 
249  // Zero out the portion of the function we are responsible for computing.
250  for (auto p = m_grid->points(); p; p.next()) {
251  const int i = p.i(), j = p.j();
252 
253  du_a[j][i].u = 0.0;
254  du_a[j][i].v = 0.0;
255  }
256 
257  // Aliases to help with notation consistency below.
258  const array::Scalar *dirichletLocations = &m_bc_mask;
259  const array::Vector *dirichletValues = &m_bc_values;
260  double dirichletWeight = m_dirichletScale;
261 
262  Vector2d u_e[Nk];
263  Vector2d U[Nq_max], U_x[Nq_max], U_y[Nq_max];
264 
265  Vector2d du_e[Nk];
266 
267  double dzeta_e[Nk];
268 
269  double zeta_e[Nk];
270 
271  double dB_e[Nk];
272  double dB_q[Nq_max];
273 
274  fem::DirichletData_Vector dirichletBC(dirichletLocations, dirichletValues,
275  dirichletWeight);
277 
278  // Loop through all elements.
279  const int
280  xs = m_element_index.xs,
281  xm = m_element_index.xm,
282  ys = m_element_index.ys,
283  ym = m_element_index.ym;
284 
285  ParallelSection loop(m_grid->com);
286  try {
287  for (int j =ys; j<ys+ym; j++) {
288  for (int i =xs; i<xs+xm; i++) {
289 
290  // Zero out the element-local residual in prep for updating it.
291  for (unsigned int k=0; k<Nk; k++) {
292  du_e[k].u = 0;
293  du_e[k].v = 0;
294  }
295 
296  // Initialize the map from global to local degrees of freedom for this element.
297  m_element.reset(i, j);
298 
299  // Obtain the value of the solution at the nodes adjacent to the element,
300  // fix dirichlet values, and compute values at quad pts.
301  m_element.nodal_values(u.array(), u_e);
302  if (dirichletBC) {
303  dirichletBC.constrain(m_element);
304  dirichletBC.enforce(m_element, u_e);
305  }
306  m_element.evaluate(u_e, U, U_x, U_y);
307 
308  // Compute dzeta at the nodes
309  m_element.nodal_values(dzeta_local->array(), dzeta_e);
310  if (fixedZeta) {
311  fixedZeta.enforce_homogeneous(m_element, dzeta_e);
312  }
313 
314  // Compute the change in hardav with respect to zeta at the quad points.
315  m_element.nodal_values(m_zeta->array(), zeta_e);
316  for (unsigned int k=0; k<Nk; k++) {
317  m_design_param.toDesignVariable(zeta_e[k], NULL, dB_e + k);
318  dB_e[k]*=dzeta_e[k];
319  }
320  m_element.evaluate(dB_e, dB_q);
321 
322  double thickness[Nq_max];
323  {
324  Coefficients coeffs[Nk];
325  int mask[Nq_max];
326  double tauc[Nq_max];
327  double hardness[Nq_max];
328 
329  m_element.nodal_values(m_coefficients.array(), coeffs);
330 
332  mask, thickness, tauc, hardness);
333  }
334 
335  for (unsigned int q = 0; q < Nq; q++) {
336  // Symmetric gradient at the quadrature point.
337  double Duqq[3] = {U_x[q].u, U_y[q].v, 0.5 * (U_y[q].u + U_x[q].v)};
338 
339  double d_nuH = 0;
340  if (thickness[q] >= strength_extension->get_min_thickness()) {
341  m_flow_law->effective_viscosity(dB_q[q],
342  secondInvariant_2D(U_x[q], U_y[q]),
343  &d_nuH, NULL);
344  d_nuH *= (2.0 * thickness[q]);
345  }
346 
347  auto W = m_element.weight(q);
348 
349  for (unsigned int k = 0; k < Nk; k++) {
350  const fem::Germ &testqk = m_element.chi(q, k);
351  du_e[k].u += W*d_nuH*(testqk.dx*(2*Duqq[0] + Duqq[1]) + testqk.dy*Duqq[2]);
352  du_e[k].v += W*d_nuH*(testqk.dy*(2*Duqq[1] + Duqq[0]) + testqk.dx*Duqq[2]);
353  }
354  } // q
355  m_element.add_contribution(du_e, du_a);
356  } // j
357  } // i
358  } catch (...) {
359  loop.failed();
360  }
361  loop.check();
362 
363  if (dirichletBC) {
364  dirichletBC.fix_residual_homogeneous(du_a);
365  }
366 }
367 
368 //! Applies the transpose of the design Jacobian matrix to a perturbation of the state variable.
369 /*! The return value uses a StateVector (array::Scalar) which can be ghostless; ghosts (if present) are updated.
370 \overload
371 */
373  array::Vector &du,
374  array::Scalar &dzeta) {
375  array::AccessScope l{&dzeta};
376  this->apply_jacobian_design_transpose(u, du, dzeta.array());
377 }
378 
379 //! Applies the transpose of the design Jacobian matrix to a perturbation of the state variable.
380 /*! The return value uses a Vec for the benefit of TAO. It is assumed to be ghostless; no communication is done.
381 \overload */
383  array::Vector &du,
384  Vec dzeta) {
385 
386  petsc::DM::Ptr da2 = m_grid->get_dm(1, m_config->get_number("grid.max_stencil_width"));
387  petsc::DMDAVecArray dzeta_a(da2, dzeta);
388  this->apply_jacobian_design_transpose(u, du, (double**)dzeta_a.get());
389 }
390 
391 //! @brief Applies the transpose of the design Jacobian matrix to a
392 //! perturbation of the state variable.
393 
394 /*! The matrix depends on the current value of the design variable
395  \f$\zeta\f$ and the current value of the state variable \f$u\f$.
396  The specification of \f$\zeta\f$ is done earlier with set_design
397  or linearize_at. The value of \f$u\f$ is specified explicitly as
398  an argument to this method.
399 
400  @param[in] u Current state variable value.
401 
402  @param[in] du Perturbation of the state variable. Prefers vectors
403  with ghosts; will copy to a ghosted vector if need be.
404 
405  @param[out] dzeta_a Computed corresponding perturbation of the
406  design variable. The array \a dzeta_a should be
407  extracted first from a Vec or an array::Array.
408 
409  Typically this method is called via one of its overloads.
410 */
412  array::Vector &du,
413  double **dzeta_a) {
414 
415  const unsigned int Nk = fem::q1::n_chi;
416  const unsigned int Nq = m_element.n_pts();
417  const unsigned int Nq_max = fem::MAX_QUADRATURE_SIZE;
418 
420 
421  array::Vector *du_local;
422  if (du.stencil_width() > 0) {
423  du_local = &du;
424  } else {
425  m_du_local.copy_from(du);
426  du_local = &m_du_local;
427  }
428  list.add(*du_local);
429 
430  Vector2d u_e[Nk];
431  Vector2d U[Nq_max], U_x[Nq_max], U_y[Nq_max];
432 
433  Vector2d du_e[Nk];
434  Vector2d du_q[Nq_max];
435  Vector2d du_dx_q[Nq_max];
436  Vector2d du_dy_q[Nq_max];
437 
438  double dzeta_e[Nk];
439 
440  // Aliases to help with notation consistency.
441  const array::Scalar *dirichletLocations = &m_bc_mask;
442  const array::Vector *dirichletValues = &m_bc_values;
443  double dirichletWeight = m_dirichletScale;
444 
445  fem::DirichletData_Vector dirichletBC(dirichletLocations, dirichletValues,
446  dirichletWeight);
447 
448  // Zero out the portion of the function we are responsible for computing.
449  for (auto p = m_grid->points(); p; p.next()) {
450  const int i = p.i(), j = p.j();
451 
452  dzeta_a[j][i] = 0;
453  }
454 
455  const int
456  xs = m_element_index.xs,
457  xm = m_element_index.xm,
458  ys = m_element_index.ys,
459  ym = m_element_index.ym;
460 
461  ParallelSection loop(m_grid->com);
462  try {
463  for (int j = ys; j < ys + ym; j++) {
464  for (int i = xs; i < xs + xm; i++) {
465  // Initialize the map from global to local degrees of freedom for this element.
466  m_element.reset(i, j);
467 
468  // Obtain the value of the solution at the nodes adjacent to the element.
469  // Compute the solution values and symmetric gradient at the quadrature points.
470  m_element.nodal_values(du.array(), du_e);
471  if (dirichletBC) {
472  dirichletBC.enforce_homogeneous(m_element, du_e);
473  }
474  m_element.evaluate(du_e, du_q, du_dx_q, du_dy_q);
475 
476  m_element.nodal_values(u.array(), u_e);
477  if (dirichletBC) {
478  dirichletBC.enforce(m_element, u_e);
479  }
480  m_element.evaluate(u_e, U, U_x, U_y);
481 
482  // Zero out the element-local residual in prep for updating it.
483  for (unsigned int k = 0; k < Nk; k++) {
484  dzeta_e[k] = 0;
485  }
486 
487  double thickness[Nq_max];
488  {
489  Coefficients coeffs[Nk];
490  int mask[Nq_max];
491  double tauc[Nq_max];
492  double hardness[Nq_max];
493 
494  m_element.nodal_values(m_coefficients.array(), coeffs);
495 
497  mask, thickness, tauc, hardness);
498  }
499 
500  for (unsigned int q = 0; q < Nq; q++) {
501  // Symmetric gradient at the quadrature point.
502  double Duqq[3] = {U_x[q].u, U_y[q].v, 0.5 * (U_y[q].u + U_x[q].v)};
503 
504  // Determine "d_nuH / dB" at the quadrature point
505  double d_nuH_dB = 0;
506  if (thickness[q] >= strength_extension->get_min_thickness()) {
507  m_flow_law->effective_viscosity(1.0,
508  secondInvariant_2D(U_x[q], U_y[q]),
509  &d_nuH_dB, NULL);
510  d_nuH_dB *= (2.0 * thickness[q]);
511  }
512 
513  auto W = m_element.weight(q);
514 
515  for (unsigned int k = 0; k < Nk; k++) {
516  dzeta_e[k] += W*d_nuH_dB*m_element.chi(q, k).val*((du_dx_q[q].u*(2*Duqq[0] + Duqq[1]) +
517  du_dy_q[q].u*Duqq[2]) +
518  (du_dy_q[q].v*(2*Duqq[1] + Duqq[0]) +
519  du_dx_q[q].v*Duqq[2]));
520  }
521  } // q
522 
523  m_element.add_contribution(dzeta_e, dzeta_a);
524  } // j
525  } // i
526  } catch (...) {
527  loop.failed();
528  }
529  loop.check();
530 
531  for (auto p = m_grid->points(); p; p.next()) {
532  const int i = p.i(), j = p.j();
533 
534  double dB_dzeta;
535  m_design_param.toDesignVariable((*m_zeta)(i, j), NULL, &dB_dzeta);
536  dzeta_a[j][i] *= dB_dzeta;
537  }
538 
541  fixedZeta.fix_residual_homogeneous(dzeta_a);
542  }
543 }
544 
545 /*!\brief Applies the linearization of the forward map (i.e. the reduced gradient \f$DF\f$ described in
546 the class-level documentation.) */
547 /*! As described previously,
548 \f[
549 Df = J_{\rm State}^{-1} J_{\rm Design}.
550 \f]
551 Applying the linearization then involves the solution of a linear equation.
552 The matrices \f$J_{\rm State}\f$ and \f$J_{\rm Design}\f$ both depend on the value of the
553 design variable \f$\zeta\f$ and the value of the corresponding state variable \f$u=F(\zeta)\f$.
554 These are established by first calling linearize_at.
555  @param[in] dzeta Perturbation of the design variable
556  @param[out] du Computed corresponding perturbation of the state variable; ghosts (if present) are updated.
557 */
559 
560  PetscErrorCode ierr;
561 
562  if (m_rebuild_J_state) {
564  m_rebuild_J_state = false;
565  }
566 
568  m_du_global.scale(-1);
569 
570  // call PETSc to solve linear system by iterative method.
571  ierr = KSPSetOperators(m_ksp, m_J_state, m_J_state);
572  PISM_CHK(ierr, "KSPSetOperators");
573 
574  ierr = KSPSolve(m_ksp, m_du_global.vec(), m_du_global.vec());
575  PISM_CHK(ierr, "KSPSolve"); // SOLVE
576 
577  KSPConvergedReason reason;
578  ierr = KSPGetConvergedReason(m_ksp, &reason);
579  PISM_CHK(ierr, "KSPGetConvergedReason");
580 
581  if (reason < 0) {
582  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "IP_SSAHardavForwardProblem::apply_linearization solve"
583  " failed to converge (KSP reason %s)",
584  KSPConvergedReasons[reason]);
585  } else {
586  m_log->message(4,
587  "IP_SSAHardavForwardProblem::apply_linearization converged"
588  " (KSP reason %s)\n",
589  KSPConvergedReasons[reason]);
590  }
591 
593 }
594 
595 /*! \brief Applies the transpose of the linearization of the forward map
596  (i.e. the transpose of the reduced gradient \f$DF\f$ described in the class-level documentation.) */
597 /*! As described previously,
598 \f[
599 Df = J_{\rm State}^{-1} J_{\rm Design}.
600 \f]
601 so
602 \f[
603 Df^t = J_{\rm Design}^t \; (J_{\rm State}^t)^{-1} .
604 \f]
605 Applying the transpose of the linearization then involves the solution of a linear equation.
606 The matrices \f$J_{\rm State}\f$ and \f$J_{\rm Design}\f$ both depend on the value of the
607 design variable \f$\zeta\f$ and the value of the corresponding state variable \f$u=F(\zeta)\f$.
608 These are established by first calling linearize_at.
609  @param[in] du Perturbation of the state variable
610  @param[out] dzeta Computed corresponding perturbation of the design variable; ghosts (if present) are updated.
611 */
613  array::Scalar &dzeta) {
614 
615  PetscErrorCode ierr;
616 
617  if (m_rebuild_J_state) {
619  m_rebuild_J_state = false;
620  }
621 
622  // Aliases to help with notation consistency below.
623  const array::Scalar *dirichletLocations = &m_bc_mask;
624  const array::Vector *dirichletValues = &m_bc_values;
625  double dirichletWeight = m_dirichletScale;
626 
628 
629  fem::DirichletData_Vector dirichletBC(dirichletLocations, dirichletValues,
630  dirichletWeight);
631  if (dirichletBC) {
634  }
635 
636  // call PETSc to solve linear system by iterative method.
637  ierr = KSPSetOperators(m_ksp, m_J_state, m_J_state);
638  PISM_CHK(ierr, "KSPSetOperators");
639 
640  ierr = KSPSolve(m_ksp, m_du_global.vec(), m_du_global.vec());
641  PISM_CHK(ierr, "KSPSolve"); // SOLVE
642 
643  KSPConvergedReason reason;
644  ierr = KSPGetConvergedReason(m_ksp, &reason);
645  PISM_CHK(ierr, "KSPGetConvergedReason");
646 
647  if (reason < 0) {
648  throw RuntimeError::formatted(PISM_ERROR_LOCATION, "IP_SSAHardavForwardProblem::apply_linearization solve failed to converge (KSP reason %s)",
649  KSPConvergedReasons[reason]);
650  } else {
651  m_log->message(4,
652  "IP_SSAHardavForwardProblem::apply_linearization converged (KSP reason %s)\n",
653  KSPConvergedReasons[reason]);
654  }
655 
657  dzeta.scale(-1);
658 
659  if (dzeta.stencil_width() > 0) {
660  dzeta.update_ghosts();
661  }
662 }
663 
664 } // end of namespace inverse
665 } // end of namespace pism
const Config::ConstPtr m_config
configuration database used by this component
Definition: Component.hh:158
const Logger::ConstPtr m_log
logger (for easy access)
Definition: Component.hh:162
const std::shared_ptr< const Grid > m_grid
grid used by this component
Definition: Component.hh:156
array::Scalar1 sea_level_elevation
Definition: Geometry.hh:48
void ensure_consistency(double ice_free_thickness_threshold)
Definition: Geometry.cc:112
array::Scalar1 ice_area_specific_volume
Definition: Geometry.hh:52
array::Scalar2 ice_thickness
Definition: Geometry.hh:51
array::Scalar2 bed_elevation
Definition: Geometry.hh:47
void failed()
Indicates a failure of a parallel section.
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
This class represents a 2D vector field (such as ice velocity) at a certain grid point.
Definition: Vector2d.hh:29
T * rawptr()
Definition: Wrapper.hh:39
std::shared_ptr< Wrapper > Ptr
Definition: Wrapper.hh:30
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
void copy_from(const Array2D< T > &source)
Definition: Array2D.hh:73
void add(double alpha, const Array2D< T > &x)
Definition: Array2D.hh:65
petsc::Vec & vec() const
Definition: Array.cc:339
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
Definition: Array.cc:253
void set(double c)
Result: v[j] <- c for all j.
Definition: Array.cc:707
void update_ghosts()
Updates ghost points.
Definition: Array.cc:693
unsigned int stencil_width() const
Get the stencil width of the current Array. Returns 0 if ghosts are not available.
Definition: Array.cc:331
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition: Array.cc:553
void enforce_homogeneous(const Element2 &element, double *x_e)
void fix_residual_homogeneous(double **r_global)
void enforce(const Element2 &element, Vector2d *x_e)
void fix_residual_homogeneous(Vector2d **r)
void enforce_homogeneous(const Element2 &element, Vector2d *x_e)
void constrain(Element2 &element)
Constrain element, i.e. ensure that quadratures do not contribute to Dirichlet nodes by marking corre...
void evaluate(const T *x, T *vals, T *dx, T *dy)
Given nodal values, compute the values and partial derivatives at the quadrature points.
Definition: Element.hh:195
void reset(int i, int j)
Initialize the Element to element (i, j) for the purposes of inserting into global residual and Jacob...
Definition: Element.cc:187
void add_contribution(const T *local, T **y_global) const
Add the values of element-local contributions y to the global vector y_global.
Definition: Element.hh:231
void nodal_values(const array::Scalar &x_global, int *result) const
Get nodal values of an integer mask.
Definition: Element.cc:176
int xm
total number of elements to loop over in the x-direction.
int ym
total number of elements to loop over in the y-direction.
int ys
y-coordinate of the first element to loop over.
int xs
x-coordinate of the first element to loop over.
const Germ & chi(unsigned int q, unsigned int k) const
Definition: Element.hh:73
int n_pts() const
Number of quadrature points.
Definition: Element.hh:80
double weight(unsigned int q) const
Weight of the quadrature point q
Definition: Element.hh:85
virtual void convertToDesignVariable(array::Scalar &zeta, array::Scalar &d, bool communicate=true)
Transforms a vector of values to a vector of values.
virtual void toDesignVariable(double zeta, double *value, double *derivative)=0
Converts from parameterization value to .
petsc::Mat m_J_state
Mat used in apply_linearization and apply_linearization_transpose.
virtual void assemble_residual(array::Vector &u, array::Vector &R)
Computes the residual function as defined in the class-level documentation.
virtual void apply_jacobian_design_transpose(array::Vector &u, array::Vector &du, array::Scalar &dzeta)
Applies the transpose of the design Jacobian matrix to a perturbation of the state variable.
array::Vector m_du_global
Temporary storage when state vectors need to be used without ghosts.
virtual void apply_linearization(array::Scalar &dzeta, array::Vector &du)
Applies the linearization of the forward map (i.e. the reduced gradient described in the class-level...
virtual void assemble_jacobian_state(array::Vector &u, Mat J)
Assembles the state Jacobian matrix.
IPDesignVariableParameterization & m_design_param
The function taking to .
array::Scalar1 m_hardav
Vertically-averaged ice hardness.
array::Scalar * m_fixed_design_locations
Locations where should not be adjusted.
array::Scalar1 m_dzeta_local
Storage for d_zeta with ghosts, if needed when an argument d_zeta is ghost-less.
IP_SSAHardavForwardProblem(std::shared_ptr< const Grid > g, IPDesignVariableParameterization &tp)
Constructs from the same objects as SSAFEM, plus a specification of how is parameterized.
std::shared_ptr< array::Vector > m_velocity_shared
virtual void apply_jacobian_design(array::Vector &u, array::Scalar &dzeta, array::Vector &du)
Applies the design Jacobian matrix to a perturbation of the design variable.
virtual std::shared_ptr< TerminationReason > linearize_at(array::Scalar &zeta)
Sets the current value of the design variable and solves the SSA to find the associated .
array::Scalar * m_zeta
Current value of zeta, provided from caller.
bool m_rebuild_J_state
Flag indicating that the state jacobian matrix needs rebuilding.
virtual void apply_linearization_transpose(array::Vector &du, array::Scalar &dzeta)
Applies the transpose of the linearization of the forward map (i.e. the transpose of the reduced grad...
virtual void set_design(array::Scalar &zeta)
Sets the current value of of the design paramter .
array::Vector1 m_du_local
Temporary storage when state vectors need to be used with ghosts.
petsc::KSP m_ksp
KSP used in apply_linearization and apply_linearization_transpose.
const array::Scalar * basal_yield_stress
const array::Scalar * bc_mask
const array::Array3D * age
const array::Scalar * water_column_pressure
const array::Array3D * enthalpy
const array::Scalar * basal_melt_rate
const array::Vector * bc_values
void compute_local_function(Vector2d const *const *const velocity, Vector2d **residual)
Implements the callback for computing the residual.
Definition: SSAFEM.cc:737
void quad_point_values(const fem::Element &Q, const Coefficients *x, int *mask, double *thickness, double *tauc, double *hardness) const
Compute quadrature point values of various coefficients given a quadrature Q and nodal values.
Definition: SSAFEM.cc:347
void cache_inputs(const Inputs &inputs)
Initialize stored data from the coefficients in the SSA. Called by SSAFEM::solve.
Definition: SSAFEM.cc:269
void compute_local_jacobian(Vector2d const *const *const velocity, Mat J)
Implements the callback for computing the Jacobian.
Definition: SSAFEM.cc:959
array::Scalar1 m_bc_mask
Definition: SSAFEM.hh:69
std::shared_ptr< TerminationReason > solve_nocache()
Definition: SSAFEM.cc:195
array::Vector1 m_bc_values
Definition: SSAFEM.hh:70
array::Array2D< Coefficients > m_coefficients
Definition: SSAFEM.hh:76
double get_min_thickness() const
Returns minimum thickness to trigger use of extension.
Definition: SSA.cc:66
SSAStrengthExtension * strength_extension
Definition: SSA.hh:115
std::shared_ptr< petsc::DM > m_da
Definition: SSA.hh:149
std::shared_ptr< rheology::FlowLaw > m_flow_law
#define PISM_CHK(errcode, name)
#define PISM_ERROR_LOCATION
const int n_chi
Definition: FEM.hh:191
const unsigned int MAX_QUADRATURE_SIZE
Definition: FEM.hh:173
static double secondInvariant_2D(const Vector2d &U_x, const Vector2d &U_y)
Definition: FlowLaw.hh:45
static const double g
Definition: exactTestP.cc:36
static const double k
Definition: exactTestP.cc:42
double dy
Function derivative with respect to y.
Definition: FEM.hh:157
double val
Function value.
Definition: FEM.hh:153
double dx
Function deriviative with respect to x.
Definition: FEM.hh:155
Struct for gathering the value and derivative of a function at a point.
Definition: FEM.hh:151