PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
IPLogRatioFunctional.cc
Go to the documentation of this file.
1 // Copyright (C) 2013, 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/IPLogRatioFunctional.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}|u_{\rm obs}| \f$ everywhere.
34 */
35 void IPLogRatioFunctional::normalize(double scale) {
36 
37  double value = 0;
38 
39  double w = 1.0;
40 
42 
43  if (m_weights) {
44  list.add(*m_weights);
45  }
46 
47  for (auto p = m_grid->points(); p; p.next()) {
48  const int i = p.i(), j = p.j();
49 
50  if (m_weights) {
51  w = (*m_weights)(i, j);
52  }
53 
54  Vector2d &u_obs_ij = m_u_observed(i, j);
55  double obsMagSq = u_obs_ij.u*u_obs_ij.u + u_obs_ij.v*u_obs_ij.v + m_eps*m_eps;
56 
57  double modelMagSq = scale*scale*(u_obs_ij.u*u_obs_ij.u + u_obs_ij.v*u_obs_ij.v) + m_eps*m_eps;
58 
59  double v = log(modelMagSq/obsMagSq);
60  value += w*v*v;
61  }
62 
63  m_normalization = GlobalSum(m_grid->com, value);
64 }
65 
66 void IPLogRatioFunctional::valueAt(array::Vector &x, double *OUTPUT) {
67 
68  // The value of the objective
69  double value = 0;
70 
71  double w = 1.;
72 
74 
75  if (m_weights) {
76  list.add(*m_weights);
77  }
78 
79  for (auto p = m_grid->points(); p; p.next()) {
80  const int i = p.i(), j = p.j();
81 
82  if (m_weights) {
83  w = (*m_weights)(i, j);
84  }
85  Vector2d &x_ij = x(i, j);
86  Vector2d &u_obs_ij = m_u_observed(i, j);
87  Vector2d u_model_ij = x_ij+u_obs_ij;
88  double obsMagSq = u_obs_ij.u*u_obs_ij.u + u_obs_ij.v*u_obs_ij.v + m_eps*m_eps;
89 
90  double modelMagSq = (u_model_ij.u*u_model_ij.u + u_model_ij.v*u_model_ij.v)+m_eps*m_eps;
91  double v = log(modelMagSq/obsMagSq);
92  value += w*v*v;
93  }
94 
95  value /= m_normalization;
96 
97  GlobalSum(m_grid->com, &value, OUTPUT, 1);
98 }
99 
101  gradient.set(0);
102 
103  double w = 1.;
104 
105  array::AccessScope list{&x, &gradient, &m_u_observed};
106 
107  if (m_weights) {
108  list.add(*m_weights);
109  }
110 
111  for (auto p = m_grid->points(); p; p.next()) {
112  const int i = p.i(), j = p.j();
113 
114  if (m_weights) {
115  w = (*m_weights)(i, j);
116  }
117  Vector2d &x_ij = x(i, j);
118  Vector2d &u_obs_ij = m_u_observed(i, j);
119  Vector2d u_model_ij = x_ij+u_obs_ij;
120 
121  double obsMagSq = u_obs_ij.u*u_obs_ij.u + u_obs_ij.v*u_obs_ij.v + m_eps*m_eps;
122  double modelMagSq = (u_model_ij.u*u_model_ij.u + u_model_ij.v*u_model_ij.v)+m_eps*m_eps;
123  double v = log(modelMagSq/obsMagSq);
124  double dJdw = 2*w*v/modelMagSq;
125 
126  gradient(i, j).u = dJdw*2*u_model_ij.u/m_normalization;
127  gradient(i, j).v = dJdw*2*u_model_ij.v/m_normalization;
128  }
129 }
130 
131 } // end of namespace inverse
132 } // 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)