gphys 1.4.3.2 → 1.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|