View Javadoc
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              // add version attribute
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 }