package org.esa.beam.smos.ee2netcdf; import com.bc.ceres.binio.CompoundData; import com.bc.ceres.binio.SequenceData; import org.esa.beam.dataio.netcdf.nc.NFileWriteable; import org.esa.beam.dataio.netcdf.nc.NVariable; import org.esa.beam.dataio.smos.L1cScienceSmosFile; import org.esa.beam.dataio.smos.SnapshotInfo; import org.esa.beam.framework.datamodel.MetadataAttribute; import org.esa.beam.framework.datamodel.MetadataElement; import org.esa.beam.framework.datamodel.Product; import org.esa.beam.smos.ee2netcdf.geometry.GeometryFilter; import org.esa.beam.smos.ee2netcdf.geometry.GeometryFilterFactory; import org.esa.beam.smos.ee2netcdf.variable.VariableDescriptor; import org.esa.beam.smos.ee2netcdf.variable.VariableWriter; import org.esa.beam.smos.ee2netcdf.variable.VariableWriterFactory; import org.esa.beam.util.StringUtils; import java.awt.*; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Set; class L1CFormatExporter extends AbstractFormatExporter { private int numSnapshotsToExport; private int numSnapshotsInInput; private HashMap<String, Integer> dimensionMap; private ArrayList<Integer> snapshotIdList; private L1cScienceSmosFile scienceSmosFile; @Override public void initialize(Product product, ExportParameter exportParameter) throws IOException { super.initialize(product, exportParameter); scienceSmosFile = (L1cScienceSmosFile) explorerFile; final SnapshotInfo snapshotInfo = scienceSmosFile.getSnapshotInfo(); numSnapshotsToExport = snapshotInfo.getSnapshotIds().size(); numSnapshotsInInput = numSnapshotsToExport; snapshotIdList = new ArrayList<>(); applyScalingFromHeaderFile(product); } private void applyScalingFromHeaderFile(Product product) { final MetadataElement specificProductHeader = ExporterUtils.getSpecificProductHeader(product); if (specificProductHeader == null) { return; } final MetadataAttribute radiometricAccuracyAttribute = specificProductHeader.getAttribute("Radiometric_Accuracy_Scale"); if (radiometricAccuracyAttribute != null) { final double scaleFactor = radiometricAccuracyAttribute.getData().getElemDouble(); if (scaleFactor != 1.0) { ExporterUtils.correctScaleFactor(variableDescriptors, "Radiometric_Accuracy", scaleFactor); ExporterUtils.correctScaleFactor(variableDescriptors, "Radiometric_Accuracy_of_Pixel", scaleFactor); } } final MetadataAttribute pixelFootprintAttribute = specificProductHeader.getAttribute("Pixel_Footprint_Scale"); if (pixelFootprintAttribute != null) { final double scaleFactor = pixelFootprintAttribute.getData().getElemDouble(); if (scaleFactor != 1.0) { ExporterUtils.correctScaleFactor(variableDescriptors, "Footprint_Axis1", scaleFactor); ExporterUtils.correctScaleFactor(variableDescriptors, "Footprint_Axis2", scaleFactor); } } } @Override public void prepareGeographicSubset(NFileWriteable nFileWriteable, ExportParameter exportParameter) throws IOException { if (exportParameter.getRegion() != null) { final GeometryFilter geometryFilter = GeometryFilterFactory.create(exportParameter.getRegion()); gpIndexList = new ArrayList<>(gridPointCount); for (int i = 0; i < gridPointCount; i++) { final CompoundData gridPointData = explorerFile.getGridPointData(i); if (geometryFilter.accept(gridPointData)) { gpIndexList.add(i); final SequenceData btDataList = scienceSmosFile.getBtDataList(i); final int elementCount = btDataList.getElementCount(); for (int j = 0; j < elementCount; j++) { final CompoundData btData = btDataList.getCompound(j); final int snapshotId = btData.getInt("Snapshot_ID_of_Pixel"); if (!snapshotIdList.contains(snapshotId)) { snapshotIdList.add(snapshotId); } } } } gridPointCount = gpIndexList.size(); numSnapshotsToExport = snapshotIdList.size(); } } @Override public void addDimensions(NFileWriteable nFileWriteable) throws IOException { nFileWriteable.addDimension("n_grid_points", gridPointCount); nFileWriteable.addDimension("n_bt_data", 300); nFileWriteable.addDimension("n_radiometric_accuracy", 2); nFileWriteable.addDimension("n_snapshots", numSnapshotsToExport); dimensionMap = new HashMap<>(); dimensionMap.put("n_grid_points", gridPointCount); dimensionMap.put("n_bt_data", 300); dimensionMap.put("n_radiometric_accuracy", 2); dimensionMap.put("n_snapshots", numSnapshotsToExport); } @Override public void writeData(NFileWriteable nFileWriteable) throws IOException { final L1cScienceSmosFile l1cScienceSmosFile = (L1cScienceSmosFile) explorerFile; writeGridPointVariables(nFileWriteable); writeSnapshotVariables(nFileWriteable, l1cScienceSmosFile); } private void writeSnapshotVariables(NFileWriteable nFileWriteable, L1cScienceSmosFile l1cScienceSmosFile) throws IOException { final VariableWriter[] snapshotVariableWriters = createVariableWriters(nFileWriteable, false); if (snapshotIdList.isEmpty()) { writeAllSnapshots(l1cScienceSmosFile, snapshotVariableWriters); } else { writeSnapshotSubset(l1cScienceSmosFile, snapshotVariableWriters); } } private void writeAllSnapshots(L1cScienceSmosFile l1cScienceSmosFile, VariableWriter[] snapshotVariableWriters) throws IOException { for (int i = 0; i < numSnapshotsInInput; i++) { final CompoundData snapshotData = l1cScienceSmosFile.getSnapshotData(i); final SequenceData radiometricAccuracy = snapshotData.getSequence("Radiometric_Accuracy"); for (VariableWriter writer : snapshotVariableWriters) { writer.write(snapshotData, radiometricAccuracy, i); } } for (VariableWriter writer : snapshotVariableWriters) { writer.close(); } } private void writeSnapshotSubset(L1cScienceSmosFile l1cScienceSmosFile, VariableWriter[] snapshotVariableWriters) throws IOException { int writeIndex = 0; for (int i = 0; i < numSnapshotsInInput; i++) { final CompoundData snapshotData = l1cScienceSmosFile.getSnapshotData(i); final int snapshotId = snapshotData.getInt("Snapshot_ID"); if (!snapshotIdList.contains(snapshotId)) { continue; } final SequenceData radiometricAccuracy = snapshotData.getSequence("Radiometric_Accuracy"); for (VariableWriter writer : snapshotVariableWriters) { writer.write(snapshotData, radiometricAccuracy, writeIndex); } ++writeIndex; } for (VariableWriter writer : snapshotVariableWriters) { writer.close(); } } private void writeGridPointVariables(NFileWriteable nFileWriteable) throws IOException { final VariableWriter[] gridPointVariableWriters = createVariableWriters(nFileWriteable, true); if (gpIndexList == null) { for (int i = 0; i < gridPointCount; i++) { writeGridPointData(i, i, gridPointVariableWriters); } } else { int writeIndex = 0; for (int index : gpIndexList) { writeGridPointData(index, writeIndex, gridPointVariableWriters); ++writeIndex; } } for (VariableWriter writer : gridPointVariableWriters) { writer.close(); } } private void writeGridPointData(int readIndex, int writeIndex, VariableWriter[] gridPointVariableWriters) throws IOException { final CompoundData gridPointData = scienceSmosFile.getGridPointData(readIndex); final SequenceData btDataList = scienceSmosFile.getBtDataList(readIndex); for (VariableWriter writer : gridPointVariableWriters) { writer.write(gridPointData, btDataList, writeIndex); } } private VariableWriter[] createVariableWriters(NFileWriteable nFileWriteable, boolean gridPointData) { final Set<String> variableNameKeys = variableDescriptors.keySet(); final ArrayList<Object> variableWriterList = new ArrayList<>(variableNameKeys.size()); for (final String ncVariableName : variableNameKeys) { final NVariable nVariable = nFileWriteable.findVariable(ncVariableName); final VariableDescriptor variableDescriptor = variableDescriptors.get(ncVariableName); if (gridPointData != variableDescriptor.isGridPointData()) { continue; } final Dimension dimension = extractDimensions(variableDescriptor.getDimensionNames(), dimensionMap); variableWriterList.add(VariableWriterFactory.create(nVariable, variableDescriptor, dimension.width, dimension.height)); } return variableWriterList.toArray(new VariableWriter[variableWriterList.size()]); } // package access for testing only tb 2014-07-15 static Dimension extractDimensions(String dimensionNames, HashMap<String, Integer> dimensionMap) { final String[] dimNamesArray = StringUtils.split(dimensionNames, new char[]{' '}, true); final Dimension dimension = new Dimension(); dimension.width = dimensionMap.get(dimNamesArray[0]); if (dimNamesArray.length > 1) { dimension.height = dimensionMap.get(dimNamesArray[1]); } else { dimension.height = -1; } return dimension; } }