55import com .bc .fiduceo .reader .*;
66import com .bc .fiduceo .reader .amsu_mhs .nat .*;
77import 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
219import java .io .File ;
2210import java .io .IOException ;
2311import java .util .*;
2412
25- import static com .bc .fiduceo .core .NodeType .UNDEFINED ;
2613import static com .bc .fiduceo .reader .amsu_mhs .nat .EPS_Constants .*;
27- import static ucar .ma2 .DataType .INT ;
2814
2915public 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 ) {
0 commit comments