1 package au.gov.amsa.util.netcdf;
2
3 import java.io.File;
4 import java.io.IOException;
5 import java.util.Arrays;
6 import java.util.HashMap;
7 import java.util.List;
8 import java.util.Map;
9
10 import com.google.common.base.Optional;
11 import com.google.common.base.Preconditions;
12 import com.google.common.collect.Lists;
13
14 import ucar.ma2.Array;
15 import ucar.ma2.DataType;
16 import ucar.ma2.InvalidRangeException;
17 import ucar.nc2.Attribute;
18 import ucar.nc2.Dimension;
19 import ucar.nc2.NetcdfFileWriter;
20 import ucar.nc2.NetcdfFileWriter.Version;
21 import ucar.nc2.Variable;
22
23 public class NetCdfWriter implements AutoCloseable {
24
25 private final NetcdfFileWriter f;
26 private final Map<Var<?>, List<?>> map = new HashMap<>();
27
28 public NetCdfWriter(File file, String version) {
29 try {
30 f = NetcdfFileWriter.createNew(Version.netcdf3, file.getPath());
31
32 f.addGroupAttribute(null, new Attribute("version", version));
33 } catch (IOException e) {
34 throw new RuntimeException(e);
35 }
36 }
37
38 public NetcdfFileWriter writer() {
39 return f;
40 }
41
42 public NetCdfWriter addAttribute(String name, String value) {
43 f.addGroupAttribute(null, new Attribute(name, value));
44 return this;
45 }
46
47 public <T> VarBuilder<T> addVariable(String shortName, Class<T> cls) {
48 return new VarBuilder<T>(this, shortName, cls);
49 }
50
51 public <T> Var<T> addVariable(String shortName, Optional<String> longName,
52 Optional<String> units, Optional<String> encoding, Class<T> cls, int numRecords) {
53 Preconditions.checkNotNull(shortName);
54 Preconditions.checkNotNull(longName);
55 Preconditions.checkNotNull(units);
56 Preconditions.checkNotNull(encoding);
57 Preconditions.checkNotNull(cls);
58 Dimension dimension = f.addDimension(null, shortName, numRecords);
59 Variable variable = f.addVariable(null, shortName, toDataType(cls),
60 Arrays.asList(dimension));
61 if (longName.isPresent())
62 variable.addAttribute(new Attribute("long_name", longName.get()));
63 if (units.isPresent())
64 variable.addAttribute(new Attribute("units", units.get()));
65 if (encoding.isPresent())
66 variable.addAttribute(new Attribute("encoding", encoding.get()));
67 return new Var<T>(this, variable, cls);
68 }
69
70 public <T> NetCdfWriter add(Var<T> variable, T value) {
71 @SuppressWarnings("unchecked")
72 List<Object> list = (List<Object>) map.get(variable);
73 if (list == null) {
74 list = Lists.newArrayList();
75 map.put(variable, list);
76 }
77 list.add(value);
78 return this;
79 }
80
81 @Override
82 public void close() {
83
84 try {
85 f.create();
86 for (Var<?> var : map.keySet()) {
87 List<?> list = map.get(var);
88 int[] shape = new int[] { list.size() };
89 Array data = Array.factory(DataType.getType(var.cls()), shape);
90 for (int i = 0; i < list.size(); i++) {
91 data.setObject(i, list.get(i));
92 }
93 f.write(var.variable(), data);
94 }
95 f.close();
96 } catch (IOException e) {
97 throw new RuntimeException(e);
98 } catch (InvalidRangeException e) {
99 throw new RuntimeException(e);
100 }
101 }
102
103 private static DataType toDataType(Class<?> cls) {
104 return DataType.DOUBLE;
105 }
106
107 public static class VarBuilder<T> {
108 private final NetCdfWriter writer;
109 final String shortName;
110 final Class<T> cls;
111 Optional<String> longName = Optional.absent();
112 Optional<String> units = Optional.absent();
113 Optional<String> encoding = Optional.absent();
114 Optional<Integer> numRecords = Optional.absent();
115
116 VarBuilder(NetCdfWriter writer, String shortName, Class<T> cls) {
117 this.writer = writer;
118 this.shortName = shortName;
119 this.cls = cls;
120 }
121
122 public VarBuilder<T> longName(String s) {
123 longName = Optional.of(s);
124 return this;
125 }
126
127 public VarBuilder<T> units(String s) {
128 longName = Optional.of(s);
129 return this;
130 }
131
132 public VarBuilder<T> encoding(String s) {
133 longName = Optional.of(s);
134 return this;
135 }
136
137 public VarBuilder<T> numRecords(int n) {
138 this.numRecords = Optional.of(n);
139 return this;
140 }
141
142 public Var<T> build() {
143 return writer.addVariable(shortName, longName, units, encoding, cls, numRecords.get());
144 }
145
146 }
147
148 public static class Var<T> {
149
150 private final Variable variable;
151 private final Class<T> cls;
152 private final NetCdfWriter writer;
153
154 public Var(NetCdfWriter writer, Variable variable, Class<T> cls) {
155 this.writer = writer;
156 this.variable = variable;
157 this.cls = cls;
158 }
159
160 public Variable variable() {
161 return variable;
162 }
163
164 public Class<T> cls() {
165 return cls;
166 }
167
168 public NetCdfWriter writer() {
169 return writer;
170 }
171
172 public Var<T> add(T t) {
173 writer.add(this, t);
174 return this;
175 }
176
177 }
178
179 }