Skip to content

Commit acd91e1

Browse files
committed
finished mhs l1b reader
1 parent d75cafd commit acd91e1

File tree

10 files changed

+664
-333
lines changed

10 files changed

+664
-333
lines changed

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

Lines changed: 2 additions & 202 deletions
Original file line numberDiff line numberDiff line change
@@ -5,36 +5,19 @@
55
import com.bc.fiduceo.reader.*;
66
import com.bc.fiduceo.reader.amsu_mhs.nat.*;
77
import com.bc.fiduceo.reader.amsu_mhs.nat.record_types.MDR;
8-
import com.bc.fiduceo.reader.amsu_mhs.nat.record_types.MPHR;
9-
import com.bc.fiduceo.reader.time.TimeLocator;
10-
import com.bc.fiduceo.reader.time.TimeLocator_StartStopDate;
11-
import com.bc.fiduceo.util.NetCDFUtils;
12-
import com.bc.fiduceo.util.VariableProxy;
13-
import org.esa.snap.core.util.StringUtils;
14-
import ucar.ma2.Array;
15-
import ucar.ma2.ArrayInt;
16-
import ucar.ma2.DataType;
17-
import ucar.ma2.InvalidRangeException;
18-
import ucar.nc2.Attribute;
19-
import ucar.nc2.Variable;
208

219
import java.io.File;
2210
import java.io.IOException;
2311
import java.util.*;
2412

25-
import static com.bc.fiduceo.core.NodeType.UNDEFINED;
2613
import static com.bc.fiduceo.reader.amsu_mhs.nat.EPS_Constants.*;
27-
import static ucar.ma2.DataType.INT;
2814

2915
public class AMSUA_L1B_Reader extends Abstract_L1B_NatReader {
3016

3117
public static final String RESOURCE_KEY = "AMSUA_L1B";
32-
private static final int NUM_SPLITS = 2;
33-
private Dimension productSize;
3418

3519
AMSUA_L1B_Reader(ReaderContext readerContext) {
3620
super(readerContext);
37-
productSize = null;
3821
}
3922

4023
@Override
@@ -46,202 +29,19 @@ public void open(File file) throws IOException {
4629
ensureMdrVersionSupported(mdrs.get(0).getHeader());
4730
}
4831

49-
@Override
50-
public void close() throws IOException {
51-
productSize = null;
52-
super.close();
53-
}
54-
5532
@Override
5633
public AcquisitionInfo read() throws IOException {
57-
final AcquisitionInfo acquisitionInfo = new AcquisitionInfo();
58-
acquisitionInfo.setNodeType(UNDEFINED);
59-
60-
final MPHR recordMPHR = cache.getMPHR();
61-
setSensingDates(acquisitionInfo, recordMPHR);
62-
63-
final Array lon = cache.getScaled(LON_VAR_NAME);
64-
final Array lat = cache.getScaled(LAT_VAR_NAME);
65-
66-
final Geometries geometries = extractGeometries(lon, lat, NUM_SPLITS, new Interval(6, 20));
67-
acquisitionInfo.setBoundingGeometry(geometries.getBoundingGeometry());
68-
ReaderUtils.setTimeAxes(acquisitionInfo, geometries.getTimeAxesGeometry(), geometryFactory);
69-
70-
return acquisitionInfo;
34+
return super.read(new Interval(6, 20));
7135
}
7236

7337
@Override
7438
public String getRegEx() {
7539
return "AMSA_[A-Z0-9x]{3}_1B_M0[123]_[0-9]{14}Z_[0-9]{14}Z_[A-Z0-9x]{1}_[A-Z0-9x]{1}_[0-9]{14}Z\\.nat";
7640
}
7741

78-
@Override
79-
public TimeLocator getTimeLocator() throws IOException {
80-
// for the test file, the array returned contains only zeros - same as for MHS
81-
// According to the sparse documentation, I would expect this to contain seconds since epoch
82-
// tb 2025-09-04
83-
// Array timeAttitude = cache.getRaw("TIME_ATTITUDE");
84-
85-
// Instead, we interpolate between header start and stop times tb 2025-09-04
86-
final MPHR mphr = cache.getMPHR();
87-
// @todo 2 tb this is not good, because I need to know the name, better offer explicit getters for sensing start and stop
88-
final Date sensingStart = mphr.getDate(SENSING_START_KEY);
89-
final Date sensingStop = mphr.getDate(SENSING_STOP_KEY);
90-
91-
return new TimeLocator_StartStopDate(sensingStart, sensingStop, getProductSize().getNy());
92-
}
93-
94-
@Override
95-
public Array readRaw(int centerX, int centerY, Interval interval, String variableName) throws IOException, InvalidRangeException {
96-
final Array rawData = cache.getRaw(variableName);
97-
final VariableDefinition variableDef = registry.getVariableDef(variableName);
98-
final Number fillValue = EpsReaderUtils.getFillValue(variableDef.getData_type());
99-
final Dimension productSize = getProductSize();
100-
return RawDataReader.read(centerX, centerY, interval, fillValue, rawData, productSize);
101-
}
102-
103-
@Override
104-
public Array readScaled(int centerX, int centerY, Interval interval, String variableName) throws IOException, InvalidRangeException {
105-
final Array rawData = readRaw(centerX, centerY, interval, variableName);
106-
final VariableDefinition variableDef = registry.getVariableDef(variableName);
107-
return EpsReaderUtils.scale(rawData, variableDef.getScale_factor());
108-
}
109-
110-
@Override
111-
public ArrayInt.D2 readAcquisitionTime(int x, int y, Interval interval) throws IOException, InvalidRangeException {
112-
final int width = interval.getX();
113-
final int height = interval.getY();
114-
final int[] timeArray = new int[width * height];
115-
116-
final Dimension size = getProductSize();
117-
final int sceneRasterHeight = size.getNy();
118-
final int sceneRasterWidth = size.getNx();
119-
final int halfHeight = height / 2;
120-
final int halfWidth = width / 2;
121-
int writeOffset = 0;
122-
final int fillValue = NetCDFUtils.getDefaultFillValue(int.class).intValue();
123-
final TimeLocator timeLocator = getTimeLocator();
124-
125-
for (int yRead = y - halfHeight; yRead <= y + halfHeight; yRead++) {
126-
int lineTimeSeconds = fillValue;
127-
if (yRead >= 0 && yRead < sceneRasterHeight) {
128-
final long lineTimeMillis = timeLocator.getTimeFor(x, yRead);
129-
lineTimeSeconds = (int) Math.round(lineTimeMillis * 0.001);
130-
}
131-
132-
for (int xRead = x - halfWidth; xRead <= x + halfWidth; xRead++) {
133-
if (xRead >= 0 && xRead < sceneRasterWidth) {
134-
timeArray[writeOffset] = lineTimeSeconds;
135-
} else {
136-
timeArray[writeOffset] = fillValue;
137-
}
138-
++writeOffset;
139-
}
140-
}
141-
142-
final int[] shape = new int[]{interval.getY(), interval.getX()};
143-
return (ArrayInt.D2) Array.factory(INT, shape, timeArray);
144-
}
145-
146-
@Override
147-
public List<Variable> getVariables() throws InvalidRangeException, IOException {
148-
final ArrayList<Variable> variables = new ArrayList<>();
149-
150-
final Map<String, VariableDefinition> regVariables = registry.getVariables();
151-
final Set<String> keySet = regVariables.keySet();
152-
for (String variableName : keySet) {
153-
final VariableDefinition variableDefinition = regVariables.get(variableName);
154-
final int productDataType = variableDefinition.getProductData_type();
155-
final DataType netcdfDataType = NetCDFUtils.getNetcdfDataType(productDataType);
156-
final List<Attribute> attributes = extractCFAttributes(variableDefinition);
157-
158-
final VariableProxy variable = new VariableProxy(variableName, netcdfDataType, attributes);
159-
variables.add(variable);
160-
}
161-
// + SCENE_RADIANCE_01 -> SCENE_RADIANCE_15 , scale_factor 10^7, integer4
162-
// ANGULAR_RELATION, solar_zenith_angle, satellite_zenith_angle, solar_azimuth_angle, satellite_azimuth_angle
163-
// scale_factor 10^2, units degree, integer2
164-
// + EARTH_LOCATION, latitude, longitude, scale_factor 10^4, units degree, integer4
165-
// SURFACE_PROPERTIES surface_property, property(0 = water, 1 = mixed/coast, 2 = land), integer2
166-
// TERRAIN_ELEVATION terrain_elevation, units m, integer2
167-
//
168-
// to be discussed:
169-
// REFLECTOR_A11_POSITION, REFLECTOR_A12_POSITION, REFLECTOR_A2_POSITION
170-
171-
return variables;
172-
}
173-
17442
@Override
17543
public Dimension getProductSize() throws IOException {
176-
if (productSize == null) {
177-
final int numScanLines = cache.getMdrs().size();
178-
179-
productSize = new Dimension("size", AMSUA_FOV_COUNT, numScanLines);
180-
}
181-
return productSize;
182-
}
183-
184-
@Override
185-
public String getLongitudeVariableName() {
186-
return "longitude";
187-
}
188-
189-
@Override
190-
public String getLatitudeVariableName() {
191-
return "latitude";
192-
}
193-
194-
// package access for testing only tb 2025-09-17
195-
static List<Attribute> extractCFAttributes(VariableDefinition variableDefinition) {
196-
final ArrayList<Attribute> attributes = new ArrayList<>();
197-
198-
final String units = variableDefinition.getUnits();
199-
if (StringUtils.isNotNullAndNotEmpty(units)) {
200-
attributes.add(new Attribute("units", units));
201-
}
202-
203-
final double scaleFactor = variableDefinition.getScale_factor();
204-
if (scaleFactor != 1.0) {
205-
attributes.add(new Attribute("scale_factor", scaleFactor));
206-
attributes.add(new Attribute("add_offset", 0.0));
207-
}
208-
209-
final String dataType = variableDefinition.getData_type();
210-
if (StringUtils.isNotNullAndNotEmpty(dataType)) {
211-
final Number fillValue = EpsReaderUtils.getFillValue(dataType);
212-
if (fillValue != null) {
213-
attributes.add(new Attribute("_FillValue", fillValue));
214-
}
215-
}
216-
217-
final String flagMeanings = variableDefinition.getFlag_meanings();
218-
final String flagValues = variableDefinition.getFlag_values();
219-
if (StringUtils.isNotNullAndNotEmpty(flagMeanings) && StringUtils.isNotNullAndNotEmpty(flagValues)) {
220-
attributes.add(new Attribute("flag_meanings", flagMeanings));
221-
222-
final Array valuesArray = toValuesArray(flagValues, variableDefinition.getData_type());
223-
attributes.add(new Attribute("flag_values", valuesArray));
224-
}
225-
226-
final String standardName = variableDefinition.getStandard_name();
227-
if (StringUtils.isNotNullAndNotEmpty(standardName)) {
228-
attributes.add(new Attribute("standard_name", standardName));
229-
}
230-
231-
return attributes;
232-
}
233-
234-
// package access for testing only tb 2025-09-17
235-
static Array toValuesArray(String valuesString, String dataType) {
236-
final String[] valueStrings = StringUtils.split(valuesString, new char[]{','}, true);
237-
final int snapDataType = EpsReaderUtils.mapToProductData(dataType);
238-
239-
Array dataVector = Array.factory(NetCDFUtils.getNetcdfDataType(snapDataType), new int[]{valueStrings.length});
240-
241-
for (int i = 0; i < valueStrings.length; i++) {
242-
dataVector.setDouble(i, Double.parseDouble(valueStrings[i]));
243-
}
244-
return dataVector;
44+
return super.getProductSize(AMSUA_FOV_COUNT);
24545
}
24646

24747
static void ensureMdrVersionSupported(GENERIC_RECORD_HEADER header) {

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

Lines changed: 3 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -2,31 +2,17 @@
22

33
import com.bc.fiduceo.core.Dimension;
44
import com.bc.fiduceo.core.Interval;
5-
import com.bc.fiduceo.core.NodeType;
6-
import com.bc.fiduceo.geometry.*;
7-
import com.bc.fiduceo.location.PixelLocator;
85
import com.bc.fiduceo.reader.*;
96
import com.bc.fiduceo.reader.amsu_mhs.nat.*;
10-
import com.bc.fiduceo.reader.amsu_mhs.nat.record_types.MPHR;
11-
import com.bc.fiduceo.reader.time.TimeLocator_StartStopDate;
12-
import com.bc.fiduceo.reader.time.TimeLocator;
13-
import ucar.ma2.Array;
14-
import ucar.ma2.ArrayInt;
15-
import ucar.ma2.InvalidRangeException;
16-
import ucar.nc2.Variable;
177

188
import java.io.File;
199
import java.io.IOException;
20-
import java.util.Date;
21-
import java.util.List;
2210

23-
import static com.bc.fiduceo.reader.amsu_mhs.nat.EPS_Constants.SENSING_START_KEY;
24-
import static com.bc.fiduceo.reader.amsu_mhs.nat.EPS_Constants.SENSING_STOP_KEY;
11+
import static com.bc.fiduceo.reader.amsu_mhs.nat.EPS_Constants.*;
2512

2613
public class MHS_L1B_Reader extends Abstract_L1B_NatReader {
2714

2815
public static final String RESOURCE_KEY = "MHS_L1B";
29-
private static final int NUM_SPLITS = 2;
3016

3117
MHS_L1B_Reader(ReaderContext readerContext) {
3218
super(readerContext);
@@ -38,90 +24,18 @@ public void open(File file) throws IOException {
3824
readDataToCache(file, EPS_Constants.MHS_FOV_COUNT);
3925
}
4026

41-
@Override
42-
public void close() throws IOException {
43-
super.close();
44-
}
45-
4627
@Override
4728
public AcquisitionInfo read() throws IOException {
48-
final AcquisitionInfo acquisitionInfo = new AcquisitionInfo();
49-
acquisitionInfo.setNodeType(NodeType.UNDEFINED);
50-
51-
MPHR recordMPHR = cache.getMPHR();
52-
setSensingDates(acquisitionInfo, recordMPHR);
53-
54-
final Array lon = cache.getScaled("longitude");
55-
final Array lat = cache.getScaled("latitude");
56-
57-
final Geometries geometries = extractGeometries(lon, lat, NUM_SPLITS, new Interval(10, 20));
58-
acquisitionInfo.setBoundingGeometry(geometries.getBoundingGeometry());
59-
ReaderUtils.setTimeAxes(acquisitionInfo, geometries.getTimeAxesGeometry(), geometryFactory);
60-
61-
return acquisitionInfo;
29+
return super.read(new Interval(10, 20));
6230
}
6331

6432
@Override
6533
public String getRegEx() {
6634
return "MHSx_[A-Z0-9x]{3}_1B_M0[123]_[0-9]{14}Z_[0-9]{14}Z_[A-Z0-9x]{1}_[A-Z0-9x]{1}_[0-9]{14}Z\\.nat";
6735
}
6836

69-
@Override
70-
public TimeLocator getTimeLocator() throws IOException {
71-
// for the test file, the array returned contains only zeros - same as for AMSUA
72-
// According to the sparse documentation, I would expect this to contain seconds since epoch
73-
// tb 2025-09-04
74-
// Array timeAttitude = cache.getRaw("TIME_ATTITUDE");
75-
76-
// Instead, we interpolate between header start and stop times tb 2025-09-04
77-
final MPHR mphr = cache.getMPHR();
78-
// @todo 2 tb this is not good, because I need to know the name, better offer explicit getters for sensing start and stop
79-
final Date sensingStart = mphr.getDate(SENSING_START_KEY);
80-
final Date sensingStop = mphr.getDate(SENSING_STOP_KEY);
81-
82-
final int numScanLines = cache.getMdrs().size();
83-
return new TimeLocator_StartStopDate(sensingStart, sensingStop, numScanLines);
84-
}
85-
86-
@Override
87-
public Array readRaw(int centerX, int centerY, Interval interval, String variableName) throws IOException, InvalidRangeException {
88-
// todo 28-08-2025 BL: evaluate functionality and test edge cases
89-
Array array = cache.getRaw(variableName);
90-
// todo 28-08-2025 BL: figure out what the fill values are
91-
Number fillValue = Double.NaN;
92-
return RawDataReader.read(centerX, centerY, interval, fillValue, array, new Dimension("size", EPS_Constants.MHS_FOV_COUNT, 0));
93-
}
94-
95-
@Override
96-
public Array readScaled(int centerX, int centerY, Interval interval, String variableName) throws IOException, InvalidRangeException {
97-
// todo 28-08-2025 BL: evaluate functionality and test edge cases
98-
Array array = readRaw(centerX, centerY, interval, variableName);
99-
double scaleFactor = registry.getVariableDef(variableName).getScale_factor();
100-
return EpsReaderUtils.scale(array, scaleFactor);
101-
}
102-
103-
@Override
104-
public ArrayInt.D2 readAcquisitionTime(int x, int y, Interval interval) throws IOException, InvalidRangeException {
105-
throw new RuntimeException("not implemented");
106-
}
107-
108-
@Override
109-
public List<Variable> getVariables() throws InvalidRangeException, IOException {
110-
throw new RuntimeException("not implemented");
111-
}
112-
11337
@Override
11438
public Dimension getProductSize() throws IOException {
115-
throw new RuntimeException("not implemented");
116-
}
117-
118-
@Override
119-
public String getLongitudeVariableName() {
120-
throw new RuntimeException("not implemented");
121-
}
122-
123-
@Override
124-
public String getLatitudeVariableName() {
125-
throw new RuntimeException("not implemented");
39+
return super.getProductSize(MHS_FOV_COUNT);
12640
}
12741
}

0 commit comments

Comments
 (0)