-
Notifications
You must be signed in to change notification settings - Fork 1
/
netcdf.clj
103 lines (84 loc) · 3 KB
/
netcdf.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
(ns tech.netcdf
(:require [tech.v2.datatype :as dtype]
[tech.resource :as resource]
[camel-snake-kebab.core :refer [->kebab-case]]
[tech.libs.netcdf :as lib-netcdf]
[tech.v2.tensor :as tens])
(:import [ucar.nc2.dataset NetcdfDataset]
[ucar.nc2 Dimension NetcdfFile Attribute Variable]
[ucar.ma2 DataType]))
(set! *warn-on-reflection* true)
;; Text format is cdl. NetCDF doesn't know how to deal with that.
(def test-cdl-file "test/data/sresa1b_ncar_ccsm3-example.cdl")
;; Binary formats are .nc or .nc3, etc. These we can open.
(def test-nc-file "test/data/sresa1b_ncar_ccsm3-example.nc")
(defn fname->netcdf
"Open a netcdf file. The return value is tracked via 'tech.resource/track. If the
user wishes to release the memory early they can call .close on the object."
^NetcdfFile [fname]
;;Files are Closeable and AutoCloseable so the resource system knows how to
;;deal with them.
(-> (NetcdfDataset/openFile fname, nil)
resource/track))
(defn dim->clj
[^Dimension dim]
{:name (.getName dim)
:length (.getLength dim)
:shared? (.isShared dim)
:unlimited? (.isUnlimited dim)
:variable-length? (.isVariableLength dim)})
(defn dimensions
[^NetcdfFile netcdf]
(->> (.getDimensions netcdf)
(map dim->clj)))
(defn att->clj
[^Attribute att]
{:name (.getName att)
:datatype (-> (.getDataType att)
lib-netcdf/netcdf-datatype-map)
:is-array? (.isArray att)
:is-string? (.isString att)
:value (when-not (.isArray att)
(if (.isString att)
(.getStringValue att)
(.getNumericValue att)))})
(defn named-item->map
[named-item-seq]
(->> named-item-seq
(map (juxt :name identity))
(into {})))
(defn attributes
[^NetcdfFile netcdf]
(->> (.getGlobalAttributes netcdf)
(map att->clj)
named-item->map))
(defn var->clj
[^Variable variable]
{:name (.getName variable)
:dimensions (->> (.getDimensions variable)
(map dim->clj))
:attributes (->> (.getAttributes variable)
(map att->clj)
named-item->map)
:datatype (-> (.getDataType variable)
lib-netcdf/netcdf-datatype-map)
:shape (vec (.getShape variable))
;;Maybe you don't need the data right away
:data (delay (.read variable))})
(defn variables
[^NetcdfFile netcdf]
(->> (.getVariables netcdf)
(map var->clj)
named-item->map))
(defn overview
[netcdf]
(->> (variables netcdf)
vals
(map (fn [{:keys [attributes dimensions] :as vardata}]
(assoc (select-keys vardata [:name :shape :data])
:shape-names (mapv :name dimensions)
:fullname (get-in attributes ["standard_name" :value]
(:name vardata))
:units (get-in attributes ["units" :value])
:missing-value (get-in attributes ["missing_value" :value]))))
named-item->map))