diff --git a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1AHawkeyeFileReader.java b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1AHawkeyeFileReader.java index 663f9a376..3eb794041 100644 --- a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1AHawkeyeFileReader.java +++ b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1AHawkeyeFileReader.java @@ -31,14 +31,7 @@ public class L1AHawkeyeFileReader extends SeadasFileReader { @Override public Product createProduct() throws ProductIOException { - String historyName = getStringAttribute("history"); - String productName = "SEAHAWK1_HAWKEYE20210319T084332.L1A.nc"; - if (historyName != null) { - int indexSEAHAWK = historyName.indexOf("SEAHAWK"); - int indexL1Anc = historyName.indexOf("L1A.nc"); - productName = historyName.substring(indexSEAHAWK, (indexL1Anc + 6)); - } - + String productName = productReader.getInputFile().getName(); numPixels = getDimension("number_of_pixels"); numScans = getDimension("number_of_scans"); title = getStringAttribute("title"); @@ -108,7 +101,7 @@ public void addGeocoding(final Product product) throws ProductIOException { lats = geoNcFile.findVariable("geolocation_data/latitude"); lons = geoNcFile.findVariable("geolocation_data/longitude"); - //Use lat/lon with PixelGeoCoding + //Use lat/lon with TiePointGeoCoding int[] dims = lats.getShape(); float[] latTiePoints; float[] lonTiePoints; diff --git a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1BPaceOciFileReader.java b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1BPaceOciFileReader.java index e5d6c8749..e0bf01dd0 100644 --- a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1BPaceOciFileReader.java +++ b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1BPaceOciFileReader.java @@ -266,11 +266,11 @@ private Map addOciBands(Product product, List variable private WvlType getWvlType(String productName) { WvlType wvltype = null; - if (productName.equals("Lt_blue")) { + if (productName.equals("Lt_blue") || productName.equals("rhot_blue")) { wvltype = WvlType.BLUE; - } else if (productName.equals("Lt_red")) { + } else if (productName.equals("Lt_red") || productName.equals("rhot_red")) { wvltype = WvlType.RED; - } else if (productName.equals("Lt_SWIR")) { + } else if (productName.equals("Lt_SWIR") || productName.equals("rhot_SWIR")) { wvltype = WvlType.SWIR; } return wvltype; diff --git a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1BPaceOcisFileReader.java b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1BPaceOcisFileReader.java index e902d7f87..01fcc8d99 100644 --- a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1BPaceOcisFileReader.java +++ b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1BPaceOcisFileReader.java @@ -268,11 +268,11 @@ private Map addOciBands(Product product, List variable private WvlType getWvlType(String productName) { WvlType wvltype = null; - if (productName.equals("Lt_blue")) { + if (productName.equals("Lt_blue") || productName.equals("rhot_blue")) { wvltype = WvlType.BLUE; - } else if (productName.equals("Lt_red")) { + } else if (productName.equals("Lt_red") || productName.equals("rhot_red")) { wvltype = WvlType.RED; - } else if (productName.equals("Lt_SWIR")) { + } else if (productName.equals("Lt_SWIR") || productName.equals("rhot_SWIR")) { wvltype = WvlType.SWIR; } return wvltype; diff --git a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1CPaceFileReader.java b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1CPaceFileReader.java new file mode 100644 index 000000000..b7a08de62 --- /dev/null +++ b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1CPaceFileReader.java @@ -0,0 +1,800 @@ +/* + * Copyright (C) 2014 Brockmann Consult GmbH (info@brockmann-consult.de) + * + * 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 gov.nasa.gsfc.seadas.dataio; + +import org.esa.snap.core.dataio.ProductIOException; +import org.esa.snap.core.datamodel.*; +import ucar.ma2.Array; +import ucar.ma2.InvalidRangeException; +import ucar.nc2.Attribute; +import ucar.nc2.Group; +import ucar.nc2.Variable; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class L1CPaceFileReader extends SeadasFileReader { + + L1CPaceFileReader(SeadasProductReader productReader) { + super(productReader); + } + +// enum WvlType { +// RED("red_wavelengths"), +// BLUE("blue_wavelengths"), +// SWIR("swir_wavelengths"); +// +// private String name; +// +// private WvlType(String nm) { +// name = nm; +// } +// +// public String toString() { +// return name; +// } +// } +// +// Array blue_wavlengths = null; +// Array red_wavlengths = null; +// Array swir_wavlengths = null; + + + @Override + public Product createProduct() throws ProductIOException { + + int sceneHeight = ncFile.findDimension("bins_along_track").getLength(); + int sceneWidth = ncFile.findDimension("bins_across_track").getLength(); + + String productName = productReader.getInputFile().getName(); + +// try { +// productName = getStringAttribute("product_name"); +// } catch (Exception ignored) { +// productName = productReader.getInputFile().getName(); +// } + + + mustFlipY = mustFlipX = false; + SeadasProductReader.ProductType productType = productReader.getProductType(); + + Product product = new Product(productName, productType.toString(), sceneWidth, sceneHeight); + product.setDescription(productName); + + Attribute startTime = findAttribute("time_coverage_start"); +// ProductData.UTC utcStart = getUTCAttribute("time_coverage_start"); +// ProductData.UTC utcEnd = getUTCAttribute("time_coverage_end"); +// if (startTime == null) { +// utcStart = getUTCAttribute("Start_Time"); +// utcEnd = getUTCAttribute("End_Time"); +// } +// // only needed as a stop-gap to handle an intermediate version of l2gen metadata +// if (utcEnd == null) { +// utcEnd = getUTCAttribute("time_coverage_stop"); +// } + + product.setFileLocation(productReader.getInputFile()); + product.setProductReader(productReader); + + addGlobalMetadata(product); + Attribute scene_title = ncFile.findGlobalAttributeIgnoreCase("Title"); + + if (scene_title.toString().contains("PACE OCI Level-1C Data")) { + variableMap = addOciBands(product, ncFile.getVariables()); + } else if (scene_title.toString().contains("HARP2 Level-1C Data")) { + variableMap = addHarpBands(product, ncFile.getVariables()); + } else if (scene_title.toString().contains("PACE SPEXone Level-1C Data")) { + variableMap = addSPEXoneBands(product, ncFile.getVariables()); + } + + + addGeocoding(product); + addMetadata(product, "products", "Band_Metadata"); + addMetadata(product, "navigation", "Navigation_Metadata"); + + if (scene_title.toString().contains("PACE OCI Level-1C Data")) { + product.setAutoGrouping("I_-20:I_20:obs_per_view:"); + } else if (scene_title.toString().contains("HARP2 Level-1C Data")) { + product.setAutoGrouping("I:Q:U:DOLP:I_noise:Q_noise:U_noise:DOLP_noise:Sensor_Zenith:Sensor_Azimuth:Solar_Zenith:Solar_Azimuth:obs_per_view:view_time_offsets"); + } else if (scene_title.toString().contains("PACE SPEXone Level-1C Data")) { +// product.setAutoGrouping("QC_58:QC_22:QC_4:QC_-22:QC_-58:QC_bitwise_58:QC_bitwise_22:QC_bitwise_4:QC_bitwise_-22:QC_bitwise_-58:" + +// "QC_polsample_bitwise_58:QC_polsample_bitwise_22:QC_polsample_bitwise_4:QC_polsample_bitwise_-22:QC_polsample_bitwise_-58:" + +// "QC_polsample_58:QC_polsample_22:QC_polsample_4:QC_polsample_-22:QC_polsample_-58:" + +// "I_58:I_22:I_4:I_-22:I_-58:" + +// "I_noise_58:I_noise_22:I_noise_4:I_noise_-22:I_noise_-58:" + +// "I_noisefree_58:I_noisefree_22:I_noisefree_4:I_noisefree_-22:I_noisefree_-58:" + +// "I_polsample_58:I_polsample_22:I_polsample_4:I_polsample_-22:I_polsample_-58:" + +// "I_polsample_noise_58:I_polsample_noise_22:I_polsample_noise_4:I_polsample_noise_-22:I_polsample_noise_-58:" + +// "I_noisefree_polsample_58:I_noisefree_polsample_22:I_noisefree_polsample_4:I_noisefree_polsample_-22:I_noisefree_polsample_-58:" + +// "DOLP_58:DOLP_22:DOLP_4:DOLP_-22:DOLP_-58:" + +// "DOLP_noise_58:DOLP_noise_22:DOLP_noise_4:DOLP_noise_-22:DOLP_noise_-58:" + +// "DOLP_noisefree_58:DOLP_noisefree_22:DOLP_noisefree_4:DOLP_noisefree_-22:DOLP_noisefree_-58:" + +// "Q_over_I_58:Q_over_I_22:Q_over_I_4:Q_over_I_-22:Q_over_I_-58:" + +// "Q_over_I_noise_58:Q_over_I_noise_22:Q_over_I_noise_4:Q_over_I_noise_-22:Q_over_I_noise_-58:" + +// "Q_over_I_noisefree_58:Q_over_I_noisefree_22:Q_over_I_noisefree_4:Q_over_I_noisefree_-22:Q_over_I_noisefree_-58:" + +// "AOLP:AOLP_58:AOLP:AOLP_22:AOLP:AOLP_4:AOLP:AOLP_-22:AOLP:AOLP_-58:" + +// "AOLP_noisefree_58:AOLP_noisefree_22:AOLP_noisefree_4:AOLP_noisefree_-22:AOLP_noisefree_-58:" + +// "U_over_I_58:U_over_I_22:U_over_I_4:U_over_I_-22:U_over_I_-58:" + +// "U_over_I_noise_58:U_over_I_noise_22:U_over_I_noise_4:U_over_I_noise_-22:U_over_I_noise_-58:" + +// "U_over_I_noisefree_58:U_over_I_noisefree_22:U_over_I_noisefree_4:U_over_I_noisefree_-22:U_over_I_noisefree_-58:" + +// "scattering_angle:sensor_azimuth:sensor_zenith:solar_azimuth:solar_zenith:obs_per_view:view_time_offsets"); + product.setAutoGrouping("QC:QC_bitwise:QC_polsample_bitwise:QC_polsample:I:I_noise:I_noisefree:I_polsample:I_polsample_noise:" + + "I_noisefree_polsample:DOLP:DOLP_noise:DOLP_noisefree:Q_over_I:Q_over_I_noise:Q_over_I_noisefree:AOLP:AOLP_noisefree:U_over_I:" + + "U_over_I_noise:U_over_I_noisefree:scattering_angle:sensor_azimuth:sensor_zenith:solar_azimuth:solar_zenith:obs_per_view:view_time_offsets"); + } +// product.setAutoGrouping("I_-20:I_20"); + + return product; + } + + + public void addMetadata(Product product, String groupname, String meta_element) throws ProductIOException { + Group group = ncFile.findGroup(groupname); + + if (group != null) { + final MetadataElement bandAttributes = new MetadataElement(meta_element); + List variables = group.getVariables(); + for (Variable variable : variables) { + final String name = variable.getShortName(); + final MetadataElement sdsElement = new MetadataElement(name + ".attributes"); + final int dataType = getProductDataType(variable); + final MetadataAttribute prodtypeattr = new MetadataAttribute("data_type", dataType); + + sdsElement.addAttribute(prodtypeattr); + bandAttributes.addElement(sdsElement); + + final List list = variable.getAttributes(); + for (Attribute varAttribute : list) { + addAttributeToElement(sdsElement, varAttribute); + } + } + final MetadataElement metadataRoot = product.getMetadataRoot(); + metadataRoot.addElement(bandAttributes); + } + } + + private Map addHarpBands(Product product, List variables) { + final int sceneRasterWidth = product.getSceneRasterWidth(); + final int sceneRasterHeight = product.getSceneRasterHeight(); + Band band; + + Array wavelengths = null; + Array view_angles = null; + + Map bandToVariableMap = new HashMap(); + int spectralBandIndex = 0; + for (Variable variable : variables) { + if (variable.getParentGroup().equals("sensor_views_bands")) + continue; + if ((variable.getShortName().equals("latitude")) || (variable.getShortName().equals("longitude"))) + continue; + int variableRank = variable.getRank(); + + if (variableRank == 2) { + final int[] dimensions = variable.getShape(); + final int height = dimensions[0]; + final int width = dimensions[1]; + + if (height == sceneRasterHeight && width == sceneRasterWidth) { + // final List list = variable.getAttributes(); + + String units = variable.getUnitsString(); + String name = variable.getShortName(); + final int dataType = getProductDataType(variable); + band = new Band(name, dataType, width, height); + product.addBand(band); + + final List list = variable.getAttributes(); + for (Attribute hdfAttribute : list) { + final String attribName = hdfAttribute.getShortName(); + if ("units".equals(attribName)) { + band.setUnit(hdfAttribute.getStringValue()); + } else if ("long_name".equals(attribName)) { + band.setDescription(hdfAttribute.getStringValue()); + } else if ("slope".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("intercept".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("scale_factor".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("add_offset".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("bad_value_scaled".equals(attribName)) { + band.setNoDataValue(hdfAttribute.getNumericValue(0).doubleValue()); + band.setNoDataValueUsed(true); + } + } + bandToVariableMap.put(band, variable); + band.setUnit(units); + band.setDescription(variable.getDescription()); + } + } else if (variableRank == 3) { + spectralBandIndex = -1; + final int[] dimensions = variable.getShape(); + final int views = dimensions[0]; + final int height = dimensions[1]; + final int width = dimensions[2]; + + if (height == sceneRasterHeight && width == sceneRasterWidth) { + // final List list = variable.getAttributes(); + + String units = variable.getUnitsString(); + String description = variable.getShortName(); + + Variable view_angle = ncFile.findVariable("sensor_views_bands/view_angles"); + Variable wvl = ncFile.findVariable("sensor_views_bands/intensity_wavelengths"); + Variable wvl_sliced = null; + + if (view_angle != null && wvl != null) { + try { + view_angles = view_angle.read(); + try { + wvl_sliced = wvl.slice(0,0); + } catch (InvalidRangeException e) { + e.printStackTrace(); //Todo change body of catch statement. + } + wavelengths = wvl_sliced.read(); + } catch (IOException e) { + } + ArrayList wavelength_list = new ArrayList(); + for (int i = 0; i < views; i++) { + StringBuilder longname = new StringBuilder(description); + longname.append("_"); + longname.append(view_angles.getInt(i)); + longname.append("_"); + longname.append(wavelengths.getInt(i)); + String name = longname.toString(); + + final int dataType = getProductDataType(variable); + band = new Band(name, dataType, width, height); + product.addBand(band); + + band.setSpectralWavelength(wavelengths.getFloat(i)); + if (!wavelength_list.contains(wavelengths.getInt(i))) { + wavelength_list.add(wavelengths.getInt(i)); + spectralBandIndex++; + } + band.setSpectralBandIndex(spectralBandIndex); + + Variable sliced = null; + try { + sliced = variable.slice(0, i); + } catch (InvalidRangeException e) { + e.printStackTrace(); //Todo change body of catch statement. + } + + final List list = variable.getAttributes(); + for (Attribute hdfAttribute : list) { + final String attribName = hdfAttribute.getShortName(); + if ("units".equals(attribName)) { + band.setUnit(hdfAttribute.getStringValue()); + } else if ("long_name".equals(attribName)) { + band.setDescription(hdfAttribute.getStringValue()); + } else if ("slope".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("intercept".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("scale_factor".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("add_offset".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("bad_value_scaled".equals(attribName)) { + band.setNoDataValue(hdfAttribute.getNumericValue(0).doubleValue()); + band.setNoDataValueUsed(true); + } + } + bandToVariableMap.put(band, sliced); + band.setUnit(units); + band.setDescription(description); + } + } + } + } + + + } + return bandToVariableMap; + } + + private Map addOciBands(Product product, List variables) { + final int sceneRasterWidth = product.getSceneRasterWidth(); + final int sceneRasterHeight = product.getSceneRasterHeight(); + Band band; + + Array wavelengths = null; + Array view_angles = null; + + Map bandToVariableMap = new HashMap(); + int spectralBandIndex = 0; + for (Variable variable : variables) { + if (variable.getParentGroup().equals("sensor_views_bands")) + continue; + if ((variable.getShortName().equals("latitude")) || (variable.getShortName().equals("longitude"))) + continue; + int variableRank = variable.getRank(); + + if (variableRank == 2) { + final int[] dimensions = variable.getShape(); + final int height = dimensions[0]; + final int width = dimensions[1]; + + if (height == sceneRasterHeight && width == sceneRasterWidth) { + // final List list = variable.getAttributes(); + + String units = variable.getUnitsString(); + String name = variable.getShortName(); + final int dataType = getProductDataType(variable); + band = new Band(name, dataType, width, height); + product.addBand(band); + + final List list = variable.getAttributes(); + for (Attribute hdfAttribute : list) { + final String attribName = hdfAttribute.getShortName(); + if ("units".equals(attribName)) { + band.setUnit(hdfAttribute.getStringValue()); + } else if ("long_name".equals(attribName)) { + band.setDescription(hdfAttribute.getStringValue()); + } else if ("slope".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("intercept".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("scale_factor".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("add_offset".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("bad_value_scaled".equals(attribName)) { + band.setNoDataValue(hdfAttribute.getNumericValue(0).doubleValue()); + band.setNoDataValueUsed(true); + } + } + bandToVariableMap.put(band, variable); + band.setUnit(units); + band.setDescription(variable.getDescription()); + } + } else if (variableRank == 3) { + final int[] dimensions = variable.getShape(); + final int views = dimensions[2]; + final int height = dimensions[0]; + final int width = dimensions[1]; + + if (height == sceneRasterHeight && width == sceneRasterWidth) { + // final List list = variable.getAttributes(); + + String units = variable.getUnitsString(); + String description = variable.getShortName(); + + Variable view_angle = ncFile.findVariable("sensor_views_bands/view_angles"); + + if (view_angle != null) { + try { + view_angles = view_angle.read(); + } catch (IOException e) { + } + + for (int i = 0; i < views; i++) { + StringBuilder longname = new StringBuilder(description); + longname.append("_"); + longname.append(view_angles.getInt(i)); + String name = longname.toString(); + final int dataType = getProductDataType(variable); + band = new Band(name, dataType, width, height); + product.addBand(band); + + Variable sliced = null; + try { + sliced = variable.slice(2, i); + } catch (InvalidRangeException e) { + e.printStackTrace(); //Todo change body of catch statement. + } + + final List list = variable.getAttributes(); + for (Attribute hdfAttribute : list) { + final String attribName = hdfAttribute.getShortName(); + if ("units".equals(attribName)) { + band.setUnit(hdfAttribute.getStringValue()); + } else if ("long_name".equals(attribName)) { + band.setDescription(hdfAttribute.getStringValue()); + } else if ("slope".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("intercept".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("scale_factor".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("add_offset".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("bad_value_scaled".equals(attribName)) { + band.setNoDataValue(hdfAttribute.getNumericValue(0).doubleValue()); + band.setNoDataValueUsed(true); + } + } + bandToVariableMap.put(band, sliced); + band.setUnit(units); + band.setDescription(description); + } + } + } + } else if (variableRank == 4) { + final int[] dimensions = variable.getShape(); + final int views = dimensions[2]; + final int height = dimensions[0]; + final int width = dimensions[1]; + final int bands = dimensions[3]; + + if (height == sceneRasterHeight && width == sceneRasterWidth) { + + String units = variable.getUnitsString(); + String description = variable.getShortName(); + + Variable view_angle = ncFile.findVariable("sensor_views_bands/view_angles"); + Variable wvl = ncFile.findVariable("sensor_views_bands/intensity_wavelengths"); + Variable wvl_sliced = null; + + if (view_angle != null && wvl != null) { + try { + view_angles = view_angle.read(); + try { + wvl_sliced = wvl.slice(0,1); + } catch (InvalidRangeException e) { + e.printStackTrace(); //Todo change body of catch statement. + } + wavelengths = wvl_sliced.read(); + wavelengths.setInt(120, wavelengths.getInt(120) + 1); + wavelengths.setInt(121, wavelengths.getInt(121) + 1); + wavelengths.setInt(122, wavelengths.getInt(122) + 1); + wavelengths.setInt(123, wavelengths.getInt(123) + 1); + wavelengths.setInt(243, wavelengths.getInt(243) + 1); + wavelengths.setInt(246, wavelengths.getInt(246) + 1); + + } catch (IOException e) { + } + + + for (int i = 0; i < views; i++) { + for (int j = 0; j < bands; j++) { + StringBuilder longname = new StringBuilder(description); + longname.append("_"); + longname.append(view_angles.getInt(i)); + longname.append("_"); + longname.append(wavelengths.getInt(j)); + String name = longname.toString(); + + final int dataType = getProductDataType(variable); + band = new Band(name, dataType, width, height); + product.addBand(band); + + band.setSpectralWavelength(wavelengths.getFloat(j)); + band.setSpectralBandIndex(j); + + Variable sliced1 = null; + Variable sliced = null; + try { + sliced1 = variable.slice(2, i); + sliced = sliced1.slice(2, j); + } catch (InvalidRangeException e) { + e.printStackTrace(); //Todo change body of catch statement. + } + + final List list = variable.getAttributes(); + for (Attribute hdfAttribute : list) { + final String attribName = hdfAttribute.getShortName(); + if ("units".equals(attribName)) { + band.setUnit(hdfAttribute.getStringValue()); + } else if ("long_name".equals(attribName)) { + band.setDescription(hdfAttribute.getStringValue()); + } else if ("slope".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("intercept".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("scale_factor".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("add_offset".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("bad_value_scaled".equals(attribName)) { + band.setNoDataValue(hdfAttribute.getNumericValue(0).doubleValue()); + band.setNoDataValueUsed(true); + } + } + bandToVariableMap.put(band, sliced); + band.setUnit(units); + band.setDescription(description); + } + } + } + } + } + + + } + return bandToVariableMap; + } + + private Map addSPEXoneBands(Product product, List variables) { + final int sceneRasterWidth = product.getSceneRasterWidth(); + final int sceneRasterHeight = product.getSceneRasterHeight(); + Band band; + + Array wavelengths = null; + Array wavelengths_pol = null; + Array view_angles = null; + + Map bandToVariableMap = new HashMap(); + int spectralBandIndex = 0; + for (Variable variable : variables) { + if (variable.getParentGroup().equals("sensor_views_bands")) + continue; + if ((variable.getShortName().equals("latitude")) || (variable.getShortName().equals("longitude"))) + continue; + int variableRank = variable.getRank(); + + if (variableRank == 2) { + final int[] dimensions = variable.getShape(); + final int height = dimensions[0]; + final int width = dimensions[1]; + + if (height == sceneRasterHeight && width == sceneRasterWidth) { + // final List list = variable.getAttributes(); + + String units = variable.getUnitsString(); + String name = variable.getShortName(); + final int dataType = getProductDataType(variable); + band = new Band(name, dataType, width, height); + product.addBand(band); + + final List list = variable.getAttributes(); + for (Attribute hdfAttribute : list) { + final String attribName = hdfAttribute.getShortName(); + if ("units".equals(attribName)) { + band.setUnit(hdfAttribute.getStringValue()); + } else if ("long_name".equals(attribName)) { + band.setDescription(hdfAttribute.getStringValue()); + } else if ("slope".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("intercept".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("scale_factor".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("add_offset".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("bad_value_scaled".equals(attribName)) { + band.setNoDataValue(hdfAttribute.getNumericValue(0).doubleValue()); + band.setNoDataValueUsed(true); + } + } + bandToVariableMap.put(band, variable); + band.setUnit(units); + band.setDescription(variable.getDescription()); + } + } else if (variableRank == 3) { + final int[] dimensions = variable.getShape(); + final int views = dimensions[2]; + final int height = dimensions[0]; + final int width = dimensions[1]; + + if (height == sceneRasterHeight && width == sceneRasterWidth) { + // final List list = variable.getAttributes(); + + String units = variable.getUnitsString(); + String description = variable.getShortName(); + + Variable view_angle = ncFile.findVariable("sensor_views_bands/view_angles"); + + if (view_angle != null) { + try { + view_angles = view_angle.read(); + } catch (IOException e) { + } + + for (int i = 0; i < views; i++) { + StringBuilder longname = new StringBuilder(description); + longname.append("_"); + if ((i > views / 2) && (view_angles.getInt(i) == view_angles.getInt(views - 1 - i))) { + longname.append(-view_angles.getInt(i)); + } else { + longname.append(view_angles.getInt(i)); + } + String name = longname.toString(); + final int dataType = getProductDataType(variable); + band = new Band(name, dataType, width, height); + product.addBand(band); + + Variable sliced = null; + try { + sliced = variable.slice(2, i); + } catch (InvalidRangeException e) { + e.printStackTrace(); //Todo change body of catch statement. + } + + final List list = variable.getAttributes(); + for (Attribute hdfAttribute : list) { + final String attribName = hdfAttribute.getShortName(); + if ("units".equals(attribName)) { + band.setUnit(hdfAttribute.getStringValue()); + } else if ("long_name".equals(attribName)) { + band.setDescription(hdfAttribute.getStringValue()); + } else if ("slope".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("intercept".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("scale_factor".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("add_offset".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("bad_value_scaled".equals(attribName)) { + band.setNoDataValue(hdfAttribute.getNumericValue(0).doubleValue()); + band.setNoDataValueUsed(true); + } + } + bandToVariableMap.put(band, sliced); + band.setUnit(units); + band.setDescription(description); + } + } + } + } else if (variableRank == 4) { + final int[] dimensions = variable.getShape(); + final int views = dimensions[2]; + final int height = dimensions[0]; + final int width = dimensions[1]; + final int bands = dimensions[3]; + + if (height == sceneRasterHeight && width == sceneRasterWidth) { + + String units = variable.getUnitsString(); + String description = variable.getShortName(); + + Variable view_angle = ncFile.findVariable("sensor_views_bands/view_angles"); + Variable wvl = ncFile.findVariable("sensor_views_bands/intensity_wavelengths"); + Variable wvl_sliced = null; + Variable wvl_pol = ncFile.findVariable("sensor_views_bands/polarization_wavelengths"); + Variable wvl_sliced_pol = null; + + if (view_angle != null && wvl != null) { + try { + view_angles = view_angle.read(); + try { + wvl_sliced = wvl.slice(0,1); + wvl_sliced_pol = wvl_pol.slice(0,1); + } catch (InvalidRangeException e) { + e.printStackTrace(); //Todo change body of catch statement. + } + wavelengths = wvl_sliced.read(); + wavelengths_pol = wvl_sliced_pol.read(); + + } catch (IOException e) { + } + + + for (int i = 0; i < views; i++) { + for (int j = 0; j < bands; j++) { + StringBuilder longname = new StringBuilder(description); + longname.append("_"); + if ((i > views / 2) && (view_angles.getInt(i) == view_angles.getInt(views - 1 - i))) { + longname.append(-view_angles.getInt(i)); + } else { + longname.append(view_angles.getInt(i)); + } + longname.append("_"); + if (bands == 400) { + longname.append(wavelengths.getInt(j)); + } else { + longname.append(wavelengths_pol.getInt(j)); + } + String name = longname.toString(); + final int dataType = getProductDataType(variable); + band = new Band(name, dataType, width, height); + product.addBand(band); + + if (bands == 400) { + band.setSpectralWavelength(wavelengths.getFloat(j)); + } else { + band.setSpectralWavelength(wavelengths_pol.getFloat(j)); + } + band.setSpectralBandIndex(j); + + + Variable sliced1 = null; + Variable sliced = null; + try { + sliced1 = variable.slice(2, i); + sliced = sliced1.slice(2, j); + } catch (InvalidRangeException e) { + e.printStackTrace(); //Todo change body of catch statement. + } + + final List list = variable.getAttributes(); + for (Attribute hdfAttribute : list) { + final String attribName = hdfAttribute.getShortName(); + if ("units".equals(attribName)) { + band.setUnit(hdfAttribute.getStringValue()); + } else if ("long_name".equals(attribName)) { + band.setDescription(hdfAttribute.getStringValue()); + } else if ("slope".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("intercept".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("scale_factor".equals(attribName)) { + band.setScalingFactor(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("add_offset".equals(attribName)) { + band.setScalingOffset(hdfAttribute.getNumericValue(0).doubleValue()); + } else if ("bad_value_scaled".equals(attribName)) { + band.setNoDataValue(hdfAttribute.getNumericValue(0).doubleValue()); + band.setNoDataValueUsed(true); + } + } + bandToVariableMap.put(band, sliced); + band.setUnit(units); + band.setDescription(description); + } + } + } + } + } + + + } + return bandToVariableMap; + } + + public ProductData readDataFlip(Variable variable) throws ProductIOException { + final int dataType = getProductDataType(variable); + Array array; + Object storage; + try { + array = variable.read(); + storage = array.flip(0).copyTo1DJavaArray(); + } catch (IOException e) { + throw new ProductIOException(e.getMessage(), e); + } + return ProductData.createInstance(dataType, storage); + } + + public void addGeocoding(final Product product) throws ProductIOException { + final String longitude = "longitude"; + final String latitude = "latitude"; + String navGroup = "geolocation_data"; + + Variable latVar = ncFile.findVariable(navGroup + "/" + latitude); + Variable lonVar = ncFile.findVariable(navGroup + "/" + longitude); + + if (latVar != null && lonVar != null) { + final ProductData lonRawData; + final ProductData latRawData; + if (mustFlipY) { + lonRawData = readDataFlip(lonVar); + latRawData = readDataFlip(latVar); + } else { + lonRawData = readData(lonVar); + latRawData = readData(latVar); + } + + Band latBand = product.addBand(latVar.getShortName(), ProductData.TYPE_FLOAT32); + Band lonBand = product.addBand(lonVar.getShortName(), ProductData.TYPE_FLOAT32); + latBand.setNoDataValue(-999.); + lonBand.setNoDataValue(-999.); + latBand.setNoDataValueUsed(true); + lonBand.setNoDataValueUsed(true); + latBand.setData(latRawData); + lonBand.setData(lonRawData); + + product.setSceneGeoCoding(GeoCodingFactory.createPixelGeoCoding(latBand, lonBand, null, 5)); + + } + } +} \ No newline at end of file diff --git a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1CPaceProductReaderPlugIn.java b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1CPaceProductReaderPlugIn.java new file mode 100644 index 000000000..163f06b84 --- /dev/null +++ b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L1CPaceProductReaderPlugIn.java @@ -0,0 +1,179 @@ +package gov.nasa.gsfc.seadas.dataio; + +import org.esa.snap.core.dataio.DecodeQualification; +import org.esa.snap.core.dataio.ProductReader; +import org.esa.snap.core.util.io.SnapFileFilter; +import org.esa.snap.dataio.netcdf.GenericNetCdfReaderPlugIn; +import org.esa.snap.dataio.netcdf.util.NetcdfFileOpener; +import ucar.nc2.Attribute; +import ucar.nc2.NetcdfFile; +import ucar.nc2.iosp.hdf5.H5iosp; +import ucar.nc2.util.DebugFlags; +import ucar.nc2.util.DebugFlagsImpl; + +import java.io.File; +import java.io.IOException; +import java.util.Locale; + +public class L1CPaceProductReaderPlugIn extends GenericNetCdfReaderPlugIn { + + // Set to "true" to output debugging information. + // Don't forget to setback to "false" in production code! + // + private static final boolean DEBUG = false; + + private static final String DEFAULT_FILE_EXTENSION = ".nc"; + + public static final String READER_DESCRIPTION = "PACE OCIS L1C Products"; + public static final String FORMAT_NAME = "PACE-L1C"; + + + /** + * Checks whether the given object is an acceptable input for this product reader and if so, the method checks if it + * is capable of decoding the input's content. + */ + @Override + public DecodeQualification getDecodeQualification(Object input) { + final File file = SeadasProductReader.getInputFile(input); + if (file == null) { + return DecodeQualification.UNABLE; + } + if (!file.exists()) { + if (DEBUG) { + System.out.println("# File not found: " + file); + } + return DecodeQualification.UNABLE; + } + if (!file.isFile()) { + if (DEBUG) { + System.out.println("# Not a file: " + file); + } + return DecodeQualification.UNABLE; + } + NetcdfFile ncfile = null; + H5iosp.setDebugFlags(new DebugFlagsImpl("HdfEos/turnOff")); + + try { + ncfile = NetcdfFileOpener.open(file.getPath()); + if (ncfile != null) { + Attribute scene_title = ncfile.findGlobalAttributeIgnoreCase("Title"); + + if (scene_title != null) { + if (scene_title.toString().contains("PACE OCI Level-1C Data") + || scene_title.toString().contains("PACE SPEXone Level-1C Data") + || scene_title.toString().contains("HARP2 Level-1C Data")){ + if (DEBUG) { + System.out.println(file); + } + ncfile.close(); + DebugFlags debugFlags = new DebugFlagsImpl("HdfEos/turnOff"); + debugFlags.set("HdfEos/turnOff", false); + H5iosp.setDebugFlags(debugFlags); + return DecodeQualification.INTENDED; + } else { + if (DEBUG) { + System.out.println("# Unrecognized scene title =[" + scene_title + "]: " + file); + } + } + } else { + if (DEBUG) { + System.out.println("# Missing scene title attribute': " + file); + } + } + } else { + if (DEBUG) { + System.out.println("# Can't open as NetCDF: " + file); + } + } + } catch (Exception ignore) { + if (DEBUG) { + System.out.println("# I/O exception caught: " + file); + } + } finally { + DebugFlags debugFlags = new DebugFlagsImpl("HdfEos/turnOff"); + debugFlags.set("HdfEos/turnOff", false); + H5iosp.setDebugFlags(debugFlags); + if (ncfile != null) { + try { + ncfile.close(); + } catch (IOException ignore) { + } + } + } + return DecodeQualification.UNABLE; + } + + /** + * Returns an array containing the classes that represent valid input types for this reader. + *

+ *

Intances of the classes returned in this array are valid objects for the setInput method of the + * ProductReader interface (the method will not throw an InvalidArgumentException in this + * case). + * + * @return an array containing valid input types, never null + */ + @Override + public Class[] getInputTypes() { + return new Class[]{String.class, File.class}; + } + + /** + * Creates an instance of the actual product reader class. This method should never return null. + * + * @return a new reader instance, never null + */ + @Override + public ProductReader createReaderInstance() { + return new SeadasProductReader(this); + } + + @Override + public SnapFileFilter getProductFileFilter() { + String[] formatNames = getFormatNames(); + String formatName = ""; + if (formatNames.length > 0) { + formatName = formatNames[0]; + } + return new SnapFileFilter(formatName, getDefaultFileExtensions(), getDescription(null)); + } + + /** + * Gets the default file extensions associated with each of the format names returned by the {@link + * #getFormatNames} method.

The string array returned shall always have the same length as the array + * returned by the {@link #getFormatNames} method.

The extensions returned in the string array shall + * always include a leading colon ('.') character, e.g. ".hdf" + * + * @return the default file extensions for this product I/O plug-in, never null + */ + @Override + public String[] getDefaultFileExtensions() { + // todo: return regular expression to clean up the extensions. + return new String[]{ + DEFAULT_FILE_EXTENSION + }; + } + + /** + * Gets a short description of this plug-in. If the given locale is set to null the default locale is + * used. + *

+ *

In a GUI, the description returned could be used as tool-tip text. + * + * @param locale the local for the given decription string, if null the default locale is used + * @return a textual description of this product reader/writer + */ + @Override + public String getDescription(Locale locale) { + return READER_DESCRIPTION; + } + + /** + * Gets the names of the product formats handled by this product I/O plug-in. + * + * @return the names of the product formats handled by this product I/O plug-in, never null + */ + @Override + public String[] getFormatNames() { + return new String[]{FORMAT_NAME}; + } +} diff --git a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L3ProductReaderPlugIn.java b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L3ProductReaderPlugIn.java index b47fad876..ce586b94c 100644 --- a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L3ProductReaderPlugIn.java +++ b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/L3ProductReaderPlugIn.java @@ -108,7 +108,7 @@ public DecodeQualification getDecodeQualification(Object input) { ncfile.close(); return DecodeQualification.UNABLE; } - if(title.matches(".*Level-3 Standard Mapped Image")){ + if(title.matches("(.*)Level-3 Standard Mapped Image") || title.matches("(.*)Level-3 Equidistant Cylindrical Mapped Image")){ if (DEBUG) { System.out.println(file); } diff --git a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SMIFileReader.java b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SMIFileReader.java index bf7db21b4..6d7a4eae1 100644 --- a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SMIFileReader.java +++ b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SMIFileReader.java @@ -111,6 +111,7 @@ public Product createProduct() throws ProductIOException { Dimension tileSize = new Dimension(640, 320); product.setPreferredTileSize(tileSize); } + product.setAutoGrouping("Rrs:nLw:Lt:La:Lr:Lw:L_q:L_u:Es:TLg:rhom:rhos:rhot:Taua:Kd:aot:adg:aph_:bbp:vgain:BT:tg_sol:tg_sen"); return product; } diff --git a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SeadasFileReader.java b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SeadasFileReader.java index ff904377a..5599c2718 100644 --- a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SeadasFileReader.java +++ b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SeadasFileReader.java @@ -390,6 +390,21 @@ protected void addFlagsAndMasks(Product product) { product.getSceneRasterWidth(), product.getSceneRasterHeight(), "l2_flags.PRODFAIL", FailRed, 0.1)); + product.getMaskGroup().add(Mask.BandMathsType.create("Quality_L2", "Product could be computed (l2_flags composite)", + product.getSceneRasterWidth(), + + product.getSceneRasterHeight(), "!(l2_flags.ATMFAIL or l2_flags.LAND or l2_flags.HILT or l2_flags.STRAYLIGHT or l2_flags.CLDICE or l2_flags.NAVFAIL)", + DarkGreen, 0.0)); + + product.getMaskGroup().add(Mask.BandMathsType.create("Quality_L3", "Best quality (l2_flags composite)", + product.getSceneRasterWidth(), + + product.getSceneRasterHeight(), "!(l2_flags.ATMFAIL or l2_flags.LAND or l2_flags.HIGLINT or l2_flags.HILT or l2_flags.STRAYLIGHT or l2_flags.CLDICE or l2_flags.COCCOLITH or l2_flags.HISOLZEN or l2_flags.LOWLW or l2_flags.CHLFAIL or l2_flags.NAVWARN or l2_flags.MAXAERITER or l2_flags.CHLWARN or l2_flags.ATMWARN or l2_flags.NAVFAIL or l2_flags.FILTER)", + Color.GREEN, 0.0)); + product.getMaskGroup().add(Mask.BandMathsType.create("Water", "Not land (l2_flags.LAND)", + product.getSceneRasterWidth(), + product.getSceneRasterHeight(), "!l2_flags.LAND", + Color.BLUE, 0.0)); } Band QFBandSST = product.getBand("flags_sst"); diff --git a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SeadasProductReader.java b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SeadasProductReader.java index 738bab4b9..7aa4bc30d 100644 --- a/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SeadasProductReader.java +++ b/seadas-reader/src/main/java/gov/nasa/gsfc/seadas/dataio/SeadasProductReader.java @@ -62,6 +62,7 @@ enum ProductType { Level1B_OCM2("OCM2_L1B"), Level1B_PaceOCI("PaceOCI_L1B"), Level1B_PaceOCIS("PaceOCIS_L1B"), + Level1C_Pace("Pace_L1C"), Level2("Level 2"), Level2_DscovrEpic("DscovrEpic Level 2"), Level2_PaceOCI("OCI Level-2"), @@ -153,6 +154,9 @@ protected Product readProductNodesImpl() throws IOException { case Level1B_PaceOCIS: seadasFileReader = new L1BPaceOcisFileReader(this); break; + case Level1C_Pace: + seadasFileReader = new L1CPaceFileReader(this); + break; case Level3_Bin: seadasFileReader = new L3BinFileReader(this); break; @@ -338,6 +342,10 @@ public ProductType findProductType() throws ProductIOException { return ProductType.Level1B_PaceOCI; } else if (title.contains("PACE OCIS Level-1B Data")) { return ProductType.Level1B_PaceOCIS; + } else if (title.contains("PACE OCI Level-1C Data") + || title.contains("PACE SPEXone Level-1C Data") + || title.contains("HARP2 Level-1C Data")) { + return ProductType.Level1C_Pace; } else if (title.equals("OCIS Level-2 Data")) { return ProductType.Level2_PaceOCIS; } else if (title.equals("OCI Level-2 Data")) { @@ -368,7 +376,7 @@ public ProductType findProductType() throws ProductIOException { return ProductType.ANCNRT2; } else if (title.equals("SeaWiFS Climatological Ancillary Data")) { return ProductType.ANCCLIM; - } else if (title.contains("Level-3 Standard Mapped Image")) { + } else if (title.matches("(.*)Level-3 Standard Mapped Image") || title.matches("(.*)Level-3 Equidistant Cylindrical Mapped Image")) { return ProductType.SMI; } else if (title.contains("Level-3 Binned Data") || title.contains("level-3_binned_data")) { return ProductType.Level3_Bin; diff --git a/seadas-reader/src/main/resources/META-INF/services/org.esa.snap.core.dataio.ProductReaderPlugIn b/seadas-reader/src/main/resources/META-INF/services/org.esa.snap.core.dataio.ProductReaderPlugIn index 904b4963d..7f4dba036 100644 --- a/seadas-reader/src/main/resources/META-INF/services/org.esa.snap.core.dataio.ProductReaderPlugIn +++ b/seadas-reader/src/main/resources/META-INF/services/org.esa.snap.core.dataio.ProductReaderPlugIn @@ -11,5 +11,6 @@ gov.nasa.gsfc.seadas.dataio.L3ProductReaderPlugIn gov.nasa.gsfc.seadas.dataio.BrowseProductReaderPlugIn gov.nasa.gsfc.seadas.dataio.L1BViirsProductReaderPlugin gov.nasa.gsfc.seadas.dataio.L1BPaceProductReaderPlugIn +gov.nasa.gsfc.seadas.dataio.L1CPaceProductReaderPlugIn gov.nasa.gsfc.seadas.dataio.L2DscovrEpicProductReaderPlugIn