PISM, A Parallel Ice Sheet Model  stable v2.1-1-g6902d5502 committed by Ed Bueler on 2023-12-20 08:38:27 -0800
ISMIP6Climate.cc
Go to the documentation of this file.
1 // Copyright (C) 2019, 2021, 2022, 2023 PISM Authors
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/coupler/surface/ISMIP6Climate.hh"
20 
21 #include "pism/util/Grid.hh"
22 #include "pism/coupler/util/options.hh"
23 #include "pism/util/io/io_helpers.hh"
24 #include "pism/geometry/Geometry.hh"
25 #include "pism/util/array/Forcing.hh"
26 
27 namespace pism {
28 namespace surface {
29 
30 ISMIP6::ISMIP6(std::shared_ptr<const Grid> grid, std::shared_ptr<atmosphere::AtmosphereModel> input)
31  : SurfaceModel(grid),
32  m_mass_flux_reference(m_grid, "climatic_mass_balance"),
33  m_temperature_reference(m_grid, "ice_surface_temp"),
34  m_surface_reference(m_grid, "usurf")
35 {
36  (void) input;
37 
38  // allocate model outputs
41 
42  // set metadata of reference fields
43  {
45  .long_name("reference surface mass balance rate")
46  .units("kg m-2 s-1")
47  .output_units("kg m-2 year-1")
48  .standard_name("land_ice_surface_specific_mass_balance_flux")
49  .set_time_independent(true);
50 
51  auto smb_max = m_config->get_number("surface.given.smb_max", "kg m-2 second-1");
52  m_mass_flux_reference.metadata()["valid_range"] = { -smb_max, smb_max };
53 
55  .long_name("reference surface altitude")
56  .units("m")
57  .standard_name("surface_altitude")
58  .set_time_independent(true);
59 
60  m_surface_reference.metadata()["valid_range"] = { 0.0, m_grid->Lz() };
61 
63  .long_name("reference temperature")
64  .units("Kelvin")
65  .set_time_independent(true);
66 
67  m_temperature_reference.metadata()["valid_range"] = { 0.0, 373.15 };
68  }
69 
70  // allocate storage for time-dependent inputs
71  ForcingOptions opt(*m_grid->ctx(), "surface.ismip6");
72 
73  {
74  unsigned int buffer_size = m_config->get_number("input.forcing.buffer_size");
75 
77 
78  {
80  std::make_shared<array::Forcing>(m_grid, file, "climatic_mass_balance_anomaly",
81  "", // no standard name
82  buffer_size, opt.periodic);
83 
84  m_mass_flux_anomaly->metadata(0)
85  .long_name("surface mass balance rate anomaly")
86  .units("kg m-2 s-1")
87  .output_units("kg m-2 year-1");
88  }
89 
90  {
92  std::make_shared<array::Forcing>(m_grid, file, "climatic_mass_balance_gradient",
93  "", // no standard name
94  buffer_size, opt.periodic);
95 
96  m_mass_flux_gradient->metadata(0)
97  .long_name("surface mass balance rate elevation lapse rate")
98  .units("kg m-2 s-1 m-1")
99  .output_units("kg m-2 year-1 m-1");
100  }
101 
102  {
104  std::make_shared<array::Forcing>(m_grid, file, "ice_surface_temp_anomaly",
105  "", // no standard name
106  buffer_size, opt.periodic);
107 
108  m_temperature_anomaly->metadata(0)
109  .long_name("ice surface temperature anomaly")
110  .units("Kelvin");
111  }
112 
113  {
115  std::make_shared<array::Forcing>(m_grid, file, "ice_surface_temp_gradient",
116  "", // no standard name
117  buffer_size, opt.periodic);
118 
119  m_temperature_gradient->metadata(0)
120  .long_name("ice surface temperature elevation lapse rate")
121  .units("Kelvin m-1");
122  }
123  }
124 }
125 
126 void ISMIP6::init_impl(const Geometry &geometry) {
127  (void) geometry;
128 
129  m_log->message(2, "* Initializing the ISMIP6 surface model...\n");
130 
131  {
132  // File with reference surface elevation, temperature, and climatic mass balance
133  auto reference_filename = m_config->get_string("surface.ismip6.reference_file");
134  File reference_file(m_grid->com, reference_filename, io::PISM_GUESS, io::PISM_READONLY);
135 
136  m_mass_flux_reference.regrid(reference_file, io::Default::Nil());
137  m_surface_reference.regrid(reference_file, io::Default::Nil());
139  }
140 
141  {
142  ForcingOptions opt(*m_grid->ctx(), "surface.ismip6");
143 
144  m_mass_flux_anomaly->init(opt.filename, opt.periodic);
145  m_mass_flux_gradient->init(opt.filename, opt.periodic);
146 
147  m_temperature_anomaly->init(opt.filename, opt.periodic);
148  m_temperature_gradient->init(opt.filename, opt.periodic);
149  }
150 }
151 
152 void ISMIP6::update_impl(const Geometry &geometry, double t, double dt) {
153 
154  // inputs
155  const array::Scalar &h = geometry.ice_surface_elevation;
156  const array::Scalar &h_ref = m_surface_reference;
157  const array::Scalar &T_ref = m_temperature_reference;
158  const array::Scalar &SMB_ref = m_mass_flux_reference;
159 
164 
165  // outputs
168 
169  // get time-dependent input fields at the current time
170  {
171  aT.update(t, dt);
172  aSMB.update(t, dt);
173  dTdz.update(t, dt);
174  dSMBdz.update(t, dt);
175 
176  aT.average(t, dt);
177  aSMB.average(t, dt);
178  dTdz.average(t, dt);
179  dSMBdz.average(t, dt);
180  }
181 
182  // From http://www.climate-cryosphere.org/wiki/index.php?title=ISMIP6-Projections-Greenland:
183  // SMB(x,y,t) = SMB_ref(x,y) + aSMB(x,y,t) + dSMBdz(x,y,t) * [h(x,y,t) - h_ref(x,y)]
184 
185  array::AccessScope list{ &h, &h_ref, &SMB, &SMB_ref, &aSMB, &dSMBdz, &T, &T_ref, &aT, &dTdz };
186 
187  for (auto p = m_grid->points(); p; p.next()) {
188  const int i = p.i(), j = p.j();
189 
190  SMB(i, j) = SMB_ref(i, j) + aSMB(i, j) + dSMBdz(i, j) * (h(i, j) - h_ref(i, j));
191  T(i, j) = T_ref(i, j) + aT(i, j) + dTdz(i, j) * (h(i, j) - h_ref(i, j));
192  }
193 
195  dummy_melt(SMB, *m_melt);
197 }
198 
200  using std::min;
201 
202  auto dt = m_temperature_anomaly->max_timestep(t);
203  dt = min(dt, m_temperature_gradient->max_timestep(t));
204  dt = min(dt, m_mass_flux_anomaly->max_timestep(t));
205  dt = min(dt, m_mass_flux_gradient->max_timestep(t));
206 
207  if (dt.finite()) {
208  return MaxTimestep(dt.value(), "surface ISMIP6");
209  }
210  return MaxTimestep("surface ISMIP6");
211 }
212 
214  return *m_mass_flux;
215 }
216 
218  return *m_temperature;
219 }
220 
222  return *m_accumulation;
223 }
224 
226  return *m_melt;
227 }
228 
230  return *m_runoff;
231 }
232 
233 } // end of namespace surface
234 } // 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
High-level PISM I/O class.
Definition: File.hh:56
array::Scalar2 ice_surface_elevation
Definition: Geometry.hh:57
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
Definition: MaxTimestep.hh:31
VariableMetadata & standard_name(const std::string &input)
VariableMetadata & long_name(const std::string &input)
VariableMetadata & output_units(const std::string &input)
VariableMetadata & units(const std::string &input)
VariableMetadata & set_time_independent(bool flag)
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition: Array.hh:65
void regrid(const std::string &filename, io::Default default_value)
Definition: Array.cc:814
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition: Array.cc:553
void average(double t, double dt)
Definition: Forcing.cc:673
void update(double t, double dt)
Read some data to make sure that the interval (t, t + dt) is covered.
Definition: Forcing.cc:429
2D time-dependent inputs (for climate forcing, etc)
Definition: Forcing.hh:41
static Default Nil()
Definition: IO_Flags.hh:97
array::Scalar m_mass_flux_reference
const array::Scalar & mass_flux_impl() const
std::shared_ptr< array::Forcing > m_mass_flux_anomaly
const array::Scalar & temperature_impl() const
void update_impl(const Geometry &geometry, double t, double dt)
const array::Scalar & accumulation_impl() const
std::shared_ptr< array::Scalar > m_temperature
std::shared_ptr< array::Scalar > m_mass_flux
void init_impl(const Geometry &geometry)
std::shared_ptr< array::Forcing > m_temperature_anomaly
std::shared_ptr< array::Forcing > m_temperature_gradient
const array::Scalar & melt_impl() const
MaxTimestep max_timestep_impl(double t) const
const array::Scalar & runoff_impl() const
array::Scalar m_temperature_reference
std::shared_ptr< array::Forcing > m_mass_flux_gradient
array::Scalar m_surface_reference
ISMIP6(std::shared_ptr< const Grid > g, std::shared_ptr< atmosphere::AtmosphereModel > input)
static std::shared_ptr< array::Scalar > allocate_mass_flux(std::shared_ptr< const Grid > grid)
Definition: SurfaceModel.cc:73
void dummy_accumulation(const array::Scalar &smb, array::Scalar &result)
std::shared_ptr< array::Scalar > m_melt
static std::shared_ptr< array::Scalar > allocate_temperature(std::shared_ptr< const Grid > grid)
Definition: SurfaceModel.cc:92
std::shared_ptr< array::Scalar > m_runoff
void dummy_melt(const array::Scalar &smb, array::Scalar &result)
std::shared_ptr< array::Scalar > m_accumulation
void dummy_runoff(const array::Scalar &smb, array::Scalar &result)
The interface of PISM's surface models.
Definition: SurfaceModel.hh:42
double min(const array::Scalar &input)
Finds minimum over all the values in an array::Scalar object. Ignores ghosts.
Definition: Scalar.cc:193
@ PISM_GUESS
Definition: IO_Flags.hh:56
@ PISM_NETCDF3
Definition: IO_Flags.hh:57
@ PISM_READONLY
open an existing file for reading only
Definition: IO_Flags.hh:72
std::string filename
Definition: options.hh:33