22
33import com .bc .fiduceo .core .Dimension ;
44import 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 ;
85import com .bc .fiduceo .reader .*;
9- import com .bc .fiduceo .reader .amsr .AmsrUtils ;
106import com .bc .fiduceo .reader .amsu_mhs .nat .*;
117import com .bc .fiduceo .reader .amsu_mhs .nat .record_types .MDR ;
128import com .bc .fiduceo .reader .amsu_mhs .nat .record_types .MPHR ;
139import com .bc .fiduceo .reader .time .TimeLocator ;
1410import 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 ;
1614import ucar .ma2 .Array ;
1715import ucar .ma2 .ArrayInt ;
16+ import ucar .ma2 .DataType ;
1817import ucar .ma2 .InvalidRangeException ;
18+ import ucar .nc2 .Attribute ;
1919import ucar .nc2 .Variable ;
2020
2121import java .io .File ;
2222import java .io .IOException ;
23- import java .util .Date ;
24- import java .util .List ;
23+ import java .util .*;
2524
2625import static com .bc .fiduceo .core .NodeType .UNDEFINED ;
2726import static com .bc .fiduceo .reader .amsu_mhs .nat .EPS_Constants .*;
27+ import static ucar .ma2 .DataType .INT ;
2828
2929public 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
0 commit comments