21 #include <petscdraw.h>
24 #include "pism/util/IceModelVec2V.hh"
25 #include "pism/util/IceModelVec_impl.hh"
33 #include "pism/util/Logger.hh"
34 #include "pism/util/Profiling.hh"
35 #include "pism/util/petscwrappers/VecScatter.hh"
36 #include "pism/util/petscwrappers/Viewer.hh"
37 #include "pism/util/Mask.hh"
38 #include "pism/util/IceModelVec2CellType.hh"
39 #include "pism/util/Context.hh"
40 #include "pism/util/VariableMetadata.hh"
41 #include "pism/util/io/File.hh"
49 ierr = DMGlobalToLocalBegin(dm, source, INSERT_VALUES, destination);
50 PISM_CHK(ierr,
"DMGlobalToLocalBegin");
52 ierr = DMGlobalToLocalEnd(dm, source, INSERT_VALUES, destination);
53 PISM_CHK(ierr,
"DMGlobalToLocalEnd");
57 const std::string &name,
61 const std::vector<double> &zlevels) {
71 auto max_stencil_width =
grid->ctx()->config()->get_number(
"grid.max_stencil_width");
80 auto system =
m_impl->
grid->ctx()->unit_system();
84 for (
unsigned int j = 0; j <
m_impl->
dof; ++j) {
92 if (zlevels.size() > 1) {
96 "Failed to allocate a GSL interpolation accelerator");
165 return {(int)
grid->My(), (int)
grid->Mx()};
176 for (
unsigned int j = 0; j <
m_impl->
dof; ++j) {
197 ierr = VecMin(
vec(), NULL, &
min);
201 ierr = VecMax(
vec(), NULL, &
max);
226 return NORM_INFINITY;
237 PetscErrorCode ierr = VecAXPY(
vec(), alpha, x.
vec());
245 PetscErrorCode ierr = VecShift(
vec(), alpha);
253 PetscErrorCode ierr = VecScale(
vec(), alpha);
274 this->
get_dof(destination_da, destination, 0, N);
279 unsigned int start,
unsigned int count)
const {
287 ***result_a =
static_cast<double***
>(tmp_res.get()),
288 ***source_a =
static_cast<double***
>(tmp_v.
get());
293 const int i = p.i(), j = p.j();
294 PetscErrorCode ierr = PetscMemcpy(result_a[j][i], &source_a[j][i][start],
295 count*
sizeof(PetscScalar));
305 unsigned int start,
unsigned int count) {
313 ***source_a =
static_cast<double***
>(tmp_src.get()),
314 ***result_a =
static_cast<double***
>(tmp_v.
get());
319 const int i = p.i(), j = p.j();
320 PetscErrorCode ierr = PetscMemcpy(&result_a[j][i][start], source_a[j][i],
321 count*
sizeof(PetscScalar));
344 PetscErrorCode ierr = 0;
347 PISM_CHK(ierr,
"DMCreateLocalVector");
350 PISM_CHK(ierr,
"DMCreateGlobalVector");
400 const std::string &long_name,
401 const std::string &units,
402 const std::string &glaciological_units,
403 const std::string &standard_name,
404 unsigned int component) {
406 metadata(component)[
"long_name"] = long_name;
408 metadata(component)[
"units"] = units;
410 if (not
m_impl->
grid->ctx()->config()->get_flag(
"output.use_MKS")) {
411 metadata(component)[
"glaciological_units"] = glaciological_units;
414 metadata(component)[
"pism_intent"] = pism_intent;
416 metadata(component)[
"standard_name"] = standard_name;
423 double default_value) {
425 bool allow_extrapolation =
grid()->ctx()->config()->get_flag(
"grid.allow_extrapolation");
450 auto da2 =
grid()->get_dm(1, 0);
456 for (
unsigned int j = 0; j <
ndof(); ++j) {
479 log->message(4,
" Reading %s...\n",
m_impl->
name.c_str());
499 auto da2 =
grid()->get_dm(1, 0);
505 for (
unsigned int j = 0; j <
ndof(); ++j) {
524 for (
unsigned int j = 0; j <
ndof(); ++j) {
526 type = type ==
PISM_NAT ? default_type : type;
534 assert(N < m_impl->dof);
539 assert(N < m_impl->dof);
547 log->message(4,
" Writing %s...\n",
m_impl->
name.c_str());
574 for (
unsigned int j = 0; j <
ndof(); ++j) {
602 PetscInt X_size, Y_size;
609 ierr = VecGetSize(
vec(), &X_size);
612 ierr = VecGetSize(other.
vec(), &Y_size);
615 if (X_size != Y_size) {
632 PISM_CHK(ierr,
"DMDAVecGetArrayDOF");
648 "IceModelVec::end_access(): a == NULL (looks like begin_acces() was not called)");
659 PISM_CHK(ierr,
"DMDAVecRestoreArrayDOF");
662 PISM_CHK(ierr,
"DMDAVecRestoreArray");
675 ierr = DMLocalToLocalBegin(*
dm(),
vec(), INSERT_VALUES,
vec());
676 PISM_CHK(ierr,
"DMLocalToLocalBegin");
678 ierr = DMLocalToLocalEnd(*
dm(),
vec(), INSERT_VALUES,
vec());
679 PISM_CHK(ierr,
"DMLocalToLocalEnd");
684 PetscErrorCode ierr = VecSet(
vec(),c);
691 double ghost_width = 0;
701 bool out_of_range = (i <
m_impl->
grid->xs() - ghost_width) ||
703 (j < m_impl->
grid->ys() - ghost_width) ||
729 const IceModelVec*
const z,
int &ghosts,
bool &scatter) {
775 PetscErrorCode ierr = VecStrideNormAll(
vec(), type, &result[0]);
778 PetscErrorCode ierr = VecNorm(
vec(), type, &result[0]);
788 " not implemented (called as %s.norm_all(...))",
805 case NORM_INFINITY: {
813 " (called as %s.norm_all(...))",
835 this->
read(file, time);
839 double default_value) {
843 this->
regrid(file, flag, default_value);
846 this->
get_name().c_str(), filename.c_str());
877 double default_value) {
878 m_impl->
grid->ctx()->log()->message(3,
" [%s] Regridding %s...\n",
881 m_impl->
grid->ctx()->profiling().begin(
"io.regridding");
890 m_impl->
grid->ctx()->profiling().end(
"io.regridding");
895 if (time_spent > 1.0) {
896 m_impl->
grid->ctx()->log()->message(3,
" done in %f seconds.\n", time_spent);
898 m_impl->
grid->ctx()->log()->message(3,
" done.\n");
910 m_impl->
grid->ctx()->log()->message(3,
" [%s] Writing %s...",
920 megabyte = pow(2, 20),
921 mb_double =
sizeof(double) *
size() / megabyte,
922 mb_float =
sizeof(float) *
size() / megabyte;
925 std::string spacer(
timestamp.size(),
' ');
926 if (time_spent > 1) {
929 " [%s] Done writing %s (%f Mb double, %f Mb float)\n"
930 " %s in %f seconds (%f minutes).\n"
931 " %s Effective throughput: double: %f Mb/s, float: %f Mb/s.\n",
933 spacer.c_str(), time_spent, time_spent / 60.0,
935 mb_double / time_spent, mb_float / time_spent);
937 m_impl->
grid->ctx()->log()->message(3,
" done.\n");
946 while (not
m_vecs.empty()) {
948 m_vecs.back()->end_access();
957 for (
const auto *j : vecs) {
958 assert(j !=
nullptr);
973 for (
const auto *v : vecs) {
974 assert(v !=
nullptr);
992 return Mx * My * Mz * dof;
1002 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"v_proc0", (PetscObject*)&v_proc0);
1005 if (v_proc0 == NULL) {
1012 ierr = DMDACreateNaturalVector(*
dm(), natural_work.
rawptr());
1013 PISM_CHK(ierr,
"DMDACreateNaturalVector");
1016 ierr = PetscObjectCompose((PetscObject)
dm()->get(),
"natural_work",
1017 (PetscObject)((::Vec)natural_work));
1018 PISM_CHK(ierr,
"PetscObjectCompose");
1026 ierr = VecScatterCreateToZero(natural_work, scatter_to_zero.
rawptr(),
1028 PISM_CHK(ierr,
"VecScatterCreateToZero");
1031 ierr = PetscObjectCompose((PetscObject)
dm()->get(),
"scatter_to_zero",
1032 (PetscObject)((::VecScatter)scatter_to_zero));
1033 PISM_CHK(ierr,
"PetscObjectCompose");
1036 ierr = PetscObjectCompose((PetscObject)
dm()->get(),
"v_proc0",
1037 (PetscObject)v_proc0);
1038 PISM_CHK(ierr,
"PetscObjectCompose");
1046 ierr = VecDuplicate(v_proc0, &result);
1049 return std::shared_ptr<petsc::Vec>(
new petsc::Vec(result));
1053 PetscErrorCode ierr = 0;
1054 VecScatter scatter_to_zero = NULL;
1055 Vec natural_work = NULL;
1057 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"scatter_to_zero",
1058 (PetscObject*)&scatter_to_zero);
1059 PISM_CHK(ierr,
"PetscObjectQuery");
1061 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"natural_work",
1062 (PetscObject*)&natural_work);
1063 PISM_CHK(ierr,
"PetscObjectQuery");
1065 if (natural_work == NULL || scatter_to_zero == NULL) {
1069 ierr = DMDAGlobalToNaturalBegin(*
dm(), parallel, INSERT_VALUES, natural_work);
1070 PISM_CHK(ierr,
"DMDAGlobalToNaturalBegin");
1072 ierr = DMDAGlobalToNaturalEnd(*
dm(), parallel, INSERT_VALUES, natural_work);
1073 PISM_CHK(ierr,
"DMDAGlobalToNaturalEnd");
1075 ierr = VecScatterBegin(scatter_to_zero, natural_work, onp0,
1076 INSERT_VALUES, SCATTER_FORWARD);
1079 ierr = VecScatterEnd(scatter_to_zero, natural_work, onp0,
1080 INSERT_VALUES, SCATTER_FORWARD);
1097 PetscErrorCode ierr;
1099 VecScatter scatter_to_zero = NULL;
1100 Vec natural_work = NULL;
1101 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"scatter_to_zero",
1102 (PetscObject*)&scatter_to_zero);
1103 PISM_CHK(ierr,
"PetscObjectQuery");
1105 ierr = PetscObjectQuery((PetscObject)
dm()->get(),
"natural_work",
1106 (PetscObject*)&natural_work);
1107 PISM_CHK(ierr,
"PetscObjectQuery");
1109 if (natural_work == NULL || scatter_to_zero == NULL) {
1113 ierr = VecScatterBegin(scatter_to_zero, onp0, natural_work,
1114 INSERT_VALUES, SCATTER_REVERSE);
1117 ierr = VecScatterEnd(scatter_to_zero, onp0, natural_work,
1118 INSERT_VALUES, SCATTER_REVERSE);
1121 ierr = DMDANaturalToGlobalBegin(*
dm(), natural_work, INSERT_VALUES, parallel);
1122 PISM_CHK(ierr,
"DMDANaturalToGlobalBegin");
1124 ierr = DMDANaturalToGlobalEnd(*
dm(), natural_work, INSERT_VALUES, parallel);
1125 PISM_CHK(ierr,
"DMDANaturalToGlobalEnd");
1154 MPI_Comm_rank(com, &rank);
1156 uint64_t result = 0;
1161 PetscErrorCode ierr = VecGetLocalSize(*v, &
size);
1166 MPI_Bcast(&result, 1, MPI_UINT64_T, 0, com);
1179 static_assert(
sizeof(
double) == 2 *
sizeof(uint32_t),
"Cannot compile IceModelVec::fletcher64() (sizeof(double) != 2 * sizeof(uint32_t))");
1181 MPI_Status mpi_stat;
1182 const int checksum_tag = 42;
1187 MPI_Comm_rank(com, &rank);
1190 MPI_Comm_size(com, &comm_size);
1192 PetscInt local_size = 0;
1193 PetscErrorCode ierr = VecGetLocalSize(
vec(), &local_size);
PISM_CHK(ierr,
"VecGetLocalSize");
1202 std::vector<uint64_t> sums(comm_size);
1206 for (
int r = 1; r < comm_size; ++r) {
1207 MPI_Recv(&sums[r], 1, MPI_UINT64_T, r, checksum_tag, com, &mpi_stat);
1213 MPI_Send(&
sum, 1, MPI_UINT64_T, 0, checksum_tag, com);
1217 MPI_Bcast(&
sum, 1, MPI_UINT64_T, 0, com);
1234 log->message(1,
"%s%s: %s\n", prefix,
m_impl->
name.c_str(),
checksum(serial).c_str());
1238 const std::string &spec1,
const std::string &spec2) {
1242 PetscInt data_size = 0;
1243 PetscErrorCode ierr = VecGetLocalSize(v, &data_size);
1252 bool include_floating_ice,
1266 const int i = p.i(), j = p.j();
1269 (include_floating_ice and cell_type.
icy(i, j))) {
1270 auto M = cell_type.
star(i, j);
1271 auto F = input.
star(i, j);
1273 int n = 0, e = 0, s = 0, w = 0;
1274 if (include_floating_ice) {
1275 n =
static_cast<int>(
icy(M.n));
1276 e =
static_cast<int>(
icy(M.e));
1277 s =
static_cast<int>(
icy(M.s));
1278 w =
static_cast<int>(
icy(M.w));
1286 if (
n + e + s + w > 0) {
1287 result(i, j) = (
n *
F.n + e *
F.e + s *
F.s + w *
F.w) / (
n + e + s + w);
1299 bool include_floating_ice,
1313 const int i = p.i(), j = p.j();
1315 auto M = cell_type.
star(i, j);
1316 auto F = input.
star(i, j);
1318 int n = 0, e = 0, s = 0, w = 0;
1319 if (include_floating_ice) {
1320 n =
static_cast<int>(
icy(M.n));
1321 e =
static_cast<int>(
icy(M.e));
1322 s =
static_cast<int>(
icy(M.s));
1323 w =
static_cast<int>(
icy(M.w));
1332 result(i, j).u = (e *
F.e + w *
F.w) / (e + w);
1334 result(i, j).u = 0.0;
1338 result(i, j).v = (
n *
F.n + s *
F.s) / (
n + s);
1340 result(i, j).v = 0.0;
1347 PetscErrorCode ierr;
1351 "cannot 'view' a 3D field '%s'",
1361 for (
unsigned int i = 0; i <
ndof(); ++i) {
1365 glaciological_units =
m_impl->
metadata[i].get_string(
"glaciological_units"),
1366 title = long_name +
" (" + glaciological_units +
")";
1368 PetscViewer v = *viewers[i].get();
1370 PetscDraw draw = NULL;
1371 ierr = PetscViewerDrawGetDraw(v, 0, &draw);
1372 PISM_CHK(ierr,
"PetscViewerDrawGetDraw");
1374 ierr = PetscDrawSetTitle(draw, title.c_str());
1375 PISM_CHK(ierr,
"PetscDrawSetTitle");
1380 units, glaciological_units);
1382 double bounds[2] = {0.0, 0.0};
1383 ierr = VecMin(tmp, NULL, &bounds[0]);
PISM_CHK(ierr,
"VecMin");
1384 ierr = VecMax(tmp, NULL, &bounds[1]);
PISM_CHK(ierr,
"VecMax");
1386 if (bounds[0] == bounds[1]) {
1391 ierr = PetscViewerDrawSetBounds(v, 1, bounds);
1392 PISM_CHK(ierr,
"PetscViewerDrawSetBounds");
1394 ierr = VecView(tmp, v);
std::vector< const PetscAccessible * > m_vecs
void add(const PetscAccessible &v)
Makes sure that we call begin_access() and end_access() for all accessed IceModelVecs.
std::string filename() const
High-level PISM I/O class.
std::shared_ptr< const IceGrid > ConstPtr
bool icy(int i, int j) const
bool grounded_ice(int i, int j) const
"Cell type" mask. Adds convenience methods to IceModelVec2Int.
stencils::Star< int > star(int i, int j) const
stencils::Star< double > star(int i, int j) const
Returns the values at interfaces of the cell i,j using the staggered grid.
A class for storing and accessing internal staggered-grid 2D fields. Uses dof=2 storage....
std::vector< int > shape() const
size_t size() const
Return the total number of elements in the owned part of an array.
void regrid_impl(const File &file, RegriddingFlag flag, double default_value=0.0)
Gets an IceModelVec from a file file, interpolating onto the current grid.
void update_ghosts()
Updates ghost points.
void get_dof(std::shared_ptr< petsc::DM > da_result, petsc::Vec &result, unsigned int start, unsigned int count=1) const
void read_impl(const File &file, unsigned int time)
Reads appropriate NetCDF variable(s) into an IceModelVec.
std::string checksum(bool serial) const
void set_name(const std::string &name)
Sets the variable name to name.
unsigned int stencil_width() const
Get the stencil width of the current IceModelVec. Returns 0 if ghosts are not available.
SpatialVariableMetadata & metadata(unsigned int N=0)
Returns a reference to the SpatialVariableMetadata object containing metadata for the compoment N.
void view(std::vector< std::shared_ptr< petsc::Viewer > > viewers) const
View a 2D vector field using existing PETSc viewers.
void dump(const char filename[]) const
Dumps a variable to a file, overwriting this file's contents (for debugging).
uint64_t fletcher64() const
uint64_t fletcher64_serial() const
void set_attrs(const std::string &pism_intent, const std::string &long_name, const std::string &units, const std::string &glaciological_units, const std::string &standard_name, unsigned int component)
Sets NetCDF attributes of an IceModelVec object.
void regrid(const std::string &filename, RegriddingFlag flag, double default_value=0.0)
void print_checksum(const char *prefix="", bool serial=false) const
virtual void begin_access() const
Checks if an IceModelVec is allocated and calls DAVecGetArray.
std::shared_ptr< petsc::DM > dm() const
void set(double c)
Result: v[j] <- c for all j.
void get_from_proc0(petsc::Vec &onp0)
Gets a local IceModelVec2 from processor 0.
void scale(double alpha)
Result: v <- v * alpha. Calls VecScale.
void read(const std::string &filename, unsigned int time)
IceGrid::ConstPtr grid() const
void put_on_proc0(petsc::Vec &onp0) const
Puts a local IceModelVec2S on processor 0.
void check_array_indices(int i, int j, unsigned int k) const
Check array indices and warn if they are out of range.
void set_dof(std::shared_ptr< petsc::DM > da_source, petsc::Vec &source, unsigned int start, unsigned int count=1)
std::array< double, 2 > range() const
Result: min <- min(v[j]), max <- max(v[j]).
std::vector< double > levels() const
void checkCompatibility(const char *function, const IceModelVec &other) const
Checks if two IceModelVecs have compatible sizes, dimensions and numbers of degrees of freedom.
void define(const File &file, IO_Type default_type=PISM_DOUBLE) const
Define variables corresponding to an IceModelVec in a file opened using file.
void write(const std::string &filename) const
virtual void end_access() const
Checks if an IceModelVec is allocated and calls DAVecRestoreArray.
void copy_to_vec(std::shared_ptr< petsc::DM > destination_da, petsc::Vec &destination) const
Copies v to a global vector 'destination'. Ghost points are discarded.
void write_impl(const File &file) const
Writes an IceModelVec to a NetCDF file.
std::shared_ptr< petsc::Vec > allocate_proc0_copy() const
void set_begin_access_use_dof(bool flag)
std::vector< double > norm(int n) const
Computes the norm of all the components of an IceModelVec.
unsigned int ndims() const
Returns the number of spatial dimensions.
const std::string & get_name() const
Get the name of an IceModelVec object.
void inc_state_counter()
Increment the object state counter.
int state_counter() const
Get the object state counter.
void shift(double alpha)
Result: v[j] <- v[j] + alpha for all j. Calls VecShift.
unsigned int ndof() const
Returns the number of degrees of freedom per grid point.
IceModelVec(IceGrid::ConstPtr grid, const std::string &name, IceModelVecKind ghostedp, size_t dof, size_t stencil_width, const std::vector< double > &zlevels)
void add(double alpha, const IceModelVec &x)
Result: v <- v + alpha * x. Calls VecAXPY.
void set_time_independent(bool flag)
Set the time independent flag for all variables corresponding to this IceModelVec instance.
Abstract class for reading, writing, allocating, and accessing a DA-based PETSc Vec (2D and 3D fields...
std::shared_ptr< const Logger > ConstPtr
void failed()
Indicates a failure of a parallel section.
virtual void begin_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
Wrapper around VecGetArray and VecRestoreArray.
void convert_doubles(double *data, size_t length) const
std::shared_ptr< System > Ptr
#define PISM_CHK(errcode, name)
#define PISM_ERROR_LOCATION
void append_time(const File &file, const Config &config, double time_seconds)
Prepare a file for output.
void read_spatial_variable(const SpatialVariableMetadata &variable, const IceGrid &grid, const File &file, unsigned int time, double *output)
Read a variable from a file into an array output.
void define_spatial_variable(const SpatialVariableMetadata &var, const IceGrid &grid, const File &file, IO_Type default_type)
Define a NetCDF variable corresponding to a VariableMetadata object.
void write_spatial_variable(const SpatialVariableMetadata &var, const IceGrid &grid, const File &file, const double *input)
Write a double array to a file.
void regrid_spatial_variable(SpatialVariableMetadata &var, const IceGrid &grid, const File &file, RegriddingFlag flag, bool report_range, bool allow_extrapolation, double default_value, InterpolationType interpolation_type, double *output)
Regrid from a NetCDF file into a distributed array output.
void define_time(const File &file, const Context &ctx)
Prepare a file for output.
bool icy(int M)
Ice-filled cell (grounded or floating).
void compute_params(const IceModelVec *const x, const IceModelVec *const y, const IceModelVec *const z, int &ghosts, bool &scatter)
Compute parameters for 2D loop computations involving 3 IceModelVecs.
double max(const IceModelVec2S &input)
Finds maximum over all the values in an IceModelVec2S object. Ignores ghosts.
static double F(double SL, double B, double H, double alpha)
static double start_time(const Config &config, const Logger &log, const File *file, const std::string &reference_date, const std::string &calendar, const units::Unit &time_units)
void GlobalMax(MPI_Comm comm, double *local, double *result, int count)
IO_Backend string_to_backend(const std::string &backend)
static NormType int_to_normtype(int input)
std::string printf(const char *format,...)
uint64_t fletcher64(const uint32_t *data, size_t length)
static double end_time(const Config &config, double time_start, const std::string &calendar, const units::Unit &time_units)
static void global_to_local(petsc::DM &dm, Vec source, Vec destination)
std::string timestamp(MPI_Comm com)
Creates a time-stamp used for the history NetCDF attribute.
double min(const IceModelVec2S &input)
Finds minimum over all the values in an IceModelVec2S object. Ignores ghosts.
void handle_fatal_errors(MPI_Comm com)
@ PISM_READWRITE_CLOBBER
create a file for writing, overwrite if present
@ PISM_READWRITE
open an existing file for reading and writing
@ PISM_READONLY
open an existing file for reading only
void GlobalMin(MPI_Comm comm, double *local, double *result, int count)
void GlobalSum(MPI_Comm comm, double *local, double *result, int count)
void convert_vec(petsc::Vec &v, units::System::Ptr system, const std::string &spec1, const std::string &spec2)
void staggered_to_regular(const IceModelVec2CellType &cell_type, const IceModelVec2Stag &input, bool include_floating_ice, IceModelVec2S &result)
IceModelVecKind
What "kind" of a vector to create: with or without ghosts.
double sum(const IceModelVec2S &input)
Sums up all the values in an IceModelVec2S object. Ignores ghosts.
bool report_range
If true, report range when regridding.
InterpolationType interpolation_type
std::shared_ptr< petsc::DM > da
distributed mesh manager (DM)
std::vector< double > zlevels
Vertical levels (for 3D fields)
unsigned int da_stencil_width
stencil width supported by the DA
int state_counter
Internal IceModelVec "revision number".
std::vector< SpatialVariableMetadata > metadata
Metadata (NetCDF variable attributes)
bool begin_access_use_dof
If true, use DMDAVecGetArrayDOF() in begin_access()
unsigned int dof
number of "degrees of freedom" per grid point
gsl_interp_accel * bsearch_accel
bool ghosted
true if this IceModelVec is ghosted
IceGrid::ConstPtr grid
The computational grid.