/* * Copyright (C) 2016 by Array Systems Computing Inc. http://www.array.ca * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 3 of the License, or (at your option) * any later version. * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, see http://www.gnu.org/licenses/ */ package org.esa.s1tbx.io.kompsat5; import com.bc.ceres.core.ProgressMonitor; import org.apache.commons.math3.util.FastMath; import org.esa.s1tbx.io.binary.ArrayCopy; import org.esa.s1tbx.io.netcdf.NcAttributeMap; import org.esa.s1tbx.io.netcdf.NcRasterDim; import org.esa.s1tbx.io.netcdf.NcVariableMap; import org.esa.s1tbx.io.netcdf.NetCDFReader; import org.esa.s1tbx.io.netcdf.NetCDFUtils; import org.esa.s1tbx.io.netcdf.NetcdfConstants; import org.esa.snap.core.dataio.IllegalFileFormatException; import org.esa.snap.core.dataio.ProductReaderPlugIn; import org.esa.snap.core.datamodel.Band; import org.esa.snap.core.datamodel.MetadataAttribute; import org.esa.snap.core.datamodel.MetadataElement; import org.esa.snap.core.datamodel.Product; import org.esa.snap.core.datamodel.ProductData; import org.esa.snap.core.datamodel.TiePointGrid; import org.esa.snap.core.util.Guardian; import org.esa.snap.core.util.SystemUtils; import org.esa.snap.engine_utilities.datamodel.AbstractMetadata; import org.esa.snap.engine_utilities.datamodel.Unit; import org.esa.snap.engine_utilities.eo.Constants; import org.esa.snap.engine_utilities.gpf.OperatorUtils; import org.esa.snap.engine_utilities.gpf.ReaderUtils; import ucar.ma2.Array; import ucar.ma2.InvalidRangeException; import ucar.nc2.NetcdfFile; import ucar.nc2.Variable; import java.io.File; import java.io.IOException; import java.text.DateFormat; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by luis on 12/08/2016. */ public class K5HDF implements K5Format { private final ProductReaderPlugIn readerPlugIn; private final Kompsat5Reader reader; private Product product = null; private NetcdfFile netcdfFile = null; private NcVariableMap variableMap = null; private boolean yFlipped = false; private boolean useFloatBands = false; private boolean isComplex = false; private final DateFormat standardDateFormat = ProductData.UTC.createDateFormat("yyyy-MM-dd HH:mm:ss"); private final Map<Band, Variable> bandMap = new HashMap<>(10); public K5HDF(final ProductReaderPlugIn readerPlugIn, final Kompsat5Reader reader) { this.readerPlugIn = readerPlugIn; this.reader = reader; } public Product open(final File inputFile) throws IOException { final NetcdfFile netcdfFile = NetcdfFile.open(inputFile.getPath()); if (netcdfFile == null) { close(); throw new IllegalFileFormatException(inputFile.getName() + " Could not be interpreted by the reader."); } final Map<NcRasterDim, List<Variable>> variableListMap = NetCDFUtils.getVariableListMap(netcdfFile.getRootGroup()); if (variableListMap.isEmpty()) { close(); throw new IllegalFileFormatException("No netCDF variables found which could\n" + "be interpreted as remote sensing bands."); /*I18N*/ } removeQuickLooks(variableListMap); final NcRasterDim rasterDim = NetCDFUtils.getBestRasterDim(variableListMap); final Variable[] rasterVariables = getRasterVariables(variableListMap, rasterDim); final Variable[] tiePointGridVariables = NetCDFUtils.getTiePointGridVariables(variableListMap, rasterVariables); this.netcdfFile = netcdfFile; variableMap = new NcVariableMap(rasterVariables); yFlipped = false; final NcAttributeMap globalAttributes = NcAttributeMap.create(this.netcdfFile); final String productType = NetCDFUtils.getProductType(globalAttributes, readerPlugIn.getFormatNames()[0]); final int rasterWidth = rasterDim.getDimX().getLength(); final int rasterHeight = rasterDim.getDimY().getLength(); product = new Product(inputFile.getName(), productType, rasterWidth, rasterHeight, reader); product.setFileLocation(inputFile); product.setDescription(NetCDFUtils.getProductDescription(globalAttributes)); product.setStartTime(NetCDFUtils.getSceneRasterStartTime(globalAttributes)); product.setEndTime(NetCDFUtils.getSceneRasterStopTime(globalAttributes)); addMetadataToProduct(); addBandsToProduct(rasterVariables); addTiePointGridsToProduct(tiePointGridVariables); addGeoCodingToProduct(product, rasterDim); addSlantRangeToFirstPixel(); addFirstLastLineTimes(product, rasterHeight); addSRGRCoefficients(product); addDopplerCentroidCoefficients(product); return product; } public void close() throws IOException { if (product != null) { product = null; variableMap.clear(); variableMap = null; netcdfFile.close(); netcdfFile = null; } } private static Variable[] getRasterVariables(Map<NcRasterDim, List<Variable>> variableLists, NcRasterDim rasterDim) { final List<Variable> varList = variableLists.get(rasterDim); final List<Variable> list = new ArrayList<>(5); for (Variable var : varList) { if (!var.getShortName().equals("GIM")) { list.add(var); } } return list.toArray(new Variable[list.size()]); } private static void removeQuickLooks(Map<NcRasterDim, List<Variable>> variableListMap) { final String[] excludeList = {"qlk"}; final NcRasterDim[] keys = variableListMap.keySet().toArray(new NcRasterDim[variableListMap.keySet().size()]); final List<NcRasterDim> removeList = new ArrayList<>(); for (final NcRasterDim rasterDim : keys) { final List<Variable> varList = variableListMap.get(rasterDim); boolean found = false; for (Variable v : varList) { if (found) break; final String vName = v.getShortName().toLowerCase(); for (String str : excludeList) { if (vName.contains(str)) { removeList.add(rasterDim); found = true; break; } } } } for (NcRasterDim key : removeList) { variableListMap.remove(key); } } private void addGeoCodingToProduct(final Product product, final NcRasterDim rasterDim) throws IOException { if (product.getSceneGeoCoding() == null) { NetCDFReader.setTiePointGeoCoding(product); } if (product.getSceneGeoCoding() == null) { NetCDFReader.setPixelGeoCoding(product); } if (product.getSceneGeoCoding() == null) { yFlipped = NetCDFReader.setMapGeoCoding(rasterDim, product, netcdfFile, yFlipped); } } private void addMetadataToProduct() throws IOException { try { final MetadataElement origMetadataRoot = AbstractMetadata.addOriginalProductMetadata(product.getMetadataRoot()); NetCDFUtils.addAttributes(origMetadataRoot, NetcdfConstants.GLOBAL_ATTRIBUTES_NAME, netcdfFile.getGlobalAttributes()); addAuxXML(product); for (final Variable variable : variableMap.getAll()) { NetCDFUtils.addAttributes(origMetadataRoot, variable.getShortName(), variable.getAttributes()); } //final Group rootGroup = netcdfFile.getRootGroup(); //NetCDFUtils.addGroups(product.getMetadataRoot(), rootGroup); addAbstractedMetadataHeader(product, product.getMetadataRoot()); } catch (Exception e) { SystemUtils.LOG.severe("Error reading metadata for " + product.getName() + ": " + e.getMessage()); } } private void addAbstractedMetadataHeader(Product product, MetadataElement root) throws IOException { final MetadataElement absRoot = AbstractMetadata.addAbstractedMetadataHeader(root); final String defStr = AbstractMetadata.NO_METADATA_STRING; final int defInt = AbstractMetadata.NO_METADATA; final MetadataElement origRoot = AbstractMetadata.addOriginalProductMetadata(product.getMetadataRoot()); final MetadataElement globalElem = origRoot.getElement(NetcdfConstants.GLOBAL_ATTRIBUTES_NAME); final MetadataElement auxElem = origRoot.getElement("Auxiliary").getElement("Root"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.PRODUCT, globalElem.getAttributeString("Product_Filename", defStr)); final String productType = globalElem.getAttributeString("Product_Type", defStr); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.PRODUCT_TYPE, productType); final String mode = globalElem.getAttributeString("Acquisition_Mode", defStr); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.SPH_DESCRIPTOR, mode); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ACQUISITION_MODE, mode); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.MISSION, "Kompsat5"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.PROC_TIME, ReaderUtils.getTime(globalElem, "Product_Generation_UTC", standardDateFormat)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ProcessingSystemIdentifier, globalElem.getAttributeString("Processing_Centre", defStr)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.antenna_pointing, globalElem.getAttributeString("Look_Side", defStr).toLowerCase()); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ABS_ORBIT, globalElem.getAttributeInt("Orbit_Number", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.PASS, globalElem.getAttributeString("Orbit_Direction", defStr)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.SAMPLE_TYPE, getSampleType(globalElem)); useFloatBands = globalElem.getAttributeString("Sample_Format", defStr).equals("FLOAT"); // final ProductData.UTC startTime = ReaderUtils.getTime(globalElem, "Scene_Sensing_Start_UTC", standardDateFormat); // final ProductData.UTC stopTime = ReaderUtils.getTime(globalElem, "Scene_Sensing_Stop_UTC", standardDateFormat); // AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_line_time, startTime); // AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_line_time, stopTime); // product.setStartTime(startTime); // product.setEndTime(stopTime); //AbstractMetadata.setAttribute(absRoot, AbstractMetadata.line_time_interval, // ReaderUtils.getLineTimeInterval(startTime, stopTime, product.getSceneRasterHeight())); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.num_output_lines, product.getSceneRasterHeight()); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.num_samples_per_line, product.getSceneRasterWidth()); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.TOT_SIZE, ReaderUtils.getTotalSize(product)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.radar_frequency, globalElem.getAttributeDouble("Radar_Frequency", defInt) / Constants.oneMillion); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.algorithm, globalElem.getAttributeString("Focusing_Algorithm_ID", defStr)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.geo_ref_system, globalElem.getAttributeString("Ellipsoid_Designator", defStr)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_looks, globalElem.getAttributeDouble("Range_Processing_Number_of_Looks", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.azimuth_looks, globalElem.getAttributeDouble("Azimuth_Processing_Number_of_Looks", defInt)); if (productType.contains("GEC")) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.map_projection, globalElem.getAttributeString("Projection_ID", defStr)); } // Global calibration attributes /* AbstractMetadata.setAttribute(absRoot, AbstractMetadata.abs_calibration_flag, globalElem.getAttributeInt("Calibration_Constant_Compensation_Flag")); */ AbstractMetadata.setAttribute(absRoot, AbstractMetadata.coregistered_stack, 0); final String rngSpreadComp = globalElem.getAttributeString( "Range_Spreading_Loss_Compensation_Geometry", defStr); if (rngSpreadComp.equals("NONE")) AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_spread_comp_flag, 0); else AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_spread_comp_flag, 1); final String incAngComp = globalElem.getAttributeString( "Incidence_Angle_Compensation_Geometry", defStr); if (incAngComp.equals("NONE")) AbstractMetadata.setAttribute(absRoot, AbstractMetadata.inc_angle_comp_flag, 0); else AbstractMetadata.setAttribute(absRoot, AbstractMetadata.inc_angle_comp_flag, 1); final String antElevComp = globalElem.getAttributeString( "Range_Antenna_Pattern_Compensation_Geometry", defStr); if (antElevComp.equals("NONE")) AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ant_elev_corr_flag, 0); else AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ant_elev_corr_flag, 1); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ref_inc_angle, globalElem.getAttributeDouble("Reference_Incidence_Angle", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ref_slant_range, globalElem.getAttributeDouble("Reference_Slant_Range", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.ref_slant_range_exp, globalElem.getAttributeDouble("Reference_Slant_Range_Exponent", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.rescaling_factor, globalElem.getAttributeDouble("Rescaling_Factor", defInt)); final MetadataElement s01Elem = globalElem.getElement("S01"); if (s01Elem != null) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.pulse_repetition_frequency, s01Elem.getAttributeDouble("PRF", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_sampling_rate, s01Elem.getAttributeDouble("Sampling_Rate", defInt) / Constants.oneMillion); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.mds1_tx_rx_polar, s01Elem.getAttributeString("Polarisation", defStr)); // add Range and Azimuth bandwidth final double rangeBW = s01Elem.getAttributeDouble("Range_Focusing_Bandwidth"); // Hz final double azimuthBW = s01Elem.getAttributeDouble("Azimuth_Focusing_Bandwidth"); // Hz AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_bandwidth, rangeBW / Constants.oneMillion); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.azimuth_bandwidth, azimuthBW); // Calibration constant read from Global_Metadata during calibration initialization } else { final String prefix = "S01_"; AbstractMetadata.setAttribute(absRoot, AbstractMetadata.pulse_repetition_frequency, globalElem.getAttributeDouble(prefix + "PRF", defInt)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_sampling_rate, globalElem.getAttributeDouble(prefix + "Sampling_Rate", defInt) / Constants.oneMillion); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.mds1_tx_rx_polar, globalElem.getAttributeString(prefix + "Polarisation", defStr)); // add Range and Azimuth bandwidth final double rangeBW = globalElem.getAttributeDouble(prefix + "Range_Focusing_Bandwidth"); // Hz final double azimuthBW = globalElem.getAttributeDouble(prefix + "Azimuth_Focusing_Bandwidth"); // Hz AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_bandwidth, rangeBW / Constants.oneMillion); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.azimuth_bandwidth, azimuthBW); } final MetadataElement s02Elem = globalElem.getElement("S02"); if (s02Elem != null) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.mds2_tx_rx_polar, s02Elem.getAttributeString("Polarisation", defStr)); } else { final String prefix = "S02_"; AbstractMetadata.setAttribute(absRoot, AbstractMetadata.mds2_tx_rx_polar, globalElem.getAttributeString(prefix + "Polarisation", defStr)); } if (isComplex) { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.srgr_flag, 0); } else { AbstractMetadata.setAttribute(absRoot, AbstractMetadata.srgr_flag, 1); } addOrbitStateVectors(absRoot, globalElem); } private void addSlantRangeToFirstPixel() { final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); final MetadataElement bandElem = getBandElement(product.getBandAt(0)); if (bandElem != null) { final double slantRangeTime = bandElem.getAttributeDouble("Zero_Doppler_Range_First_Time", 0); //s AbstractMetadata.setAttribute(absRoot, AbstractMetadata.slant_range_to_first_pixel, slantRangeTime * Constants.halfLightSpeed); } } private void addOrbitStateVectors(final MetadataElement absRoot, final MetadataElement globalElem) { final MetadataElement orbitVectorListElem = absRoot.getElement(AbstractMetadata.orbit_state_vectors); final ProductData.UTC referenceUTC = ReaderUtils.getTime(globalElem, "Reference_UTC", standardDateFormat); final int numPoints = globalElem.getAttributeInt("Number_of_State_Vectors"); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.STATE_VECTOR_TIME, referenceUTC); for (int i = 0; i < numPoints; i++) { final double stateVectorTime = globalElem.getAttribute("State_Vectors_Times").getData().getElemDoubleAt(i); final ProductData.UTC orbitTime = new ProductData.UTC(referenceUTC.getMJD() + stateVectorTime / Constants.secondsInDay); final ProductData pos = globalElem.getAttribute("ECEF_Satellite_Position").getData(); final ProductData vel = globalElem.getAttribute("ECEF_Satellite_Velocity").getData(); final double satellitePositionX = pos.getElemDoubleAt(3 * i); final double satellitePositionY = pos.getElemDoubleAt(3 * i + 1); final double satellitePositionZ = pos.getElemDoubleAt(3 * i + 2); final double satelliteVelocityX = vel.getElemDoubleAt(3 * i); final double satelliteVelocityY = vel.getElemDoubleAt(3 * i + 1); final double satelliteVelocityZ = vel.getElemDoubleAt(3 * i + 2); final MetadataElement orbitVectorElem = new MetadataElement(AbstractMetadata.orbit_vector + (i + 1)); orbitVectorElem.setAttributeUTC(AbstractMetadata.orbit_vector_time, orbitTime); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_x_pos, satellitePositionX); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_y_pos, satellitePositionY); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_z_pos, satellitePositionZ); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_x_vel, satelliteVelocityX); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_y_vel, satelliteVelocityY); orbitVectorElem.setAttributeDouble(AbstractMetadata.orbit_vector_z_vel, satelliteVelocityZ); orbitVectorListElem.addElement(orbitVectorElem); } } private static void addDopplerCentroidCoefficients(final Product product) { final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); final MetadataElement root = AbstractMetadata.getOriginalProductMetadata(product); final MetadataElement globalElem = root.getElement(NetcdfConstants.GLOBAL_ATTRIBUTES_NAME); final MetadataElement dopplerCentroidCoefficientsElem = absRoot.getElement(AbstractMetadata.dop_coefficients); final MetadataElement dopplerListElem = new MetadataElement(AbstractMetadata.dop_coef_list + ".1"); dopplerCentroidCoefficientsElem.addElement(dopplerListElem); final ProductData.UTC utcTime = absRoot.getAttributeUTC(AbstractMetadata.first_line_time, AbstractMetadata.NO_METADATA_UTC); dopplerListElem.setAttributeUTC(AbstractMetadata.dop_coef_time, utcTime); AbstractMetadata.addAbstractedAttribute(dopplerListElem, AbstractMetadata.slant_range_time, ProductData.TYPE_FLOAT64, "ns", "Slant Range Time"); AbstractMetadata.setAttribute(dopplerListElem, AbstractMetadata.slant_range_time, 0.0); for (int i = 0; i < 6; i++) { final double coefValue = globalElem.getAttribute("Centroid_vs_Range_Time_Polynomial").getData().getElemDoubleAt(i); final MetadataElement coefElem = new MetadataElement(AbstractMetadata.coefficient + '.' + (i + 1)); dopplerListElem.addElement(coefElem); AbstractMetadata.addAbstractedAttribute(coefElem, AbstractMetadata.dop_coef, ProductData.TYPE_FLOAT64, "", "Doppler Centroid Coefficient"); AbstractMetadata.setAttribute(coefElem, AbstractMetadata.dop_coef, coefValue); } } private void addFirstLastLineTimes(final Product product, final int rasterHeight) { final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); final MetadataElement root = AbstractMetadata.getOriginalProductMetadata(product); final MetadataElement globalElem = root.getElement(NetcdfConstants.GLOBAL_ATTRIBUTES_NAME); final MetadataElement bandElem = getBandElement(product.getBandAt(0)); if (bandElem != null) { final double referenceUTC = ReaderUtils.getTime(globalElem, "Reference_UTC", standardDateFormat).getMJD(); // in days double firstLineTime = bandElem.getAttributeDouble("Zero_Doppler_Azimuth_First_Time", 0) / (24 * 3600); // in days if (firstLineTime == 0) { final MetadataElement s01Elem = globalElem.getElement("S01"); if (s01Elem != null) { firstLineTime = s01Elem.getElement("B001").getAttributeDouble("Azimuth_First_Time") / (24 * 3600); // in days } else { firstLineTime = globalElem.getAttributeDouble("S01_B001_Azimuth_First_Time") / (24 * 3600); // in days } } double lastLineTime = bandElem.getAttributeDouble("Zero_Doppler_Azimuth_Last_Time", 0) / (24 * 3600); // in days if (lastLineTime == 0) { final MetadataElement s01Elem = globalElem.getElement("S01"); if (s01Elem != null) { lastLineTime = s01Elem.getElement("B001").getAttributeDouble("Azimuth_Last_Time") / (24 * 3600); // in days } else { lastLineTime = globalElem.getAttributeDouble("S01_B001_Azimuth_Last_Time") / (24 * 3600); // in days } } double lineTimeInterval = bandElem.getAttributeDouble("Line_Time_Interval", 0); // in s final ProductData.UTC startTime = new ProductData.UTC(referenceUTC + firstLineTime); final ProductData.UTC stopTime = new ProductData.UTC(referenceUTC + lastLineTime); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.first_line_time, startTime); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.last_line_time, stopTime); product.setStartTime(startTime); product.setEndTime(stopTime); if (lineTimeInterval == 0 || lastLineTime == AbstractMetadata.NO_METADATA) { lineTimeInterval = ReaderUtils.getLineTimeInterval(startTime, stopTime, rasterHeight); } double lineTimeInterval2 = ReaderUtils.getLineTimeInterval(startTime, stopTime, rasterHeight); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.line_time_interval, lineTimeInterval); } } private void addSRGRCoefficients(final Product product) { // For detail of ground range to slant range conversion, please see P80 in COSMO-SkyMed SAR Products Handbook. final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); final MetadataElement root = AbstractMetadata.getOriginalProductMetadata(product); final MetadataElement globalElem = root.getElement(NetcdfConstants.GLOBAL_ATTRIBUTES_NAME); final MetadataAttribute attribute = globalElem.getAttribute("Ground_Projection_Polynomial_Reference_Range"); if (attribute == null) { return; } final double referenceRange = attribute.getData().getElemDouble(); final MetadataElement bandElem = getBandElement(product.getBandAt(0)); final double rangeSpacing = bandElem.getAttributeDouble("Column_Spacing", AbstractMetadata.NO_METADATA); final MetadataElement srgrCoefficientsElem = absRoot.getElement(AbstractMetadata.srgr_coefficients); final MetadataElement srgrListElem = new MetadataElement(AbstractMetadata.srgr_coef_list); srgrCoefficientsElem.addElement(srgrListElem); final ProductData.UTC utcTime = absRoot.getAttributeUTC(AbstractMetadata.first_line_time, AbstractMetadata.NO_METADATA_UTC); srgrListElem.setAttributeUTC(AbstractMetadata.srgr_coef_time, utcTime); AbstractMetadata.addAbstractedAttribute(srgrListElem, AbstractMetadata.ground_range_origin, ProductData.TYPE_FLOAT64, "m", "Ground Range Origin"); AbstractMetadata.setAttribute(srgrListElem, AbstractMetadata.ground_range_origin, 0.0); final int numCoeffs = 6; for (int i = 0; i < numCoeffs; i++) { double srgrCoeff = globalElem.getAttribute("Ground_to_Slant_Polynomial").getData().getElemDoubleAt(i); if (i == 0) { srgrCoeff += referenceRange; } else { srgrCoeff /= FastMath.pow(rangeSpacing, i); } final MetadataElement coefElem = new MetadataElement(AbstractMetadata.coefficient + '.' + (i + 1)); srgrListElem.addElement(coefElem); AbstractMetadata.addAbstractedAttribute(coefElem, AbstractMetadata.srgr_coef, ProductData.TYPE_FLOAT64, "", "SRGR Coefficient"); AbstractMetadata.setAttribute(coefElem, AbstractMetadata.srgr_coef, srgrCoeff); } } private String getSampleType(final MetadataElement globalElem) { if (globalElem.getAttributeInt("Samples_per_Pixel", 0) > 1) { isComplex = true; return "COMPLEX"; } isComplex = false; return "DETECTED"; } private void addBandsToProduct(final Variable[] variables) { int cnt = 1; for (Variable variable : variables) { final int height = variable.getDimension(0).getLength(); final int width = variable.getDimension(1).getLength(); String cntStr = ""; final String polStr = getPolarization(product, cnt); if (polStr != null) { cntStr = '_' + polStr; } else { cntStr = "_" + cnt; } ++cnt; if (isComplex) { // add i and q final Band bandI = useFloatBands ? NetCDFUtils.createBand(variable, width, height, ProductData.TYPE_FLOAT32) : NetCDFUtils.createBand(variable, width, height); createUniqueBandName(product, bandI, 'i' + cntStr); bandI.setUnit(Unit.REAL); bandI.setNoDataValue(0); bandI.setNoDataValueUsed(true); product.addBand(bandI); bandMap.put(bandI, variable); final Band bandQ = useFloatBands ? NetCDFUtils.createBand(variable, width, height, ProductData.TYPE_FLOAT32) : NetCDFUtils.createBand(variable, width, height); createUniqueBandName(product, bandQ, 'q' + cntStr); bandQ.setUnit(Unit.IMAGINARY); bandQ.setNoDataValue(0); bandQ.setNoDataValueUsed(true); product.addBand(bandQ); bandMap.put(bandQ, variable); ReaderUtils.createVirtualIntensityBand(product, bandI, bandQ, cntStr); } else { final Band band = useFloatBands ? NetCDFUtils.createBand(variable, width, height, ProductData.TYPE_FLOAT32) : NetCDFUtils.createBand(variable, width, height); createUniqueBandName(product, band, "Amplitude" + cntStr); band.setUnit(Unit.AMPLITUDE); band.setNoDataValue(0); band.setNoDataValueUsed(true); product.addBand(band); bandMap.put(band, variable); reader.createVirtualIntensityBand(product, band, cntStr); } } } private static String getPolarization(final Product product, final int cnt) { final MetadataElement globalElem = AbstractMetadata.getOriginalProductMetadata(product).getElement(NetcdfConstants.GLOBAL_ATTRIBUTES_NAME); if (globalElem != null) { final MetadataElement s01Elem = globalElem.getElement("S0" + cnt); if (s01Elem != null) { final String polStr = s01Elem.getAttributeString("Polarisation", ""); if (!polStr.isEmpty()) return polStr; } else { final String prefix = "S0" + cnt + '_'; final String polStr = globalElem.getAttributeString(prefix + "Polarisation", ""); if (!polStr.isEmpty()) return polStr; } } return null; } private static void createUniqueBandName(final Product product, final Band band, final String origName) { int cnt = 1; band.setName(origName); while (product.getBand(band.getName()) != null) { band.setName(origName + cnt); ++cnt; } } private void addTiePointGridsToProduct(final Variable[] variables) throws IOException { // for (Variable variable : variables) { // final int rank = variable.getRank(); // final int gridWidth = variable.getDimension(rank - 1).getLength(); // int gridHeight = variable.getDimension(rank - 2).getLength(); // if (rank >= 3 && gridHeight <= 1) // gridHeight = variable.getDimension(rank - 3).getLength(); // final TiePointGrid tpg = NetCDFUtils.createTiePointGrid(variable, gridWidth, gridHeight, // product.getSceneRasterWidth(), product.getSceneRasterHeight()); // // product.addTiePointGrid(tpg); // } final MetadataElement bandElem = getBandElement(product.getBandAt(0)); addIncidenceAnglesSlantRangeTime(product, bandElem); addGeocodingFromMetadata(product, bandElem); } private static void addIncidenceAnglesSlantRangeTime(final Product product, final MetadataElement bandElem) { if (bandElem == null) return; final int gridWidth = 11; final int gridHeight = 11; final float subSamplingX = product.getSceneRasterWidth() / (float) (gridWidth - 1); final float subSamplingY = product.getSceneRasterHeight() / (float) (gridHeight - 1); final double nearRangeAngle = bandElem.getAttributeDouble("Near_Incidence_Angle", 0); final double farRangeAngle = bandElem.getAttributeDouble("Far_Incidence_Angle", 0); final double firstRangeTime = bandElem.getAttributeDouble("Zero_Doppler_Range_First_Time", 0) * Constants.oneBillion; final double lastRangeTime = bandElem.getAttributeDouble("Zero_Doppler_Range_Last_Time", 0) * Constants.oneBillion; final float[] incidenceCorners = new float[]{(float) nearRangeAngle, (float) farRangeAngle, (float) nearRangeAngle, (float) farRangeAngle}; final float[] slantRange = new float[]{(float) firstRangeTime, (float) lastRangeTime, (float) firstRangeTime, (float) lastRangeTime}; final float[] fineAngles = new float[gridWidth * gridHeight]; final float[] fineTimes = new float[gridWidth * gridHeight]; ReaderUtils.createFineTiePointGrid(2, 2, gridWidth, gridHeight, incidenceCorners, fineAngles); ReaderUtils.createFineTiePointGrid(2, 2, gridWidth, gridHeight, slantRange, fineTimes); final TiePointGrid incidentAngleGrid = new TiePointGrid(OperatorUtils.TPG_INCIDENT_ANGLE, gridWidth, gridHeight, 0, 0, subSamplingX, subSamplingY, fineAngles); incidentAngleGrid.setUnit(Unit.DEGREES); product.addTiePointGrid(incidentAngleGrid); final TiePointGrid slantRangeGrid = new TiePointGrid(OperatorUtils.TPG_SLANT_RANGE_TIME, gridWidth, gridHeight, 0, 0, subSamplingX, subSamplingY, fineTimes); slantRangeGrid.setUnit(Unit.NANOSECONDS); product.addTiePointGrid(slantRangeGrid); } private MetadataElement getBandElement(final Band band) { final MetadataElement root = AbstractMetadata.getOriginalProductMetadata(product); final Variable variable = bandMap.get(band); final String varName = variable.getShortName(); MetadataElement bandElem = null; for (MetadataElement elem : root.getElements()) { if (elem.getName().equalsIgnoreCase(varName)) { bandElem = elem; break; } } return bandElem; } private static void addGeocodingFromMetadata(final Product product, final MetadataElement bandElem) { if (bandElem == null) return; final MetadataElement absRoot = AbstractMetadata.getAbstractedMetadata(product); try { String str = bandElem.getAttributeString("Top_Left_Geodetic_Coordinates"); final float latUL = Float.parseFloat(str.substring(0, str.indexOf(','))); final float lonUL = Float.parseFloat(str.substring(str.indexOf(',') + 1, str.lastIndexOf(','))); str = bandElem.getAttributeString("Top_Right_Geodetic_Coordinates"); final float latUR = Float.parseFloat(str.substring(0, str.indexOf(','))); final float lonUR = Float.parseFloat(str.substring(str.indexOf(',') + 1, str.lastIndexOf(','))); str = bandElem.getAttributeString("Bottom_Left_Geodetic_Coordinates"); final float latLL = Float.parseFloat(str.substring(0, str.indexOf(','))); final float lonLL = Float.parseFloat(str.substring(str.indexOf(',') + 1, str.lastIndexOf(','))); str = bandElem.getAttributeString("Bottom_Right_Geodetic_Coordinates"); final float latLR = Float.parseFloat(str.substring(0, str.indexOf(','))); final float lonLR = Float.parseFloat(str.substring(str.indexOf(',') + 1, str.lastIndexOf(','))); absRoot.setAttributeDouble(AbstractMetadata.first_near_lat, latUL); absRoot.setAttributeDouble(AbstractMetadata.first_near_long, lonUL); absRoot.setAttributeDouble(AbstractMetadata.first_far_lat, latUR); absRoot.setAttributeDouble(AbstractMetadata.first_far_long, lonUR); absRoot.setAttributeDouble(AbstractMetadata.last_near_lat, latLL); absRoot.setAttributeDouble(AbstractMetadata.last_near_long, lonLL); absRoot.setAttributeDouble(AbstractMetadata.last_far_lat, latLR); absRoot.setAttributeDouble(AbstractMetadata.last_far_long, lonLR); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.range_spacing, bandElem.getAttributeDouble("Column_Spacing", AbstractMetadata.NO_METADATA)); AbstractMetadata.setAttribute(absRoot, AbstractMetadata.azimuth_spacing, bandElem.getAttributeDouble("Line_Spacing", AbstractMetadata.NO_METADATA)); final float[] latCorners = new float[]{latUL, latUR, latLL, latLR}; final float[] lonCorners = new float[]{lonUL, lonUR, lonLL, lonLR}; ReaderUtils.addGeoCoding(product, latCorners, lonCorners); } catch (Exception e) { System.out.println(e.getMessage()); // continue } } public void readBandRasterDataImpl(int sourceOffsetX, int sourceOffsetY, int sourceWidth, int sourceHeight, int sourceStepX, int sourceStepY, Band destBand, int destOffsetX, int destOffsetY, int destWidth, int destHeight, ProductData destBuffer, ProgressMonitor pm) throws IOException { Guardian.assertTrue("sourceStepX == 1 && sourceStepY == 1", sourceStepX == 1 && sourceStepY == 1); Guardian.assertTrue("sourceWidth == destWidth", sourceWidth == destWidth); Guardian.assertTrue("sourceHeight == destHeight", sourceHeight == destHeight); final int sceneHeight = product.getSceneRasterHeight(); final int y0 = yFlipped ? (sceneHeight - 1) - sourceOffsetY : sourceOffsetY; final Variable variable = bandMap.get(destBand); final int rank = variable.getRank(); final int[] origin = new int[rank]; final int[] shape = new int[rank]; for (int i = 0; i < rank; i++) { shape[i] = 1; origin[i] = 0; } shape[0] = 1; shape[1] = destWidth; origin[1] = sourceOffsetX; if (isComplex && destBand.getUnit().equals(Unit.IMAGINARY)) { origin[2] = 1; } pm.beginTask("Reading data from band " + destBand.getName(), destHeight); try { for (int y = 0; y < destHeight; y++) { origin[0] = yFlipped ? y0 - y : y0 + y; final Array array; synchronized (netcdfFile) { array = variable.read(origin, shape); } if (destBand.getDataType() == ProductData.TYPE_FLOAT32) { for (int x = 0; x < destWidth; x++) { destBuffer.setElemFloatAt(y * destWidth + x, ArrayCopy.toFloat(array.getShort(x))); } } else { System.arraycopy(array.getStorage(), 0, destBuffer.getElems(), y * destWidth, destWidth); } pm.worked(1); if (pm.isCanceled()) { throw new IOException("Process terminated by user."); /*I18N*/ } } } catch (InvalidRangeException e) { final IOException ioException = new IOException(e.getMessage()); ioException.initCause(e); throw ioException; } finally { pm.done(); } } }