PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
IPLogRelativeFunctional.cc
Go to the documentation of this file.
1 // Copyright (C) 2012, 2014, 2015, 2016, 2017, 2020, 2022, 2023 David Maxwell
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/functional/IPLogRelativeFunctional.hh"
20 #include "pism/util/Grid.hh"
21 #include "pism/util/array/Vector.hh"
22 #include "pism/util/array/Scalar.hh"
23 #include "pism/util/pism_utilities.hh"
24 
25 namespace pism {
26 namespace inverse {
27 
28 //! Determine the normalization constant for the functional.
29 /*! Sets the normalization constant \f$c_N\f$ so that
30 \f[
31 J(x)=1
32 \f]
33 if \f$|x| = \mathtt{scale}\f$ everywhere.
34 */
36 
37  // The local value of the weights
38  double value = 0;
39 
40  double scale_sq = scale*scale;
41 
42  double w = 1.;
43 
45 
46  if (m_weights) {
47  list.add(*m_weights);
48  }
49 
50  for (auto p = m_grid->points(); p; p.next()) {
51  const int i = p.i(), j = p.j();
52 
53  Vector2d &u_obs_ij = m_u_observed(i, j);
54  if (m_weights) {
55  w = (*m_weights)(i, j);
56  }
57  double obsMagSq = (u_obs_ij.u*u_obs_ij.u + u_obs_ij.v*u_obs_ij.v) + m_eps*m_eps;
58  value += log(1 + w*scale_sq/obsMagSq);
59  }
60 
61  m_normalization = GlobalSum(m_grid->com, value);
62 }
63 
65 
66  // The value of the objective
67  double value = 0;
68 
69  double w = 1;
70 
72  if (m_weights) {
73  list.add(*m_weights);
74  }
75 
76  for (auto p = m_grid->points(); p; p.next()) {
77  const int i = p.i(), j = p.j();
78 
79  Vector2d &x_ij = x(i, j);
80  Vector2d &u_obs_ij = m_u_observed(i, j);
81  if (m_weights) {
82  w = (*m_weights)(i, j);
83  }
84  double obsMagSq = (u_obs_ij.u*u_obs_ij.u + u_obs_ij.v*u_obs_ij.v) + m_eps*m_eps;
85  value += log(1 + w*(x_ij.u*x_ij.u + x_ij.v*x_ij.v)/obsMagSq);
86  }
87 
88  value /= m_normalization;
89 
90  GlobalSum(m_grid->com, &value, OUTPUT, 1);
91 }
92 
94  gradient.set(0);
95 
96  double w = 1;
97 
98  array::AccessScope list{&x, &gradient, &m_u_observed};
99  if (m_weights) {
100  list.add(*m_weights);
101  }
102 
103  for (auto p = m_grid->points(); p; p.next()) {
104  const int i = p.i(), j = p.j();
105 
106  Vector2d &x_ij = x(i, j);
107  Vector2d &u_obs_ij = m_u_observed(i, j);
108  if (m_weights) {
109  w = (*m_weights)(i, j);
110  }
111  double obsMagSq = u_obs_ij.u*u_obs_ij.u + u_obs_ij.v*u_obs_ij.v + m_eps*m_eps;
112  double dJdxsq = w/(obsMagSq + w*(x_ij.u*x_ij.u + x_ij.v*x_ij.v));
113 
114  gradient(i, j).u = dJdxsq*2*x_ij.u/m_normalization;
115  gradient(i, j).v = dJdxsq*2*x_ij.v/m_normalization;
116  }
117 }
118 
119 } // end of namespace inverse
120 } // end of namespace pism
This class represents a 2D vector field (such as ice velocity) at a certain grid point.
Definition: Vector2d.hh:29
void add(const PetscAccessible &v)
Definition: Array.cc:933
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
void add(double alpha, const Array2D< T > &x)
Definition: Array2D.hh:65
void set(double c)
Result: v[j] <- c for all j.
Definition: Array.cc:707
std::shared_ptr< const Grid > m_grid
Definition: IPFunctional.hh:71
virtual void normalize(double scale)
Determine the normalization constant for the functional.
virtual void valueAt(array::Vector &x, double *OUTPUT)
Computes the value of the functional at the vector x.
virtual void gradientAt(array::Vector &x, array::Vector &gradient)
Computes the gradient of the functional at the vector x.
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)