package org.esa.beam.dataio.smos; import com.bc.ceres.binio.*; import com.bc.ceres.glevel.MultiLevelImage; import com.bc.ceres.glevel.MultiLevelSource; import com.bc.ceres.glevel.support.DefaultMultiLevelImage; import org.esa.beam.dataio.smos.dddb.BandDescriptor; import org.esa.beam.dataio.smos.dddb.Dddb; import org.esa.beam.dataio.smos.dddb.Family; import org.esa.beam.framework.datamodel.Band; import org.esa.beam.framework.datamodel.Product; import org.esa.beam.framework.datamodel.ProductData; import org.esa.beam.smos.EEFilePair; import org.esa.beam.smos.dgg.SmosDgg; import org.esa.beam.util.io.FileUtils; import org.jdom.Document; import org.jdom.Element; import org.jdom.Namespace; import java.awt.*; import java.awt.geom.Area; import java.io.IOException; import java.text.MessageFormat; public class DggFile extends ExplorerFile { private final GridPointList gridPointList; private final int gridPointIdIndex; private final Area area; private final GridPointInfo gridPointInfo; protected DggFile(EEFilePair eeFilePair, DataContext dataContext, boolean fromZones) throws IOException { super(eeFilePair, dataContext); try { if (fromZones) { gridPointList = createGridPointListFromZones(getDataBlock().getSequence(0)); } else { gridPointList = createGridPointList(getDataBlock().getSequence(SmosConstants.GRID_POINT_LIST_NAME)); } gridPointIdIndex = gridPointList.getCompoundType().getMemberIndex(SmosConstants.GRID_POINT_ID_NAME); } catch (IOException e) { throw new IOException(MessageFormat.format( "Unable to read SMOS File ''{0}'': {1}.", eeFilePair.getDblFile().getPath(), e.getMessage()), e); } area = DggUtils.computeArea(this.getGridPointList()); gridPointInfo = createGridPointInfo(); } private GridPointList createGridPointList(SequenceData sequence) { return new PlainGridPointList(sequence); } private GridPointList createGridPointListFromZones(SequenceData zoneSequence) throws IOException { final SequenceData[] zones = new SequenceData[zoneSequence.getElementCount()]; for (int i = 0; i < zones.length; i++) { zones[i] = zoneSequence.getCompound(i).getSequence(1); } return new ZoneGridPointList(zones); } public final int getGridPointCount() { return gridPointList.getElementCount(); } public final int getGridPointSeqnum(int i) throws IOException { return SmosDgg.gridPointIdToSeqnum(getGridPointId(i)); } private int getGridPointId(int i) throws IOException { final int gridPointId = gridPointList.getCompound(i).getInt(gridPointIdIndex); if (gridPointId < SmosDgg.MIN_GRID_POINT_ID || gridPointId > SmosDgg.MAX_GRID_POINT_ID) { throw new IOException(MessageFormat.format("Invalid Grid Point ID {0} at index {1}.", gridPointId, i)); } return gridPointId; } public final GridPointList getGridPointList() { return gridPointList; } public int getGridPointIndex(int seqnum) { return gridPointInfo.getGridPointIndex(seqnum); } public final CompoundType getGridPointType() { return gridPointList.getCompoundType(); } public CompoundData getGridPointData(int gridPointIndex) throws IOException { return gridPointList.getCompound(gridPointIndex); } @Override public Area getArea() { return new Area(area); } @Override public final Product createProduct() throws IOException { final String productName = FileUtils.getFilenameWithoutExtension(getDataFile()); final String productType = getProductType(); final Dimension dimension = ProductHelper.getSceneRasterDimension(); final Product product = new Product(productName, productType, dimension.width, dimension.height); product.setFileLocation(getDataFile()); product.setPreferredTileSize(512, 512); ProductHelper.addMetadata(product.getMetadataRoot(), this); product.setGeoCoding(ProductHelper.createGeoCoding(dimension)); addBands(product); setTimes(product); return product; } protected void addBands(Product product) { final String formatName = getDataFormat().getName(); final Family<BandDescriptor> descriptors = Dddb.getInstance().getBandDescriptors(formatName); if (descriptors != null) { for (final BandDescriptor descriptor : descriptors.asList()) { addBand(product, descriptor); } } } protected void addBand(Product product, BandDescriptor descriptor) { addBand(product, descriptor, getGridPointType()); } protected final void addBand(Product product, BandDescriptor descriptor, CompoundType compoundType) { if (!descriptor.isVisible()) { return; } final int memberIndex = compoundType.getMemberIndex(descriptor.getMemberName()); if (memberIndex >= 0) { final CompoundMember member = compoundType.getMember(memberIndex); final int dataType = ProductHelper.getDataType(member.getType()); final Band band = product.addBand(descriptor.getBandName(), dataType); band.setScalingOffset(descriptor.getScalingOffset()); setScaling(band, descriptor); if (descriptor.hasFillValue()) { band.setNoDataValueUsed(true); band.setNoDataValue(descriptor.getFillValue()); } if (!descriptor.getValidPixelExpression().isEmpty()) { band.setValidPixelExpression(descriptor.getValidPixelExpression()); } if (!descriptor.getUnit().isEmpty()) { band.setUnit(descriptor.getUnit()); } if (!descriptor.getDescription().isEmpty()) { band.setDescription(descriptor.getDescription()); } if (descriptor.getFlagDescriptors() != null) { ProductHelper.addFlagsAndMasks(product, band, descriptor.getFlagCodingName(), descriptor.getFlagDescriptors()); } final ValueProvider valueProvider = createValueProvider(descriptor); band.setSourceImage(createSourceImage(band, valueProvider)); band.setImageInfo(ProductHelper.createImageInfo(band, descriptor)); } } protected void setScaling(Band band, BandDescriptor descriptor) { band.setScalingFactor(descriptor.getScalingFactor()); } protected AbstractValueProvider createValueProvider(BandDescriptor descriptor) { final int memberIndex = getGridPointType().getMemberIndex(descriptor.getMemberName()); switch (descriptor.getSampleModel()) { case 1: return new DefaultValueProvider(this, memberIndex) { @Override protected int getInt(int gridPointIndex) throws IOException { return (int) (getLong(memberIndex) & 0x00000000FFFFFFFFL); } }; case 2: return new DefaultValueProvider(this, memberIndex) { @Override public int getInt(int gridPointIndex) throws IOException { return (int) (getLong(memberIndex) >>> 32); } }; default: return new DefaultValueProvider(this, memberIndex); } } protected MultiLevelImage createSourceImage(final Band band, final ValueProvider valueProvider) { return new DefaultMultiLevelImage(createMultiLevelSource(band, valueProvider)); } private MultiLevelSource createMultiLevelSource(Band band, ValueProvider valueProvider) { return new SmosMultiLevelSource(band, valueProvider); } private GridPointInfo createGridPointInfo() throws IOException { int minSeqnum = getGridPointSeqnum(0); int maxSeqnum = minSeqnum; final int gridPointCount = getGridPointCount(); final int[] seqNumbers = new int[gridPointCount]; seqNumbers[0] = minSeqnum; for (int i = 1; i < gridPointCount; i++) { final int seqnum = getGridPointSeqnum(i); seqNumbers[i] = seqnum; if (seqnum < minSeqnum) { minSeqnum = seqnum; } else { if (seqnum > maxSeqnum) { maxSeqnum = seqnum; } } } final GridPointInfo gridPointInfo = new GridPointInfo(minSeqnum, maxSeqnum); gridPointInfo.setSequenceNumbers(seqNumbers); return gridPointInfo; } private void setTimes(Product product) { final String pattern = "'UTC='yyyy-MM-dd'T'HH:mm:ss"; try { final Document document = getDocument(); final Namespace namespace = document.getRootElement().getNamespace(); final Element validityPeriod = getElement(document.getRootElement(), "Validity_Period"); final String validityStart = validityPeriod.getChildText("Validity_Start", namespace); final String validityStop = validityPeriod.getChildText("Validity_Stop", namespace); product.setStartTime(ProductData.UTC.parse(validityStart, pattern)); product.setEndTime(ProductData.UTC.parse(validityStop, pattern)); } catch (Exception e) { System.out.println("e.getMessage() = " + e.getMessage()); e.printStackTrace(); } } private static final class PlainGridPointList implements GridPointList { private final SequenceData sequence; private final int latIndex; private final int lonIndex; public PlainGridPointList(SequenceData sequence) { this.sequence = sequence; lonIndex = getCompoundType().getMemberIndex(SmosConstants.GRID_POINT_LON_NAME); latIndex = getCompoundType().getMemberIndex(SmosConstants.GRID_POINT_LAT_NAME); } @Override public final int getElementCount() { return sequence.getElementCount(); } @Override public final CompoundData getCompound(int i) throws IOException { return sequence.getCompound(i); } @Override public final CompoundType getCompoundType() { return (CompoundType) sequence.getType().getElementType(); } @Override public final double getLon(int i) throws IOException { return getCompound(i).getFloat(lonIndex); } @Override public final double getLat(int i) throws IOException { return getCompound(i).getFloat(latIndex); } } private static final class ZoneGridPointList implements GridPointList { private final SequenceData[] zones; private final int lonIndex; private final int latIndex; public ZoneGridPointList(SequenceData[] zones) { this.zones = zones; lonIndex = getCompoundType().getMemberIndex(SmosConstants.GRID_POINT_LON_NAME); latIndex = getCompoundType().getMemberIndex(SmosConstants.GRID_POINT_LAT_NAME); } @Override public final int getElementCount() { int elementCount = 0; for (final SequenceData zone : zones) { elementCount += zone.getElementCount(); } return elementCount; } @Override public final CompoundData getCompound(int i) throws IOException { for (int z = 0, counts = 0, offset = 0, zonesLength = zones.length; z < zonesLength; z++) { counts += zones[z].getElementCount(); if (i < counts) { return zones[z].getCompound(i - offset); } offset = counts; } throw new IOException(MessageFormat.format("Cannot read compound data for index {0}", i)); } @Override public final CompoundType getCompoundType() { return (CompoundType) zones[0].getType().getElementType(); } @Override public double getLon(int i) throws IOException { return getCompound(i).getFloat(lonIndex); } @Override public double getLat(int i) throws IOException { return getCompound(i).getFloat(latIndex); } } }