PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/wrfv2_fire/external/io_grib_share/gridnav.c

http://github.com/jbeezley/wrf-fire
C | 493 lines | 338 code | 47 blank | 108 comment | 24 complexity | 5cf51504f56cb5cfd1965a6b3b6048db MD5 | raw file
Possible License(s): AGPL-1.0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <math.h>
  4. #include "gridnav.h"
  5. #define MISSING -999
  6. #define PI 3.1415927
  7. #define RAD_TO_DEG 57.29577951
  8. /* #define EARTH_RAD 6371.200 */
  9. #define EARTH_RAD 6370.000
  10. int fill_proj_parms(GridNav *gridnav);
  11. /*****************************************************************************
  12. * Fills up the gridnav structure using arguments input to the function
  13. *
  14. * input:
  15. * central_lat - the central latitude of the projection, in degrees
  16. * central_lon - the central longitude of the projection, in degrees
  17. * projection - the projection number (defined by #define's in gridnav.h)
  18. * truelat1 - the first "true" latitude. Only has an effect with
  19. * polar stereographic and lambert projections
  20. * truelat2 - the second true latitude. Only has an effect with lambert
  21. * projection
  22. * num_columns - number of columns in grid
  23. * num_rows - number of rows in grid
  24. * dx,dy - east-west (dx) and north-south (dy) distance between grid
  25. * points, in degrees for latlon (i.e., cylindrical
  26. * equidistant) projection, in km for all other projections
  27. * (including mercator).
  28. * lat_origin - latitude of grid point defined in origin_column, origin_row
  29. * lon_origin - longitude of grid point defined in origin_column, origin_row
  30. * origin_column - column for lat_origin, long_origin pair
  31. * origin_row - row for lat_origin, long_origin pair
  32. *
  33. * output:
  34. * gridnav - filled gridnav structure
  35. *
  36. *****************************************************************************/
  37. int GRID_init(float central_lat, float central_lon, int projection,
  38. float truelat1, float truelat2, int num_columns,
  39. int num_rows, float dx, float dy, float lat_origin,
  40. float lon_origin, float origin_column, float origin_row,
  41. GridNav *gridnav)
  42. {
  43. int status = 1;
  44. gridnav->proj.central_lon = central_lon;
  45. gridnav->proj.central_lat = central_lat;
  46. gridnav->proj.map_proj = projection;
  47. gridnav->proj.truelat1 = truelat1;
  48. gridnav->proj.truelat2 = truelat2;
  49. gridnav->grid.num_columns = num_columns;
  50. gridnav->grid.num_rows = num_rows;
  51. gridnav->grid.dx = dx;
  52. gridnav->grid.dy = dy;
  53. gridnav->grid.lat_origin = lat_origin;
  54. gridnav->grid.lon_origin = lon_origin;
  55. gridnav->grid.origin_column = origin_column;
  56. gridnav->grid.origin_row = origin_row;
  57. fill_proj_parms(gridnav);
  58. return status;
  59. }
  60. /*****************************************************************************
  61. * Outputs the latitude and longitude of a grid point.
  62. *
  63. * input:
  64. * *gridnav - a pointer to a filled gridnav structure. The gridnav
  65. * structure should have been filled using one of the init
  66. * functions.
  67. * column - the column in the grid to retrieve.
  68. * row - the row in the grid to retrieve.
  69. *
  70. * output:
  71. * *lat - pointer to output latitude
  72. * *lon - pointer to output longitude
  73. *
  74. *****************************************************************************/
  75. int GRID_to_latlon(GridNav *gridnav, float column, float row, float *lat,
  76. float *lon)
  77. {
  78. /*
  79. * Calculate the latitude and longitude for an input grid point location
  80. */
  81. double X, Y, R;
  82. int status = 1;
  83. double eps = 0.00001;
  84. switch (gridnav->proj.map_proj)
  85. {
  86. case GRID_MERCATOR:
  87. *lat = 2 * RAD_TO_DEG *
  88. atan(exp((gridnav->proj_transform.parm2 + gridnav->grid.dx *
  89. (row - gridnav->grid.origin_row)) /
  90. gridnav->proj_transform.parm1 )) - 90;
  91. *lon = gridnav->grid.lon_origin + RAD_TO_DEG * gridnav->grid.dx *
  92. (column - gridnav->grid.origin_column) /
  93. gridnav->proj_transform.parm1;
  94. break;
  95. case GRID_LAMCON:
  96. X = (column - gridnav->grid.origin_column) * gridnav->grid.dx +
  97. gridnav->proj_transform.parm6;
  98. Y = (row - gridnav->grid.origin_row) * gridnav->grid.dy +
  99. gridnav->proj_transform.parm3 + gridnav->proj_transform.parm7;
  100. R = sqrt(X*X + Y*Y);
  101. *lat = gridnav->proj_transform.parm5 * 90 -
  102. 2 * RAD_TO_DEG * atan(gridnav->proj_transform.parm4 *
  103. pow(R, 1 /
  104. gridnav->proj_transform.parm2));
  105. *lon = gridnav->proj.central_lon +
  106. RAD_TO_DEG / gridnav->proj_transform.parm2 *
  107. atan(X / (gridnav->proj_transform.parm5 * -Y));
  108. while (*lon > 180) *lon -= 360;
  109. while (*lon <= -180) *lon += 360;
  110. break;
  111. case GRID_POLSTR:
  112. X = (column - gridnav->grid.origin_column) *
  113. gridnav->proj_transform.parm3 +
  114. gridnav->proj_transform.parm1;
  115. Y = (row - gridnav->grid.origin_row) *
  116. gridnav->proj_transform.parm3 +
  117. gridnav->proj_transform.parm2 + eps;
  118. *lon = gridnav->proj_transform.parm5 * -1 *
  119. atan(X / Y) * RAD_TO_DEG + gridnav->proj.central_lon;
  120. *lat = (gridnav->proj_transform.parm5 * 90) - 2 * RAD_TO_DEG *
  121. atan(X / (2 * EARTH_RAD *
  122. sin((*lon - gridnav->proj.central_lon ) /
  123. RAD_TO_DEG) + eps) );
  124. while (*lon > 180) *lon -= 360;
  125. while (*lon <= -180) *lon += 360;
  126. break;
  127. case GRID_LATLON:
  128. *lat = (row - gridnav->grid.origin_row)*gridnav->grid.dy +
  129. gridnav->grid.lat_origin;
  130. *lon = (column - gridnav->grid.origin_column)*gridnav->grid.dx +
  131. gridnav->grid.lon_origin;
  132. break;
  133. default:
  134. /*
  135. * Unsupported map projection: set lat-lon to no-data values.
  136. */
  137. fprintf(stderr,"GRID_to_latlon: Unsupport map projection type %d\n",
  138. gridnav->proj.map_proj);
  139. *lon = -9999;
  140. *lat = -9999;
  141. status = 0;
  142. break;
  143. } /* end of switch on map projection type */
  144. return status;
  145. }
  146. /*****************************************************************************
  147. * Outputs grid point indices, given lat/lon location.
  148. *
  149. * input:
  150. * *gridnav - a pointer to a filled gridnav structure. The gridnav
  151. * structure should have been filled using one of the init
  152. * functions.
  153. * lat - latitude for location
  154. * lon - longitude for location
  155. * output:
  156. * *column - pointer to value for column
  157. * *row - pointer to value for row
  158. *
  159. *****************************************************************************/
  160. int GRID_from_latlon(GridNav *gridnav, float lat, float lon, float *column,
  161. float *row)
  162. {
  163. double X, Y, Rs;
  164. double lat_rad;
  165. int status = 1;
  166. switch (gridnav->proj.map_proj)
  167. {
  168. case GRID_MERCATOR:
  169. X = gridnav->proj_transform.parm1 *
  170. ((lon - gridnav->grid.lon_origin) / RAD_TO_DEG);
  171. *column = gridnav->grid.origin_column + X / gridnav->grid.dx;
  172. lat_rad = lat / RAD_TO_DEG;
  173. Y = gridnav->proj_transform.parm1 * log((1 + sin(lat_rad)) /
  174. cos(lat_rad));
  175. *row = gridnav->grid.origin_row +
  176. ((Y-gridnav->proj_transform.parm2) / gridnav->grid.dy);;
  177. break;
  178. case GRID_LAMCON:
  179. Rs = (EARTH_RAD / gridnav->proj_transform.parm2) *
  180. sin(gridnav->proj_transform.parm1) *
  181. pow(tan((gridnav->proj_transform.parm5 * 90 - lat) /
  182. (2 * RAD_TO_DEG))/
  183. tan(gridnav->proj_transform.parm1 / 2),
  184. gridnav->proj_transform.parm2);
  185. *row = gridnav->grid.origin_row -
  186. (1 / gridnav->grid.dy) *
  187. (gridnav->proj_transform.parm3 +
  188. Rs * cos(gridnav->proj_transform.parm2*
  189. (lon - gridnav->proj.central_lon) / RAD_TO_DEG)) -
  190. gridnav->proj_transform.parm7 / gridnav->grid.dy;
  191. *column = gridnav->grid.origin_column +
  192. ( gridnav->proj_transform.parm5*
  193. ((Rs / gridnav->grid.dx)*
  194. sin(gridnav->proj_transform.parm2 *
  195. (lon - gridnav->proj.central_lon) / RAD_TO_DEG) -
  196. gridnav->proj_transform.parm6 / gridnav->grid.dx));
  197. break;
  198. case GRID_POLSTR:
  199. Rs = 2 * EARTH_RAD * tan ( (45 - fabs(lat)/2) / RAD_TO_DEG );
  200. Y = gridnav->proj_transform.parm5 * -1 * Rs *
  201. cos ((lon - gridnav->proj.central_lon) / RAD_TO_DEG);
  202. X = Rs * sin ((lon - gridnav->proj.central_lon) / RAD_TO_DEG);
  203. *row = (Y - gridnav->proj_transform.parm2) /
  204. gridnav->proj_transform.parm3
  205. + gridnav->grid.origin_row;
  206. *column = (X - gridnav->proj_transform.parm1) /
  207. gridnav->proj_transform.parm3
  208. + gridnav->grid.origin_column;
  209. break;
  210. case GRID_LATLON:
  211. *row = ((lat - gridnav->grid.lat_origin) / gridnav->grid.dy) +
  212. gridnav->grid.origin_row;
  213. /* If lon is negative, make it positive */
  214. while (lon < 0) lon += 360.;
  215. *column = ((lon - gridnav->grid.lon_origin) / gridnav->grid.dx) +
  216. gridnav->grid.origin_column;
  217. break;
  218. default:
  219. fprintf(stderr,"GRID_from_latlon: Unsupported map projection type %d\n",
  220. gridnav->proj.map_proj);
  221. *column = -9999;
  222. *row = -9999;
  223. status = 0;
  224. break;
  225. } /* End of switch on map projection type */
  226. return status;
  227. }
  228. int fill_proj_parms(GridNav *gridnav)
  229. {
  230. double orig_lat_rad;
  231. double R_orig;
  232. double r_not;
  233. double r_truelat1;
  234. int hemifactor;
  235. switch (gridnav->proj.map_proj)
  236. {
  237. case GRID_MERCATOR:
  238. gridnav->proj_transform.parm1 =
  239. EARTH_RAD * cos(gridnav->proj.truelat1 / RAD_TO_DEG);
  240. orig_lat_rad = (gridnav->grid.lat_origin) / RAD_TO_DEG;
  241. gridnav->proj_transform.parm2 =
  242. gridnav->proj_transform.parm1 *
  243. log((1. + sin(orig_lat_rad)) / cos(orig_lat_rad));
  244. gridnav->proj_transform.parm3 = MISSING;
  245. gridnav->proj_transform.parm4 = MISSING;
  246. gridnav->proj_transform.parm5 = MISSING;
  247. break;
  248. case GRID_LAMCON:
  249. if (gridnav->proj.truelat1 >= 0)
  250. {
  251. hemifactor = 1;
  252. }
  253. else
  254. {
  255. hemifactor = -1;
  256. }
  257. /* This is Psi1 in MM5 speak */
  258. gridnav->proj_transform.parm1 =
  259. hemifactor*(PI/2 - fabs(gridnav->proj.truelat1) / RAD_TO_DEG);
  260. /* This is Kappa in MM5 speak */
  261. if (fabs(gridnav->proj.truelat1 - gridnav->proj.truelat2) < .01)
  262. {
  263. gridnav->proj_transform.parm2 =
  264. fabs(sin(gridnav->proj.truelat1 / RAD_TO_DEG));
  265. }
  266. else
  267. {
  268. gridnav->proj_transform.parm2 =
  269. (log10(cos(gridnav->proj.truelat1 / RAD_TO_DEG)) -
  270. log10(cos(gridnav->proj.truelat2 / RAD_TO_DEG))) /
  271. (log10(tan((45 - fabs(gridnav->proj.truelat1) / 2) / RAD_TO_DEG)) -
  272. log10(tan((45 - fabs(gridnav->proj.truelat2) / 2) / RAD_TO_DEG)));
  273. }
  274. /* This is Yc in MM5 speak */
  275. gridnav->proj_transform.parm3 =
  276. -EARTH_RAD/gridnav->proj_transform.parm2 *
  277. sin(gridnav->proj_transform.parm1) *
  278. pow(
  279. (tan((hemifactor * 90 - gridnav->grid.lat_origin) /
  280. (RAD_TO_DEG * 2)) /
  281. tan(gridnav->proj_transform.parm1 / 2)),
  282. gridnav->proj_transform.parm2);
  283. gridnav->proj_transform.parm4 =
  284. tan(gridnav->proj_transform.parm1 / 2)*
  285. pow(hemifactor * (gridnav->proj_transform.parm2)/
  286. (EARTH_RAD * sin(gridnav->proj_transform.parm1)),
  287. 1 / gridnav->proj_transform.parm2);
  288. gridnav->proj_transform.parm5 = hemifactor;
  289. R_orig = (EARTH_RAD / gridnav->proj_transform.parm2) *
  290. sin(gridnav->proj_transform.parm1) *
  291. pow(tan((gridnav->proj_transform.parm5 * 90 -
  292. gridnav->grid.lat_origin) /
  293. (2 * RAD_TO_DEG))/
  294. tan(gridnav->proj_transform.parm1 / 2),
  295. gridnav->proj_transform.parm2);
  296. /* X origin */
  297. gridnav->proj_transform.parm6 =
  298. R_orig * sin(gridnav->proj_transform.parm2 *
  299. (gridnav->grid.lon_origin -
  300. gridnav->proj.central_lon) / RAD_TO_DEG);
  301. /* Y origin */
  302. gridnav->proj_transform.parm7 = -(gridnav->proj_transform.parm3 +
  303. R_orig * cos(gridnav->proj_transform.parm2 *
  304. (gridnav->grid.lon_origin -
  305. gridnav->proj.central_lon) / RAD_TO_DEG));
  306. break;
  307. case GRID_POLSTR:
  308. if (gridnav->proj.central_lat > 0)
  309. {
  310. hemifactor = 1;
  311. }
  312. else
  313. {
  314. hemifactor = -1;
  315. }
  316. /* Calculate X for origin */
  317. r_not = 2 * EARTH_RAD *
  318. tan((45 - fabs(gridnav->grid.lat_origin) / 2) / RAD_TO_DEG);
  319. gridnav->proj_transform.parm1 =
  320. r_not *
  321. sin ( (gridnav->grid.lon_origin - gridnav->proj.central_lon) /
  322. RAD_TO_DEG);
  323. /* Calculate Y for origin */
  324. gridnav->proj_transform.parm2 =
  325. hemifactor * -1 * r_not *
  326. cos ( (gridnav->grid.lon_origin - gridnav->proj.central_lon) /
  327. RAD_TO_DEG);
  328. /* Calculate grid spacing at pole */
  329. r_truelat1 = 2 * EARTH_RAD *
  330. tan((45 - fabs(gridnav->proj.truelat1) / 2) / RAD_TO_DEG);
  331. gridnav->proj_transform.parm3 =
  332. gridnav->grid.dx * r_truelat1 /
  333. ( EARTH_RAD * cos (gridnav->proj.truelat1 / RAD_TO_DEG));
  334. gridnav->proj_transform.parm4 = MISSING;
  335. gridnav->proj_transform.parm5 = hemifactor;
  336. break;
  337. case GRID_LATLON:
  338. gridnav->proj_transform.parm1 = MISSING;
  339. gridnav->proj_transform.parm2 = MISSING;
  340. gridnav->proj_transform.parm3 = MISSING;
  341. gridnav->proj_transform.parm4 = MISSING;
  342. gridnav->proj_transform.parm5 = MISSING;
  343. break;
  344. default:
  345. fprintf(stderr,"GRID_init_mm5data: Invalid Projection\n");
  346. return 0;
  347. }
  348. return 1;
  349. }
  350. /*****************************************************************************
  351. * Rotates u and v components of wind, from being relative to earth, to
  352. * relative to grid.
  353. *
  354. * input:
  355. * *gridnav - a pointer to a filled gridnav structure. The gridnav
  356. * structure should have been filled using one of the init
  357. * functions.
  358. * lon - longitude for location
  359. * u_earth - the u component of the wind in earth (north-relative)
  360. * coordinates.
  361. * v_earth - the v component of the wind in earth (north-relative)
  362. * coordinates.
  363. * output:
  364. * *u_grid - pointer to value for u in grid coordinates
  365. * *v_grid - pointer to value for v in grid coordinates
  366. *
  367. *****************************************************************************/
  368. int GRID_rotate_from_earth_coords(GridNav *gridnav, float lon, float u_earth,
  369. float v_earth, float *u_grid, float *v_grid)
  370. {
  371. float speed, dir;
  372. float dir_grid;
  373. /* Calculate Speed and Direction from u,v */
  374. switch (gridnav->proj.map_proj)
  375. {
  376. case GRID_MERCATOR:
  377. *u_grid = u_earth;
  378. *v_grid = v_earth;
  379. break;
  380. case GRID_POLSTR: case GRID_LAMCON:
  381. speed = sqrt(u_earth * u_earth + v_earth * v_earth);
  382. dir = RAD_TO_DEG * atan2(-u_earth,-v_earth);
  383. while (dir >= 360) dir -= 360;
  384. while (dir < 0) dir += 360;
  385. dir_grid = dir - (lon - gridnav->proj.central_lon) *
  386. gridnav->proj_transform.parm2;
  387. while (dir_grid >= 360) dir_grid -= 360;
  388. while (dir_grid < 0) dir_grid += 360;
  389. *u_grid = -1. * speed * sin(dir_grid / RAD_TO_DEG);
  390. *v_grid = -1. * speed * cos(dir_grid / RAD_TO_DEG);
  391. break;
  392. default:
  393. fprintf(stderr,
  394. "GRID_rotate_from_earth_coords: Invalid Projection\n");
  395. return 0;
  396. } /* End of switch projection */
  397. return 1;
  398. }
  399. /*****************************************************************************
  400. * Rotates u and v components of wind, from being relative to earth, to
  401. * relative to grid.
  402. *
  403. * input:
  404. * *gridnav - a pointer to a filled gridnav structure. The gridnav
  405. * structure should have been filled using one of the init
  406. * functions.
  407. * lon - longitude for location
  408. * u_grid - the u component of the wind in grid coordinates
  409. * v_grid - the v component of the wind in grid coordinates
  410. *
  411. * output:
  412. * *u_earth - pointer to value for u in earth-relative coordinates
  413. * *v_grid - pointer to value for v in earth-relative coordinates
  414. *
  415. *****************************************************************************/
  416. int GRID_rotate_to_earth_coords(GridNav *gridnav, float lon, float u_grid,
  417. float v_grid, float *u_earth, float *v_earth)
  418. {
  419. float speed, dir_grid;
  420. float dir_earth;
  421. /* Calculate Speed and Direction from u,v */
  422. switch (gridnav->proj.map_proj)
  423. {
  424. case GRID_MERCATOR:
  425. *u_earth = u_grid;
  426. *v_earth = v_grid;
  427. break;
  428. case GRID_POLSTR: case GRID_LAMCON:
  429. speed = sqrt(u_grid * u_grid + v_grid * v_grid);
  430. dir_grid = RAD_TO_DEG * atan2(-u_grid, -v_grid);
  431. while (dir_grid >= 360) dir_grid -= 360;
  432. while (dir_grid < 0) dir_grid += 360;
  433. dir_earth = dir_grid + (lon - gridnav->proj.central_lon) *
  434. gridnav->proj_transform.parm2;
  435. while (dir_earth >= 360) dir_earth -= 360;
  436. while (dir_earth < 0) dir_earth += 360;
  437. *u_earth = -1. * speed * sin(dir_earth / RAD_TO_DEG);
  438. *v_earth = -1. * speed * cos(dir_earth / RAD_TO_DEG);
  439. break;
  440. default:
  441. fprintf(stderr,
  442. "GRID_rotate_to_earth_coords: Invalid Projection\n");
  443. return 0;
  444. } /* End of switch projection */
  445. return 1;
  446. }