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.
- checksums.yaml +7 -0
- data/.gitignore +8 -17
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/ChangeLog +5762 -753
- data/LICENSE.txt +30 -18
- data/Rakefile +1 -0
- data/bin/console +14 -0
- data/bin/gpcat +43 -2
- data/bin/gpcut +16 -0
- data/bin/gpvect +167 -15
- data/bin/gpview +254 -51
- data/bin/setup +7 -0
- data/dim_op.c +1220 -0
- data/doc/attribute.html +19 -0
- data/doc/attributenetcdf.html +15 -0
- data/doc/axis.html +387 -0
- data/doc/coordmapping.html +111 -0
- data/doc/coordtransform.html +36 -0
- data/doc/dclext.html +821 -0
- data/doc/derivative/gphys-derivative.html +100 -0
- data/doc/derivative/index.html +21 -0
- data/doc/derivative/index.rd +14 -0
- data/doc/derivative/math-doc/document.pdf +0 -0
- data/doc/derivative/math-doc/document.tex +158 -0
- data/doc/derivative/math-doc/document/document.css +30 -0
- data/doc/derivative/math-doc/document/document.html +57 -0
- data/doc/derivative/math-doc/document/images.aux +1 -0
- data/doc/derivative/math-doc/document/images.log +385 -0
- data/doc/derivative/math-doc/document/images.pl +186 -0
- data/doc/derivative/math-doc/document/images.tex +364 -0
- data/doc/derivative/math-doc/document/img1.png +0 -0
- data/doc/derivative/math-doc/document/img10.png +0 -0
- data/doc/derivative/math-doc/document/img11.png +0 -0
- data/doc/derivative/math-doc/document/img12.png +0 -0
- data/doc/derivative/math-doc/document/img13.png +0 -0
- data/doc/derivative/math-doc/document/img14.png +0 -0
- data/doc/derivative/math-doc/document/img15.png +0 -0
- data/doc/derivative/math-doc/document/img16.png +0 -0
- data/doc/derivative/math-doc/document/img17.png +0 -0
- data/doc/derivative/math-doc/document/img18.png +0 -0
- data/doc/derivative/math-doc/document/img19.png +0 -0
- data/doc/derivative/math-doc/document/img2.png +0 -0
- data/doc/derivative/math-doc/document/img20.png +0 -0
- data/doc/derivative/math-doc/document/img21.png +0 -0
- data/doc/derivative/math-doc/document/img22.png +0 -0
- data/doc/derivative/math-doc/document/img23.png +0 -0
- data/doc/derivative/math-doc/document/img24.png +0 -0
- data/doc/derivative/math-doc/document/img25.png +0 -0
- data/doc/derivative/math-doc/document/img26.png +0 -0
- data/doc/derivative/math-doc/document/img27.png +0 -0
- data/doc/derivative/math-doc/document/img28.png +0 -0
- data/doc/derivative/math-doc/document/img29.png +0 -0
- data/doc/derivative/math-doc/document/img3.png +0 -0
- data/doc/derivative/math-doc/document/img30.png +0 -0
- data/doc/derivative/math-doc/document/img4.png +0 -0
- data/doc/derivative/math-doc/document/img5.png +0 -0
- data/doc/derivative/math-doc/document/img6.png +0 -0
- data/doc/derivative/math-doc/document/img7.png +0 -0
- data/doc/derivative/math-doc/document/img8.png +0 -0
- data/doc/derivative/math-doc/document/img9.png +0 -0
- data/doc/derivative/math-doc/document/index.html +57 -0
- data/doc/derivative/math-doc/document/labels.pl +13 -0
- data/doc/derivative/math-doc/document/next.png +0 -0
- data/doc/derivative/math-doc/document/next_g.png +0 -0
- data/doc/derivative/math-doc/document/node1.html +238 -0
- data/doc/derivative/math-doc/document/node2.html +75 -0
- data/doc/derivative/math-doc/document/prev.png +0 -0
- data/doc/derivative/math-doc/document/prev_g.png +0 -0
- data/doc/derivative/math-doc/document/up.png +0 -0
- data/doc/derivative/math-doc/document/up_g.png +0 -0
- data/doc/derivative/numru-derivative.html +158 -0
- data/doc/ep_flux/ep_flux.html +469 -0
- data/doc/ep_flux/ggraph_on_merdional_section.html +71 -0
- data/doc/ep_flux/index.html +31 -0
- data/doc/ep_flux/index.rd +24 -0
- data/doc/ep_flux/math-doc/document.pdf +0 -0
- data/doc/ep_flux/math-doc/document.tex +2018 -0
- data/doc/ep_flux/math-doc/document/WARNINGS +1 -0
- data/doc/ep_flux/math-doc/document/contents.png +0 -0
- data/doc/ep_flux/math-doc/document/crossref.png +0 -0
- data/doc/ep_flux/math-doc/document/document.css +30 -0
- data/doc/ep_flux/math-doc/document/document.html +101 -0
- data/doc/ep_flux/math-doc/document/images.aux +1 -0
- data/doc/ep_flux/math-doc/document/images.log +1375 -0
- data/doc/ep_flux/math-doc/document/images.pl +1328 -0
- data/doc/ep_flux/math-doc/document/images.tex +1471 -0
- data/doc/ep_flux/math-doc/document/img1.png +0 -0
- data/doc/ep_flux/math-doc/document/img10.png +0 -0
- data/doc/ep_flux/math-doc/document/img100.png +0 -0
- data/doc/ep_flux/math-doc/document/img101.png +0 -0
- data/doc/ep_flux/math-doc/document/img102.png +0 -0
- data/doc/ep_flux/math-doc/document/img103.png +0 -0
- data/doc/ep_flux/math-doc/document/img104.png +0 -0
- data/doc/ep_flux/math-doc/document/img105.png +0 -0
- data/doc/ep_flux/math-doc/document/img106.png +0 -0
- data/doc/ep_flux/math-doc/document/img107.png +0 -0
- data/doc/ep_flux/math-doc/document/img108.png +0 -0
- data/doc/ep_flux/math-doc/document/img109.png +0 -0
- data/doc/ep_flux/math-doc/document/img11.png +0 -0
- data/doc/ep_flux/math-doc/document/img110.png +0 -0
- data/doc/ep_flux/math-doc/document/img111.png +0 -0
- data/doc/ep_flux/math-doc/document/img112.png +0 -0
- data/doc/ep_flux/math-doc/document/img113.png +0 -0
- data/doc/ep_flux/math-doc/document/img114.png +0 -0
- data/doc/ep_flux/math-doc/document/img115.png +0 -0
- data/doc/ep_flux/math-doc/document/img116.png +0 -0
- data/doc/ep_flux/math-doc/document/img117.png +0 -0
- data/doc/ep_flux/math-doc/document/img118.png +0 -0
- data/doc/ep_flux/math-doc/document/img119.png +0 -0
- data/doc/ep_flux/math-doc/document/img12.png +0 -0
- data/doc/ep_flux/math-doc/document/img120.png +0 -0
- data/doc/ep_flux/math-doc/document/img121.png +0 -0
- data/doc/ep_flux/math-doc/document/img122.png +0 -0
- data/doc/ep_flux/math-doc/document/img123.png +0 -0
- data/doc/ep_flux/math-doc/document/img124.png +0 -0
- data/doc/ep_flux/math-doc/document/img125.png +0 -0
- data/doc/ep_flux/math-doc/document/img126.png +0 -0
- data/doc/ep_flux/math-doc/document/img127.png +0 -0
- data/doc/ep_flux/math-doc/document/img128.png +0 -0
- data/doc/ep_flux/math-doc/document/img129.png +0 -0
- data/doc/ep_flux/math-doc/document/img13.png +0 -0
- data/doc/ep_flux/math-doc/document/img130.png +0 -0
- data/doc/ep_flux/math-doc/document/img131.png +0 -0
- data/doc/ep_flux/math-doc/document/img132.png +0 -0
- data/doc/ep_flux/math-doc/document/img133.png +0 -0
- data/doc/ep_flux/math-doc/document/img134.png +0 -0
- data/doc/ep_flux/math-doc/document/img135.png +0 -0
- data/doc/ep_flux/math-doc/document/img136.png +0 -0
- data/doc/ep_flux/math-doc/document/img137.png +0 -0
- data/doc/ep_flux/math-doc/document/img138.png +0 -0
- data/doc/ep_flux/math-doc/document/img139.png +0 -0
- data/doc/ep_flux/math-doc/document/img14.png +0 -0
- data/doc/ep_flux/math-doc/document/img140.png +0 -0
- data/doc/ep_flux/math-doc/document/img141.png +0 -0
- data/doc/ep_flux/math-doc/document/img142.png +0 -0
- data/doc/ep_flux/math-doc/document/img143.png +0 -0
- data/doc/ep_flux/math-doc/document/img144.png +0 -0
- data/doc/ep_flux/math-doc/document/img145.png +0 -0
- data/doc/ep_flux/math-doc/document/img146.png +0 -0
- data/doc/ep_flux/math-doc/document/img147.png +0 -0
- data/doc/ep_flux/math-doc/document/img148.png +0 -0
- data/doc/ep_flux/math-doc/document/img149.png +0 -0
- data/doc/ep_flux/math-doc/document/img15.png +0 -0
- data/doc/ep_flux/math-doc/document/img150.png +0 -0
- data/doc/ep_flux/math-doc/document/img151.png +0 -0
- data/doc/ep_flux/math-doc/document/img152.png +0 -0
- data/doc/ep_flux/math-doc/document/img153.png +0 -0
- data/doc/ep_flux/math-doc/document/img154.png +0 -0
- data/doc/ep_flux/math-doc/document/img155.png +0 -0
- data/doc/ep_flux/math-doc/document/img156.png +0 -0
- data/doc/ep_flux/math-doc/document/img157.png +0 -0
- data/doc/ep_flux/math-doc/document/img158.png +0 -0
- data/doc/ep_flux/math-doc/document/img159.png +0 -0
- data/doc/ep_flux/math-doc/document/img16.png +0 -0
- data/doc/ep_flux/math-doc/document/img160.png +0 -0
- data/doc/ep_flux/math-doc/document/img161.png +0 -0
- data/doc/ep_flux/math-doc/document/img162.png +0 -0
- data/doc/ep_flux/math-doc/document/img163.png +0 -0
- data/doc/ep_flux/math-doc/document/img164.png +0 -0
- data/doc/ep_flux/math-doc/document/img165.png +0 -0
- data/doc/ep_flux/math-doc/document/img166.png +0 -0
- data/doc/ep_flux/math-doc/document/img167.png +0 -0
- data/doc/ep_flux/math-doc/document/img168.png +0 -0
- data/doc/ep_flux/math-doc/document/img169.png +0 -0
- data/doc/ep_flux/math-doc/document/img17.png +0 -0
- data/doc/ep_flux/math-doc/document/img170.png +0 -0
- data/doc/ep_flux/math-doc/document/img171.png +0 -0
- data/doc/ep_flux/math-doc/document/img172.png +0 -0
- data/doc/ep_flux/math-doc/document/img173.png +0 -0
- data/doc/ep_flux/math-doc/document/img174.png +0 -0
- data/doc/ep_flux/math-doc/document/img175.png +0 -0
- data/doc/ep_flux/math-doc/document/img176.png +0 -0
- data/doc/ep_flux/math-doc/document/img177.png +0 -0
- data/doc/ep_flux/math-doc/document/img178.png +0 -0
- data/doc/ep_flux/math-doc/document/img179.png +0 -0
- data/doc/ep_flux/math-doc/document/img18.png +0 -0
- data/doc/ep_flux/math-doc/document/img180.png +0 -0
- data/doc/ep_flux/math-doc/document/img181.png +0 -0
- data/doc/ep_flux/math-doc/document/img182.png +0 -0
- data/doc/ep_flux/math-doc/document/img183.png +0 -0
- data/doc/ep_flux/math-doc/document/img184.png +0 -0
- data/doc/ep_flux/math-doc/document/img185.png +0 -0
- data/doc/ep_flux/math-doc/document/img186.png +0 -0
- data/doc/ep_flux/math-doc/document/img187.png +0 -0
- data/doc/ep_flux/math-doc/document/img188.png +0 -0
- data/doc/ep_flux/math-doc/document/img189.png +0 -0
- data/doc/ep_flux/math-doc/document/img19.png +0 -0
- data/doc/ep_flux/math-doc/document/img190.png +0 -0
- data/doc/ep_flux/math-doc/document/img191.png +0 -0
- data/doc/ep_flux/math-doc/document/img192.png +0 -0
- data/doc/ep_flux/math-doc/document/img193.png +0 -0
- data/doc/ep_flux/math-doc/document/img194.png +0 -0
- data/doc/ep_flux/math-doc/document/img195.png +0 -0
- data/doc/ep_flux/math-doc/document/img196.png +0 -0
- data/doc/ep_flux/math-doc/document/img197.png +0 -0
- data/doc/ep_flux/math-doc/document/img198.png +0 -0
- data/doc/ep_flux/math-doc/document/img199.png +0 -0
- data/doc/ep_flux/math-doc/document/img2.png +0 -0
- data/doc/ep_flux/math-doc/document/img20.png +0 -0
- data/doc/ep_flux/math-doc/document/img200.png +0 -0
- data/doc/ep_flux/math-doc/document/img21.png +0 -0
- data/doc/ep_flux/math-doc/document/img22.png +0 -0
- data/doc/ep_flux/math-doc/document/img23.png +0 -0
- data/doc/ep_flux/math-doc/document/img24.png +0 -0
- data/doc/ep_flux/math-doc/document/img25.png +0 -0
- data/doc/ep_flux/math-doc/document/img26.png +0 -0
- data/doc/ep_flux/math-doc/document/img27.png +0 -0
- data/doc/ep_flux/math-doc/document/img28.png +0 -0
- data/doc/ep_flux/math-doc/document/img29.png +0 -0
- data/doc/ep_flux/math-doc/document/img3.png +0 -0
- data/doc/ep_flux/math-doc/document/img30.png +0 -0
- data/doc/ep_flux/math-doc/document/img31.png +0 -0
- data/doc/ep_flux/math-doc/document/img32.png +0 -0
- data/doc/ep_flux/math-doc/document/img33.png +0 -0
- data/doc/ep_flux/math-doc/document/img34.png +0 -0
- data/doc/ep_flux/math-doc/document/img35.png +0 -0
- data/doc/ep_flux/math-doc/document/img36.png +0 -0
- data/doc/ep_flux/math-doc/document/img37.png +0 -0
- data/doc/ep_flux/math-doc/document/img38.png +0 -0
- data/doc/ep_flux/math-doc/document/img39.png +0 -0
- data/doc/ep_flux/math-doc/document/img4.png +0 -0
- data/doc/ep_flux/math-doc/document/img40.png +0 -0
- data/doc/ep_flux/math-doc/document/img41.png +0 -0
- data/doc/ep_flux/math-doc/document/img42.png +0 -0
- data/doc/ep_flux/math-doc/document/img43.png +0 -0
- data/doc/ep_flux/math-doc/document/img44.png +0 -0
- data/doc/ep_flux/math-doc/document/img45.png +0 -0
- data/doc/ep_flux/math-doc/document/img46.png +0 -0
- data/doc/ep_flux/math-doc/document/img47.png +0 -0
- data/doc/ep_flux/math-doc/document/img48.png +0 -0
- data/doc/ep_flux/math-doc/document/img49.png +0 -0
- data/doc/ep_flux/math-doc/document/img5.png +0 -0
- data/doc/ep_flux/math-doc/document/img50.png +0 -0
- data/doc/ep_flux/math-doc/document/img51.png +0 -0
- data/doc/ep_flux/math-doc/document/img52.png +0 -0
- data/doc/ep_flux/math-doc/document/img53.png +0 -0
- data/doc/ep_flux/math-doc/document/img54.png +0 -0
- data/doc/ep_flux/math-doc/document/img55.png +0 -0
- data/doc/ep_flux/math-doc/document/img56.png +0 -0
- data/doc/ep_flux/math-doc/document/img57.png +0 -0
- data/doc/ep_flux/math-doc/document/img58.png +0 -0
- data/doc/ep_flux/math-doc/document/img59.png +0 -0
- data/doc/ep_flux/math-doc/document/img6.png +0 -0
- data/doc/ep_flux/math-doc/document/img60.png +0 -0
- data/doc/ep_flux/math-doc/document/img61.png +0 -0
- data/doc/ep_flux/math-doc/document/img62.png +0 -0
- data/doc/ep_flux/math-doc/document/img63.png +0 -0
- data/doc/ep_flux/math-doc/document/img64.png +0 -0
- data/doc/ep_flux/math-doc/document/img65.png +0 -0
- data/doc/ep_flux/math-doc/document/img66.png +0 -0
- data/doc/ep_flux/math-doc/document/img67.png +0 -0
- data/doc/ep_flux/math-doc/document/img68.png +0 -0
- data/doc/ep_flux/math-doc/document/img69.png +0 -0
- data/doc/ep_flux/math-doc/document/img7.png +0 -0
- data/doc/ep_flux/math-doc/document/img70.png +0 -0
- data/doc/ep_flux/math-doc/document/img71.png +0 -0
- data/doc/ep_flux/math-doc/document/img72.png +0 -0
- data/doc/ep_flux/math-doc/document/img73.png +0 -0
- data/doc/ep_flux/math-doc/document/img74.png +0 -0
- data/doc/ep_flux/math-doc/document/img75.png +0 -0
- data/doc/ep_flux/math-doc/document/img76.png +0 -0
- data/doc/ep_flux/math-doc/document/img77.png +0 -0
- data/doc/ep_flux/math-doc/document/img78.png +0 -0
- data/doc/ep_flux/math-doc/document/img79.png +0 -0
- data/doc/ep_flux/math-doc/document/img8.png +0 -0
- data/doc/ep_flux/math-doc/document/img80.png +0 -0
- data/doc/ep_flux/math-doc/document/img81.png +0 -0
- data/doc/ep_flux/math-doc/document/img82.png +0 -0
- data/doc/ep_flux/math-doc/document/img83.png +0 -0
- data/doc/ep_flux/math-doc/document/img84.png +0 -0
- data/doc/ep_flux/math-doc/document/img85.png +0 -0
- data/doc/ep_flux/math-doc/document/img86.png +0 -0
- data/doc/ep_flux/math-doc/document/img87.png +0 -0
- data/doc/ep_flux/math-doc/document/img88.png +0 -0
- data/doc/ep_flux/math-doc/document/img89.png +0 -0
- data/doc/ep_flux/math-doc/document/img9.png +0 -0
- data/doc/ep_flux/math-doc/document/img90.png +0 -0
- data/doc/ep_flux/math-doc/document/img91.png +0 -0
- data/doc/ep_flux/math-doc/document/img92.png +0 -0
- data/doc/ep_flux/math-doc/document/img93.png +0 -0
- data/doc/ep_flux/math-doc/document/img94.png +0 -0
- data/doc/ep_flux/math-doc/document/img95.png +0 -0
- data/doc/ep_flux/math-doc/document/img96.png +0 -0
- data/doc/ep_flux/math-doc/document/img97.png +0 -0
- data/doc/ep_flux/math-doc/document/img98.png +0 -0
- data/doc/ep_flux/math-doc/document/img99.png +0 -0
- data/doc/ep_flux/math-doc/document/index.html +101 -0
- data/doc/ep_flux/math-doc/document/internals.pl +258 -0
- data/doc/ep_flux/math-doc/document/labels.pl +265 -0
- data/doc/ep_flux/math-doc/document/next.png +0 -0
- data/doc/ep_flux/math-doc/document/next_g.png +0 -0
- data/doc/ep_flux/math-doc/document/node1.html +104 -0
- data/doc/ep_flux/math-doc/document/node10.html +164 -0
- data/doc/ep_flux/math-doc/document/node11.html +86 -0
- data/doc/ep_flux/math-doc/document/node12.html +166 -0
- data/doc/ep_flux/math-doc/document/node13.html +897 -0
- data/doc/ep_flux/math-doc/document/node14.html +1065 -0
- data/doc/ep_flux/math-doc/document/node15.html +72 -0
- data/doc/ep_flux/math-doc/document/node16.html +81 -0
- data/doc/ep_flux/math-doc/document/node2.html +82 -0
- data/doc/ep_flux/math-doc/document/node3.html +91 -0
- data/doc/ep_flux/math-doc/document/node4.html +149 -0
- data/doc/ep_flux/math-doc/document/node5.html +330 -0
- data/doc/ep_flux/math-doc/document/node6.html +99 -0
- data/doc/ep_flux/math-doc/document/node7.html +98 -0
- data/doc/ep_flux/math-doc/document/node8.html +83 -0
- data/doc/ep_flux/math-doc/document/node9.html +140 -0
- data/doc/ep_flux/math-doc/document/prev.png +0 -0
- data/doc/ep_flux/math-doc/document/prev_g.png +0 -0
- data/doc/ep_flux/math-doc/document/up.png +0 -0
- data/doc/ep_flux/math-doc/document/up_g.png +0 -0
- data/doc/gdir.html +412 -0
- data/doc/gdir_client.html +16 -0
- data/doc/gdir_connect_ftp-like.html +61 -0
- data/doc/gdir_server.html +45 -0
- data/doc/ggraph.html +1119 -0
- data/doc/gpcat.html +45 -0
- data/doc/gpcut.html +47 -0
- data/doc/gphys.html +624 -0
- data/doc/gphys_fft.html +324 -0
- data/doc/gphys_grads_io.html +69 -0
- data/doc/gphys_grib_io.html +82 -0
- data/doc/gphys_io.html +183 -0
- data/doc/gphys_io_common.html +18 -0
- data/doc/gphys_netcdf_io.html +283 -0
- data/doc/gplist.html +24 -0
- data/doc/gpmath.html +52 -0
- data/doc/gpmaxmin.html +32 -0
- data/doc/gpprint.html +35 -0
- data/doc/gpview.html +349 -0
- data/doc/grads2nc_with_gphys.html +21 -0
- data/doc/grads_gridded.html +307 -0
- data/doc/grib.html +149 -0
- data/doc/grid.html +224 -0
- data/doc/index.html +145 -0
- data/doc/index.rd +138 -0
- data/doc/netcdf_convention.html +136 -0
- data/doc/unumeric.html +176 -0
- data/doc/update +69 -0
- data/doc/update_rdoc +8 -0
- data/doc/varray.html +299 -0
- data/doc/varraycomposite.html +67 -0
- data/ext_init.c +1 -0
- data/extconf.rb +16 -6
- data/gphys.gemspec +33 -26
- data/interpo.c +1 -1
- data/lib/numru/dclext.rb +718 -546
- data/lib/numru/derivative.rb +2 -0
- data/lib/numru/ganalysis.rb +38 -0
- data/lib/numru/ganalysis/beta_plane.rb +103 -0
- data/lib/numru/ganalysis/eof.rb +3 -2
- data/lib/numru/ganalysis/fitting.rb +559 -0
- data/lib/numru/ganalysis/histogram.rb +36 -19
- data/lib/numru/ganalysis/log_p.rb +130 -0
- data/lib/numru/ganalysis/met.rb +396 -2
- data/lib/numru/ganalysis/met_z.rb +300 -0
- data/lib/numru/ganalysis/planet.rb +17 -7
- data/lib/numru/ganalysis/qg.rb +685 -0
- data/lib/numru/ganalysis/sigma_coord.rb +90 -0
- data/lib/numru/gdir.rb +2 -1
- data/lib/numru/ggraph.rb +204 -60
- data/lib/numru/ggraph_on_merdional_section.rb +1 -1
- data/lib/numru/gphys.rb +6 -0
- data/lib/numru/gphys/assoccoords.rb +18 -3
- data/lib/numru/gphys/axis.rb +209 -8
- data/lib/numru/gphys/derivative.rb +11 -0
- data/lib/numru/gphys/gphys.rb +539 -48
- data/lib/numru/gphys/gphys_dim_op.rb +331 -0
- data/lib/numru/gphys/gphys_fft.rb +48 -2
- data/lib/numru/gphys/gphys_io.rb +241 -13
- data/lib/numru/gphys/gphys_netcdf_io.rb +77 -39
- data/lib/numru/gphys/gphys_nusdas_io.rb +3 -0
- data/lib/numru/gphys/grib.rb +133 -54
- data/lib/numru/gphys/grib_params.rb +26 -3
- data/lib/numru/gphys/grid.rb +75 -34
- data/lib/numru/gphys/interpolate.rb +24 -10
- data/lib/numru/gphys/mdstorage.rb +160 -0
- data/lib/numru/gphys/netcdf_convention.rb +4 -2
- data/lib/numru/gphys/subsetmapping.rb +0 -1
- data/lib/numru/gphys/unumeric.rb +50 -5
- data/lib/numru/gphys/varray.rb +15 -30
- data/lib/numru/gphys/varraycomposite.rb +107 -24
- data/lib/numru/gphys/varraynetcdf.rb +9 -3
- data/lib/numru/gphys/version.rb +5 -0
- data/sample/druby_cli1.rb +2 -0
- data/sample/druby_cli2.rb +0 -6
- data/sample/druby_serv2.rb +0 -13
- data/spec/gphys_spec.rb +11 -0
- data/spec/spec_helper.rb +2 -0
- data/test/test_assoccoords.rb +102 -0
- data/test/test_axis.rb +61 -0
- data/test/test_fitting.rb +116 -0
- data/test/test_gphys.rb +20 -0
- data/test/test_met_z.rb +96 -0
- data/test/test_sigma_coord.rb +50 -0
- data/{test → test_old}/eof_slp.rb +0 -0
- data/{test → test_old}/mltbit.dat +0 -0
- data/{test → test_old}/test_ep_flux.rb +0 -0
- data/{test → test_old}/test_multibitIO.rb +0 -0
- metadata +530 -191
- data/README.md +0 -29
- data/lib/gphys.rb +0 -2
- data/lib/numru/dclext_datetime_ax.rb +0 -220
- 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
|