Loading [MathJax]/extensions/tex2jax.js
PISM, A Parallel Ice Sheet Model 2.2.1-cd005eec8 committed by Constantine Khrulev on 2025-03-07
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Forcing.cc
Go to the documentation of this file.
1// Copyright (C) 2009--2024 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 <petsc.h>
20#include <cassert>
21#include <cmath> // std::floor
22#include <array>
23
24#include "pism/util/array/Forcing.hh"
25#include "pism/util/io/File.hh"
26#include "pism/util/pism_utilities.hh"
27#include "pism/util/Time.hh"
28#include "pism/util/Grid.hh"
29#include "pism/util/ConfigInterface.hh"
30
31#include "pism/util/error_handling.hh"
32#include "pism/util/io/io_helpers.hh"
33#include "pism/util/Logger.hh"
34#include "pism/util/Interpolation1D.hh"
35#include "pism/util/Context.hh"
36#include "pism/util/array/Array_impl.hh"
37#include "pism/util/VariableMetadata.hh"
38#include "pism/util/io/IO_Flags.hh"
39#include "pism/util/InputInterpolation.hh"
40
41namespace pism {
42namespace array {
43
46 : array(nullptr),
47 first(-1),
48 n_records(0),
49 period(0.0),
50 period_start(0.0) {
51 // empty
52 }
53 //! all the times available in filename
54 std::vector<double> time;
55
56 //! the range of times covered by data in `filename`
57 std::array<double,2> time_range;
58
59 //! name of the file to read (regrid) from
60 std::string filename;
61
62 //! DM with dof equal to buffer_size
63 std::shared_ptr<petsc::DM> da;
64
65 //! a 3D Vec used to store records
67
68 //! pointer used to access records stored in memory
69 double ***array;
70
71 //! maximum number of records stored in memory
72 unsigned int buffer_size;
73
74 //! in-file index of the first record stored in memory (a signed `int` to allow
75 //! `first==-1` as an *invalid* first value)
76 int first;
77
78 //! number of records currently kept in memory
79 unsigned int n_records;
80
81 //! temporal interpolation type
83
84 //! temporal interpolation code
85 std::shared_ptr<Interpolation1D> interp;
86
87 //! forcing period, in seconds
88 double period;
89
90 //! start of the period, in seconds
92
93 //! minimum time step length in max_timestep(), in seconds
94 double dt_min;
95};
96
97/*!
98 * Allocate an instance that will be used to load and use a forcing field from a file.
99 *
100 * Checks the number of records in a file and allocates storage accordingly.
101 *
102 * If `periodic` is true, allocate enough storage to hold all the records, otherwise
103 * allocate storage for at most `max_buffer_size` records.
104 *
105 * @param[in] grid computational grid
106 * @param[in] file input file
107 * @param[in] short_name variable name in `file`
108 * @param[in] standard_name standard name (if available); leave blank to ignore
109 * @param[in] max_buffer_size maximum buffer size for non-periodic fields
110 * @param[in] periodic true if this forcing field should be interpreted as periodic
111 * @param[in] interpolation_type type of temporal interpolation (LINEAR or PIECEWISE_CONSTANT)
112 */
113Forcing::Forcing(std::shared_ptr<const Grid> grid,
114 const File &file,
115 const std::string &short_name,
116 const std::string &standard_name,
117 unsigned int max_buffer_size,
118 bool periodic,
119 InterpolationType interpolation_type)
120 : array::Scalar(grid, short_name, 0),
121 m_data(new Data()) {
122
123 unsigned int n_records = file.nrecords(short_name, standard_name,
124 grid->ctx()->unit_system());
125
126 unsigned int buffer_size = 0;
127 if (periodic) {
128 // In the periodic case we try to keep all the records in RAM.
129 buffer_size = n_records;
130
131 if (interpolation_type == LINEAR) {
132 // add two more records at the beginning and the end of the period to simplify
133 // interpolation in time
134 buffer_size += 2;
135 }
136 } else {
137 buffer_size = std::min(n_records, max_buffer_size);
138 }
139
140 // Allocate storage for one record if the variable was not found. This is needed to be
141 // able to cheaply allocate and then discard an "-atmosphere given" model
142 // (atmosphere::Given) when "-surface given" (Given) is selected.
143 buffer_size = std::max(buffer_size, 1U);
144
145 allocate(buffer_size, interpolation_type);
146}
147
148std::shared_ptr<Forcing> Forcing::Constant(std::shared_ptr<const Grid> grid,
149 const std::string &short_name,
150 double value) {
151 // note: cannot use std::make_shared because of a private constructor
152 std::shared_ptr<Forcing> result(new Forcing(grid, short_name, 1,
154
155 // set constant value everywhere
156 result->set(value);
157 result->set_record(0);
158
159 // set the time to zero
160 result->m_data->time = {0.0};
161 result->m_data->n_records = 1;
162 result->m_data->first = 0;
163
164 // set fake time bounds:
165 double eps = 0.5 * result->m_data->dt_min;
166 result->m_data->time_range = {-eps, eps};
167
168 return result;
169}
170
171Forcing::Forcing(std::shared_ptr<const Grid> grid, const std::string &short_name,
172 unsigned int buffer_size,
173 InterpolationType interpolation_type)
174 : array::Scalar(grid, short_name, 0),
175 m_data(new Data()) {
176 allocate(buffer_size, interpolation_type);
177}
178
179void Forcing::allocate(unsigned int buffer_size, InterpolationType interpolation_type) {
180
181 if (buffer_size > 1) {
182 m_impl->report_range = false;
183 }
184
185 m_data->interp_type = interpolation_type;
187
188 auto config = m_impl->grid->ctx()->config();
189
190 m_data->dt_min = config->get_number("time_stepping.resolution");
191
194 throw RuntimeError(PISM_ERROR_LOCATION, "unsupported interpolation type");
195 }
196
197 // initialize the m_data->da member:
199
200 // allocate the 3D Vec:
201 PetscErrorCode ierr = DMCreateGlobalVector(*m_data->da, m_data->v.rawptr());
202 PISM_CHK(ierr, "DMCreateGlobalVector");
203}
204
206 delete m_data;
207}
208
209unsigned int Forcing::buffer_size() const {
210 return m_data->buffer_size;
211}
212
213double*** Forcing::array3() {
214 return m_data->array;
215}
216
218 if (m_impl->access_counter == 0) {
219 PetscErrorCode ierr = DMDAVecGetArrayDOF(*m_data->da, m_data->v, &m_data->array);
220 PISM_CHK(ierr, "DMDAVecGetArrayDOF");
221 }
222
223 // this call will increment the m_access_counter
225}
226
228 // this call will decrement the m_access_counter
230
231 if (m_impl->access_counter == 0) {
232 PetscErrorCode ierr = DMDAVecRestoreArrayDOF(*m_data->da, m_data->v, &m_data->array);
233 PISM_CHK(ierr, "DMDAVecRestoreArrayDOF");
234 m_data->array = nullptr;
235 }
236}
237
238void Forcing::init(const std::string &filename, bool periodic) {
239 try {
240 auto ctx = m_impl->grid->ctx();
241 auto time = ctx->time();
242
243 m_data->filename = filename;
244
246 auto var = file.find_variable(m_impl->metadata[0].get_name(),
247 m_impl->metadata[0]["standard_name"]);
248 if (not var.exists) {
249 throw RuntimeError(PISM_ERROR_LOCATION, "variable not found");
250 }
251
252 auto time_name = io::time_dimension(ctx->unit_system(), file, var.name);
253
254 // dimension_length() will return 0 if a dimension is missing
255 bool one_record = file.dimension_length(time_name) < 2;
256
257 if (not one_record) {
258 std::vector<double> times{};
259 std::vector<double> bounds{};
260 io::read_time_info(ctx->unit_system(), file, time_name, time->units_string(), times, bounds);
261
262 if (periodic) {
263 m_data->period_start = bounds.front();
264 m_data->period = bounds.back() - bounds.front();
265 }
266
268 // Time bounds data overrides the time variable: we make t[j] be the
269 // left end-point of the j-th interval
270 for (unsigned int k = 0; k < times.size(); ++k) {
271 times[k] = bounds[2*k + 0];
272 }
273 }
274
275 m_data->time = times;
276 m_data->time_range = {bounds.front(), bounds.back()};
277
278 bool extrapolate = ctx->config()->get_flag("input.forcing.time_extrapolation");
279 if (not (extrapolate or periodic)) {
280 check_forcing_duration(*time, bounds.front(), bounds.back());
281 }
282
283 } else {
284 // Only one time record or no time dimension at all: set fake time bounds assuming
285 // that the user wants to use constant-in-time forcing for the whole simulation
286
287 // this value does not matter
288 m_data->time = {0.0};
289
290 // set fake time bounds:
291 double eps = 0.5 * m_data->dt_min;
292 m_data->time_range = {-eps, eps};
293
294 // note that in this case all data is periodic and constant in time
295 m_data->period = 0.0;
296 m_data->period_start = 0.0;
297 }
298
299 if (periodic) {
300 // read periodic data right away (we need to hold it all in memory anyway)
301 init_periodic_data(file);
302 }
303 } catch (RuntimeError &e) {
304 e.add_context("reading '%s' (%s) from '%s'",
305 m_impl->metadata[0].get_string("long_name").c_str(),
306 m_impl->metadata[0].get_name().c_str(),
307 m_data->filename.c_str());
308 throw;
309 }
310}
311
312/*!
313 * Read all periodic data from the file and add two more records to simplify
314 * interpolation.
315 */
317
318 auto ctx = grid()->ctx();
319
320 auto name = get_name();
321 auto n_records = file.nrecords(name, metadata()["standard_name"],
322 ctx->unit_system());
323
324 auto buffer_required = n_records + 2 * static_cast<int>(m_data->interp_type == LINEAR);
325
326 if (buffer_size() < buffer_required) {
328 "the buffer is too small to contain periodic data");
329 }
330
331 int offset = m_data->interp_type == LINEAR ? 1 : 0;
332
333 // Read all the records and store them. The index offset leaves room for an extra record
334 // needed to simplify interpolation
335 auto variable = m_impl->metadata[0];
336 auto V = file.find_variable(variable.get_name(), variable["standard_name"]);
337
338 auto interp = grid()->get_interpolation({0.0}, file, V.name, m_impl->interpolation_type);
339
340 for (unsigned int j = 0; j < n_records; ++j) {
341
342 interp->regrid(variable, file, (int)j, *grid(), vec());
343
344 auto time = ctx->time();
345 auto log = ctx->log();
346 log->message(5, " %s: reading entry #%02d, time %s...\n", name.c_str(), j,
347 time->date(m_data->time[j]).c_str());
348
349 set_record(offset + j);
350 }
351
352 m_data->n_records = buffer_required;
353 m_data->first = 0;
354
356 return;
357 }
358
359 double t0 = m_data->time_range[0];
360 double t1 = m_data->time_range[1];
361
362 // compute the interpolation factor used to find the value at the beginning of the
363 // period
364 double alpha = 0.0;
365 {
366 double dt1 = m_data->time.front() - t0;
367 double dt2 = t1 - m_data->time.back();
368
369 alpha = dt1 + dt2 > 0 ? dt2 / (dt1 + dt2) : 0.0;
370 }
371
372 // indexes used to access the first and the last entry in the buffer
373 int first = 1;
374 int last = buffer_required - 2;
375
376 array::AccessScope list{ this };
377
378 // compute values at the beginning (and so at the end) of the period
379 double **a2 = array();
380 double ***a3 = array3();
381 for (auto p = grid()->points(); p; p.next()) {
382 const int i = p.i(), j = p.j();
383
384 a2[j][i] = (1.0 - alpha) * a3[j][i][last] + alpha * a3[j][i][first];
385 }
386
387 set_record(0);
388 set_record(buffer_size() - 1);
389
390 // add two more records to m_data->time
391 {
392 if (m_data->time[0] - t0 > 0.0) {
393 m_data->time.insert(m_data->time.begin(), t0);
394 } else {
395 // The first time record is at the beginning of the time interval covered by
396 // forcing. This means that the first record we added (set_record(0) above) is the
397 // same as the second one (at index 1). Only one of them is needed.
398 //
399 // Here we use an arbitrary time *before* the beginning of the forcing time interval
400 // to ensure that m_data->time is strictly increasing.
401 //
402 // Note: this time will not be used.
403 const double dt = 1.0; // arbitrary; could be any positive number
404 m_data->time.insert(m_data->time.begin(), t0 - dt);
405 }
406 if (t1 - m_data->time.back() > 0.0) {
407 m_data->time.push_back(t1);
408 } else {
409 // The last time record is at the end of the time interval covered by forcing. This
410 // means that the last record we added (set_record(m_data->buffer_size - 1) above)
411 // is the same as the one before it. Only one of them is needed.
412 //
413 // Here we use an arbitrary time *after* the end of the forcing time interval to
414 // ensure that m_data->time is strictly increasing.
415 //
416 // Note: this time will not be used.
417 const double dt = 1.0; // arbitrary; could be any positive number
418 m_data->time.push_back(t1 + dt);
419 }
420 }
421}
422
423//! Read some data to make sure that the interval (t, t + dt) is covered.
424void Forcing::update(double t, double dt) {
425
426 if (m_data->filename.empty()) {
427 // We are not reading data from a file.
428 return;
429 }
430
431 if (m_data->period > 0.0) {
432 // we read all data in Forcing::init() (see above)
433 return;
434 }
435
436 if (m_data->n_records > 0) {
437 // in-file index of the last record currently in memory
438 unsigned int last = m_data->first + (m_data->n_records - 1);
439
440 double t0{}, t1{};
441 if (m_data->interp_type == LINEAR) {
442 t0 = m_data->time[m_data->first];
443 t1 = m_data->time[last];
444 } else {
445 // piece-wise constant
446 t0 = m_data->time[m_data->first];
447 if (last + 1 < m_data->time.size()) {
448 t1 = m_data->time[last + 1];
449 } else {
450 t1 = m_data->time_range[1];
451 }
452 }
453
454 // just return if we have all the data we need:
455 if (t >= t0 and t + dt <= t1) {
456 return;
457 }
458 }
459
460 Interpolation1D I(m_data->interp_type, m_data->time, { t, t + dt });
461
462 unsigned int first = I.left(0), last = I.right(1), N = last - first + 1;
463
464 // check if all the records necessary to cover this interval fit in the
465 // buffer:
466 if (N > buffer_size()) {
468 "cannot read %d records of %s (buffer size: %d)", N,
469 m_impl->name.c_str(), buffer_size());
470 }
471
472 update(first);
473}
474
475//! Update by reading at most buffer_size records from the file.
476void Forcing::update(unsigned int start) {
477
478 unsigned int time_size = (int)m_data->time.size();
479
480 if (start >= time_size) {
482 "Forcing::update(int start): start = %d is invalid", start);
483 }
484
485 unsigned int missing = std::min(buffer_size(), time_size - start);
486
487 if (start == static_cast<unsigned int>(m_data->first)) {
488 // nothing to do
489 return;
490 }
491
492 int kept = 0;
493 if (m_data->first >= 0) {
494 unsigned int last = m_data->first + (m_data->n_records - 1);
495 if ((m_data->n_records > 0) && (start >= (unsigned int)m_data->first) && (start <= last)) {
496 int discarded = start - m_data->first;
497 kept = last - start + 1;
498 discard(discarded);
499 missing -= kept;
500 start += kept;
501 m_data->first += discarded;
502 } else {
503 m_data->first = start;
504 }
505 } else {
506 m_data->first = start;
507 }
508
509 if (missing <= 0) {
510 return;
511 }
512
513 m_data->n_records = kept + missing;
514
515 auto t = m_impl->grid->ctx()->time();
516
517 auto log = m_impl->grid->ctx()->log();
518 if (buffer_size() > 1) {
519 log->message(4,
520 " reading \"%s\" into buffer\n"
521 " (short_name = %s): %d records, time %s through %s...\n",
522 metadata().get_string("long_name").c_str(), m_impl->name.c_str(), missing,
523 t->date(m_data->time[start]).c_str(),
524 t->date(m_data->time[start + missing - 1]).c_str());
525 }
526
528
529 auto variable = m_impl->metadata[0];
530
531 try {
532 auto V = file.find_variable(variable.get_name(), variable["standard_name"]);
533
534 auto interp = grid()->get_interpolation({0.0}, file, V.name, m_impl->interpolation_type);
535
536 for (unsigned int j = 0; j < missing; ++j) {
537 interp->regrid(variable, file, (int)(start + j), *grid(), vec());
538
539 log->message(5, " %s: reading entry #%02d, year %s...\n", m_impl->name.c_str(), start + j,
540 t->date(m_data->time[start + j]).c_str());
541
542 set_record(kept + j);
543 }
544 } catch (RuntimeError &e) {
545 e.add_context("regridding '%s' from '%s'", this->get_name().c_str(), m_data->filename.c_str());
546 throw;
547 }
548}
549
550//! Discard the first N records, shifting the rest of them towards the "beginning".
551void Forcing::discard(int number) {
552
553 if (number == 0) {
554 return;
555 }
556
557 m_data->n_records -= number;
558
559 array::AccessScope l{this};
560
561 double ***a3 = array3();
562 for (auto p = m_impl->grid->points(); p; p.next()) {
563 const int i = p.i(), j = p.j();
564
565 for (unsigned int k = 0; k < m_data->n_records; ++k) {
566 a3[j][i][k] = a3[j][i][k + number];
567 }
568 }
569}
570
571//! Sets the record number n to the contents of the (internal) Vec v.
573
574 array::AccessScope l{this};
575
576 double **a2 = array();
577 double ***a3 = array3();
578 for (auto p = m_impl->grid->points(); p; p.next()) {
579 const int i = p.i(), j = p.j();
580 a3[j][i][n] = a2[j][i];
581 }
582}
583
584//! @brief Given the time t determines the maximum possible time-step this Forcing
585//! allows.
587 auto time_size = m_data->time.size();
588
589 if (m_data->period > 0.0) {
590 // all periodic data is stored in RAM and there is no time step restriction
591 return {};
592 }
593
594 if (t >= m_data->time.back()) {
595 // Reached the end of forcing: no time step restriction. We will need only one record
596 // to use constant extrapolation and it will surely fit in the buffer.
597 return {};
598 }
599
600 // find the index k such that m_data->time[k] <= x < m_data->time[k + 1]
601 // Note: `L` below will be strictly less than `time_size - 1`.
602 size_t L = gsl_interp_bsearch(m_data->time.data(), t, 0, time_size - 1);
603
604 // find the index of the last record we could read in given the size of the buffer
605 size_t R = L + buffer_size() - 1;
606
607 if (R >= time_size - 1) {
608 // We can read all the remaining records: no time step restriction from now on
609 return {};
610 }
611
613 // in the piece-wise constant case we can go all the way to the *next* record
614 R = std::min(R + 1, time_size - 1);
615 return m_data->time[R] - t;
616 }
617
618 return m_data->time[R] - t;
619}
620
621/*
622 * @brief Initialize Forcing with the value at time `t`.
623 *
624 * @note This method does not check if an update() call is necessary!
625 *
626 * @param[in] t requested time
627 *
628 */
629void Forcing::interp(double t) {
630
632
633 // There is only one point to interpolate at ("t" above). Here we get interpolation
634 // indexes and the corresponding weight. Here L == R for the piecewise-constant
635 // interpolation.
636 int L = m_data->interp->left(0);
637 int R = m_data->interp->right(0);
638 double alpha = m_data->interp->alpha(0);
639
640 array::AccessScope l{this};
641 double ***a3 = array3();
642 double **a2 = array();
643
644 for (auto p = m_impl->grid->points(); p; p.next()) {
645 const int i = p.i(), j = p.j();
646 auto *column = a3[j][i];
647 // result (LHS) is a weighted average of two values.
648 a2[j][i] = column[L] + alpha * (column[R] - column[L]);
649 }
650}
651
652
653/**
654 * Compute the average value over the time interval `[t, t + dt]`.
655 *
656 * @param t start of the time interval, in seconds
657 * @param dt length of the time interval, in seconds
658 *
659 */
660void Forcing::average(double t, double dt) {
661
662 // if only one record, nothing to do
663 if (m_data->time.size() == 1 or
664 m_data->n_records == 1 or
665 dt == 0.0) {
666 interp(t);
667 return;
668 }
669
670 const double *data = &m_data->time[m_data->first];
671 size_t data_size = m_data->n_records;
672 auto type = m_data->interp_type;
673
674 std::map<size_t, double> weights{};
675
676 if (m_data->period > 0.0) {
677 double a = t;
678 double b = t + dt;
679 double t0 = m_data->period_start;
680 double P = m_data->period;
681
682 // N_periods is the number of complete periods in the *middle* of the integration
683 // interval
684 //
685 // Note that the total number of complete periods is equal to (N_periods + 1) *if*
686 // delta == 0.0.
687 double N_periods = 0.0;
688 double delta = 0.0;
689 double gamma = 0.0;
690 {
691 double N = std::floor((a - t0) / P);
692 double M = std::floor((b - t0) / P);
693
694 N_periods = M - (N + 1);
695 delta = (a - t0) - P * N;
696 gamma = (b - t0) - P * M;
697 }
698
699 if (N_periods >= 0.0) {
700 assert(t0 + delta < t0 + P);
701 auto W1 = integration_weights(data, data_size, type, t0 + delta, t0 + P);
702
703 std::map<size_t, double> W2{};
704 if (N_periods > 0) {
705 // note: we know that t0 < t0 + P because P > 0
706 W2 = integration_weights(data, data_size, type, t0, t0 + P);
707 } else {
708 W2 = {};
709 }
710
711 std::map<size_t, double> W3{};
712 if (gamma > 0.0) {
713 W3 = integration_weights(data, data_size, type, t0, t0 + gamma);
714 } else {
715 W3 = {};
716 }
717
718 // before the first complete period:
719 weights = W1;
720 // an integer number of complete periods:
721 for (const auto &w : W2) {
722 weights[w.first] += N_periods * w.second;
723 }
724 // after the last complete period:
725 for (const auto &w : W3) {
726 weights[w.first] += w.second;
727 }
728 } else {
729 assert(t0 + delta < t0 + gamma);
730 weights = integration_weights(data, data_size, type, t0 + delta, t0 + gamma);
731 }
732 } else {
733 assert(dt > 0.0);
734 weights = integration_weights(data, data_size, type, t, t + dt);
735 }
736
737 array::AccessScope l{this};
738 double **a2 = array();
739 double ***a3 = array3();
740
741 for (auto p = m_impl->grid->points(); p; p.next()) {
742 const int i = p.i(), j = p.j();
743
744 a2[j][i] = 0.0;
745 for (const auto &weight : weights) {
746 size_t k = weight.first;
747 double w = weight.second;
748 a2[j][i] += w * a3[j][i][k];
749 }
750 a2[j][i] /= dt;
751 }
752}
753
754/**
755 * \brief Compute weights for the piecewise-constant interpolation.
756 * This is used *both* for time-series and "snapshots".
757 *
758 * @param ts requested times, in seconds
759 *
760 */
761void Forcing::init_interpolation(const std::vector<double> &ts) {
762
763 assert(m_data->first >= 0);
764
765 // Compute "periodized" times if necessary.
766 std::vector<double> times_requested(ts.size());
767 if (m_data->period > 0.0) {
768 double P = m_data->period;
769 double T0 = m_data->period_start;
770
771 for (unsigned int k = 0; k < ts.size(); ++k) {
772 double t = ts[k] - T0;
773
774 t -= std::floor(t / P) * P;
775
776 times_requested[k] = T0 + t;
777 }
778 } else {
779 times_requested = ts;
780 }
781
785 times_requested.data(),
786 times_requested.size()));
787}
788
789/**
790 * \brief Compute values of the time-series using precomputed indices
791 * (and piece-wise constant or piece-wise linear interpolation).
792 *
793 * @param i,j map-plane grid point
794 * @param result pointer to an allocated array of the size matching the one passed to
795 * init_interpolation()
796 *
797 */
798void Forcing::interp(int i, int j, std::vector<double> &result) {
799 double ***a3 = array3();
800
801 result.resize(m_data->interp->alpha().size());
802
803 m_data->interp->interpolate(a3[j][i], result.data());
804}
805
806} // end of namespace array
807} // end of namespace pism
VariableLookupData find_variable(const std::string &short_name, const std::string &std_name) const
Find a variable using its standard name and/or short name.
Definition File.cc:328
unsigned int nrecords() const
Get the number of records. Uses the length of an unlimited dimension.
Definition File.cc:280
std::string name() const
Definition File.cc:274
unsigned int dimension_length(const std::string &name) const
Get the length of a dimension.
Definition File.cc:420
High-level PISM I/O class.
Definition File.hh:55
const std::vector< int > & right() const
const std::vector< int > & left() const
Combines the max. time step with the flag indicating if a restriction is active. Makes is possible to...
virtual void begin_access() const =0
virtual void end_access() const =0
void add_context(const std::string &message)
Add a message providing some context. This way we can (sort of) get a stack trace even though C++ exc...
static RuntimeError formatted(const ErrorLocation &location, const char format[],...) __attribute__((format(printf
build a RuntimeError with a formatted message
units::System::Ptr unit_system() const
T * rawptr()
Definition Wrapper.hh:39
Makes sure that we call begin_access() and end_access() for all accessed array::Arrays.
Definition Array.hh:64
const std::string & get_name() const
Get the name of an Array object.
Definition Array.cc:354
petsc::Vec & vec() const
Definition Array.cc:310
std::shared_ptr< const Grid > grid() const
Definition Array.cc:131
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
Definition Array.cc:476
MaxTimestep max_timestep(double t) const
Given the time t determines the maximum possible time-step this Forcing allows.
Definition Forcing.cc:586
void begin_access() const
Checks if an Array is allocated and calls DAVecGetArray.
Definition Forcing.cc:217
void average(double t, double dt)
Definition Forcing.cc:660
void discard(int N)
Discard the first N records, shifting the rest of them towards the "beginning".
Definition Forcing.cc:551
void init_periodic_data(const File &file)
Definition Forcing.cc:316
void interp(double t)
Definition Forcing.cc:629
void set_record(int n)
Sets the record number n to the contents of the (internal) Vec v.
Definition Forcing.cc:572
void init(const std::string &filename, bool periodic)
Definition Forcing.cc:238
double *** array3()
Definition Forcing.cc:213
void allocate(unsigned int buffer_size, InterpolationType interpolation_type)
Definition Forcing.cc:179
void end_access() const
Checks if an Array is allocated and calls DAVecRestoreArray.
Definition Forcing.cc:227
Forcing(std::shared_ptr< const Grid > grid, const File &file, const std::string &short_name, const std::string &standard_name, unsigned int max_buffer_size, bool periodic, InterpolationType interpolation_type=PIECEWISE_CONSTANT)
Definition Forcing.cc:113
void init_interpolation(const std::vector< double > &ts)
Compute weights for the piecewise-constant interpolation. This is used both for time-series and "snap...
Definition Forcing.cc:761
static std::shared_ptr< Forcing > Constant(std::shared_ptr< const Grid > grid, const std::string &short_name, double value)
Definition Forcing.cc:148
void update(double t, double dt)
Read some data to make sure that the interval (t, t + dt) is covered.
Definition Forcing.cc:424
unsigned int buffer_size() const
Definition Forcing.cc:209
2D time-dependent inputs (for climate forcing, etc)
Definition Forcing.hh:41
#define PISM_CHK(errcode, name)
#define PISM_ERROR_LOCATION
static const double L
Definition exactTestL.cc:40
#define n
Definition exactTestM.c:37
@ PISM_GUESS
Definition IO_Flags.hh:56
@ PISM_READONLY
open an existing file for reading only
Definition IO_Flags.hh:68
void read_time_info(std::shared_ptr< units::System > unit_system, const File &file, const std::string &time_name, const std::string &time_units, std::vector< double > &times, std::vector< double > &bounds)
std::string time_dimension(units::System::Ptr unit_system, const File &file, const std::string &variable_name)
@ PIECEWISE_CONSTANT
std::map< size_t, double > integration_weights(const double *x, size_t x_size, InterpolationType type, double a, double b)
static const double k
Definition exactTestP.cc:42
void check_forcing_duration(const Time &time, double forcing_start, double forcing_end)
Definition Time.cc:923
std::shared_ptr< const Grid > grid
The computational grid.
Definition Array_impl.hh:77
InterpolationType interpolation_type
bool report_range
If true, report range when regridding.
Definition Array_impl.hh:62
unsigned int da_stencil_width
stencil width supported by the DA
Definition Array_impl.hh:83
std::vector< SpatialVariableMetadata > metadata
Metadata (NetCDF variable attributes)
Definition Array_impl.hh:74
double period_start
start of the period, in seconds
Definition Forcing.cc:91
unsigned int n_records
number of records currently kept in memory
Definition Forcing.cc:79
std::vector< double > time
all the times available in filename
Definition Forcing.cc:54
std::string filename
name of the file to read (regrid) from
Definition Forcing.cc:60
double period
forcing period, in seconds
Definition Forcing.cc:88
InterpolationType interp_type
temporal interpolation type
Definition Forcing.cc:82
double dt_min
minimum time step length in max_timestep(), in seconds
Definition Forcing.cc:94
std::array< double, 2 > time_range
the range of times covered by data in filename
Definition Forcing.cc:57
std::shared_ptr< Interpolation1D > interp
temporal interpolation code
Definition Forcing.cc:85
unsigned int buffer_size
maximum number of records stored in memory
Definition Forcing.cc:72
std::shared_ptr< petsc::DM > da
DM with dof equal to buffer_size.
Definition Forcing.cc:63
petsc::Vec v
a 3D Vec used to store records
Definition Forcing.cc:66
double *** array
pointer used to access records stored in memory
Definition Forcing.cc:69