PISM, A Parallel Ice Sheet Model 2.3.0-79cae578d committed by Constantine Khrulev on 2026-03-22
Loading...
Searching...
No Matches
VariableMetadata.hh
Go to the documentation of this file.
1// Copyright (C) 2009--2018, 2020, 2021, 2022, 2023, 2024, 2024, 2025 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#ifndef PISM_VARIABLEMETADATA_H
20#define PISM_VARIABLEMETADATA_H
21
22#include <map>
23#include <vector>
24#include <string>
25#include <memory>
26
27#include "pism/util/GridInfo.hh"
28
29namespace pism {
30namespace units {
31class System;
32}
33
34namespace io {
35enum Type : int;
36}
37
38class Grid;
39class Logger;
40
41//! @brief A class for handling variable metadata, reading, writing and converting
42//! from input units and to output units.
43/*! A NetCDF variable can have any number of attributes, but some of them get
44 special treatment:
45
46 - units: specifies internal units. When read, a variable is
47 converted to these units. When written, it is converted from these
48 to output_units.
49
50 - output_units: is never written to a file; replaces 'units'
51 in the output file.
52
53 - valid_min, valid_max: specify the valid range of a variable. Are
54 read from an input file *only* if not specified previously. If
55 both are set, then valid_range is used in the output instead.
56
57 Also:
58
59 - empty string attributes are ignored (they are not written to the
60 output file and has_attribute("foo") returns false if "foo" is
61 absent or equal to an empty string).
62
63 Typical attributes stored here:
64
65 - long_name
66 - standard_name
67 - units
68 - output_units (saved to files as "units")
69
70 Use the `name` of "PISM_GLOBAL" to read and write global attributes.
71 (See also File.)
72
73*/
74
75class VariableMetadata;
76
77/*!
78 * Syntactic sugar used to make it easier to get attributes.
79 *
80 * This class makes it possible to get both string and numeric attributes using code that
81 * looks like `variable = metadata["attribute"]`. It tries to convert to the type of
82 * `variable` and throws an error if there is a type mismatch.
83 */
85public:
86 friend class VariableMetadata;
89
90 operator std::string() const;
91 operator double() const;
92 operator std::vector<double> () const;
93protected:
94 ConstAttribute(const VariableMetadata *var, const std::string &name);
95 ConstAttribute(ConstAttribute&& a) noexcept;
96
97 std::string m_name;
99};
100
101/*!
102 * Syntactic sugar used to make it easier to set attributes.
103 *
104 * This class makes it possible to set both string and numeric attributes using code that
105 * looks like `metadata["attribute"] = value`.
106 */
107class Attribute : public ConstAttribute {
108public:
109 friend class VariableMetadata;
110 void operator=(const std::string &value);
111 void operator=(const std::initializer_list<double> &value);
112 void operator=(const std::vector<double> &value);
113private:
115};
116
118
120public:
121 //! string and boolean attributes
122 std::map<std::string, std::string> strings;
123
124 //! scalar and array attributes
125 std::map<std::string, std::vector<double> > numbers;
126
127 //! @brief The unit system to use.
128 std::shared_ptr<units::System> unit_system;
129
130 bool is_set(const std::string &name) const;
131};
132
134public:
135 VariableMetadata(const std::string &name, std::shared_ptr<units::System> system,
136 unsigned int ndims = 0);
137 VariableMetadata(const std::string &name,
138 const std::vector<std::tuple<std::string, int> > &dimensions,
139 std::shared_ptr<units::System> system);
140 VariableMetadata(std::shared_ptr<units::System> system, const std::string &name, const Grid &grid,
141 const std::vector<double> &levels = {});
142
143 virtual ~VariableMetadata() = default;
144
145 Attribute operator[](const std::string &name) {
146 return Attribute(this, name);
147 }
148
149 ConstAttribute operator[](const std::string &name) const {
150 return ConstAttribute(this, name);
151 }
152
153 // setters for common attributes
154
155 VariableMetadata &long_name(const std::string &input) {
156 return set_string("long_name", input);
157 }
158
159 VariableMetadata &standard_name(const std::string &input) {
160 return set_string("standard_name", input);
161 }
162
163 VariableMetadata &units(const std::string &input) {
164 return set_string("units", input);
165 }
166
167 VariableMetadata &output_units(const std::string &input) {
168 return set_string("output_units", input);
169 }
170
171 // getters and setters
172 double get_number(const std::string &name) const;
173 VariableMetadata &set_number(const std::string &name, double value);
174
175 std::vector<double> get_numbers(const std::string &name) const;
176 VariableMetadata &set_numbers(const std::string &name, const std::vector<double> &values);
177
178 std::string get_name() const;
179 VariableMetadata &set_name(const std::string &name);
180
181 std::string get_string(const std::string &name) const;
182 VariableMetadata &set_string(const std::string &name, const std::string &value);
183 VariableMetadata &set_units_without_validation(const std::string &value);
184
185 bool get_time_dependent() const;
187
190
191 //! Clear all attributes
193
194 // more getters
195 std::shared_ptr<units::System> unit_system() const;
196
197 unsigned int n_spatial_dimensions() const;
198
199 /*!
200 * Spatial variables return distributed grid info. All other variables return nullptr.
201 */
203
204 const std::vector<double>& levels() const;
205
206 std::vector<DimensionMetadata> dimensions() const;
207 std::vector<std::string> dimension_names() const;
208
209 DimensionMetadata& dimension(const std::string &name);
210 const DimensionMetadata& dimension(const std::string &name) const;
211
212 bool has_attribute(const std::string &name) const;
213 bool has_attributes() const;
214
215 const std::map<std::string, std::string> &all_strings() const;
216 const std::map<std::string, std::vector<double> > &all_doubles() const;
217 const VariableAttributes &attributes() const;
218
219 void report_to_stdout(const Logger &log, int verbosity_threshold) const;
220 void check_range(const std::string &filename, double min, double max) const;
221 void report_range(const Logger &log, double min, double max) const;
222
223protected:
224 unsigned int m_n_spatial_dims;
225
226 std::vector<DimensionMetadata> m_dimensions;
227
228 std::shared_ptr<grid::DistributedGridInfo> m_grid_info;
229
230 //! vertical grid levels (or similar)
231 std::vector<double> m_levels;
232
233 virtual std::vector<DimensionMetadata> dimensions_impl() const;
234
235private:
237
238 std::string m_name;
239
241
243};
244
246public:
247 DimensionMetadata(const std::string &name, std::shared_ptr<units::System> system,
248 int length, bool coordinate_variable = false);
249 int length() const;
250 bool coordinate_variable() const;
251private:
252 std::vector<DimensionMetadata> dimensions_impl() const;
253
256};
257
258// Comparison operator for VariableMetadata (we need it to store VariableMetadata in
259// sorted containers)
260inline bool operator<(const VariableMetadata &a, const VariableMetadata &b) {
261 return a.get_name() < b.get_name();
262}
263
264} // end of namespace pism
265
266#endif // PISM_VARIABLEMETADATA_H
void operator=(const std::string &value)
ConstAttribute(const ConstAttribute &)=delete
VariableMetadata * m_var
ConstAttribute & operator=(const ConstAttribute &)=delete
std::vector< DimensionMetadata > dimensions_impl() const
Describes the PISM grid and the distribution of data across processors.
Definition Grid.hh:285
A basic logging class.
Definition Logger.hh:40
std::shared_ptr< units::System > unit_system
The unit system to use.
bool is_set(const std::string &name) const
std::map< std::string, std::string > strings
string and boolean attributes
std::map< std::string, std::vector< double > > numbers
scalar and array attributes
VariableMetadata(const std::string &name, std::shared_ptr< units::System > system, unsigned int ndims=0)
VariableMetadata & clear()
Clear all attributes.
Attribute operator[](const std::string &name)
std::vector< std::string > dimension_names() const
std::vector< double > m_levels
vertical grid levels (or similar)
std::shared_ptr< grid::DistributedGridInfo > m_grid_info
const VariableAttributes & attributes() const
DimensionMetadata & dimension(const std::string &name)
const std::vector< double > & levels() const
void report_to_stdout(const Logger &log, int verbosity_threshold) const
ConstAttribute operator[](const std::string &name) const
VariableAttributes m_attributes
VariableMetadata & long_name(const std::string &input)
VariableMetadata & units(const std::string &input)
VariableMetadata & set_name(const std::string &name)
VariableMetadata & standard_name(const std::string &input)
unsigned int n_spatial_dimensions() const
VariableMetadata & set_number(const std::string &name, double value)
Set a scalar attribute to a single (scalar) value.
virtual std::vector< DimensionMetadata > dimensions_impl() const
double get_number(const std::string &name) const
Get a single-valued scalar attribute.
std::vector< DimensionMetadata > m_dimensions
std::string get_string(const std::string &name) const
Get a string attribute.
const grid::DistributedGridInfo * grid_info() const
virtual ~VariableMetadata()=default
const std::map< std::string, std::string > & all_strings() const
void report_range(const Logger &log, double min, double max) const
Report the range of a global Vec v.
VariableMetadata & output_units(const std::string &input)
std::shared_ptr< units::System > unit_system() const
io::Type get_output_type() const
VariableMetadata & set_units_without_validation(const std::string &value)
std::vector< double > get_numbers(const std::string &name) const
Get an array-of-doubles attribute.
VariableMetadata & set_output_type(io::Type type)
VariableMetadata & set_time_dependent(bool flag)
bool has_attribute(const std::string &name) const
VariableMetadata & set_numbers(const std::string &name, const std::vector< double > &values)
Set a scalar attribute to a single (scalar) value.
std::string get_name() const
VariableMetadata & set_string(const std::string &name, const std::string &value)
Set a string attribute.
void check_range(const std::string &filename, double min, double max) const
Check if the range [min, max] is a subset of [valid_min, valid_max].
std::vector< DimensionMetadata > dimensions() const
const std::map< std::string, std::vector< double > > & all_doubles() const
bool operator<(const MaxTimestep &a, const MaxTimestep &b)
Less than operator for MaxTimestep.