Skip to content

Commit b0208ca

Browse files
committed
finished AMSU reader
1 parent a0fb820 commit b0208ca

File tree

7 files changed

+498
-34
lines changed

7 files changed

+498
-34
lines changed

core/src/main/java/com/bc/fiduceo/reader/amsu_mhs/AMSUA_L1B_Reader.java

Lines changed: 126 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,92 @@
22

33
import com.bc.fiduceo.core.Dimension;
44
import com.bc.fiduceo.core.Interval;
5-
import com.bc.fiduceo.geometry.Polygon;
6-
import com.bc.fiduceo.location.PixelGeoCodingPixelLocator;
7-
import com.bc.fiduceo.location.PixelLocator;
85
import com.bc.fiduceo.reader.*;
9-
import com.bc.fiduceo.reader.amsr.AmsrUtils;
106
import com.bc.fiduceo.reader.amsu_mhs.nat.*;
117
import com.bc.fiduceo.reader.amsu_mhs.nat.record_types.MDR;
128
import com.bc.fiduceo.reader.amsu_mhs.nat.record_types.MPHR;
139
import com.bc.fiduceo.reader.time.TimeLocator;
1410
import com.bc.fiduceo.reader.time.TimeLocator_StartStopDate;
15-
import org.esa.snap.core.dataio.geocoding.GeoChecks;
11+
import com.bc.fiduceo.util.NetCDFUtils;
12+
import com.bc.fiduceo.util.VariableProxy;
13+
import org.esa.snap.core.util.StringUtils;
1614
import ucar.ma2.Array;
1715
import ucar.ma2.ArrayInt;
16+
import ucar.ma2.DataType;
1817
import ucar.ma2.InvalidRangeException;
18+
import ucar.nc2.Attribute;
1919
import ucar.nc2.Variable;
2020

2121
import java.io.File;
2222
import java.io.IOException;
23-
import java.util.Date;
24-
import java.util.List;
23+
import java.util.*;
2524

2625
import static com.bc.fiduceo.core.NodeType.UNDEFINED;
2726
import static com.bc.fiduceo.reader.amsu_mhs.nat.EPS_Constants.*;
27+
import static ucar.ma2.DataType.INT;
2828

2929
public class AMSUA_L1B_Reader extends Abstract_L1B_NatReader {
3030

3131
public static final String RESOURCE_KEY = "AMSUA_L1B";
3232
private static final int NUM_SPLITS = 2;
33+
private Dimension productSize;
3334

3435
AMSUA_L1B_Reader(ReaderContext readerContext) {
3536
super(readerContext);
37+
productSize = null;
38+
}
39+
40+
// package access for testing only tb 2025-09-17
41+
static List<Attribute> extractCFAttributes(VariableDefinition variableDefinition) {
42+
final ArrayList<Attribute> attributes = new ArrayList<>();
43+
44+
final String units = variableDefinition.getUnits();
45+
if (StringUtils.isNotNullAndNotEmpty(units)) {
46+
attributes.add(new Attribute("units", units));
47+
}
48+
49+
final double scaleFactor = variableDefinition.getScale_factor();
50+
if (scaleFactor != 1.0) {
51+
attributes.add(new Attribute("scale_factor", scaleFactor));
52+
attributes.add(new Attribute("add_offset", 0.0));
53+
}
54+
55+
final String dataType = variableDefinition.getData_type();
56+
if (StringUtils.isNotNullAndNotEmpty(dataType)) {
57+
final Number fillValue = EpsReaderUtils.getFillValue(dataType);
58+
if (fillValue != null) {
59+
attributes.add(new Attribute("_FillValue", fillValue));
60+
}
61+
}
62+
63+
final String flagMeanings = variableDefinition.getFlag_meanings();
64+
final String flagValues = variableDefinition.getFlag_values();
65+
if (StringUtils.isNotNullAndNotEmpty(flagMeanings) && StringUtils.isNotNullAndNotEmpty(flagValues)) {
66+
attributes.add(new Attribute("flag_meanings", flagMeanings));
67+
68+
final Array valuesArray = toValuesArray(flagValues, variableDefinition.getData_type());
69+
attributes.add(new Attribute("flag_values", valuesArray));
70+
}
71+
72+
final String standardName = variableDefinition.getStandard_name();
73+
if (StringUtils.isNotNullAndNotEmpty(standardName)) {
74+
attributes.add(new Attribute("standard_name", standardName));
75+
}
76+
77+
return attributes;
78+
}
79+
80+
// package access for testing only tb 2025-09-17
81+
public static Array toValuesArray(String valuesString, String dataType) {
82+
final String[] valueStrings = StringUtils.split(valuesString, new char[]{','}, true);
83+
final int snapDataType = EpsReaderUtils.mapToProductData(dataType);
84+
85+
Array dataVector = Array.factory(NetCDFUtils.getNetcdfDataType(snapDataType), new int[]{valueStrings.length});
86+
87+
for (int i = 0; i < valueStrings.length; i++) {
88+
dataVector.setDouble(i, Double.parseDouble(valueStrings[i]));
89+
}
90+
return dataVector;
3691
}
3792

3893
@Override
@@ -46,6 +101,7 @@ public void open(File file) throws IOException {
46101

47102
@Override
48103
public void close() throws IOException {
104+
productSize = null;
49105
super.close();
50106
}
51107

@@ -57,8 +113,8 @@ public AcquisitionInfo read() throws IOException {
57113
final MPHR recordMPHR = cache.getMPHR();
58114
setSensingDates(acquisitionInfo, recordMPHR);
59115

60-
final Array lon = cache.getScaled("longitude");
61-
final Array lat = cache.getScaled("latitude");
116+
final Array lon = cache.getScaled(LON_VAR_NAME);
117+
final Array lat = cache.getScaled(LAT_VAR_NAME);
62118

63119
final Geometries geometries = extractGeometries(lon, lat, NUM_SPLITS, new Interval(6, 20));
64120
acquisitionInfo.setBoundingGeometry(geometries.getBoundingGeometry());
@@ -68,8 +124,8 @@ public AcquisitionInfo read() throws IOException {
68124
}
69125

70126
static void ensureMdrVersionSupported(GENERIC_RECORD_HEADER header) {
71-
byte recordSubClass = header.getRecordSubClass();
72-
byte recordSubClassVersion = header.getRecordSubClassVersion();
127+
final byte recordSubClass = header.getRecordSubClass();
128+
final byte recordSubClassVersion = header.getRecordSubClassVersion();
73129
if (recordSubClass != 2 || recordSubClassVersion != 3) {
74130
throw new IllegalStateException("Unsupported MDR version: " + recordSubClass + " v " + recordSubClassVersion);
75131
}
@@ -93,32 +149,76 @@ public TimeLocator getTimeLocator() throws IOException {
93149
final Date sensingStart = mphr.getDate(SENSING_START_KEY);
94150
final Date sensingStop = mphr.getDate(SENSING_STOP_KEY);
95151

96-
final int numScanLines = cache.getMdrs().size();
97-
return new TimeLocator_StartStopDate(sensingStart, sensingStop, numScanLines);
152+
return new TimeLocator_StartStopDate(sensingStart, sensingStop, getProductSize().getNy());
98153
}
99154

100155
@Override
101156
public Array readRaw(int centerX, int centerY, Interval interval, String variableName) throws IOException, InvalidRangeException {
102157
final Array rawData = cache.getRaw(variableName);
103158
final VariableDefinition variableDef = registry.getVariableDef(variableName);
104159
final Number fillValue = EpsReaderUtils.getFillValue(variableDef.getData_type());
105-
final int numScanLines = cache.getMdrs().size();
106-
return RawDataReader.read(centerX, centerY, interval, fillValue, rawData, new Dimension("size", AMSUA_FOV_COUNT, numScanLines));
160+
final Dimension productSize = getProductSize();
161+
return RawDataReader.read(centerX, centerY, interval, fillValue, rawData, productSize);
107162
}
108163

109164
@Override
110165
public Array readScaled(int centerX, int centerY, Interval interval, String variableName) throws IOException, InvalidRangeException {
111-
throw new RuntimeException("not implemented");
166+
final Array rawData = readRaw(centerX, centerY, interval, variableName);
167+
final VariableDefinition variableDef = registry.getVariableDef(variableName);
168+
return EpsReaderUtils.scale(rawData, variableDef.getScale_factor());
112169
}
113170

114171
@Override
115172
public ArrayInt.D2 readAcquisitionTime(int x, int y, Interval interval) throws IOException, InvalidRangeException {
116-
throw new RuntimeException("not implemented");
173+
final int width = interval.getX();
174+
final int height = interval.getY();
175+
final int[] timeArray = new int[width * height];
176+
177+
final Dimension size = getProductSize();
178+
final int sceneRasterHeight = size.getNy();
179+
final int sceneRasterWidth = size.getNx();
180+
final int halfHeight = height / 2;
181+
final int halfWidth = width / 2;
182+
int writeOffset = 0;
183+
final int fillValue = NetCDFUtils.getDefaultFillValue(int.class).intValue();
184+
final TimeLocator timeLocator = getTimeLocator();
185+
186+
for (int yRead = y - halfHeight; yRead <= y + halfHeight; yRead++) {
187+
int lineTimeSeconds = fillValue;
188+
if (yRead >= 0 && yRead < sceneRasterHeight) {
189+
final long lineTimeMillis = timeLocator.getTimeFor(x, yRead);
190+
lineTimeSeconds = (int) Math.round(lineTimeMillis * 0.001);
191+
}
192+
193+
for (int xRead = x - halfWidth; xRead <= x + halfWidth; xRead++) {
194+
if (xRead >= 0 && xRead < sceneRasterWidth) {
195+
timeArray[writeOffset] = lineTimeSeconds;
196+
} else {
197+
timeArray[writeOffset] = fillValue;
198+
}
199+
++writeOffset;
200+
}
201+
}
202+
203+
final int[] shape = new int[]{interval.getY(), interval.getX()};
204+
return (ArrayInt.D2) Array.factory(INT, shape, timeArray);
117205
}
118206

119207
@Override
120208
public List<Variable> getVariables() throws InvalidRangeException, IOException {
121-
throw new RuntimeException("not implemented");
209+
final ArrayList<Variable> variables = new ArrayList<>();
210+
211+
final Map<String, VariableDefinition> regVariables = registry.getVariables();
212+
final Set<String> keySet = regVariables.keySet();
213+
for (String variableName : keySet) {
214+
final VariableDefinition variableDefinition = regVariables.get(variableName);
215+
final int productDataType = variableDefinition.getProductData_type();
216+
final DataType netcdfDataType = NetCDFUtils.getNetcdfDataType(productDataType);
217+
final List<Attribute> attributes = extractCFAttributes(variableDefinition);
218+
219+
final VariableProxy variable = new VariableProxy(variableName, netcdfDataType, attributes);
220+
variables.add(variable);
221+
}
122222
// + SCENE_RADIANCE_01 -> SCENE_RADIANCE_15 , scale_factor 10^7, integer4
123223
// ANGULAR_RELATION, solar_zenith_angle, satellite_zenith_angle, solar_azimuth_angle, satellite_azimuth_angle
124224
// scale_factor 10^2, units degree, integer2
@@ -128,11 +228,18 @@ public List<Variable> getVariables() throws InvalidRangeException, IOException {
128228
//
129229
// to be discussed:
130230
// REFLECTOR_A11_POSITION, REFLECTOR_A12_POSITION, REFLECTOR_A2_POSITION
231+
232+
return variables;
131233
}
132234

133235
@Override
134236
public Dimension getProductSize() throws IOException {
135-
throw new RuntimeException("not implemented");
237+
if (productSize == null) {
238+
final int numScanLines = cache.getMdrs().size();
239+
240+
productSize = new Dimension("size", AMSUA_FOV_COUNT, numScanLines);
241+
}
242+
return productSize;
136243
}
137244

138245
@Override

core/src/main/java/com/bc/fiduceo/reader/amsu_mhs/nat/EpsReaderUtils.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ public static BigInteger readUInt64(ByteBuffer buffer, int offset) {
6868
return new BigInteger(1, bytes); // unsigned interpretation
6969
}
7070

71-
// @todo 3 tb discuss naming uf unsigned types 2025-09-03
7271
public static int mapToProductData(String value) {
7372
switch (value.toLowerCase()) {
7473
case "byte":

core/src/main/java/com/bc/fiduceo/reader/amsu_mhs/nat/VariableDefinition.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ public class VariableDefinition {
1010
private String units;
1111
private String flag_values;
1212
private String flag_meanings;
13+
private String standard_name;
1314

1415
public VariableDefinition() {
1516
scale_factor = 1.0;
@@ -86,4 +87,12 @@ public String getData_layout() {
8687
public void setData_layout(String data_layout) {
8788
this.data_layout = data_layout;
8889
}
90+
91+
public String getStandard_name() {
92+
return standard_name;
93+
}
94+
95+
public void setStandard_name(String standard_name) {
96+
this.standard_name = standard_name;
97+
}
8998
}

core/src/main/java/com/bc/fiduceo/reader/amsu_mhs/nat/VariableRegistry.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ private void initialize() {
4747
layerVariableDefinition.setScale_factor(variableDefinition.getScale_factor());
4848
layerVariableDefinition.setData_type(variableDefinition.getData_type());
4949
layerVariableDefinition.setUnits(variableDefinition.getUnits());
50+
layerVariableDefinition.setStandard_name(variableDefinition.getStandard_name());
5051
final String layerKey = key.replace("*", String.format("%02d", offset + 1));
5152
toBeAdded.put(layerKey, layerVariableDefinition);
5253
}

core/src/main/resources/com/bc/fiduceo/reader/amsu_mhs/nat/AMSUA_L1B/variables.json

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,49 +5,56 @@
55
"offset": 22,
66
"stride": 15,
77
"scale_factor": 0.0000001,
8-
"units" : "mW/m2/sr/cm-1"
8+
"units" : "mW/m2/sr/cm-1",
9+
"standard_name": "toa_radiance"
910
},
1011
"solar_zenith_angle": {
1112
"data_type": "integer2",
1213
"offset": 1842,
1314
"stride": 4,
1415
"scale_factor": 0.01,
15-
"units" : "degree"
16+
"units" : "degree",
17+
"standard_name": "solar_zenith_angle"
1618
},
1719
"satellite_zenith_angle": {
1820
"data_type": "integer2",
1921
"offset": 1844,
2022
"stride": 4,
2123
"scale_factor": 0.01,
22-
"units" : "degree"
24+
"units" : "degree",
25+
"standard_name": "platform_zenith_angle"
2326
},
2427
"solar_azimuth_angle": {
2528
"data_type": "integer2",
2629
"offset": 1846,
2730
"stride": 4,
2831
"scale_factor": 0.01,
29-
"units" : "degree"
32+
"units" : "degree",
33+
"standard_name": "solar_azimuth_angle"
3034
},
3135
"satellite_azimuth_angle": {
3236
"data_type": "integer2",
3337
"offset": 1848,
3438
"stride": 4,
3539
"scale_factor": 0.01,
36-
"units" : "degree"
40+
"units" : "degree",
41+
"standard_name": "platform_azimuth_angle"
3742
},
3843
"latitude": {
3944
"data_type": "integer4",
4045
"offset": 2082,
4146
"stride": 2,
4247
"scale_factor": 0.0001,
43-
"units" : "degree"
48+
"units" : "degree",
49+
"standard_name": "latitude"
4450
},
4551
"longitude": {
4652
"data_type": "integer4",
4753
"offset": 2086,
4854
"stride": 2,
4955
"scale_factor": 0.0001,
50-
"units" : "degree"
56+
"units" : "degree",
57+
"standard_name": "longitude"
5158
},
5259
"SURFACE_PROPERTIES": {
5360
"data_type": "integer2",
@@ -60,14 +67,16 @@
6067
"data_type": "integer2",
6168
"offset": 2382,
6269
"stride": 1,
63-
"units" : "m"
70+
"units" : "m",
71+
"standard_name": "height_above_mean_sea_level"
6472
},
6573
"TIME_ATTITUDE": {
6674
"data_type": "u-integer4",
6775
"data_layout": "VECTOR",
6876
"offset": 1824,
6977
"stride": 1,
70-
"units" : "s"
78+
"units" : "s",
79+
"standard_name": "time"
7180
}
7281
}
7382
}

0 commit comments

Comments
 (0)