netcdf 0.1.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.
@@ -0,0 +1,289 @@
1
+ /*
2
+ * netcdf.c — entry point. Defines the NetCDF module, the error class,
3
+ * shared helpers used by the submodules, and the constants table.
4
+ */
5
+ #include "internal.h"
6
+
7
+ VALUE mNetCDF;
8
+ VALUE eError;
9
+
10
+ void
11
+ nc_raise (int status)
12
+ {
13
+ VALUE msg, err;
14
+
15
+ msg = rb_str_new_cstr(nc_strerror(status));
16
+ err = rb_funcall(eError, rb_intern("new"), 1, msg);
17
+ rb_funcall(err, rb_intern("status="), 1, INT2NUM(status));
18
+ rb_exc_raise(err);
19
+ }
20
+
21
+ /* ---------------------------------------------------------- */
22
+ /* Common helpers used by io.c, var.c, etc. */
23
+ /* ---------------------------------------------------------- */
24
+
25
+ /* The array helpers below fill an array the caller provides -- one of
26
+ NC_MAX_VAR_DIMS entries on its stack holds any variable's -- rather
27
+ than allocating one, so a raise partway through (a length mismatch, an
28
+ entry that is not an Integer) leaves nothing to free. */
29
+ void
30
+ ary_to_sizet (VALUE ary, int ndims, const char *role, size_t *out)
31
+ {
32
+ long n, i;
33
+
34
+ Check_Type(ary, T_ARRAY);
35
+ n = RARRAY_LEN(ary);
36
+ if ( n != ndims ) {
37
+ rb_raise(rb_eArgError, "%s length mismatch (%ld for %d)", role, n, ndims);
38
+ }
39
+ for (i=0; i<n; i++) {
40
+ out[i] = NUM2SIZET(RARRAY_AREF(ary, i));
41
+ }
42
+ }
43
+
44
+ /* Returns false, leaving `out` untouched, when `ary` is nil. */
45
+ bool
46
+ ary_to_ptrdiff (VALUE ary, int ndims, const char *role, ptrdiff_t *out)
47
+ {
48
+ long n, i;
49
+
50
+ if ( NIL_P(ary) ) {
51
+ return false;
52
+ }
53
+ Check_Type(ary, T_ARRAY);
54
+ n = RARRAY_LEN(ary);
55
+ if ( n != ndims ) {
56
+ rb_raise(rb_eArgError, "%s length mismatch (%ld for %d)", role, n, ndims);
57
+ }
58
+ for (i=0; i<n; i++) {
59
+ out[i] = (ptrdiff_t) NUM2LL(RARRAY_AREF(ary, i));
60
+ }
61
+ return true;
62
+ }
63
+
64
+ ssize_t
65
+ nc_xtype_size (nc_type xt)
66
+ {
67
+ switch ( xt ) {
68
+ case NC_BYTE: case NC_UBYTE: case NC_CHAR: return 1;
69
+ case NC_SHORT: case NC_USHORT: return 2;
70
+ case NC_INT: case NC_UINT: case NC_FLOAT: return 4;
71
+ case NC_INT64: case NC_UINT64: case NC_DOUBLE: return 8;
72
+ default: return -1;
73
+ }
74
+ }
75
+
76
+ /* Integer conversions that refuse a value the C type cannot hold. A cast
77
+ would store 300 as NC_BYTE 44, and Ruby's own NUM2UINT / NUM2ULL wrap a
78
+ negative value around rather than raise, so -1 would be stored as the
79
+ type's maximum. */
80
+ static long long
81
+ num_in_range (VALUE v, long long lo, long long hi, const char *type)
82
+ {
83
+ long long x;
84
+
85
+ x = NUM2LL(v);
86
+ if ( x < lo || x > hi ) {
87
+ rb_raise(rb_eRangeError, "integer %lld out of range for %s", x, type);
88
+ }
89
+ return x;
90
+ }
91
+
92
+ signed char
93
+ num_to_schar (VALUE v)
94
+ {
95
+ return (signed char) num_in_range(v, SCHAR_MIN, SCHAR_MAX, "NC_BYTE");
96
+ }
97
+
98
+ unsigned char
99
+ num_to_uchar (VALUE v)
100
+ {
101
+ return (unsigned char) num_in_range(v, 0, UCHAR_MAX, "NC_UBYTE");
102
+ }
103
+
104
+ short
105
+ num_to_short (VALUE v)
106
+ {
107
+ return (short) num_in_range(v, SHRT_MIN, SHRT_MAX, "NC_SHORT");
108
+ }
109
+
110
+ unsigned short
111
+ num_to_ushort (VALUE v)
112
+ {
113
+ return (unsigned short) num_in_range(v, 0, USHRT_MAX, "NC_USHORT");
114
+ }
115
+
116
+ unsigned int
117
+ num_to_uint (VALUE v)
118
+ {
119
+ return (unsigned int) num_in_range(v, 0, UINT_MAX, "NC_UINT");
120
+ }
121
+
122
+ unsigned long long
123
+ num_to_ulonglong (VALUE v)
124
+ {
125
+ VALUE i;
126
+
127
+ i = rb_to_int(v);
128
+ if ( FIXNUM_P(i) ? FIX2LONG(i) < 0 : RBIGNUM_NEGATIVE_P(i) ) {
129
+ rb_raise(rb_eRangeError, "integer %"PRIsVALUE" out of range for NC_UINT64", i);
130
+ }
131
+ return NUM2ULL(i);
132
+ }
133
+
134
+ void
135
+ indices_to_c (int ncid, int varid, VALUE index_ary, size_t *out)
136
+ {
137
+ int ndims;
138
+
139
+ /* libnetcdf reads one coordinate per dimension of the variable, so a
140
+ shorter index would have it read past the array. */
141
+ NC_CHECK(nc_inq_varndims(ncid, varid, &ndims));
142
+ ary_to_sizet(index_ary, ndims, "index", out);
143
+ }
144
+
145
+ /* ---------------------------------------------------------- */
146
+ /* Init */
147
+ /* ---------------------------------------------------------- */
148
+
149
+ #define DEF_CONST(name) rb_define_const(mNetCDF, #name, INT2NUM(name))
150
+
151
+ void
152
+ Init_netcdf (void)
153
+ {
154
+ mNetCDF = rb_define_module("NetCDF");
155
+
156
+ eError = rb_define_class_under(mNetCDF, "Error", rb_eStandardError);
157
+ rb_define_attr(eError, "status", 1, 1);
158
+
159
+ init_nc_file();
160
+ init_nc_dim();
161
+ init_nc_var();
162
+ init_nc_att();
163
+ init_nc_io();
164
+ init_nc_group();
165
+ init_nc_types();
166
+
167
+ /* Open / create modes */
168
+ DEF_CONST(NC_NOWRITE);
169
+ DEF_CONST(NC_WRITE);
170
+ DEF_CONST(NC_CLOBBER);
171
+ DEF_CONST(NC_NOCLOBBER);
172
+ DEF_CONST(NC_SHARE);
173
+ DEF_CONST(NC_NETCDF4);
174
+ DEF_CONST(NC_CLASSIC_MODEL);
175
+ DEF_CONST(NC_64BIT_OFFSET);
176
+ #ifdef NC_DISKLESS
177
+ DEF_CONST(NC_DISKLESS);
178
+ #endif
179
+ #ifdef NC_PERSIST
180
+ DEF_CONST(NC_PERSIST);
181
+ #endif
182
+ #ifdef NC_MMAP
183
+ DEF_CONST(NC_MMAP);
184
+ #endif
185
+ #ifdef NC_INMEMORY
186
+ DEF_CONST(NC_INMEMORY);
187
+ #endif
188
+
189
+ /* Fill */
190
+ DEF_CONST(NC_FILL);
191
+ DEF_CONST(NC_NOFILL);
192
+
193
+ /* Global / unlimited */
194
+ DEF_CONST(NC_GLOBAL);
195
+ DEF_CONST(NC_UNLIMITED);
196
+
197
+ /* Types */
198
+ DEF_CONST(NC_BYTE);
199
+ DEF_CONST(NC_CHAR);
200
+ DEF_CONST(NC_SHORT);
201
+ DEF_CONST(NC_INT);
202
+ DEF_CONST(NC_FLOAT);
203
+ DEF_CONST(NC_DOUBLE);
204
+ DEF_CONST(NC_UBYTE);
205
+ DEF_CONST(NC_USHORT);
206
+ DEF_CONST(NC_UINT);
207
+ DEF_CONST(NC_INT64);
208
+ DEF_CONST(NC_UINT64);
209
+ DEF_CONST(NC_STRING);
210
+
211
+ DEF_CONST(NC_MAX_NAME);
212
+ DEF_CONST(NC_MAX_VAR_DIMS);
213
+
214
+ /* File-format codes */
215
+ DEF_CONST(NC_FORMAT_CLASSIC);
216
+ DEF_CONST(NC_FORMAT_64BIT_OFFSET);
217
+ #ifdef NC_FORMAT_64BIT_DATA
218
+ DEF_CONST(NC_FORMAT_64BIT_DATA); /* CDF-5; libnetcdf 4.4+ */
219
+ #endif
220
+ DEF_CONST(NC_FORMAT_NETCDF4);
221
+ DEF_CONST(NC_FORMAT_NETCDF4_CLASSIC);
222
+
223
+ #ifdef NC_FORMATX_NC3
224
+ DEF_CONST(NC_FORMATX_NC3);
225
+ #endif
226
+ #ifdef NC_FORMATX_NC_HDF5
227
+ DEF_CONST(NC_FORMATX_NC_HDF5);
228
+ #endif
229
+ #ifdef NC_FORMATX_NC_HDF4
230
+ DEF_CONST(NC_FORMATX_NC_HDF4);
231
+ #endif
232
+ #ifdef NC_FORMATX_PNETCDF
233
+ DEF_CONST(NC_FORMATX_PNETCDF);
234
+ #endif
235
+ #ifdef NC_FORMATX_DAP2
236
+ DEF_CONST(NC_FORMATX_DAP2);
237
+ #endif
238
+ #ifdef NC_FORMATX_DAP4
239
+ DEF_CONST(NC_FORMATX_DAP4);
240
+ #endif
241
+ #ifdef NC_FORMATX_UDF0
242
+ DEF_CONST(NC_FORMATX_UDF0);
243
+ #endif
244
+ #ifdef NC_FORMATX_UDF1
245
+ DEF_CONST(NC_FORMATX_UDF1);
246
+ #endif
247
+ #ifdef NC_FORMATX_ZARR
248
+ DEF_CONST(NC_FORMATX_ZARR);
249
+ #endif
250
+ #ifdef NC_FORMATX_UNDEFINED
251
+ DEF_CONST(NC_FORMATX_UNDEFINED);
252
+ #endif
253
+
254
+ /* Chunking / storage */
255
+ DEF_CONST(NC_CONTIGUOUS);
256
+ DEF_CONST(NC_CHUNKED);
257
+ DEF_CONST(NC_COMPACT);
258
+
259
+ /* Fletcher32 checksum modes */
260
+ DEF_CONST(NC_NOCHECKSUM);
261
+ DEF_CONST(NC_FLETCHER32);
262
+
263
+ /* Endian */
264
+ DEF_CONST(NC_ENDIAN_NATIVE);
265
+ DEF_CONST(NC_ENDIAN_LITTLE);
266
+ DEF_CONST(NC_ENDIAN_BIG);
267
+
268
+ /* Quantize modes (libnetcdf >= 4.9) */
269
+ #ifdef NC_NOQUANTIZE
270
+ DEF_CONST(NC_NOQUANTIZE);
271
+ #endif
272
+ #ifdef NC_QUANTIZE_BITGROOM
273
+ DEF_CONST(NC_QUANTIZE_BITGROOM);
274
+ #endif
275
+ #ifdef NC_QUANTIZE_GRANULARBR
276
+ DEF_CONST(NC_QUANTIZE_GRANULARBR);
277
+ #endif
278
+ #ifdef NC_QUANTIZE_BITROUND
279
+ DEF_CONST(NC_QUANTIZE_BITROUND);
280
+ #endif
281
+
282
+ /* User-defined type classes (returned by nc_inq_user_type) */
283
+ DEF_CONST(NC_VLEN);
284
+ DEF_CONST(NC_OPAQUE);
285
+ DEF_CONST(NC_ENUM);
286
+ DEF_CONST(NC_COMPOUND);
287
+
288
+ DEF_CONST(NC_FIRSTUSERTYPEID);
289
+ }
@@ -0,0 +1,3 @@
1
+ module NetCDF
2
+ VERSION = "0.1.0"
3
+ end
data/lib/netcdf.rb ADDED
@@ -0,0 +1,29 @@
1
+ require "monitor"
2
+ require "netcdf/netcdf"
3
+ require "netcdf/version"
4
+
5
+ module NetCDF
6
+ # libnetcdf, and the HDF5 under it, keep process-wide state and are not
7
+ # thread-safe: two threads inside them at once corrupt it even when they
8
+ # work on different files. Array I/O runs with the GVL released, and a
9
+ # thread holding the GVL can meanwhile call any other function -- an
10
+ # nc_close of the file being read included -- so every call is
11
+ # serialized on one lock. Waiting for it releases the GVL, so threads
12
+ # that are not using netCDF keep running. The lock is reentrant, for a
13
+ # conversion (a #to_int, say) that calls back into NetCDF.
14
+ LOCK = Monitor.new
15
+ private_constant :LOCK
16
+
17
+ synchronized = lambda do |names, visibility|
18
+ Module.new do
19
+ names.each do |name|
20
+ define_method(name) { |*args, &blk| LOCK.synchronize { super(*args, &blk) } }
21
+ end
22
+ send(visibility, *names)
23
+ end
24
+ end
25
+ # Both copies module_function makes: NetCDF.nc_open, and the private
26
+ # nc_open a class gets by including NetCDF.
27
+ singleton_class.prepend(synchronized.(singleton_methods(false), :public))
28
+ prepend(synchronized.(private_instance_methods(false), :private))
29
+ end
data/netcdf.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ Gem::Specification.new do |spec|
2
+ spec.name = "netcdf"
3
+ spec.version = File.read(File.expand_path("lib/netcdf/version.rb", __dir__))[/VERSION\s*=\s*"([^"]+)"/, 1]
4
+ spec.summary = "Ruby binding to the NetCDF C library, one Ruby method per C function"
5
+ spec.description = <<~TEXT
6
+ A literal translation of the NetCDF C library into Ruby: every function
7
+ under its own name, with libnetcdf's own documentation to read it by.
8
+ Bulk data is passed through Ruby's MemoryView protocol: an array
9
+ library's own memory is handed to libnetcdf, which reads or writes it
10
+ where it lies, and array I/O runs with the GVL released.
11
+ TEXT
12
+ spec.authors = ["himotoyoshi"]
13
+ spec.email = ["himotoyoshi@users.noreply.github.com"]
14
+ spec.license = "MIT"
15
+ spec.homepage = "https://github.com/himotoyoshi/netcdf"
16
+
17
+ spec.required_ruby_version = ">= 3.1.0"
18
+
19
+ spec.files = Dir[
20
+ "lib/**/*.rb",
21
+ "ext/netcdf/*.{c,h,rb}",
22
+ "README.md",
23
+ "CHANGELOG.md",
24
+ "docs/*.md",
25
+ "LICENSE",
26
+ "netcdf.gemspec",
27
+ ]
28
+ spec.require_paths = ["lib"]
29
+ spec.extensions = ["ext/netcdf/extconf.rb"]
30
+ end
metadata ADDED
@@ -0,0 +1,66 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: netcdf
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - himotoyoshi
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies: []
12
+ description: |
13
+ A literal translation of the NetCDF C library into Ruby: every function
14
+ under its own name, with libnetcdf's own documentation to read it by.
15
+ Bulk data is passed through Ruby's MemoryView protocol: an array
16
+ library's own memory is handed to libnetcdf, which reads or writes it
17
+ where it lies, and array I/O runs with the GVL released.
18
+ email:
19
+ - himotoyoshi@users.noreply.github.com
20
+ executables: []
21
+ extensions:
22
+ - ext/netcdf/extconf.rb
23
+ extra_rdoc_files: []
24
+ files:
25
+ - CHANGELOG.md
26
+ - LICENSE
27
+ - README.md
28
+ - docs/00_introduction.md
29
+ - docs/01_getting_started.md
30
+ - docs/02_buffers.md
31
+ - docs/03_reference.md
32
+ - ext/netcdf/extconf.rb
33
+ - ext/netcdf/internal.h
34
+ - ext/netcdf/nc_att.c
35
+ - ext/netcdf/nc_dim.c
36
+ - ext/netcdf/nc_file.c
37
+ - ext/netcdf/nc_group.c
38
+ - ext/netcdf/nc_io.c
39
+ - ext/netcdf/nc_types.c
40
+ - ext/netcdf/nc_var.c
41
+ - ext/netcdf/netcdf.c
42
+ - lib/netcdf.rb
43
+ - lib/netcdf/version.rb
44
+ - netcdf.gemspec
45
+ homepage: https://github.com/himotoyoshi/netcdf
46
+ licenses:
47
+ - MIT
48
+ metadata: {}
49
+ rdoc_options: []
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: 3.1.0
57
+ required_rubygems_version: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubygems_version: 4.0.8
64
+ specification_version: 4
65
+ summary: Ruby binding to the NetCDF C library, one Ruby method per C function
66
+ test_files: []