23 #include "pism/util/projection.hh"
24 #include "pism/util/VariableMetadata.hh"
25 #include "pism/util/error_handling.hh"
26 #include "pism/util/io/File.hh"
27 #include "pism/util/io/io_helpers.hh"
28 #include "pism/util/Grid.hh"
29 #include "pism/util/array/Scalar.hh"
30 #include "pism/util/array/Array3D.hh"
32 #include "pism/pism_config.hh"
34 #if (Pism_USE_PROJ==1)
35 #include "pism/util/Proj.hh"
41 : mapping(mapping_name, unit_system) {
51 std::string::size_type position = std::string::npos;
52 for (
const auto &auth : {
"epsg:",
"EPSG:"}) {
53 position = proj_string.find(auth);
54 if (position != std::string::npos) {
59 if (position == std::string::npos) {
61 "could not parse EPSG code '%s'", proj_string.c_str());
66 std::string epsg_code = proj_string.substr(position + auth_len);
67 const char *str = epsg_code.c_str();
69 epsg = strtol(str, &endptr, 10);
72 "failed to parse EPSG code at '%s' in PROJ string '%s'",
73 epsg_code.c_str(), proj_string.c_str());
79 mapping[
"latitude_of_projection_origin"] = {90.0};
80 mapping[
"scale_factor_at_projection_origin"] = {1.0};
81 mapping[
"straight_vertical_longitude_from_pole"] = {-45.0};
82 mapping[
"standard_parallel"] = {70.0};
83 mapping[
"false_northing"] = {0.0};
84 mapping[
"grid_mapping_name"] =
"polar_stereographic";
85 mapping[
"false_easting"] = {0.0};
88 mapping[
"latitude_of_projection_origin"] = {-90.0};
89 mapping[
"scale_factor_at_projection_origin"] = {1.0};
90 mapping[
"straight_vertical_longitude_from_pole"] = {0.0};
91 mapping[
"standard_parallel"] = {-71.0};
92 mapping[
"false_northing"] = {0.0};
93 mapping[
"grid_mapping_name"] =
"polar_stereographic";
94 mapping[
"false_easting"] = {0.0};
97 mapping[
"grid_mapping_name"] =
"lambert_conformal_conic" ;
98 mapping[
"longitude_of_central_meridian"] = {-19.} ;
99 mapping[
"false_easting"] = {500000.} ;
100 mapping[
"false_northing"] = {500000.} ;
101 mapping[
"latitude_of_projection_origin"] = {65.} ;
102 mapping[
"standard_parallel"] = {64.25, 65.75} ;
103 mapping[
"long_name"] =
"CRS definition" ;
104 mapping[
"longitude_of_prime_meridian"] = {0.} ;
105 mapping[
"semi_major_axis"] = {6378137.} ;
106 mapping[
"inverse_flattening"] = {298.257222101} ;
109 mapping[
"latitude_of_projection_origin"] = {90.0};
110 mapping[
"scale_factor_at_projection_origin"] = {1.0};
111 mapping[
"straight_vertical_longitude_from_pole"] = {-150.0};
112 mapping[
"standard_parallel"] = {90.0};
113 mapping[
"false_northing"] = {2000000.0};
114 mapping[
"grid_mapping_name"] =
"polar_stereographic";
115 mapping[
"false_easting"] = {2000000.0};
118 mapping[
"longitude_of_central_meridian"] = {-123.0};
119 mapping[
"false_easting"] = {500000.0};
120 mapping[
"false_northing"] = {0.0};
121 mapping[
"grid_mapping_name"] =
"transverse_mercator";
122 mapping[
"inverse_flattening"] = {294.978698213898};
123 mapping[
"latitude_of_projection_origin"] = {0.0};
124 mapping[
"scale_factor_at_central_meridian"] = {0.9996};
125 mapping[
"semi_major_axis"] = {6378206.4};
126 mapping[
"unit"] =
"metre";
130 (
int)epsg, proj_string.c_str());
143 if (mapping_is_empty and epsg_mapping_is_empty) {
152 "PROJ string \"%s\" requires %s = \"%s\",\n"
153 "but the mapping variable has no %s.",
155 s.first.c_str(), s.second.c_str(),
159 std::string
string = info.
mapping[s.first];
161 if (not (
string == s.second)) {
163 "%s requires %s = \"%s\",\n"
164 "but the mapping variable has %s = \"%s\".",
166 s.first.c_str(), s.second.c_str(),
176 "%s requires %s = %f,\n"
177 "but the mapping variable has no %s.",
179 d.first.c_str(), d.second[0],
185 if (std::fabs(value - d.second[0]) > 1e-12) {
187 "%s requires %s = %f,\n"
188 "but the mapping variable has %s = %f.",
190 d.first.c_str(), d.second[0],
204 bool proj_is_epsg =
false;
205 for (
const auto &auth : {
"epsg:",
"EPSG:"}) {
206 if (result.
proj.find(auth) != std::string::npos) {
242 #if (Pism_USE_PROJ==1)
245 static double triangle_area(
const double *A,
const double *B,
const double *
C) {
247 for (
int j = 0; j < 3; ++j) {
253 return 0.5*sqrt(pow(V1[1]*V2[2] - V2[1]*V1[2], 2) +
254 pow(V1[0]*V2[2] - V2[0]*V1[2], 2) +
255 pow(V1[0]*V2[1] - V2[0]*V1[1], 2));
259 auto grid = result.grid();
261 Proj pism_to_geocent(projection,
"+proj=geocent +datum=WGS84 +ellps=WGS84");
274 double dx2 = 0.5 * grid->dx(),
dy2 = 0.5 * grid->dy();
276 array::AccessScope list(result);
278 for (
auto p = grid->points(); p; p.next()) {
279 const int i = p.i(), j = p.j();
285 x_nw = x -
dx2, y_nw = y +
dy2,
286 x_ne = x +
dx2, y_ne = y +
dy2,
287 x_se = x +
dx2, y_se = y -
dy2,
288 x_sw = x -
dx2, y_sw = y -
dy2;
292 in.xy = {x_nw, y_nw};
293 out = proj_trans(*pism_to_geocent, PJ_FWD, in);
294 double nw[3] = {out.xyz.x, out.xyz.y, out.xyz.z};
296 in.xy = {x_ne, y_ne};
297 out = proj_trans(*pism_to_geocent, PJ_FWD, in);
298 double ne[3] = {out.xyz.x, out.xyz.y, out.xyz.z};
300 in.xy = {x_se, y_se};
301 out = proj_trans(*pism_to_geocent, PJ_FWD, in);
302 double se[3] = {out.xyz.x, out.xyz.y, out.xyz.z};
304 in.xy = {x_sw, y_sw};
305 out = proj_trans(*pism_to_geocent, PJ_FWD, in);
306 double sw[3] = {out.xyz.x, out.xyz.y, out.xyz.z};
313 LonLat which, array::Scalar &result) {
315 Proj crs(projection,
"EPSG:4326");
328 auto grid = result.grid();
330 array::AccessScope list{&result};
332 for (
auto p = grid->points(); p; p.next()) {
333 const int i = p.i(), j = p.j();
337 in.xy = {grid->x(i), grid->y(j)};
338 out = proj_trans(*crs, PJ_FWD, in);
341 result(i, j) = out.lp.phi;
343 result(i, j) = out.lp.lam;
350 array::Array3D &result) {
352 Proj crs(projection,
"EPSG:4326");
354 auto grid = result.grid();
356 double dx2 = 0.5 * grid->dx(),
dy2 = 0.5 * grid->dy();
360 array::AccessScope list{&result};
362 for (
auto p = grid->points(); p; p.next()) {
363 const int i = p.i(), j = p.j();
365 double x0 = grid->x(i), y0 = grid->y(j);
367 double *values = result.get_column(i, j);
369 for (
int k = 0;
k < 4; ++
k) {
373 in.xy = {x0 + x_offsets[
k], y0 + y_offsets[
k]};
376 out = proj_trans(*crs, PJ_FWD, in);
379 values[
k] = out.lp.lam;
381 values[
k] = out.lp.phi;
392 auto grid = result.
grid();
393 result.
set(grid->dx() * grid->dy());
403 " Please rebuild PISM with PROJ.");
414 " Please rebuild PISM with PROJ.");
435 #if (Pism_USE_PROJ==1)
436 Impl(
const std::string &proj_string) : coordinate_mapping(proj_string,
"EPSG:4326") {
438 Proj coordinate_mapping;
442 "Build PISM with PROJ to use pism::LonLatCalculator");
463 #if (Pism_USE_PROJ == 1)
467 out = proj_trans(*(
m_impl->coordinate_mapping), PJ_FWD, in);
469 return { out.lp.phi, out.lp.lam };
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.
std::string filename() const
std::string read_text_attribute(const std::string &var_name, const std::string &att_name) const
Get a text attribute.
High-level PISM I/O class.
std::array< double, 2 > lonlat(double x, double y) const
LonLatCalculator(const std::string &proj_string)
double lat(double x, double y) const
double lon(double x, double y) const
MappingInfo(const std::string &mapping_name, units::System::Ptr unit_system)
A wrapper for PJ that makes sure pj_destroy is called.
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
A virtual class collecting methods common to ice and bedrock 3D fields.
std::shared_ptr< const Grid > grid() const
void set(double c)
Result: v[j] <- c for all j.
std::shared_ptr< System > Ptr
#define PISM_ERROR_LOCATION
void read_attributes(const File &file, const std::string &variable_name, VariableMetadata &variable)
static void compute_lon_lat_bounds(const std::string &projection, LonLat which, array::Array3D &result)
void compute_latitude(const std::string &projection, array::Scalar &result)
void compute_longitude(const std::string &projection, array::Scalar &result)
VariableMetadata epsg_to_cf(units::System::Ptr system, const std::string &proj_string)
Return CF-Convention "mapping" variable corresponding to an EPSG code specified in a PROJ string.
void check_consistency_epsg(const MappingInfo &info)
Check consistency of the "mapping" variable with the EPSG code in the proj string.
static double triangle_area(const Point &a, const Point &b, const Point &c)
static void compute_lon_lat(const std::string &projection, LonLat which, array::Scalar &result)
MappingInfo get_projection_info(const File &input_file, const std::string &mapping_name, units::System::Ptr unit_system)
Get projection info from a file.
void compute_lat_bounds(const std::string &projection, array::Array3D &result)
void compute_cell_areas(const std::string &projection, array::Scalar &result)
void compute_lon_bounds(const std::string &projection, array::Array3D &result)
Impl(const std::string &)