gphys 1.4.3.2 → 1.5.0
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.
- data/.ChangeLog.until201303 +2156 -0
- data/.gitignore +7 -1
- data/Rakefile +36 -1
- data/bin/gpview +75 -58
- data/{dim_op.c → ext/numru/gphys/dim_op.c} +4 -1
- data/{ext_coord.c → ext/numru/gphys/ext_coord.c} +35 -17
- data/{ext_init.c → ext/numru/gphys/ext_init.c} +0 -0
- data/ext/numru/gphys/extconf.rb +43 -0
- data/{interpo.c → ext/numru/gphys/interpo.c} +35 -30
- data/{multibitIO.c → ext/numru/gphys/multibitIO.c} +19 -15
- data/gphys-bigmem.gemspec +44 -0
- data/gphys.gemspec +4 -4
- data/lib/numru/dclext.rb +55 -0
- data/lib/numru/derivative.rb +6 -5
- data/lib/numru/ganalysis/met.rb +27 -10
- data/lib/numru/ganalysis/qg.rb +4 -3
- data/lib/numru/ganalysis/sph_harmonic_iso_g.rb +290 -0
- data/lib/numru/ggraph.rb +81 -2
- data/lib/numru/gphys/derivative.rb +3 -2
- data/lib/numru/gphys/gpcommon.rb +7 -1
- data/lib/numru/gphys/gphys_fft.rb +3 -3
- data/lib/numru/gphys/gphys_hdfeos5_io.rb +14 -13
- data/lib/numru/gphys/grib.rb +18 -7
- data/lib/numru/gphys/gtool3.rb +53 -52
- data/lib/numru/gphys/interpolate.rb +3 -2
- data/lib/numru/gphys/varraycomposite.rb +1 -1
- data/lib/numru/gphys/varraynetcdf.rb +38 -0
- data/lib/numru/gphys/version.rb +2 -1
- data/test/test_axis.rb +1 -5
- data/test/test_fitting.rb +0 -1
- data/test/test_gphys.rb +9 -5
- data/test/test_met_z.rb +1 -2
- data/test/test_sigma_coord.rb +0 -1
- metadata +36 -19
- checksums.yaml +0 -15
- data/.rspec +0 -2
- data/.travis.yml +0 -3
- data/ChangeLog +0 -7007
- data/extconf.rb +0 -51
- data/spec/gphys_spec.rb +0 -11
- data/spec/spec_helper.rb +0 -2
@@ -3,8 +3,9 @@
|
|
3
3
|
#include "ruby.h"
|
4
4
|
#include "narray.h"
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
/* for compatibility for NArray and NArray with big memory patch */
|
7
|
+
#ifndef NARRAY_BIGMEM
|
8
|
+
typedef int na_shape_t;
|
8
9
|
#endif
|
9
10
|
|
10
11
|
/* for compatibility with ruby 1.6 */
|
@@ -128,10 +129,10 @@ multibit_read_2D(fp, pos, nbit, sh0, sh1, f0, l0, s0, f1, l1, s1, idx0, idx1,
|
|
128
129
|
buf = ALLOCA_N(unsigned char, size);
|
129
130
|
status = fseek(fp, pf, SEEK_SET);
|
130
131
|
if (status) { rb_raise(rb_eStandardError,
|
131
|
-
"Could not move to the specified position %
|
132
|
+
"Could not move to the specified position %ld",pf); }
|
132
133
|
sz = fread(buf,1,size,fp);
|
133
134
|
if (sz!=size) { rb_raise(rb_eStandardError,
|
134
|
-
"Could not read %
|
135
|
+
"Could not read %ld bytes from %ld",size,pf); }
|
135
136
|
|
136
137
|
// << multibit -> int32_t >>
|
137
138
|
|
@@ -194,7 +195,7 @@ ary2long(src, sh, len)
|
|
194
195
|
for (i = 0; i < *len; i++) {
|
195
196
|
x = NUM2INT(ptr[i]);
|
196
197
|
if(x<-sh||x>=sh){rb_raise(rb_eArgError,
|
197
|
-
"%
|
198
|
+
"%ld-th index (%ld) is not in the index range", i,x);}
|
198
199
|
if(x<0){x += sh;}
|
199
200
|
rtn[i] = x;
|
200
201
|
}
|
@@ -225,7 +226,7 @@ na2long(src, sh, len)
|
|
225
226
|
for (i = 0; i < *len; i++) {
|
226
227
|
x = (long)ptr[i];
|
227
228
|
if(x<-sh||x>=sh){rb_raise(rb_eArgError,
|
228
|
-
"%
|
229
|
+
"%ld-th index (%ld) is not in the index range", i,x);}
|
229
230
|
if(x<0){x += sh;}
|
230
231
|
rtn[i] = x;
|
231
232
|
}
|
@@ -283,7 +284,7 @@ wrp_multibit_read_2D(self, pos, nbit, sh0, sh1, f0, l0, s0, f1, l1, s1,
|
|
283
284
|
// Then f0, s0, and l0 must be 0, 1 and len-1 of idx0
|
284
285
|
long *Idx1; // If non-NULL, index map of the subset regarding the 2nd D
|
285
286
|
// Then f1, s1, and l1 must be 0, 1 and len-1 of idx1
|
286
|
-
|
287
|
+
na_shape_t lens[2];
|
287
288
|
long len;
|
288
289
|
int32_t *ival;
|
289
290
|
float *fval;
|
@@ -300,11 +301,11 @@ wrp_multibit_read_2D(self, pos, nbit, sh0, sh1, f0, l0, s0, f1, l1, s1,
|
|
300
301
|
if (idx0 == Qnil){
|
301
302
|
F0 = NUM2INT(f0);
|
302
303
|
if(F0<-Sh0||F0>=Sh0){rb_raise(rb_eArgError,
|
303
|
-
"f0 (=%
|
304
|
+
"f0 (=%ld) is not in the index range of the 1st dim", f0);}
|
304
305
|
if(F0<0){F0 += Sh0;}
|
305
306
|
L0 = NUM2INT(l0);
|
306
307
|
if(L0<-Sh0||L0>=Sh0){rb_raise(rb_eArgError,
|
307
|
-
"l0 (=%
|
308
|
+
"l0 (=%ld) is not in the index range of the 1st dim", l0);}
|
308
309
|
if(L0<0){L0 += Sh0;}
|
309
310
|
S0 = NUM2INT(s0);
|
310
311
|
if(S0<=0){rb_raise(rb_eArgError,"s0 (step) must be positive integer");}
|
@@ -329,11 +330,11 @@ wrp_multibit_read_2D(self, pos, nbit, sh0, sh1, f0, l0, s0, f1, l1, s1,
|
|
329
330
|
if (idx1 == Qnil){
|
330
331
|
F1 = NUM2INT(f1);
|
331
332
|
if(F1<-Sh1||F1>=Sh1){rb_raise(rb_eArgError,
|
332
|
-
"f1 (=%
|
333
|
+
"f1 (=%ld) is not in the index range of the 2nd dim", f1);}
|
333
334
|
if(F1<0){F1 += Sh1;}
|
334
335
|
L1 = NUM2INT(l1);
|
335
336
|
if(L1<-Sh1||L1>=Sh1){rb_raise(rb_eArgError,
|
336
|
-
"l1 (=%
|
337
|
+
"l1 (=%ld) is not in the index range of the 2nd dim", l1);}
|
337
338
|
if(L1<0){L1 += Sh1;}
|
338
339
|
S1 = NUM2INT(s1);
|
339
340
|
if(S1<=0){rb_raise(rb_eArgError,"s1 (step) must be positive integer");}
|
@@ -417,18 +418,21 @@ str_to_uint3(unsigned char *ptr)
|
|
417
418
|
static VALUE \
|
418
419
|
rb_str_to_uint##num(int argc, VALUE *argv, VALUE self) \
|
419
420
|
{ \
|
421
|
+
unsigned char *ptr; \
|
422
|
+
unsigned long n; \
|
423
|
+
uint i; \
|
420
424
|
if (argc > 1) { \
|
421
425
|
rb_raise(rb_eArgError, "wrong number of arguments (%d for 0)", argc); \
|
422
426
|
} \
|
423
|
-
|
427
|
+
ptr = (unsigned char*)StringValuePtr(self); \
|
424
428
|
if (argc == 1) { \
|
425
|
-
|
426
|
-
if (n >= RSTRING_LEN(self)) {
|
429
|
+
n = FIX2UINT(argv[0]); \
|
430
|
+
if (n >= (unsigned long) RSTRING_LEN(self)) { \
|
427
431
|
rb_raise(rb_eArgError, "out of index"); \
|
428
432
|
} \
|
429
433
|
ptr += n; \
|
430
434
|
} \
|
431
|
-
|
435
|
+
i = str_to_uint##num(ptr); \
|
432
436
|
return UINT2NUM(i); \
|
433
437
|
}
|
434
438
|
STR2UINT(1)
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'numru/gphys/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "gphys-bigmem"
|
8
|
+
spec.version = NumRu::GPhys::VERSION
|
9
|
+
spec.authors = ["Takeshi Horinouchi", "Ryo Mizuta",\
|
10
|
+
"Daisuke Tsukahara", "Seiya Nishizawa", "Shin-ichi Takehiro"]
|
11
|
+
spec.email = ["horinout@ees.hokudai.ac.jp"]
|
12
|
+
|
13
|
+
#if spec.respond_to?(:metadata)
|
14
|
+
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com' to prevent pushes to rubygems.org, or delete to allow pushes to any server."
|
15
|
+
#end
|
16
|
+
|
17
|
+
spec.summary = %q{A multi-purpose class to handle Gridded Physical quantities}
|
18
|
+
spec.description = %q{Comprehensive library for self-descriptive gridded physical data (in NetCDF, GrADS, or on memory) with graphics. This version works with Ruby 2.0.}
|
19
|
+
spec.homepage = 'http://www.gfd-dennou.org/arch/ruby/products/gphys/'
|
20
|
+
spec.licenses = ["BSD-2-Clause"]
|
21
|
+
|
22
|
+
spec.files = `git ls-files -z`.split("\x0")
|
23
|
+
spec.bindir = "bin"
|
24
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
25
|
+
spec.require_paths = ["ext","lib"]
|
26
|
+
spec.test_files = spec.files.grep(%r{^(test|test_old|sample|testdata)/})
|
27
|
+
spec.extensions << "ext/numru/gphys/extconf.rb"
|
28
|
+
|
29
|
+
spec.post_install_message = "Thanks for installing! You can add extra libraries (i.e., ruby-lapack, rb-grib) to enjoy powerful calculating and handling datasets."
|
30
|
+
|
31
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 1.8")
|
32
|
+
|
33
|
+
spec.add_runtime_dependency(%q<narray-bigmem>)
|
34
|
+
spec.add_runtime_dependency(%q<narray_miss-bigmem>)
|
35
|
+
spec.add_runtime_dependency(%q<numru-misc-bigmem>)
|
36
|
+
spec.add_runtime_dependency(%q<numru-units>, [">= 1.7"])
|
37
|
+
spec.add_runtime_dependency(%q<ruby-netcdf-bigmem>)
|
38
|
+
spec.add_runtime_dependency(%q<ruby-dcl-bigmem>)
|
39
|
+
spec.add_runtime_dependency(%q<ruby-fftw3-bigmem>)
|
40
|
+
#spec.add_runtime_dependency(%q<gsl>, [">= 1.14"])
|
41
|
+
#spec.add_runtime_dependency(%q<rb-gsl>, [">= 1.14"])
|
42
|
+
#spec.add_runtime_dependency(%q<ruby-lapack>, [">= 1.5"])
|
43
|
+
#spec.add_development_dependency(%q<rb-grib>, [">= 0.2.0"])
|
44
|
+
end
|
data/gphys.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = NumRu::GPhys::VERSION
|
9
9
|
spec.authors = ["Takeshi Horinouchi", "Ryo Mizuta",\
|
10
10
|
"Daisuke Tsukahara", "Seiya Nishizawa", "Shin-ichi Takehiro"]
|
11
|
-
spec.email = ["
|
11
|
+
spec.email = ["horinout@ees.hokudai.ac.jp"]
|
12
12
|
|
13
13
|
#if spec.respond_to?(:metadata)
|
14
14
|
# spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com' to prevent pushes to rubygems.org, or delete to allow pushes to any server."
|
@@ -17,14 +17,14 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.summary = %q{A multi-purpose class to handle Gridded Physical quantities}
|
18
18
|
spec.description = %q{Comprehensive library for self-descriptive gridded physical data (in NetCDF, GrADS, or on memory) with graphics. This version works with Ruby 2.0.}
|
19
19
|
spec.homepage = 'http://www.gfd-dennou.org/arch/ruby/products/gphys/'
|
20
|
-
spec.licenses = ["
|
20
|
+
spec.licenses = ["BSD-2-Clause"]
|
21
21
|
|
22
22
|
spec.files = `git ls-files -z`.split("\x0")
|
23
23
|
spec.bindir = "bin"
|
24
24
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
25
|
-
spec.require_paths = ["lib"]
|
25
|
+
spec.require_paths = ["ext","lib"]
|
26
26
|
spec.test_files = spec.files.grep(%r{^(test|test_old|sample|testdata)/})
|
27
|
-
spec.extensions << "extconf.rb"
|
27
|
+
spec.extensions << "ext/numru/gphys/extconf.rb"
|
28
28
|
|
29
29
|
spec.post_install_message = "Thanks for installing! You can add extra libraries (i.e., ruby-lapack, rb-grib) to enjoy powerful calculating and handling datasets."
|
30
30
|
|
data/lib/numru/dclext.rb
CHANGED
@@ -39,6 +39,11 @@ MATH1
|
|
39
39
|
* ((<glpack>))
|
40
40
|
* ((<gl_set_params>))
|
41
41
|
Calls (({DCL.glpset})) multiple times (for each key and val of (({hash}))).
|
42
|
+
MATH2
|
43
|
+
* ((<shtlib>))
|
44
|
+
* ((<sht_get_n>)) calculate n (total wavenum)
|
45
|
+
* ((<sht_get_m>)) calcurate m (zonal wavenum)
|
46
|
+
|
42
47
|
GRPH1
|
43
48
|
* ((<sgpack>))
|
44
49
|
* ((<sg_set_params>))
|
@@ -115,6 +120,26 @@ GRPH2
|
|
115
120
|
....
|
116
121
|
DCLExt.gl_set_params(before) # reset the change
|
117
122
|
|
123
|
+
===shtlib
|
124
|
+
---sht_get_n(mm)
|
125
|
+
calcurate n (total wavenum)
|
126
|
+
|
127
|
+
ARGUMENT
|
128
|
+
* mm (Integer) : truncation wavenumber
|
129
|
+
|
130
|
+
RETURN VALUE
|
131
|
+
* n (NArray) : an integer NArray contianing n's
|
132
|
+
|
133
|
+
---sht_get_m(mm)
|
134
|
+
|
135
|
+
calcurate m (zonal wavenum)
|
136
|
+
|
137
|
+
ARGUMENT
|
138
|
+
* mm (Integer) : truncation wavenumber
|
139
|
+
|
140
|
+
RETURN VALUE
|
141
|
+
* m (NArray) : an integer NArray contianing m's
|
142
|
+
|
118
143
|
===sgpack
|
119
144
|
---sg_set_params(hash)
|
120
145
|
Calls (({DCL.sgpset})) multiple times (for each key and val of (({hash}))).
|
@@ -668,6 +693,36 @@ module NumRu
|
|
668
693
|
|
669
694
|
@@empty_hash = Hash.new
|
670
695
|
|
696
|
+
#<<< MATH2: shtlib >>>
|
697
|
+
|
698
|
+
# calcurate n (total wavenum)
|
699
|
+
def sht_get_n(mm)
|
700
|
+
ns = NArray.int((mm+1)**2)
|
701
|
+
mi = NArray.int(mm+1).indgen!
|
702
|
+
ns[0..mm] = mi # for m=0
|
703
|
+
i = mm+1
|
704
|
+
for m in 1..mm
|
705
|
+
ns[i..(i+mm-m)] = mi[m..mm]
|
706
|
+
i += mm-m+1
|
707
|
+
ns[i..(i+mm-m)] = mi[m..mm]
|
708
|
+
i += mm-m+1
|
709
|
+
end
|
710
|
+
ns
|
711
|
+
end
|
712
|
+
|
713
|
+
# calcurate m (zonal wavenum)
|
714
|
+
def sht_get_m(mm)
|
715
|
+
ns = NArray.int((mm+1)**2)
|
716
|
+
i = mm+1
|
717
|
+
for m in 1..mm
|
718
|
+
ns[i..(i+mm-m)] = m
|
719
|
+
i += mm-m+1
|
720
|
+
ns[i..(i+mm-m)] = m
|
721
|
+
i += mm-m+1
|
722
|
+
end
|
723
|
+
ns
|
724
|
+
end
|
725
|
+
|
671
726
|
#<<< udpack >>>
|
672
727
|
|
673
728
|
def ud_coloring(clr_min=13, clr_max=99)
|
data/lib/numru/derivative.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require "narray"
|
2
3
|
|
3
4
|
############################################################
|
@@ -42,7 +43,7 @@ Module functions of Derivative Operater for NArray.
|
|
42
43
|
* x (NArray): a NArray represents the dimension which derivative respect to.
|
43
44
|
z.rank must be 1.
|
44
45
|
* dim (Numeric): a Numeric represents the dimention which derivative respect to.
|
45
|
-
you can give number count backward (((<dim>))<0), but ((<z.rank
|
46
|
+
you can give number count backward (((<dim>))<0), but ((<z.rank +dim>)) must be > 0.
|
46
47
|
* bc (Numeric) : a Numeric to represent boundary condition.
|
47
48
|
Supported conditions are expressed in terms of boundary extension
|
48
49
|
applied before differentiation:
|
@@ -69,7 +70,7 @@ Module functions of Derivative Operater for NArray.
|
|
69
70
|
to. z.rank must be 1.
|
70
71
|
* dim (Numeric): a Numeric represents the dimention which derivative
|
71
72
|
respect to. you can give number count backward (((<dim>))<0), but
|
72
|
-
((<z.rank
|
73
|
+
((<z.rank +dim>)) must be > 0.
|
73
74
|
* bc (Numeric) : a Numeric to represent boundary condition.
|
74
75
|
See ((<threepoint_O2nd_deriv>)) for supported conditions.
|
75
76
|
|
@@ -89,7 +90,7 @@ Module functions of Derivative Operater for NArray.
|
|
89
90
|
to. z.rank must be 1.
|
90
91
|
* dim (Numeric): a Numeric represents the dimention which derivative
|
91
92
|
respect to. you can give number count backward (((<dim>))<0), but
|
92
|
-
((<z.rank
|
93
|
+
((<z.rank +dim>)) must be > 0.
|
93
94
|
* bc (Numeric) : a Numeric to represent boundary condition.
|
94
95
|
See ((<threepoint_O2nd_deriv>)) for supported conditions.
|
95
96
|
|
@@ -109,7 +110,7 @@ Module functions of Derivative Operater for NArray.
|
|
109
110
|
* z (NArray): a NArray which you want to expand boundary.
|
110
111
|
* dim (Numeric): a Numeric represents the dimention which derivative
|
111
112
|
respect to. you can give number count backward (((<dim>))<0), but
|
112
|
-
((<z.rank
|
113
|
+
((<z.rank +dim>)) must be > 0.
|
113
114
|
|
114
115
|
RETURN VALUE
|
115
116
|
* expand_data (NArray):
|
@@ -124,7 +125,7 @@ Module functions of Derivative Operater for NArray.
|
|
124
125
|
* x (NArray): a NArray which you want to get difference.
|
125
126
|
* dim (Numeric): a Numeric representing the dimention which derivative
|
126
127
|
respect to. you can give number count backward (((<dim>))<0), but
|
127
|
-
((<z.rank
|
128
|
+
((<z.rank +dim>)) must be > 0.
|
128
129
|
|
129
130
|
RETURN VALUE
|
130
131
|
* cdiff_data (NArray): (x_{i+1} - x_{i-1})
|
data/lib/numru/ganalysis/met.rb
CHANGED
@@ -191,26 +191,33 @@ module NumRu
|
|
191
191
|
end
|
192
192
|
private :del_ngp
|
193
193
|
|
194
|
-
# Derive geostrophic wind from geopotential hight (spherical
|
194
|
+
# Derive geostrophic wind from geopotential hight (spherical)
|
195
195
|
#
|
196
196
|
# ARGUMENTS
|
197
197
|
# * z [GPhys] : geopotential height on the pressure (or log-pressure)
|
198
198
|
# coordinate
|
199
|
-
# * f [nil or Numeric
|
200
|
-
#
|
201
|
-
# If
|
202
|
-
#
|
199
|
+
# * f [nil or GPhys or Numeric or UNumeric] : Coriolis parameter
|
200
|
+
# If nil, local Corioris parameter is used.
|
201
|
+
# If Numeric or UNumeric, f is a constant as a matter of course
|
202
|
+
# (if Numeric, units are assumed to be "s-1").
|
203
203
|
#
|
204
204
|
def z2geostrophic_wind(z, f=nil)
|
205
205
|
if f.nil?
|
206
|
-
f =
|
206
|
+
f = get_f(z)
|
207
207
|
elsif f.is_a?(Numeric)
|
208
208
|
f = UNumeric[f,"s-1"]
|
209
209
|
end
|
210
|
-
z = z.convert_units("m")
|
211
|
-
gx, gy = GAnalysis::Planet.grad_s( z *
|
212
|
-
u = -gy
|
213
|
-
v = gx
|
210
|
+
#z = z.convert_units("m")
|
211
|
+
gx, gy = GAnalysis::Planet.grad_s( z * g )
|
212
|
+
u = -gy/f
|
213
|
+
v = gx/f
|
214
|
+
if f.respond_to? :val # supposedly a GPhys
|
215
|
+
if0 = f.val.eq(0).where
|
216
|
+
if if0.length > 0
|
217
|
+
u[true,if0,false] = 0 # replace Inf with 0
|
218
|
+
v[true,if0,false] = 0 # replace Inf with 0
|
219
|
+
end
|
220
|
+
end
|
214
221
|
u.name = "u"
|
215
222
|
u.long_name = "geostrophic U"
|
216
223
|
u.put_att("assumed_f",f.to_s)
|
@@ -220,6 +227,16 @@ module NumRu
|
|
220
227
|
[u, v]
|
221
228
|
end
|
222
229
|
|
230
|
+
# Get the Coriolis parameter
|
231
|
+
def get_f(gp)
|
232
|
+
lam, phi, = GAnalysis::Planet.get_lambda_phi(gp)
|
233
|
+
sin_phi = phi.sin
|
234
|
+
f = 2 * GAnalysis::Planet.omega * sin_phi
|
235
|
+
f.name = "f"
|
236
|
+
f.long_name = "Coriolis parameter"
|
237
|
+
f
|
238
|
+
end
|
239
|
+
|
223
240
|
# Adiabatic frontogenesis function over the sphere. --
|
224
241
|
# D/Dt(|gradH theta|) or D/Dt(|gradH theta|^2), where gradH express
|
225
242
|
# the horizontal component of gradient.
|
data/lib/numru/ganalysis/qg.rb
CHANGED
@@ -10,7 +10,7 @@ require 'numru/ganalysis/beta_plane'
|
|
10
10
|
module NumRu
|
11
11
|
module GAnalysis
|
12
12
|
|
13
|
-
# QG_common:
|
13
|
+
# QG_common: collection of common methods for QG, QG_sphere, and QG_sphere_div.
|
14
14
|
module QG_common
|
15
15
|
## module_function # disabled: module functions are specified one-by-one
|
16
16
|
|
@@ -218,7 +218,7 @@ module NumRu
|
|
218
218
|
|
219
219
|
######################################################
|
220
220
|
|
221
|
-
#
|
221
|
+
# Collection of common methods for QG_sphere and QG_sphere_div
|
222
222
|
module QG_sphere_common
|
223
223
|
|
224
224
|
# Coriolis parameter f
|
@@ -248,6 +248,7 @@ module NumRu
|
|
248
248
|
module_function
|
249
249
|
extend QG_common
|
250
250
|
|
251
|
+
# This class is for internal use only
|
251
252
|
class Uninitialized
|
252
253
|
def method_missing(method_name)
|
253
254
|
raise("Reference latitude has not been set. Call QG::set_lat0 to use the module QG.")
|
@@ -389,7 +390,7 @@ module NumRu
|
|
389
390
|
p = p.convert2("Pa")
|
390
391
|
end
|
391
392
|
else
|
392
|
-
p =
|
393
|
+
p = Met.get_prs(psi).convert_units("Pa")
|
393
394
|
end
|
394
395
|
psi_xy = psi.threepoint_O2nd_deriv(0,bc,x).threepoint_O2nd_deriv(1,bc,y)
|
395
396
|
psi_xx = psi.deriv2nd(0,bc,x)
|
@@ -0,0 +1,290 @@
|
|
1
|
+
require "numru/gphys"
|
2
|
+
require "numru/dclext" # for SHTLIB and its extensions (sht_get_n, sht_get_m)
|
3
|
+
|
4
|
+
module NumRu
|
5
|
+
module GAnalysis
|
6
|
+
|
7
|
+
# Spherical harmonics library for equally spaced lon-lat grids using SHTLIB in DCL
|
8
|
+
#
|
9
|
+
# REQUIREMENT
|
10
|
+
# * This module can handle grid data that satisfy the following
|
11
|
+
# * dimension 0 (first dim) is longitude, dimension 1 is latitude.
|
12
|
+
# * must be equally spaced and cover the globe
|
13
|
+
# such as lon = 0, 2,.., 358 [,360], or -180, -170,..,170 [,180].
|
14
|
+
# etc (in increasing order; cyclic extension is applied internally)
|
15
|
+
# and lat = -90,-88,..,90. (or 90, 98,..,-90; pole to pole)
|
16
|
+
# * Data missig is not allowed
|
17
|
+
#
|
18
|
+
module SphHarmonicIsoG
|
19
|
+
@@work = @@im = @@jm = @@mm = nil
|
20
|
+
|
21
|
+
module_function
|
22
|
+
|
23
|
+
# Check the valdity of the lon-lat grid.
|
24
|
+
#
|
25
|
+
# This method raises an exception if the data is not acceptable
|
26
|
+
#
|
27
|
+
# ARGUMENTS
|
28
|
+
# * gp [GPhys] : data to check its grid
|
29
|
+
# * mm [Integer] : truncation wavenumber
|
30
|
+
#
|
31
|
+
# RETURN VALUE
|
32
|
+
# * gphys [GPhys] : same as input, but for the 1st dim is cyclically
|
33
|
+
# extended if needed.
|
34
|
+
# * np2sp [true or false] : true if data is N.pole to S.pole,
|
35
|
+
# false if data is S.pole to N.pole
|
36
|
+
def check_and_init(gphys, mm)
|
37
|
+
|
38
|
+
raise(ArgumentError, "Invalid rank (#{gphys.rank})") if gphys.rank < 2
|
39
|
+
|
40
|
+
lon = gphys.coord(0).val
|
41
|
+
if lon[0] > lon[-1]
|
42
|
+
raise ArgumentError, "Longitude must be in the increasing order."
|
43
|
+
end
|
44
|
+
gphys = gphys.cyclic_ext(0)
|
45
|
+
|
46
|
+
lat = gphys.coord(1).convert_units("degrees").val
|
47
|
+
eps = 0.1
|
48
|
+
if (lat[0]-90.0).abs < eps && (lat[-1]+90.0).abs < eps
|
49
|
+
# N.pole to S.pole
|
50
|
+
np2sp = true
|
51
|
+
elsif (lat[0]+90.0).abs > eps || (lat[-1]-90.0).abs > eps
|
52
|
+
raise ArgumentError, "Not pole to pole: #{lat[0]..lat[-1]}."
|
53
|
+
else
|
54
|
+
np2sp = false
|
55
|
+
end
|
56
|
+
|
57
|
+
nx, ny, = gphys.shape
|
58
|
+
im = (nx-1)/2
|
59
|
+
jm = (ny-1)/2
|
60
|
+
|
61
|
+
if (mm+1)/2 > jm || mm+1 > im
|
62
|
+
raise(ArgumentError,"mm=#{mm} is too big for im=#{im} & jm=#{jm}")
|
63
|
+
end
|
64
|
+
if @@work.nil? || @@mm != mm || @@jm != jm || @@im != im
|
65
|
+
@@work = DCL.shtint(mm,jm,im)
|
66
|
+
@@mm = mm
|
67
|
+
@@jm = jm
|
68
|
+
@@im = im
|
69
|
+
end
|
70
|
+
[gphys, np2sp]
|
71
|
+
end
|
72
|
+
|
73
|
+
# Spherical harmonics filter
|
74
|
+
#
|
75
|
+
# ARGUMENTS
|
76
|
+
# * gp [GPhys] : grid data to filter (lon,lat,...: rank >= 2)
|
77
|
+
# * mm [Integer] : truncation wavenumber
|
78
|
+
# * deriv (optional) [nil(default) or Symbol]
|
79
|
+
# (let \lambda be longitude and \phi be latitude)
|
80
|
+
# if :xgrad (or :xdiv), applies del / cos\phi del\lambda,
|
81
|
+
# if :ygrad, applies del / del\phi,
|
82
|
+
# if :ydiv, applies del cos\phi / cos\phi del\phi.
|
83
|
+
# * lap (optional) [nil(default) or Integer] If 1, laplacian
|
84
|
+
# is taken; if -1 inverserser laplacian is taken -- note
|
85
|
+
# that you can also explitly take laplacian by
|
86
|
+
# using the factor_n_m block (see below).
|
87
|
+
#
|
88
|
+
# * factor_n_m (optional block)
|
89
|
+
# spectral filter in the form of {|n,m| } that
|
90
|
+
# returns the factor if n and m are integers.
|
91
|
+
# Example {|n,m| -n*(n+1)} to take laplacian.
|
92
|
+
def filt( gp, mm, deriv=nil, lap=nil, &factor_n_m )
|
93
|
+
iswg2s = isws2g = 0
|
94
|
+
case deriv
|
95
|
+
when :xgrad, :xdiv
|
96
|
+
isws2g = -1
|
97
|
+
#when :xderiv
|
98
|
+
##(horinout, developpers memo: just multiply with cos\phi afterward)
|
99
|
+
# iswg2s = -1 # don't know if isws2g is better
|
100
|
+
# raise("Under development: need cos_phi factor")
|
101
|
+
when :ygrad
|
102
|
+
isws2g = 1
|
103
|
+
when :ydiv
|
104
|
+
iswg2s = 1
|
105
|
+
when nil
|
106
|
+
# do nothing
|
107
|
+
else
|
108
|
+
raise ArgumentError,"Unsupported operation #{deriv}"
|
109
|
+
end
|
110
|
+
nlon = gp.shape[0]
|
111
|
+
gp, np2sp = check_and_init(gp, mm) # sets @@work, @@mm, @@im & @@jm
|
112
|
+
na = gp.val
|
113
|
+
na = na.to_na if na.respond_to?(:to_na) # for NArrayMiss
|
114
|
+
shape = na.shape
|
115
|
+
naf = NArray.float( *shape ) # output variable (filtered NArray)
|
116
|
+
f = __factor_n_m( &factor_n_m ) if factor_n_m
|
117
|
+
loop_for_3rd_or_greater_dim(shape){|sel|
|
118
|
+
w,s = DCL.shtg2s(@@mm,iswg2s,na[*sel],@@work)
|
119
|
+
s = DCL.shtlap(@@mm,lap,s) if lap
|
120
|
+
s = s * f if factor_n_m
|
121
|
+
s = -s if np2sp && (isws2g==1 || iswg2s==1 ) # y-reversed --> *(-1)
|
122
|
+
w,g = DCL.shts2g(@@mm,@@jm,@@im,isws2g,s,@@work)
|
123
|
+
naf[*sel] = g
|
124
|
+
}
|
125
|
+
vaf = VArray.new(naf, gp.data, gp.name)
|
126
|
+
gp = GPhys.new( gp.grid, vaf)
|
127
|
+
if gp.shape[0] != nlon
|
128
|
+
# cyclically extended --> trim it to the original shape
|
129
|
+
gp = gp[0...nlon,false]
|
130
|
+
end
|
131
|
+
gp
|
132
|
+
end
|
133
|
+
|
134
|
+
def xgrad( gp, mm, &factor_n_m )
|
135
|
+
filt( gp, mm, :xgrad, &factor_n_m )
|
136
|
+
end
|
137
|
+
alias :xdiv :xgrad
|
138
|
+
module_function :xdiv
|
139
|
+
|
140
|
+
def ygrad( gp, mm, &factor_n_m )
|
141
|
+
filt( gp, mm, :ygrad, &factor_n_m )
|
142
|
+
end
|
143
|
+
def ydiv( gp, mm, &factor_n_m )
|
144
|
+
filt( gp, mm, :ydiv, &factor_n_m )
|
145
|
+
end
|
146
|
+
|
147
|
+
# Horizontal Laplacian on the sphere
|
148
|
+
#
|
149
|
+
# * gp [GPhys] : grid data (lon,lat,...: rank >= 2)
|
150
|
+
# * mm [Integer] : truncation wavenumber
|
151
|
+
# * radius (optional; defaut=1.0) [Numeric(if non-dim) or UNumeric]
|
152
|
+
# radius of the sphere
|
153
|
+
def lapla_h( gp, mm, radius=1.0, order=1 )
|
154
|
+
if order==-1 || order==1
|
155
|
+
gp = filt( gp, mm, nil, order )
|
156
|
+
elsif order > 0
|
157
|
+
gp = filt( gp, mm ){|n,m| (-n*(n+1))**order }
|
158
|
+
else
|
159
|
+
# negative --> avoid zero division
|
160
|
+
gp = filt( gp, mm ){|n,m| n==0 ? 0 : (-n*(n+1))**order }
|
161
|
+
end
|
162
|
+
gp *= radius**(-2) if radius != 1.0
|
163
|
+
gp
|
164
|
+
end
|
165
|
+
|
166
|
+
# Horizontal divergence on the sphere
|
167
|
+
#
|
168
|
+
# ARGUMENTS
|
169
|
+
# * u,v [GPhys] : the x and y components to take divergence
|
170
|
+
# * mm [Integer] : truncation wavenumber
|
171
|
+
# * radius (optional; defaut=1.0) [Numeric(if non-dim) or UNumeric]
|
172
|
+
# radius of the sphere
|
173
|
+
def div_h(u,v, mm, radius=1.0, &factor_n_m )
|
174
|
+
gp = xdiv(u, mm, &factor_n_m) + ydiv(v, mm, &factor_n_m)
|
175
|
+
gp *= radius**(-1) if radius != 1.0
|
176
|
+
gp.long_name = "div_h(#{u.name},#{v.name})"
|
177
|
+
gp.name = "div_h"
|
178
|
+
gp
|
179
|
+
end
|
180
|
+
|
181
|
+
# Horizontal rotation on the sphere
|
182
|
+
#
|
183
|
+
# * u,v [GPhys] : the x and y components to take rotation
|
184
|
+
# * mm [Integer] : truncation wavenumber
|
185
|
+
# * radius (optional; defaut=1.0) [Numeric(if non-dim) or UNumeric]
|
186
|
+
# radius of the sphere
|
187
|
+
def rot_h(u,v, mm, radius=1.0, &factor_n_m )
|
188
|
+
gp = xdiv(v, mm, &factor_n_m) - ydiv(u, mm, &factor_n_m)
|
189
|
+
gp *= radius**(-1) if radius != 1.0
|
190
|
+
gp.long_name = "rot_h(#{u.name},#{v.name})"
|
191
|
+
gp.name = "rot_h"
|
192
|
+
gp
|
193
|
+
end
|
194
|
+
|
195
|
+
def __factor_n_m( &factor_n_m )
|
196
|
+
ms = DCLExt.sht_get_m(@@mm)
|
197
|
+
ns = DCLExt.sht_get_n(@@mm)
|
198
|
+
len = ms.length
|
199
|
+
f = NArray.float(len)
|
200
|
+
for i in 0...len
|
201
|
+
f[i] = factor_n_m.call(ns[i],ms[i])
|
202
|
+
end
|
203
|
+
f
|
204
|
+
end
|
205
|
+
|
206
|
+
def loop_for_3rd_or_greater_dim(shape,&block)
|
207
|
+
raise(ArgumentError, "block not given") if !block
|
208
|
+
sh3 = shape[2..-1]
|
209
|
+
rank3 = sh3.length
|
210
|
+
csh3 = [1]
|
211
|
+
(1...rank3).each{|d| csh3[d] = sh3[d-1]*csh3[d-1]}
|
212
|
+
len = 1
|
213
|
+
sh3.each{|n| len *= n}
|
214
|
+
for i in 0...len
|
215
|
+
sel = [true,true]
|
216
|
+
(0...rank3).each do |d|
|
217
|
+
sel.push( (i/csh3[d]) % sh3[d] )
|
218
|
+
end
|
219
|
+
block.call(sel)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
#######################################################
|
229
|
+
# test / demo part
|
230
|
+
#######################################################
|
231
|
+
if __FILE__ == $0
|
232
|
+
require "numru/ggraph"
|
233
|
+
include NumRu
|
234
|
+
include GAnalysis
|
235
|
+
include NMath
|
236
|
+
gp = GPhys::IO.open("../../../testdata/T.jan.nc","T").copy
|
237
|
+
x = gp.coord(0).val.newdim(1) * (PI/180.0)
|
238
|
+
y = gp.coord(1).val.newdim(0) * (PI/180.0)
|
239
|
+
#gp[false,-1] = sin(x)*cos(y)
|
240
|
+
gp[false,-1] = sin(x)*cos(y)**2
|
241
|
+
#gp[false,-1] = (x*0+1)*cos(y) # + 1
|
242
|
+
mm = 17
|
243
|
+
c = 1.0 / ( mm*mm*(mm+1)*(mm+1) )
|
244
|
+
gpf = SphHarmonicIsoG.filt(gp,mm)
|
245
|
+
p gpf
|
246
|
+
|
247
|
+
gpf2 = SphHarmonicIsoG.filt(gp,mm){|n,m|
|
248
|
+
[0.0, 1.0 - c*n*n*(n+1)*(n+1)].max
|
249
|
+
}
|
250
|
+
|
251
|
+
gpfxg = SphHarmonicIsoG.xgrad(gp,mm)
|
252
|
+
gpfyg = SphHarmonicIsoG.ygrad(gp,mm)
|
253
|
+
gpfyd = SphHarmonicIsoG.ydiv(gp,mm)
|
254
|
+
|
255
|
+
gpflap = SphHarmonicIsoG.lapla_h(gp,mm)
|
256
|
+
|
257
|
+
DCL.swpset('iwidth',960)
|
258
|
+
DCL.swpset('iheight',720)
|
259
|
+
DCL.sgscmn(10)
|
260
|
+
DCL.gropn(1)
|
261
|
+
DCL.sldiv("t",2,3)
|
262
|
+
DCL.sgpset("lfull",true)
|
263
|
+
DCL.sgpset('isub', 96) # control character of subscription: '_' --> '`'
|
264
|
+
DCL.glpset('lmiss',true)
|
265
|
+
GGraph.set_fig "itr"=>10,"viewport"=>[0.15,0.85,0.07,0.4]
|
266
|
+
GGraph.set_tone "color_bar"=>true
|
267
|
+
GGraph.tone gp
|
268
|
+
GGraph.tone gpf, true, "keep"=>true
|
269
|
+
GGraph.tone gpf2, true, "keep"=>true
|
270
|
+
|
271
|
+
GGraph.tone gpfxg[false,1], true
|
272
|
+
k=-1
|
273
|
+
GGraph.tone gpf[false,k], true
|
274
|
+
GGraph.tone gpfxg[false,k], true
|
275
|
+
#GGraph.tone gpfx[false,k]-gpfxg[false,k], true
|
276
|
+
|
277
|
+
GGraph.tone gpfyg[false,0], true
|
278
|
+
k=-1
|
279
|
+
GGraph.tone gpf[false,k], true
|
280
|
+
GGraph.tone gpfyg[false,k], true, "min"=>-1,"max"=>1
|
281
|
+
GGraph.tone gpfyd[false,k], true, "min"=>-1.5,"max"=>1.5
|
282
|
+
GGraph.tone gpfyg[false,k]*1.5-gpfyd[false,k], true, "log"=>true
|
283
|
+
|
284
|
+
GGraph.tone gpflap[false,k]
|
285
|
+
|
286
|
+
GGraph.set_fig "itr"=>1
|
287
|
+
GGraph.line gpf.cut(true,40,false), true
|
288
|
+
GGraph.line gpfxg.cut(true,40,false), true
|
289
|
+
DCL.grcls
|
290
|
+
end
|