gphys 1.2.2.1 → 1.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (405) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -17
  3. data/.rspec +2 -0
  4. data/.travis.yml +3 -0
  5. data/ChangeLog +5762 -753
  6. data/LICENSE.txt +30 -18
  7. data/Rakefile +1 -0
  8. data/bin/console +14 -0
  9. data/bin/gpcat +43 -2
  10. data/bin/gpcut +16 -0
  11. data/bin/gpvect +167 -15
  12. data/bin/gpview +254 -51
  13. data/bin/setup +7 -0
  14. data/dim_op.c +1220 -0
  15. data/doc/attribute.html +19 -0
  16. data/doc/attributenetcdf.html +15 -0
  17. data/doc/axis.html +387 -0
  18. data/doc/coordmapping.html +111 -0
  19. data/doc/coordtransform.html +36 -0
  20. data/doc/dclext.html +821 -0
  21. data/doc/derivative/gphys-derivative.html +100 -0
  22. data/doc/derivative/index.html +21 -0
  23. data/doc/derivative/index.rd +14 -0
  24. data/doc/derivative/math-doc/document.pdf +0 -0
  25. data/doc/derivative/math-doc/document.tex +158 -0
  26. data/doc/derivative/math-doc/document/document.css +30 -0
  27. data/doc/derivative/math-doc/document/document.html +57 -0
  28. data/doc/derivative/math-doc/document/images.aux +1 -0
  29. data/doc/derivative/math-doc/document/images.log +385 -0
  30. data/doc/derivative/math-doc/document/images.pl +186 -0
  31. data/doc/derivative/math-doc/document/images.tex +364 -0
  32. data/doc/derivative/math-doc/document/img1.png +0 -0
  33. data/doc/derivative/math-doc/document/img10.png +0 -0
  34. data/doc/derivative/math-doc/document/img11.png +0 -0
  35. data/doc/derivative/math-doc/document/img12.png +0 -0
  36. data/doc/derivative/math-doc/document/img13.png +0 -0
  37. data/doc/derivative/math-doc/document/img14.png +0 -0
  38. data/doc/derivative/math-doc/document/img15.png +0 -0
  39. data/doc/derivative/math-doc/document/img16.png +0 -0
  40. data/doc/derivative/math-doc/document/img17.png +0 -0
  41. data/doc/derivative/math-doc/document/img18.png +0 -0
  42. data/doc/derivative/math-doc/document/img19.png +0 -0
  43. data/doc/derivative/math-doc/document/img2.png +0 -0
  44. data/doc/derivative/math-doc/document/img20.png +0 -0
  45. data/doc/derivative/math-doc/document/img21.png +0 -0
  46. data/doc/derivative/math-doc/document/img22.png +0 -0
  47. data/doc/derivative/math-doc/document/img23.png +0 -0
  48. data/doc/derivative/math-doc/document/img24.png +0 -0
  49. data/doc/derivative/math-doc/document/img25.png +0 -0
  50. data/doc/derivative/math-doc/document/img26.png +0 -0
  51. data/doc/derivative/math-doc/document/img27.png +0 -0
  52. data/doc/derivative/math-doc/document/img28.png +0 -0
  53. data/doc/derivative/math-doc/document/img29.png +0 -0
  54. data/doc/derivative/math-doc/document/img3.png +0 -0
  55. data/doc/derivative/math-doc/document/img30.png +0 -0
  56. data/doc/derivative/math-doc/document/img4.png +0 -0
  57. data/doc/derivative/math-doc/document/img5.png +0 -0
  58. data/doc/derivative/math-doc/document/img6.png +0 -0
  59. data/doc/derivative/math-doc/document/img7.png +0 -0
  60. data/doc/derivative/math-doc/document/img8.png +0 -0
  61. data/doc/derivative/math-doc/document/img9.png +0 -0
  62. data/doc/derivative/math-doc/document/index.html +57 -0
  63. data/doc/derivative/math-doc/document/labels.pl +13 -0
  64. data/doc/derivative/math-doc/document/next.png +0 -0
  65. data/doc/derivative/math-doc/document/next_g.png +0 -0
  66. data/doc/derivative/math-doc/document/node1.html +238 -0
  67. data/doc/derivative/math-doc/document/node2.html +75 -0
  68. data/doc/derivative/math-doc/document/prev.png +0 -0
  69. data/doc/derivative/math-doc/document/prev_g.png +0 -0
  70. data/doc/derivative/math-doc/document/up.png +0 -0
  71. data/doc/derivative/math-doc/document/up_g.png +0 -0
  72. data/doc/derivative/numru-derivative.html +158 -0
  73. data/doc/ep_flux/ep_flux.html +469 -0
  74. data/doc/ep_flux/ggraph_on_merdional_section.html +71 -0
  75. data/doc/ep_flux/index.html +31 -0
  76. data/doc/ep_flux/index.rd +24 -0
  77. data/doc/ep_flux/math-doc/document.pdf +0 -0
  78. data/doc/ep_flux/math-doc/document.tex +2018 -0
  79. data/doc/ep_flux/math-doc/document/WARNINGS +1 -0
  80. data/doc/ep_flux/math-doc/document/contents.png +0 -0
  81. data/doc/ep_flux/math-doc/document/crossref.png +0 -0
  82. data/doc/ep_flux/math-doc/document/document.css +30 -0
  83. data/doc/ep_flux/math-doc/document/document.html +101 -0
  84. data/doc/ep_flux/math-doc/document/images.aux +1 -0
  85. data/doc/ep_flux/math-doc/document/images.log +1375 -0
  86. data/doc/ep_flux/math-doc/document/images.pl +1328 -0
  87. data/doc/ep_flux/math-doc/document/images.tex +1471 -0
  88. data/doc/ep_flux/math-doc/document/img1.png +0 -0
  89. data/doc/ep_flux/math-doc/document/img10.png +0 -0
  90. data/doc/ep_flux/math-doc/document/img100.png +0 -0
  91. data/doc/ep_flux/math-doc/document/img101.png +0 -0
  92. data/doc/ep_flux/math-doc/document/img102.png +0 -0
  93. data/doc/ep_flux/math-doc/document/img103.png +0 -0
  94. data/doc/ep_flux/math-doc/document/img104.png +0 -0
  95. data/doc/ep_flux/math-doc/document/img105.png +0 -0
  96. data/doc/ep_flux/math-doc/document/img106.png +0 -0
  97. data/doc/ep_flux/math-doc/document/img107.png +0 -0
  98. data/doc/ep_flux/math-doc/document/img108.png +0 -0
  99. data/doc/ep_flux/math-doc/document/img109.png +0 -0
  100. data/doc/ep_flux/math-doc/document/img11.png +0 -0
  101. data/doc/ep_flux/math-doc/document/img110.png +0 -0
  102. data/doc/ep_flux/math-doc/document/img111.png +0 -0
  103. data/doc/ep_flux/math-doc/document/img112.png +0 -0
  104. data/doc/ep_flux/math-doc/document/img113.png +0 -0
  105. data/doc/ep_flux/math-doc/document/img114.png +0 -0
  106. data/doc/ep_flux/math-doc/document/img115.png +0 -0
  107. data/doc/ep_flux/math-doc/document/img116.png +0 -0
  108. data/doc/ep_flux/math-doc/document/img117.png +0 -0
  109. data/doc/ep_flux/math-doc/document/img118.png +0 -0
  110. data/doc/ep_flux/math-doc/document/img119.png +0 -0
  111. data/doc/ep_flux/math-doc/document/img12.png +0 -0
  112. data/doc/ep_flux/math-doc/document/img120.png +0 -0
  113. data/doc/ep_flux/math-doc/document/img121.png +0 -0
  114. data/doc/ep_flux/math-doc/document/img122.png +0 -0
  115. data/doc/ep_flux/math-doc/document/img123.png +0 -0
  116. data/doc/ep_flux/math-doc/document/img124.png +0 -0
  117. data/doc/ep_flux/math-doc/document/img125.png +0 -0
  118. data/doc/ep_flux/math-doc/document/img126.png +0 -0
  119. data/doc/ep_flux/math-doc/document/img127.png +0 -0
  120. data/doc/ep_flux/math-doc/document/img128.png +0 -0
  121. data/doc/ep_flux/math-doc/document/img129.png +0 -0
  122. data/doc/ep_flux/math-doc/document/img13.png +0 -0
  123. data/doc/ep_flux/math-doc/document/img130.png +0 -0
  124. data/doc/ep_flux/math-doc/document/img131.png +0 -0
  125. data/doc/ep_flux/math-doc/document/img132.png +0 -0
  126. data/doc/ep_flux/math-doc/document/img133.png +0 -0
  127. data/doc/ep_flux/math-doc/document/img134.png +0 -0
  128. data/doc/ep_flux/math-doc/document/img135.png +0 -0
  129. data/doc/ep_flux/math-doc/document/img136.png +0 -0
  130. data/doc/ep_flux/math-doc/document/img137.png +0 -0
  131. data/doc/ep_flux/math-doc/document/img138.png +0 -0
  132. data/doc/ep_flux/math-doc/document/img139.png +0 -0
  133. data/doc/ep_flux/math-doc/document/img14.png +0 -0
  134. data/doc/ep_flux/math-doc/document/img140.png +0 -0
  135. data/doc/ep_flux/math-doc/document/img141.png +0 -0
  136. data/doc/ep_flux/math-doc/document/img142.png +0 -0
  137. data/doc/ep_flux/math-doc/document/img143.png +0 -0
  138. data/doc/ep_flux/math-doc/document/img144.png +0 -0
  139. data/doc/ep_flux/math-doc/document/img145.png +0 -0
  140. data/doc/ep_flux/math-doc/document/img146.png +0 -0
  141. data/doc/ep_flux/math-doc/document/img147.png +0 -0
  142. data/doc/ep_flux/math-doc/document/img148.png +0 -0
  143. data/doc/ep_flux/math-doc/document/img149.png +0 -0
  144. data/doc/ep_flux/math-doc/document/img15.png +0 -0
  145. data/doc/ep_flux/math-doc/document/img150.png +0 -0
  146. data/doc/ep_flux/math-doc/document/img151.png +0 -0
  147. data/doc/ep_flux/math-doc/document/img152.png +0 -0
  148. data/doc/ep_flux/math-doc/document/img153.png +0 -0
  149. data/doc/ep_flux/math-doc/document/img154.png +0 -0
  150. data/doc/ep_flux/math-doc/document/img155.png +0 -0
  151. data/doc/ep_flux/math-doc/document/img156.png +0 -0
  152. data/doc/ep_flux/math-doc/document/img157.png +0 -0
  153. data/doc/ep_flux/math-doc/document/img158.png +0 -0
  154. data/doc/ep_flux/math-doc/document/img159.png +0 -0
  155. data/doc/ep_flux/math-doc/document/img16.png +0 -0
  156. data/doc/ep_flux/math-doc/document/img160.png +0 -0
  157. data/doc/ep_flux/math-doc/document/img161.png +0 -0
  158. data/doc/ep_flux/math-doc/document/img162.png +0 -0
  159. data/doc/ep_flux/math-doc/document/img163.png +0 -0
  160. data/doc/ep_flux/math-doc/document/img164.png +0 -0
  161. data/doc/ep_flux/math-doc/document/img165.png +0 -0
  162. data/doc/ep_flux/math-doc/document/img166.png +0 -0
  163. data/doc/ep_flux/math-doc/document/img167.png +0 -0
  164. data/doc/ep_flux/math-doc/document/img168.png +0 -0
  165. data/doc/ep_flux/math-doc/document/img169.png +0 -0
  166. data/doc/ep_flux/math-doc/document/img17.png +0 -0
  167. data/doc/ep_flux/math-doc/document/img170.png +0 -0
  168. data/doc/ep_flux/math-doc/document/img171.png +0 -0
  169. data/doc/ep_flux/math-doc/document/img172.png +0 -0
  170. data/doc/ep_flux/math-doc/document/img173.png +0 -0
  171. data/doc/ep_flux/math-doc/document/img174.png +0 -0
  172. data/doc/ep_flux/math-doc/document/img175.png +0 -0
  173. data/doc/ep_flux/math-doc/document/img176.png +0 -0
  174. data/doc/ep_flux/math-doc/document/img177.png +0 -0
  175. data/doc/ep_flux/math-doc/document/img178.png +0 -0
  176. data/doc/ep_flux/math-doc/document/img179.png +0 -0
  177. data/doc/ep_flux/math-doc/document/img18.png +0 -0
  178. data/doc/ep_flux/math-doc/document/img180.png +0 -0
  179. data/doc/ep_flux/math-doc/document/img181.png +0 -0
  180. data/doc/ep_flux/math-doc/document/img182.png +0 -0
  181. data/doc/ep_flux/math-doc/document/img183.png +0 -0
  182. data/doc/ep_flux/math-doc/document/img184.png +0 -0
  183. data/doc/ep_flux/math-doc/document/img185.png +0 -0
  184. data/doc/ep_flux/math-doc/document/img186.png +0 -0
  185. data/doc/ep_flux/math-doc/document/img187.png +0 -0
  186. data/doc/ep_flux/math-doc/document/img188.png +0 -0
  187. data/doc/ep_flux/math-doc/document/img189.png +0 -0
  188. data/doc/ep_flux/math-doc/document/img19.png +0 -0
  189. data/doc/ep_flux/math-doc/document/img190.png +0 -0
  190. data/doc/ep_flux/math-doc/document/img191.png +0 -0
  191. data/doc/ep_flux/math-doc/document/img192.png +0 -0
  192. data/doc/ep_flux/math-doc/document/img193.png +0 -0
  193. data/doc/ep_flux/math-doc/document/img194.png +0 -0
  194. data/doc/ep_flux/math-doc/document/img195.png +0 -0
  195. data/doc/ep_flux/math-doc/document/img196.png +0 -0
  196. data/doc/ep_flux/math-doc/document/img197.png +0 -0
  197. data/doc/ep_flux/math-doc/document/img198.png +0 -0
  198. data/doc/ep_flux/math-doc/document/img199.png +0 -0
  199. data/doc/ep_flux/math-doc/document/img2.png +0 -0
  200. data/doc/ep_flux/math-doc/document/img20.png +0 -0
  201. data/doc/ep_flux/math-doc/document/img200.png +0 -0
  202. data/doc/ep_flux/math-doc/document/img21.png +0 -0
  203. data/doc/ep_flux/math-doc/document/img22.png +0 -0
  204. data/doc/ep_flux/math-doc/document/img23.png +0 -0
  205. data/doc/ep_flux/math-doc/document/img24.png +0 -0
  206. data/doc/ep_flux/math-doc/document/img25.png +0 -0
  207. data/doc/ep_flux/math-doc/document/img26.png +0 -0
  208. data/doc/ep_flux/math-doc/document/img27.png +0 -0
  209. data/doc/ep_flux/math-doc/document/img28.png +0 -0
  210. data/doc/ep_flux/math-doc/document/img29.png +0 -0
  211. data/doc/ep_flux/math-doc/document/img3.png +0 -0
  212. data/doc/ep_flux/math-doc/document/img30.png +0 -0
  213. data/doc/ep_flux/math-doc/document/img31.png +0 -0
  214. data/doc/ep_flux/math-doc/document/img32.png +0 -0
  215. data/doc/ep_flux/math-doc/document/img33.png +0 -0
  216. data/doc/ep_flux/math-doc/document/img34.png +0 -0
  217. data/doc/ep_flux/math-doc/document/img35.png +0 -0
  218. data/doc/ep_flux/math-doc/document/img36.png +0 -0
  219. data/doc/ep_flux/math-doc/document/img37.png +0 -0
  220. data/doc/ep_flux/math-doc/document/img38.png +0 -0
  221. data/doc/ep_flux/math-doc/document/img39.png +0 -0
  222. data/doc/ep_flux/math-doc/document/img4.png +0 -0
  223. data/doc/ep_flux/math-doc/document/img40.png +0 -0
  224. data/doc/ep_flux/math-doc/document/img41.png +0 -0
  225. data/doc/ep_flux/math-doc/document/img42.png +0 -0
  226. data/doc/ep_flux/math-doc/document/img43.png +0 -0
  227. data/doc/ep_flux/math-doc/document/img44.png +0 -0
  228. data/doc/ep_flux/math-doc/document/img45.png +0 -0
  229. data/doc/ep_flux/math-doc/document/img46.png +0 -0
  230. data/doc/ep_flux/math-doc/document/img47.png +0 -0
  231. data/doc/ep_flux/math-doc/document/img48.png +0 -0
  232. data/doc/ep_flux/math-doc/document/img49.png +0 -0
  233. data/doc/ep_flux/math-doc/document/img5.png +0 -0
  234. data/doc/ep_flux/math-doc/document/img50.png +0 -0
  235. data/doc/ep_flux/math-doc/document/img51.png +0 -0
  236. data/doc/ep_flux/math-doc/document/img52.png +0 -0
  237. data/doc/ep_flux/math-doc/document/img53.png +0 -0
  238. data/doc/ep_flux/math-doc/document/img54.png +0 -0
  239. data/doc/ep_flux/math-doc/document/img55.png +0 -0
  240. data/doc/ep_flux/math-doc/document/img56.png +0 -0
  241. data/doc/ep_flux/math-doc/document/img57.png +0 -0
  242. data/doc/ep_flux/math-doc/document/img58.png +0 -0
  243. data/doc/ep_flux/math-doc/document/img59.png +0 -0
  244. data/doc/ep_flux/math-doc/document/img6.png +0 -0
  245. data/doc/ep_flux/math-doc/document/img60.png +0 -0
  246. data/doc/ep_flux/math-doc/document/img61.png +0 -0
  247. data/doc/ep_flux/math-doc/document/img62.png +0 -0
  248. data/doc/ep_flux/math-doc/document/img63.png +0 -0
  249. data/doc/ep_flux/math-doc/document/img64.png +0 -0
  250. data/doc/ep_flux/math-doc/document/img65.png +0 -0
  251. data/doc/ep_flux/math-doc/document/img66.png +0 -0
  252. data/doc/ep_flux/math-doc/document/img67.png +0 -0
  253. data/doc/ep_flux/math-doc/document/img68.png +0 -0
  254. data/doc/ep_flux/math-doc/document/img69.png +0 -0
  255. data/doc/ep_flux/math-doc/document/img7.png +0 -0
  256. data/doc/ep_flux/math-doc/document/img70.png +0 -0
  257. data/doc/ep_flux/math-doc/document/img71.png +0 -0
  258. data/doc/ep_flux/math-doc/document/img72.png +0 -0
  259. data/doc/ep_flux/math-doc/document/img73.png +0 -0
  260. data/doc/ep_flux/math-doc/document/img74.png +0 -0
  261. data/doc/ep_flux/math-doc/document/img75.png +0 -0
  262. data/doc/ep_flux/math-doc/document/img76.png +0 -0
  263. data/doc/ep_flux/math-doc/document/img77.png +0 -0
  264. data/doc/ep_flux/math-doc/document/img78.png +0 -0
  265. data/doc/ep_flux/math-doc/document/img79.png +0 -0
  266. data/doc/ep_flux/math-doc/document/img8.png +0 -0
  267. data/doc/ep_flux/math-doc/document/img80.png +0 -0
  268. data/doc/ep_flux/math-doc/document/img81.png +0 -0
  269. data/doc/ep_flux/math-doc/document/img82.png +0 -0
  270. data/doc/ep_flux/math-doc/document/img83.png +0 -0
  271. data/doc/ep_flux/math-doc/document/img84.png +0 -0
  272. data/doc/ep_flux/math-doc/document/img85.png +0 -0
  273. data/doc/ep_flux/math-doc/document/img86.png +0 -0
  274. data/doc/ep_flux/math-doc/document/img87.png +0 -0
  275. data/doc/ep_flux/math-doc/document/img88.png +0 -0
  276. data/doc/ep_flux/math-doc/document/img89.png +0 -0
  277. data/doc/ep_flux/math-doc/document/img9.png +0 -0
  278. data/doc/ep_flux/math-doc/document/img90.png +0 -0
  279. data/doc/ep_flux/math-doc/document/img91.png +0 -0
  280. data/doc/ep_flux/math-doc/document/img92.png +0 -0
  281. data/doc/ep_flux/math-doc/document/img93.png +0 -0
  282. data/doc/ep_flux/math-doc/document/img94.png +0 -0
  283. data/doc/ep_flux/math-doc/document/img95.png +0 -0
  284. data/doc/ep_flux/math-doc/document/img96.png +0 -0
  285. data/doc/ep_flux/math-doc/document/img97.png +0 -0
  286. data/doc/ep_flux/math-doc/document/img98.png +0 -0
  287. data/doc/ep_flux/math-doc/document/img99.png +0 -0
  288. data/doc/ep_flux/math-doc/document/index.html +101 -0
  289. data/doc/ep_flux/math-doc/document/internals.pl +258 -0
  290. data/doc/ep_flux/math-doc/document/labels.pl +265 -0
  291. data/doc/ep_flux/math-doc/document/next.png +0 -0
  292. data/doc/ep_flux/math-doc/document/next_g.png +0 -0
  293. data/doc/ep_flux/math-doc/document/node1.html +104 -0
  294. data/doc/ep_flux/math-doc/document/node10.html +164 -0
  295. data/doc/ep_flux/math-doc/document/node11.html +86 -0
  296. data/doc/ep_flux/math-doc/document/node12.html +166 -0
  297. data/doc/ep_flux/math-doc/document/node13.html +897 -0
  298. data/doc/ep_flux/math-doc/document/node14.html +1065 -0
  299. data/doc/ep_flux/math-doc/document/node15.html +72 -0
  300. data/doc/ep_flux/math-doc/document/node16.html +81 -0
  301. data/doc/ep_flux/math-doc/document/node2.html +82 -0
  302. data/doc/ep_flux/math-doc/document/node3.html +91 -0
  303. data/doc/ep_flux/math-doc/document/node4.html +149 -0
  304. data/doc/ep_flux/math-doc/document/node5.html +330 -0
  305. data/doc/ep_flux/math-doc/document/node6.html +99 -0
  306. data/doc/ep_flux/math-doc/document/node7.html +98 -0
  307. data/doc/ep_flux/math-doc/document/node8.html +83 -0
  308. data/doc/ep_flux/math-doc/document/node9.html +140 -0
  309. data/doc/ep_flux/math-doc/document/prev.png +0 -0
  310. data/doc/ep_flux/math-doc/document/prev_g.png +0 -0
  311. data/doc/ep_flux/math-doc/document/up.png +0 -0
  312. data/doc/ep_flux/math-doc/document/up_g.png +0 -0
  313. data/doc/gdir.html +412 -0
  314. data/doc/gdir_client.html +16 -0
  315. data/doc/gdir_connect_ftp-like.html +61 -0
  316. data/doc/gdir_server.html +45 -0
  317. data/doc/ggraph.html +1119 -0
  318. data/doc/gpcat.html +45 -0
  319. data/doc/gpcut.html +47 -0
  320. data/doc/gphys.html +624 -0
  321. data/doc/gphys_fft.html +324 -0
  322. data/doc/gphys_grads_io.html +69 -0
  323. data/doc/gphys_grib_io.html +82 -0
  324. data/doc/gphys_io.html +183 -0
  325. data/doc/gphys_io_common.html +18 -0
  326. data/doc/gphys_netcdf_io.html +283 -0
  327. data/doc/gplist.html +24 -0
  328. data/doc/gpmath.html +52 -0
  329. data/doc/gpmaxmin.html +32 -0
  330. data/doc/gpprint.html +35 -0
  331. data/doc/gpview.html +349 -0
  332. data/doc/grads2nc_with_gphys.html +21 -0
  333. data/doc/grads_gridded.html +307 -0
  334. data/doc/grib.html +149 -0
  335. data/doc/grid.html +224 -0
  336. data/doc/index.html +145 -0
  337. data/doc/index.rd +138 -0
  338. data/doc/netcdf_convention.html +136 -0
  339. data/doc/unumeric.html +176 -0
  340. data/doc/update +69 -0
  341. data/doc/update_rdoc +8 -0
  342. data/doc/varray.html +299 -0
  343. data/doc/varraycomposite.html +67 -0
  344. data/ext_init.c +1 -0
  345. data/extconf.rb +16 -6
  346. data/gphys.gemspec +33 -26
  347. data/interpo.c +1 -1
  348. data/lib/numru/dclext.rb +718 -546
  349. data/lib/numru/derivative.rb +2 -0
  350. data/lib/numru/ganalysis.rb +38 -0
  351. data/lib/numru/ganalysis/beta_plane.rb +103 -0
  352. data/lib/numru/ganalysis/eof.rb +3 -2
  353. data/lib/numru/ganalysis/fitting.rb +559 -0
  354. data/lib/numru/ganalysis/histogram.rb +36 -19
  355. data/lib/numru/ganalysis/log_p.rb +130 -0
  356. data/lib/numru/ganalysis/met.rb +396 -2
  357. data/lib/numru/ganalysis/met_z.rb +300 -0
  358. data/lib/numru/ganalysis/planet.rb +17 -7
  359. data/lib/numru/ganalysis/qg.rb +685 -0
  360. data/lib/numru/ganalysis/sigma_coord.rb +90 -0
  361. data/lib/numru/gdir.rb +2 -1
  362. data/lib/numru/ggraph.rb +204 -60
  363. data/lib/numru/ggraph_on_merdional_section.rb +1 -1
  364. data/lib/numru/gphys.rb +6 -0
  365. data/lib/numru/gphys/assoccoords.rb +18 -3
  366. data/lib/numru/gphys/axis.rb +209 -8
  367. data/lib/numru/gphys/derivative.rb +11 -0
  368. data/lib/numru/gphys/gphys.rb +539 -48
  369. data/lib/numru/gphys/gphys_dim_op.rb +331 -0
  370. data/lib/numru/gphys/gphys_fft.rb +48 -2
  371. data/lib/numru/gphys/gphys_io.rb +241 -13
  372. data/lib/numru/gphys/gphys_netcdf_io.rb +77 -39
  373. data/lib/numru/gphys/gphys_nusdas_io.rb +3 -0
  374. data/lib/numru/gphys/grib.rb +133 -54
  375. data/lib/numru/gphys/grib_params.rb +26 -3
  376. data/lib/numru/gphys/grid.rb +75 -34
  377. data/lib/numru/gphys/interpolate.rb +24 -10
  378. data/lib/numru/gphys/mdstorage.rb +160 -0
  379. data/lib/numru/gphys/netcdf_convention.rb +4 -2
  380. data/lib/numru/gphys/subsetmapping.rb +0 -1
  381. data/lib/numru/gphys/unumeric.rb +50 -5
  382. data/lib/numru/gphys/varray.rb +15 -30
  383. data/lib/numru/gphys/varraycomposite.rb +107 -24
  384. data/lib/numru/gphys/varraynetcdf.rb +9 -3
  385. data/lib/numru/gphys/version.rb +5 -0
  386. data/sample/druby_cli1.rb +2 -0
  387. data/sample/druby_cli2.rb +0 -6
  388. data/sample/druby_serv2.rb +0 -13
  389. data/spec/gphys_spec.rb +11 -0
  390. data/spec/spec_helper.rb +2 -0
  391. data/test/test_assoccoords.rb +102 -0
  392. data/test/test_axis.rb +61 -0
  393. data/test/test_fitting.rb +116 -0
  394. data/test/test_gphys.rb +20 -0
  395. data/test/test_met_z.rb +96 -0
  396. data/test/test_sigma_coord.rb +50 -0
  397. data/{test → test_old}/eof_slp.rb +0 -0
  398. data/{test → test_old}/mltbit.dat +0 -0
  399. data/{test → test_old}/test_ep_flux.rb +0 -0
  400. data/{test → test_old}/test_multibitIO.rb +0 -0
  401. metadata +530 -191
  402. data/README.md +0 -29
  403. data/lib/gphys.rb +0 -2
  404. data/lib/numru/dclext_datetime_ax.rb +0 -220
  405. data/lib/version.rb +0 -3
@@ -0,0 +1,300 @@
1
+
2
+ require "numru/ganalysis/planet"
3
+ require "numru/ganalysis/met"
4
+ require "numru/ganalysis/sigma_coord"
5
+
6
+ module NumRu
7
+ module GAnalysis
8
+
9
+ # Meterological analysis regarding vertical section, integration, etc.
10
+ module MetZ
11
+ module_function
12
+
13
+ # Derive the mass stream function in the pressure coordinate
14
+ #
15
+ # Applicable both to pressure- and sigma-coordinate input data
16
+ # (the output is always on the pressure coordinate).
17
+ #
18
+ # ARGUMENTS
19
+ # * v [GPhys] : meridional wind with a vertical dimension (p or sigma)
20
+ # It must have a latitudinal dimension too. Longitudinal and time
21
+ # dimensions are optional. If it has a longitudinal dimension,
22
+ # zonal mean is taken. The order of the dimensions is not restricted.
23
+ # * ps [GPhys] : surface pressure. Its must have the same grid
24
+ # as v but for the vertical dimension (ps.rank must be v.rank-1)
25
+ # * pcoord [1D VArray](optional) : output vertical coordinate (set if nil)
26
+ # * vs [nil(default) or GPhys]: vs is not needed (neglected)
27
+ # when v has a sigma coordinate. It is an optional parameter
28
+ # to specify the surface values of v, when it is in the pressure
29
+ # coordinate. vs can be omitted (nil), even when v has a pressure
30
+ # coordinate; in that case, vs is set by interpolating v if ps is
31
+ # within the p range of v (e.g. when ps<=1000hPa), or it is naively
32
+ # extended (using the bottom values of v) if ps is out of the range
33
+ # (e.g. when ps>1000hPa). In other words, the current implementation
34
+ # assumes that v is available below the surface, as is customary
35
+ # for reanalysis data.
36
+ def mass_strm_p(v, ps, pcoord=nil, vs=nil)
37
+
38
+ pascal = Units["Pa"]
39
+ grav = Met.g.to_f
40
+
41
+ #< consolidate the p or sigma coordinate input >
42
+
43
+ if zdim = Met.find_prs_d(v) # substitution, not comparison
44
+ # has a pressure coordinate
45
+ pcv = v.coord(zdim) # pcv is v's p coord, not pcoord from outside.
46
+ # This is used only to feed c_cap_by_boundary.
47
+ pcoord = pcv.copy if pcoord.nil? # if not given from outside, use pcv
48
+
49
+ pcv_val = pcv.val
50
+ v_val = v.val # should be NArray or NArrayMiss
51
+ v_val = v_val.to_na if v_val.is_a?(NArrayMiss)
52
+ if pcv_val[0] > pcv_val[-1]
53
+ # reverse the p coordinate to the increasing order
54
+ pcv_val = pcv_val[-1..0]
55
+ v_val = v_val[ *([true]*zdim + [-1..0,false]) ]
56
+ end
57
+
58
+ pcv_val = pcv.units.convert2(pcv_val, pascal) if pcv.units!=pascal
59
+ pcv_over_g = pcv_val / grav
60
+
61
+ ps_val = ps.val
62
+ ps_val = ps_val.to_na if ps_val.is_a?(NArrayMiss)
63
+ ps_val = ps.units.convert2(ps_val, pascal) if ps.units!=pascal
64
+ ps_over_g = ps_val / grav
65
+
66
+ vs_val = vs && vs.val # nil (default) or vs.val (if vs is given)
67
+ vs_val = vs_val.to_na if vs_val.is_a?(NArrayMiss)
68
+
69
+ v_val, p_over_g, nzbound = GPhys.c_cap_by_boundary(v_val, zdim,
70
+ pcv_over_g, true, ps_over_g, vs_val)
71
+
72
+ elsif zdim = SigmaCoord.find_sigma_d(v) # substitution, not comparison
73
+ # has a sigma coordnate
74
+ sig = v.coord(zdim)
75
+ unless pcoord
76
+ pcoord = sig * 1000
77
+ pcoord.units = "hPa"
78
+ pcoord.name = "p"
79
+ pcoord.long_name = "pressure"
80
+ pcoord.put_att("standard_name","air_pressure")
81
+ pcoord.put_att("positive","down")
82
+ end
83
+ nz = sig.length
84
+ nzbound = nil
85
+ ps = ps.convert_units(pascal) if ps.units != pascal
86
+ sig_val = sig.val
87
+ v_val = v.val # should be NArray, not NArrayMiss (coz sigma)
88
+ p_over_g = SigmaCoord.sig_ps2p(ps.val/grav, sig_val, zdim)
89
+ else
90
+ raise ArgumentError, "v does not have a p or sigma coordinate."
91
+ end
92
+
93
+ #< cumulative vertical integration >
94
+
95
+ pc_val = pcoord.val
96
+ if pc_val[0] > pc_val[-1]
97
+ # change it to the increasing order
98
+ pc_val = pc_val[-1..0]
99
+ pcoord = pcoord.copy.replace_val(pc_val)
100
+ end
101
+ pc_val = pcoord.units.convert2(pc_val,pascal)
102
+
103
+ pc_over_g = pc_val / grav
104
+
105
+ rho_v_cum = GPhys.c_cum_integ_irreg(v_val, p_over_g, zdim, nzbound,
106
+ pc_over_g, nil)
107
+
108
+ #< zonal mean & latitudinal factor >
109
+
110
+ lam, phi, lond, latd = Planet.get_lambda_phi(v, false)
111
+
112
+ if latd.nil?
113
+ raise(ArgumentError, "v appears not having a latitudinal dimension")
114
+ end
115
+ if lond
116
+ rho_v_cum = rho_v_cum.mean(lond)
117
+ latd -= 1 if lond<latd
118
+ end
119
+
120
+ a_cos = NMath.cos(phi.val) * ( 2 * Math::PI * Planet.radius.to_f )
121
+ latd.times{a_cos.newdim!(0)}
122
+ (rho_v_cum.rank - latd -1).times{a_cos.newdim!(-1)}
123
+
124
+ mstrm_val = rho_v_cum * a_cos
125
+
126
+ #< make a GPhys >
127
+
128
+ axes = Array.new
129
+ for d in 0...v.rank
130
+ case d
131
+ when lond
132
+ # lost by zonal mean
133
+ when zdim
134
+ pax = Axis.new().set_pos(pcoord)
135
+ axes.push(pax)
136
+ else
137
+ axes.push(v.axis(d).copy) # kept
138
+ end
139
+ end
140
+ grid = Grid.new( *axes )
141
+
142
+ units = Units["kg.m-1"] # p/g*a : Pa / (m.s-2) * m = kg.m-1
143
+ units *= v.units
144
+ mstrm_va = VArray.new(mstrm_val, {"long_name"=>"mass stream function",
145
+ "units"=>units.to_s}, "mstrm")
146
+ mstrm = GPhys.new(grid, mstrm_va)
147
+ mstrm
148
+ end
149
+
150
+ # mass stream function on any vertical coordinate
151
+ #
152
+ # Similar to mass_strm_p, but it supports representation to have
153
+ # an arbitrary physical quantity, such as potential temperature,
154
+ # as the vertical coordinate (instead of pressure).
155
+ #
156
+ # Applicable both to pressure- and sigma-coordinate input data
157
+ #
158
+ # ARGUMENTS
159
+ # * v [GPhys] : meridional wind with a vertical dimension (p or sigma)
160
+ # It must have a latitudinal dimension too. Longitudinal and time
161
+ # dimensions are optional. If it has a longitudinal dimension,
162
+ # zonal mean is taken. The order of the dimensions is not restricted.
163
+ # * ps [GPhys] : surface pressure. Its must have the same grid
164
+ # as v but for the vertical dimension (ps.rank must be v.rank-1)
165
+ # * w [GPhys] : Grid-point values (at the same points as v) of the
166
+ # quantity used to represent the vertical coordinate.
167
+ # Its shape must be the same as that of v, as a matter of course.
168
+ # * wcoord [1D VArray] : Output vertical coordinate. It must have
169
+ # the same units as w.
170
+ # * vs [nil(default) or GPhys]: vs is not needed (neglected)
171
+ # when v has a sigma coordinate. It is an optional parameter
172
+ # to specify the surface values of v, when it is in the pressure
173
+ # coordinate. vs can be omitted (nil), even when v has a pressure
174
+ # coordinate; in that case, vs is set by interpolating v if ps is
175
+ # within the p range of v (e.g. when ps<=1000hPa), or it is naively
176
+ # extended (using the bottom values of v) if ps is out of the range
177
+ # (e.g. when ps>1000hPa). In other words, the current implementation
178
+ # assumes that v is available below the surface, as is customary
179
+ # for reanalysis data.
180
+ # * ws [nil(default) or GPhys]: same as vs but for the surface value of w.
181
+ #
182
+ def mass_strm_any(v, ps, w, wcoord, vs=nil, ws=nil)
183
+
184
+ pascal = Units["Pa"]
185
+ grav = Met.g.to_f
186
+
187
+ #< check >
188
+
189
+ raise(ArgumentError,"v.shape != w.shape") if v.shape != w.shape
190
+ raise(ArgumentError,"ps.rank != v.rank-1") if ps.rank != v.rank-1
191
+ raise(ArgumentError,"w.units !~wcoord.units") if w.units !~ wcoord.units
192
+
193
+ #< preprare data >
194
+
195
+ if zdim = Met.find_prs_d(v) # substitution, not comparison
196
+ # has a pressure coordinate
197
+ pcv = v.coord(zdim) # v's p coord
198
+ pcv_val = pcv.val
199
+ v_val = v.val # should be NArray or NArrayMiss
200
+ v_val = v_val.to_na if v_val.is_a?(NArrayMiss)
201
+ w_val = w.val # should be NArray or NArrayMiss
202
+ w_val = w_val.to_na if w_val.is_a?(NArrayMiss)
203
+ if pcv_val[0] > pcv_val[-1]
204
+ # reverse the p coordinate to the increasing order
205
+ pcv_val = pcv_val[-1..0]
206
+ v_val = v_val[ *([true]*zdim + [-1..0,false]) ]
207
+ w_val = w_val[ *([true]*zdim + [-1..0,false]) ]
208
+ end
209
+
210
+ pcv_val = pcv.units.convert2(pcv_val, pascal) if pcv.units!=pascal
211
+ pcv_over_g = pcv_val / grav
212
+
213
+ ps_val = ps.val
214
+ ps_val = ps_val.to_na if ps_val.is_a?(NArrayMiss)
215
+ ps_val = ps.units.convert2(ps_val, pascal) if ps.units!=pascal
216
+ ps_over_g = ps_val / grav
217
+
218
+ vs_val = vs && vs.val # nil (default) or vs.val (if vs is given)
219
+ vs_val = vs_val.to_na if vs_val.is_a?(NArrayMiss)
220
+
221
+ ws_val = ws && ws.val # nil (default) or ws.val (if ws is given)
222
+ ws_val = ws_val.to_na if ws_val.is_a?(NArrayMiss)
223
+
224
+ v_val, p_over_g, nzbound = GPhys.c_cap_by_boundary(v_val, zdim,
225
+ pcv_over_g, true, ps_over_g, vs_val)
226
+
227
+ w_val, p_over_g, nzbound = GPhys.c_cap_by_boundary(w_val, zdim,
228
+ pcv_over_g, true, ps_over_g, ws_val)
229
+
230
+ elsif zdim = SigmaCoord.find_sigma_d(v) # substitution, not comparison
231
+ # has a sigma coordnate
232
+ sig = v.coord(zdim)
233
+ nz = sig.length
234
+ nzbound = nil
235
+ ps = ps.convert_units(pascal) if ps.units != pascal
236
+ sig_val = sig.val
237
+ v_val = v.val # should be NArray, not NArrayMiss (coz sigma)
238
+ w_val = w.val
239
+ p_over_g = SigmaCoord.sig_ps2p(ps.val/grav, sig_val, zdim)
240
+ else
241
+ raise ArgumentError, "v does not have a p or sigma coordinate."
242
+ end
243
+
244
+ #< cumulative vertical integration >
245
+
246
+ wc_val = wcoord.val
247
+ if wc_val[0] > wc_val[-1]
248
+ # change it to the increasing order
249
+ wc_val = wc_val[-1..0]
250
+ wcoord = wcoord.copy.replace_val(wc_val)
251
+ end
252
+
253
+ rho_v_cum = GPhys.c_cum_integ_irreg(v_val, p_over_g, zdim, nzbound,
254
+ wc_val, w_val)
255
+
256
+ #< zonal mean & latitudinal factor >
257
+
258
+ lam, phi, lond, latd = Planet.get_lambda_phi(v, false)
259
+
260
+ if latd.nil?
261
+ raise(ArgumentError, "v appears not having a latitudinal dimension")
262
+ end
263
+ if lond
264
+ rho_v_cum = rho_v_cum.mean(lond)
265
+ latd -= 1 if lond<latd
266
+ end
267
+
268
+ a_cos = NMath.cos(phi.val) * ( 2 * Math::PI * Planet.radius.to_f )
269
+ latd.times{a_cos.newdim!(0)}
270
+ (rho_v_cum.rank - latd -1).times{a_cos.newdim!(-1)}
271
+
272
+ mstrm_val = rho_v_cum * a_cos
273
+
274
+ #< make a GPhys >
275
+
276
+ axes = Array.new
277
+ for d in 0...v.rank
278
+ case d
279
+ when lond
280
+ # lost by zonal mean
281
+ when zdim
282
+ wax = Axis.new().set_pos(wcoord)
283
+ axes.push(wax)
284
+ else
285
+ axes.push(v.axis(d).copy) # kept
286
+ end
287
+ end
288
+ grid = Grid.new( *axes )
289
+
290
+ units = Units["kg.m-1"] # p/g*a : Pa / (m.s-2) * m = kg.m-1
291
+ units *= v.units
292
+ mstrm_va = VArray.new(mstrm_val, {"long_name"=>"mass stream function",
293
+ "units"=>units.to_s}, "mstrm")
294
+ mstrm = GPhys.new(grid, mstrm_va)
295
+ mstrm
296
+ end
297
+
298
+ end
299
+ end
300
+ end
@@ -1,16 +1,15 @@
1
- # = NumRu::GAnalysis::Planet : Library for spherical planets (default: Earth)
2
- #
3
- # ASSUMPTIONS
4
- # * longitude is assumed to increase in the eastward direction.
5
- # * latitude is assumed to increase in the northward direction,
6
- # and it is zero at the equator.
7
-
8
1
  require "numru/gphys"
9
2
  require 'numru/gphys/derivative'
10
3
 
11
4
  module NumRu
12
5
  module GAnalysis
13
6
 
7
+ # Library for spherical planets (thin spherical shell; default: Earth)
8
+ #
9
+ # ASSUMPTIONS
10
+ # * longitude is assumed to increase in the eastward direction.
11
+ # * latitude is assumed to increase in the northward direction,
12
+ # and it is zero at the equator.
14
13
  module Planet
15
14
  module_function
16
15
 
@@ -63,6 +62,17 @@ module NumRu
63
62
  GPhys::Derivative::LINEAR_EXT
64
63
  end
65
64
 
65
+ # horizontal averaging considering the spherical geometry
66
+ def ave_s(s)
67
+ lam, phi, lond, latd = get_lambda_phi(s)
68
+ xmean = s.mean(lond)
69
+ cos_phi = phi.cos
70
+
71
+ lond,latd = find_lon_lat_dims(xmean) # find latd again
72
+ wgt = cos_phi / cos_phi.sum
73
+ (xmean * wgt).sum(latd)
74
+ end
75
+
66
76
  def rot_s(u,v)
67
77
  lam, phi, lond, latd = get_lambda_phi(u)
68
78
  cos_phi = phi.cos
@@ -0,0 +1,685 @@
1
+ # = NumRu::GAnalysis::QG : Quasi-geostrophic calculations
2
+
3
+
4
+ require "numru/gphys"
5
+ require 'numru/ganalysis/planet'
6
+ require 'numru/ganalysis/met' # for g (gravity)
7
+ require 'numru/ganalysis/log_p'
8
+ require 'numru/ganalysis/beta_plane'
9
+
10
+ module NumRu
11
+ module GAnalysis
12
+
13
+ # QG_common: correction of common methods for QG, QG_sphere, and QG_sphere_div.
14
+ module QG_common
15
+ ## module_function # disabled: module functions are specified one-by-one
16
+
17
+ # geopotential height (multi-D) -> reference geopotential profile (1D)
18
+ def gph2gpref(gph)
19
+ gp2gpref(gph) * Met::g
20
+ end
21
+ module_function :gph2gpref
22
+
23
+ # geopotential (multi-D) -> reference geopotential profile (1D)
24
+ def gp2gpref(gp)
25
+ gpref = Planet::ave_s(gp) # horizontal ave (spherical)
26
+ if gpref.rank >= 2
27
+ # likely a time sequence. need to reduce more.
28
+ pdim = Met.find_prs_d(gpref)
29
+ idxs = (0...gpref.rank).collect{|i| i}
30
+ idxs.delete(pdim)
31
+ gpref = gpref.mean(*idxs)
32
+ end
33
+ gpref.name = "gpref"
34
+ gpref.long_name = "Reference geopotential"
35
+ gpref
36
+ end
37
+ module_function :gp2gpref
38
+
39
+ # geopotential height to geopotential deviation from the global&time mean
40
+ def gph2gpd_gpref(gph)
41
+ gp = gph * Met::g
42
+ gpref = gp2gpref(gp)
43
+ gpd = gp - gpref
44
+ gpd.name = "gpd"
45
+ gpd.long_name = "Geopotential deviation"
46
+ [gpd, gpref]
47
+ end
48
+ module_function :gph2gpd_gpref
49
+
50
+ # reference geopotential -> buoyancy frequency squared
51
+ def gpref2n2(gpref)
52
+ gp_z = LogP.pcdata_dz( gpref )
53
+ gp_zz = LogP.pcdata_dz2( gpref )
54
+ gp_zz[0] = gp_zz[1] # At boundary, it's safer to extend lapse rate
55
+ gp_zz[-1] = gp_zz[-2] # At boundary, it's safer to extend lapse rate
56
+ n2 = gp_zz + gp_z * (Met::Kappa / LogP.h)
57
+ n2.name = "N2"
58
+ n2.long_name = "N**2 (log-p)"
59
+ #p "@@@@@ N2 @@@@",n2.coord(0).val.to_a, n2.val.sqrt.to_a
60
+ n2
61
+ end
62
+ module_function :gpref2n2
63
+
64
+ # [ (p/b) gp_z ]_z /p
65
+ def gpd2qzz(gp, b)
66
+ bunits = Units["s-2"] # this is assumed!
67
+ pdim = Met.find_prs_d(gp)
68
+ p = gp.coord(pdim)
69
+ z = LogP.p2z(p)
70
+ zunits = z.units
71
+ g = Derivative::b_expand_linear_ext( gp.val, pdim )
72
+ z = Derivative::b_expand_linear_ext( z.val, 0 )
73
+ p = Derivative::b_expand_linear_ext( p.val, 0 )
74
+ b = b.val
75
+ b = b.to_na if b.respond_to?(:to_na) # likely a NArrayMiss
76
+ b = Derivative::b_expand_linear_ext( b, 0 )
77
+ pb = p/b
78
+
79
+ pbm = (pb[0..-2] + pb[1..-1]) / 2.0 # pb_{i+1/2} (for i=0..-2)
80
+ pbm01 = pbm[0..-2] # pb_{i-1/2} (for i=1..-2)
81
+ pbm12 = pbm[1..-1] # pb_{i+1/2} (for i=1..-2)
82
+ dz20 = z[2..-1] - z[0..-3] # z_{i+1} - z_{i-1} (for i=1..-2)
83
+ dz21 = z[2..-1] - z[1..-2] # z_{i+1} - z_{i} (for i=1..-2)
84
+ dz10 = z[1..-2] - z[0..-3] # z_{i} - x_{i-1} (for i=1..-2)
85
+ pc = p[1..-2] # p_{i} (for i=1..-2)
86
+
87
+ a2 = 2*pbm12/(dz21*dz20)/pc
88
+ a0 = 2*pbm01/(dz10*dz20)/pc
89
+ a1 = -a2 - a0
90
+
91
+ to_rankD = [1]*pdim + [true] + [1]*(gp.rank-pdim-1)
92
+ a2 = a2.reshape(*to_rankD)
93
+ a1 = a1.reshape(*to_rankD)
94
+ a0 = a0.reshape(*to_rankD)
95
+
96
+ vqzz = g[ *([true]*pdim+[2..-1,false]) ] * a2 \
97
+ + g[ *([true]*pdim+[1..-2,false]) ] * a1 \
98
+ + g[ *([true]*pdim+[0..-3,false]) ] * a0
99
+
100
+ qzz = gp.copy
101
+ qzz.data.replace_val(vqzz)
102
+ qzz.name = "qzz"
103
+ qzz.long_name = "z-deriv term in QG PV"
104
+ qzz.units = qzz.units / zunits**2 / bunits
105
+ qzz
106
+ end
107
+ module_function :gpd2qzz
108
+
109
+
110
+ =begin
111
+ def gpd2qzz(gp, b)
112
+ pdim = Met.find_prs_d(gp)
113
+ p = gp.axis(pdim).to_gphys
114
+ gp_z = LogP.pcdata_dz( gp )
115
+ qzz = LogP.pcdata_dz( gp_z * (p/b) ) / p
116
+ qzz.name = "qzz"
117
+ qzz.long_name = "z-deriv term in QG PV"
118
+ qzz
119
+ end
120
+ =end
121
+
122
+ # Extend the bottom pressure level by the lowest thickness
123
+ # (a hypothetical "Under-ground" level is created)
124
+ # If value of the extended bottom level is set to
125
+ # val_extended (Numeric or NArray etc), if it is specified (non nil).
126
+ # If nil, the value at the original bottom level is simply copied.
127
+ def extend_bottom(z, val_extended=nil)
128
+ pdim = Met.find_prs_d(z)
129
+ plev = z.coord(pdim).val
130
+ raise("Only one pressure level is found; 2 or more needed") if (plev==1)
131
+ bottom_first = ( plev[0] - plev[1] > 0 )
132
+ np = z.shape[pdim]
133
+ idx = (0...np).collect{|i| i}
134
+ if bottom_first # The first level is the bottom one
135
+ idx.unshift(0) # idx => [0,0,1,2,...,np-1]
136
+ ihb = 0 # index of the extended bottom level
137
+ dp = plev[0] - plev[1]
138
+ phb = plev[0] + dp # pressure of the extended bottom level
139
+ else # The last level is the bottom one
140
+ idx.push(np-1) # idx => [0,1,2,...,np-1,np-1]
141
+ ihb = np # index of the extended bottom level
142
+ dp = plev[-1] - plev[-2]
143
+ phb = plev[-1] + dp # pressure of the extended bottom level
144
+ end
145
+ ze = z[ *([true]*pdim + [idx,false]) ].copy # add one level below
146
+ ze.coord(pdim)[ihb] = phb
147
+ if val_extended
148
+ ze[ *([true]*pdim + [ihb,false]) ] = val_extended
149
+ end
150
+ ze
151
+ end
152
+ module_function :extend_bottom
153
+
154
+ def cut_bottom(z)
155
+ pdim = Met.find_prs_d(z)
156
+ plev = z.coord(pdim).val
157
+ if plev[0] - plev[1] > 0
158
+ z[ *([true]*pdim + [1..-1,false]) ]
159
+ else
160
+ z[ *([true]*pdim + [0..-2,false]) ]
161
+ end
162
+ end
163
+ module_function :cut_bottom
164
+
165
+
166
+ ######################################################
167
+ ######################################################
168
+ # The following are instance methods
169
+ # for use (or "inherited") in QG or QG_sphere or QG_sphere_div
170
+ # (not module functions)
171
+ ######################################################
172
+
173
+
174
+ # div of WAF
175
+ #
176
+ # (p cos_phi)^-1 div(p waf) =
177
+ # (cos_phi)^-1 ( div_h(fx,fy) + p^-1 d_z (p fz) )
178
+ #
179
+ # * fx, fy, fz (GPhys) : the x, y and z components of waf
180
+ # * bottom_treatment (true (==default) or false) :
181
+ # If true, the lowest level vertical divergence is
182
+ # computed by assuming that fz is zero at the extended
183
+ # "underground" level. The thickness assumed (=p[1]-p[0]) is
184
+ # consistent with the ((<extend_bottom>)) method.
185
+ def div_waf(fx, fy, fz, bottom_treatment=true)
186
+ cosphi = cos_phi(fx)
187
+ p = Met.get_prs(fx)
188
+
189
+ fz_z = LogP.pcdata_dz( fz*p ) / p
190
+
191
+ #>>>>>> the lowest layer treatment consistent with qb, in which
192
+ # geopotential (or stream function) is extended by extend_bottom.
193
+ # Assumption: the first level is the lowest (bottom) one
194
+ if bottom_treatment
195
+ # using the relation p^{-1} d/dz = -H^{-1} d/dp
196
+ # and assuming fz=0 below the bottom (the "underground" level),
197
+ # p^{-1} d/dz (p fz) = -H^{-1} d/dp (p fz),
198
+ # which is H^{-1} p fz / delta_p, at the lowest level with a
199
+ # "thickness" of delta_p.
200
+ w = p[0..1].val
201
+ dp = w[1] - w[0]
202
+ p0 = w[0]
203
+ pdim = Met.find_prs_d(fz)
204
+ sel0 = [true]*pdim + [0,false] # to specify the first level
205
+ fz_z[*sel0] = fz[*sel0]*p0 / (LogP.h*dp)
206
+ end
207
+ #<<<<<<
208
+
209
+ divh = ( div_h(fx, fy) + fz_z ) / cosphi
210
+ # ^ div_h is defined in QG, QG_sphere,..., but not in QG_common
211
+ divh.name = "divwaf"
212
+ divh.long_name = "div of waf (#{fx.name},..)"
213
+ divh
214
+ end
215
+
216
+
217
+ end
218
+
219
+ ######################################################
220
+
221
+ # Correction of common methods for QG_sphere and QG_sphere_div
222
+ module QG_sphere_common
223
+
224
+ # Coriolis parameter f
225
+ def f(gphys)
226
+ lam, phi, = Planet::get_lambda_phi(gphys)
227
+ f = phi.sin * (2*Planet::omega)
228
+ f.name = "f"
229
+ f.long_name = "Coriolis parameter"
230
+ f
231
+ end
232
+
233
+ # mask where f=0
234
+ def f_mask0(gphys)
235
+ f = f(gphys)
236
+ v = f.val
237
+ vm = NArrayMiss.to_nam(v, v.ne(0))
238
+ f.replace_val(vm)
239
+ f
240
+ end
241
+ end
242
+
243
+ ######################################################
244
+
245
+ # module QG: quasi-geostrophic analysis module for Cartesian coordinates
246
+ module QG
247
+
248
+ module_function
249
+ extend QG_common
250
+
251
+ class Uninitialized
252
+ def method_missing(method_name)
253
+ raise("Reference latitude has not been set. Call QG::set_lat0 to use the module QG.")
254
+ end
255
+ end
256
+
257
+ @@bp = Uninitialized.new # a BetaPlane to be initialized by set_lat0
258
+
259
+ # Initialize the QG module by setting a reference latitude.
260
+ def set_lat0(lat0_or_latary)
261
+ @@bp = BetaPlane.new(lat0_or_latary)
262
+ end
263
+
264
+ # returns the BetaPlane object created by initialization (((<set_lat0>)))
265
+ def bp
266
+ @@bp
267
+ end
268
+
269
+ # Returns the current f0 (the Coriolis parameter at the reference latitude)
270
+ def f0; @@bp.f0; end
271
+
272
+ #def get_x_y(gphys); @@bp.get_x_y(gphys); end
273
+
274
+ # geopotential height to quasi-geostrophic potential vorticity (QGPV)
275
+ def gph2q(gph)
276
+ psi, gpref = gph2psi_gpref(gph)
277
+ n2 = gpref2n2(gpref)
278
+ psi2q(psi, n2)
279
+ end
280
+
281
+ # same as gph2q, but the QGPV is extended to reflect the lowest-level temperature anomalies
282
+ def gph2qb(gph)
283
+ psi, gpref = gph2psi_gpref(gph)
284
+ n2 = gpref2n2(gpref)
285
+ psi2qb(psi, n2)
286
+ end
287
+
288
+ # geopotential height -> geostrophic winds
289
+ def gph2ug_vg(gph)
290
+ psi, gpref = gph2psi_gpref(gph)
291
+ psi2ug_vg(psi)
292
+ end
293
+
294
+ # geopotential height -> QG stream function and the reference geopotential
295
+ def gph2psi_gpref(gph)
296
+ gpd, gpref = gph2gpd_gpref(gph)
297
+ psi = gpd / @@bp.f0
298
+ psi.name = "psi"
299
+ psi.long_name = "QG stream function"
300
+ [psi, gpref]
301
+ end
302
+
303
+ # geopotential height -> QG stream function
304
+ def gph2psi(gph, gpref)
305
+ gpd = gph * Met::g - gpref
306
+ psi = gpd / @@bp.f0
307
+ psi.name = "psi"
308
+ psi.long_name = "QG stream function"
309
+ psi
310
+ end
311
+
312
+ # QG stream function -> QGPV
313
+ def psi2q(psi, n2, perturbation=false)
314
+ x, y = @@bp.get_x_y(psi)
315
+ bc = GPhys::Derivative::CYCLIC_OR_LINEAR
316
+ f0 = @@bp.f0
317
+ vor = psi.deriv2nd(0,bc,x) + psi.deriv2nd(1,bc,y)
318
+ if !perturbation
319
+ avor = vor + (f0 + @@bp.beta*y)
320
+ avor.name = "qgavor"
321
+ avor.long_name = "QG abs vor"
322
+ else
323
+ vor.name = "qgvor"
324
+ vor.long_name = "QG vorticity"
325
+ avor = vor
326
+ end
327
+ qzz = gpd2qzz(psi, n2) * (f0*f0)
328
+ q = avor + qzz
329
+ q.name = "q"
330
+ q.long_name = "QG PV"
331
+
332
+ [q, avor, qzz]
333
+ end
334
+
335
+ # same as psi2q, but the QGPV is extended to reflect the lowest-level temperature anomalies
336
+ def psi2qb(psi, n2, perturbation=false)
337
+ psie = extend_bottom(psi, nil)
338
+ n2e = extend_bottom(n2, nil)
339
+ results = psi2q(psie, n2e, perturbation)
340
+ results.collect{|z| cut_bottom(z)}
341
+ end
342
+
343
+ # QG stream function -> geostrophic winds
344
+ def psi2ug_vg(psi)
345
+ bc = GPhys::Derivative::CYCLIC_OR_LINEAR
346
+ x, y = @@bp.get_x_y(psi)
347
+ vg = psi.cderiv(0,bc,x)
348
+ ug = -psi.threepoint_O2nd_deriv(1,bc,y)
349
+ ug.name = "ug"
350
+ vg.name = "vg"
351
+ ug.long_name = "ug"
352
+ vg.long_name = "vg"
353
+ [ug, vg]
354
+ end
355
+
356
+ # QG stream function -> the Q-vector
357
+ def psi2Qvector(psi)
358
+ bc = GPhys::Derivative::CYCLIC_OR_LINEAR
359
+ f0 = @@bp.f0
360
+ x, y = @@bp.get_x_y(psi)
361
+ p = Met.get_prs(psi).convert_units("Pa")
362
+ psi_x = psi.threepoint_O2nd_deriv(0,bc,x)
363
+ psi_y = psi.threepoint_O2nd_deriv(1,bc,y)
364
+ psi_xp = psi_x.threepoint_O2nd_deriv(2,bc,p)
365
+ psi_yp = psi_y.threepoint_O2nd_deriv(2,bc,p)
366
+ psi_xy = psi_x.threepoint_O2nd_deriv(1,bc,y)
367
+ psi_xx = psi.deriv2nd(0,bc,x)
368
+ psi_yy = psi.deriv2nd(1,bc,y)
369
+ q1 = (-psi_xy*psi_xp + psi_xx*psi_yp) * f0
370
+ q2 = (-psi_yy*psi_xp + psi_xy*psi_yp) * f0
371
+ q1.name = q1.long_name = "Q1"
372
+ q2.name = q2.long_name = "Q2"
373
+ [q1,q2]
374
+ end
375
+
376
+ # same as psi2Qvector, but temperature is given independently
377
+ #
378
+ # p (nil or UNumeric or VArray or..) : specify pressure if the input data
379
+ # does not have a pressure axis
380
+ def psi_T2Qvector(psi, temp, p=nil)
381
+ bc = GPhys::Derivative::CYCLIC_OR_LINEAR
382
+ f0 = @@bp.f0
383
+ x, y = @@bp.get_x_y(psi)
384
+ if p
385
+ if p.respond_to?(:convert_units)
386
+ p = p.convert_units("Pa")
387
+ else
388
+ # UNumeric
389
+ p = p.convert2("Pa")
390
+ end
391
+ else
392
+ p = LogP.get_p(psi).convert_units("Pa")
393
+ end
394
+ psi_xy = psi.threepoint_O2nd_deriv(0,bc,x).threepoint_O2nd_deriv(1,bc,y)
395
+ psi_xx = psi.deriv2nd(0,bc,x)
396
+ psi_yy = psi.deriv2nd(1,bc,y)
397
+ t_x = temp.threepoint_O2nd_deriv(0,bc,x)
398
+ t_y = temp.threepoint_O2nd_deriv(1,bc,y)
399
+ q1 = (psi_xy*t_x - psi_xx*t_y) * (Met::R / p)
400
+ q2 = (psi_yy*t_x - psi_xy*t_y) * (Met::R / p)
401
+ #puts "@@@ psi_T2Qvector @@@", psi.units, psi_xx.units, t_x.units, q1.units
402
+ q1.name = q1.long_name = "Q1"
403
+ q2.name = q2.long_name = "Q2"
404
+ [q1,q2]
405
+ end
406
+
407
+ # horizontal gradient (Cartesian)
408
+ def grad_h(gphys)
409
+ @@bp.grad_h(gphys)
410
+ end
411
+
412
+ # horizontal divergence (Cartesian)
413
+ def div_h(gphys_u, gphys_v)
414
+ @@bp.div_h(gphys_u, gphys_v)
415
+ end
416
+
417
+ end
418
+
419
+ ######################################################
420
+ # QG on sphere with non-divergent but inaccurate geostrophic wind
421
+ #
422
+ ######################################################
423
+ module QG_sphere
424
+ module_function
425
+ extend QG_common
426
+ extend QG_sphere_common
427
+
428
+ # geopotential height to quasi-geostrophic potential vorticity (QGPV)
429
+ def gph2q(gph)
430
+ psi, gpref = gph2psi_gpref(gph)
431
+ n2 = gpref2n2(gpref)
432
+ psi2q(psi, n2)
433
+ end
434
+
435
+ # same as gph2q, but the QGPV is extended to reflect the lowest-level temperature anomalies
436
+ def gph2qb(gph)
437
+ psi, gpref = gph2psi_gpref(gph)
438
+ n2 = gpref2n2(gpref)
439
+ psi2qb(psi, n2)
440
+ end
441
+
442
+ # geopotential height -> geostrophic winds
443
+ def gph2ug_vg(gph)
444
+ psi, gpref = gph2psi_gpref(gph)
445
+ psi2ug_vg(psi)
446
+ end
447
+
448
+ # geopotential height -> QG stream function and the reference geopotential
449
+ def gph2psi_gpref(gph)
450
+ gpd, gpref = gph2gpd_gpref(gph)
451
+ f = f_mask0(gph)
452
+ psi = gpd / f
453
+ psi.name = "psi"
454
+ psi.long_name = "QG stream function"
455
+ [psi, gpref]
456
+ end
457
+
458
+ # geopotential height -> QG stream function
459
+ def gph2psi(gph, gpref)
460
+ gpd = gph * Met::g - gpref
461
+ f = f_mask0(gph)
462
+ psi = gpd / f
463
+ psi.name = "psi"
464
+ psi.long_name = "QG stream function"
465
+ psi
466
+ end
467
+
468
+ # QG stream function -> QGPV
469
+ def psi2q(psi, n2, perturbation=false)
470
+ ug, vg = psi2ug_vg(psi)
471
+
472
+ if !perturbation
473
+ avor = Planet::absvor_s(ug,vg)
474
+ avor.name = "qgavor"
475
+ avor.long_name = "QG abs vor"
476
+ else
477
+ vor = Planet::vor_s(ug,vg)
478
+ vor.name = "qgvor"
479
+ vor.long_name = "QG vorticity"
480
+ avor = vor
481
+ end
482
+
483
+ f = f_mask0(psi)
484
+ qzz = gpd2qzz(psi, n2) * (f*f)
485
+
486
+ q = avor + qzz
487
+ q.name = "q"
488
+ q.long_name = "QG PV"
489
+
490
+ [q, avor, qzz, ug, vg]
491
+ end
492
+
493
+ # cosine of latitude
494
+ def cos_phi(gphys)
495
+ lam, phi, = Planet::get_lambda_phi(gphys)
496
+ phi.cos
497
+ end
498
+
499
+ #########
500
+ # same as psi2q, but the QGPV is extended to reflect the lowest-level temperature anomalies
501
+ def psi2qb(psi, n2, perturbation=false)
502
+ psie = extend_bottom(psi, nil)
503
+ n2e = extend_bottom(n2, nil)
504
+ results = psi2q(psie, n2e, perturbation)
505
+ results.collect{|z| cut_bottom(z)}
506
+ end
507
+
508
+ # QG stream function -> geostrophic winds
509
+ def psi2ug_vg(psi)
510
+ f = f_mask0(psi)
511
+ gpx, gpy = Planet::grad_s(psi)
512
+ vg = gpx
513
+ ug = -gpy
514
+ ug.name = "ug"
515
+ vg.name = "vg"
516
+ ug.long_name = "ug"
517
+ vg.long_name = "vg"
518
+ [ug, vg]
519
+ end
520
+
521
+ # horizontal gradient (spherical)
522
+ def grad_h(gphys)
523
+ Planet::grad_s(gphys)
524
+ end
525
+
526
+ # horizontal divergence (spherical)
527
+ def div_h(fx, fy)
528
+ Planet::div_s(fx, fy)
529
+ end
530
+
531
+
532
+ #############################################
533
+ # wave activity flux
534
+
535
+ # divergence of wave activity flux (redirected to ((<div_waf>)))
536
+ def self.div_waf(*args)
537
+ super(*args) # defined in QG_common
538
+ end
539
+
540
+ # Flux of the pseudo-momentum in x direction by Plumb (1986).
541
+ # Specifically, B_2j in Eq.(2.9), but without the factor p.
542
+ # This flux is relative to the mean flow.
543
+ # Averaged over time (if the data is 4D).
544
+ #
545
+ def waf_plumb1986_B2(psi, n2)
546
+ psi_x, psi_y = Planet::grad_s(psi)
547
+ psi_z = LogP.pcdata_dz( psi )
548
+ f2 = f_mask0(psi) ** 2
549
+ cosphi = cos_phi(psi)
550
+ fx = (psi_x**2 - psi_y**2 - psi_z**2 * f2 / n2) * cosphi / 2.0
551
+ fy = psi_x * psi_y * cosphi
552
+ fz = psi_x * psi_z * (cosphi * f2) / n2
553
+ fx.name = "B21"
554
+ fy.name = "B22"
555
+ fz.name = "B23"
556
+ fx.long_name = "WAF B2x"
557
+ fy.long_name = "WAF B2y"
558
+ fz.long_name = "WAF B2z"
559
+ if psi.rank >= 4
560
+ fx = fx.mean(-1)
561
+ fy = fy.mean(-1)
562
+ fz = fz.mean(-1)
563
+ end
564
+ [fx, fy, fz]
565
+ end
566
+
567
+ # Flux of the pseudo-momentum in y direction by Plumb (1986).
568
+ # Specifically, B_1j in Eq.(2.9), but without the factor p.
569
+ # This flux is relative to the mean flow.
570
+ # Averaged over time (if the data is 4D).
571
+ #
572
+ def waf_plumb1986_B1(psi, n2)
573
+ psi_x, psi_y = Planet::grad_s(psi)
574
+ psi_z = LogP.pcdata_dz( psi )
575
+ f2 = f_mask0(psi) ** 2
576
+ cosphi = cos_phi(psi)
577
+ fx = -psi_x * psi_y * cosphi
578
+ fy = (psi_x**2 - psi_y**2 + psi_z**2 * f2 / n2) * cosphi / 2.0
579
+ fz = -psi_y * psi_z * (cosphi * f2) / n2
580
+ fx.name = "B_11"
581
+ fy.name = "B_12"
582
+ fz.name = "B_13"
583
+ fx.long_name = "x-comp of Px flux Plumb86"
584
+ fy.long_name = "y-comp of Px flux Plumb86"
585
+ fz.long_name = "z-comp of Px flux Plumb86"
586
+ if psi.rank >= 4
587
+ fx = fx.mean(-1)
588
+ fy = fy.mean(-1)
589
+ fz = fz.mean(-1)
590
+ end
591
+ [fx, fy, fz]
592
+ end
593
+ end
594
+
595
+ ######################################################
596
+ # QG on sphere with divergence in the geostrophic wind
597
+ #
598
+ # The geostrophic wind is defined as
599
+ #
600
+ # [ug, vg] = 1/f curl gpd,
601
+ #
602
+ # where gpd is the geostrophic geopotential,
603
+ # which is the deviation of geopotential from some globally uniform
604
+ # background. A background can be defined as the global
605
+ # mean geopotential, as is done in the method gph2gpd_gpref.
606
+ #
607
+ ######################################################
608
+ module QG_sphere_div
609
+ module_function
610
+ extend QG_common
611
+ extend QG_sphere_common
612
+
613
+ # geopotential height to quasi-geostrophic potential vorticity (QGPV)
614
+ def gph2q(gph)
615
+ gpd, gpref = gph2gpd_gpref(gph)
616
+ n2 = gpref2n2(gpref)
617
+ gpd2q(gpd, n2)
618
+ end
619
+
620
+ # same as gph2q, but the QGPV is extended to reflect the lowest-level temperature anomalies
621
+ def gph2qb(gph)
622
+ gpd, gpref = gph2gpd_gpref(gph)
623
+ n2 = gpref2n2(gpref)
624
+ gpd2qb(gpd, n2)
625
+ end
626
+
627
+ # geopotential height -> geostrophic winds
628
+ def gph2ug_vg(gph)
629
+ gpd, gpref = gph2gpd_gpref(gph)
630
+ gpd2ug_vg(gpd)
631
+ end
632
+
633
+ #########
634
+ def gpd2q(gpd, n2)
635
+ ug, vg = gpd2ug_vg(gpd)
636
+
637
+ avor = Planet::absvor_s(ug,vg)
638
+ avor.name = "qgavor"
639
+ avor.long_name = "QG abs vor"
640
+
641
+ f = f_mask0(gpd)
642
+ qzz = gpd2qzz(gpd, n2) * f
643
+
644
+ q = avor + qzz
645
+ q.name = "q"
646
+ q.long_name = "QG PV"
647
+
648
+ [q, avor, qzz, ug, vg]
649
+ end
650
+
651
+ # geopotential height (gpd: deviation from the reference profie) to the extended QGPV
652
+ #
653
+ # qb: q including the contribution from the bottom boundary
654
+ def gpd2qb(gpd, n2)
655
+ gpde = extend_bottom(gpd, nil)
656
+ n2e = extend_bottom(n2, nil)
657
+ results = gpd2q(gpde, n2e)
658
+ results.collect{|z| cut_bottom(z)}
659
+ end
660
+
661
+ def gpd2ug_vg(gpd)
662
+ f = f_mask0(gpd)
663
+ gpx, gpy = Planet::grad_s(gpd)
664
+ vg = gpx/f
665
+ ug = gpy* (-1/f)
666
+ ug.name = "ug"
667
+ vg.name = "vg"
668
+ ug.long_name = "ug"
669
+ vg.long_name = "vg"
670
+ [ug, vg]
671
+ end
672
+
673
+ end
674
+
675
+ end
676
+ end
677
+
678
+
679
+ ########################################
680
+ ##### test part ######
681
+ if $0 == __FILE__
682
+ include NumRu
683
+ GAnalysis::QG.set_lat0(45.0)
684
+ p GAnalysis::QG.f0
685
+ end