/*
* Copyright (C) 2010 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 org.esa.beam.dataio.smos;
import com.bc.ceres.binio.CompoundData;
import com.bc.ceres.binio.DataContext;
import com.bc.ceres.binio.SequenceData;
import org.esa.beam.framework.datamodel.Product;
import org.esa.beam.framework.datamodel.TiePointGrid;
import org.esa.beam.smos.DateTimeUtils;
import org.esa.beam.smos.EEFilePair;
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.awt.geom.Rectangle2D;
import java.io.IOException;
import java.text.MessageFormat;
class VTecFile extends ExplorerFile {
private static final String TAG_IONEX_DESCRIPTOR = "IONEX_Descriptor";
private static final String TAG_LATITUDE_VECTOR = "Latitude_Vector";
private static final String TAG_LATITUDE_VECTOR_1ST = "Latitude_Vector_1st";
private static final String TAG_LATITUDE_VECTOR_2ND = "Latitude_Vector_2nd";
private static final String TAG_LATITUDE_VECTOR_INCREMENT = "Latitude_Vector_Increment";
private static final String TAG_LONGITUDE_VECTOR = "Longitude_Vector";
private static final String TAG_LONGITUDE_VECTOR_1ST = "Longitude_Vector_1st";
private static final String TAG_LONGITUDE_VECTOR_2ND = "Longitude_Vector_2nd";
private static final String TAG_LONGITUDE_VECTOR_INCREMENT = "Longitude_Vector_Increment";
private static final String TAG_SCALING_FACTOR_EXPONENT = "Scale_Factor";
private static final String DAYS_NAME = "Days";
private static final String EPOCH_CURRENT_MAP_NAME = "Epoch_Current_Map";
private static final String MAP_NUMBER_NAME = "Map_Number";
private static final String MICROSECONDS_NAME = "Microseconds";
private static final String SECONDS_NAME = "Seconds";
private static final String VTEC_INFO_NAME = "VTEC_Info";
private static final String VTEC_RECORD_NAME = "VTEC_Record";
private static final String VTEC_DATA_NAME = "VTEC_Data";
private static final String VTEC_VALUE_NAME = "VTEC_value";
private final SequenceData mapData;
private final double lat1;
private final double lat2;
private final double latDelta;
private final double lon1;
private final double lon2;
private final double lonDelta;
private double scalingFactor;
private final int rowCount;
private final int colCount;
VTecFile(EEFilePair eeFilePair, DataContext dataContext) throws IOException {
super(eeFilePair, dataContext);
final Document document = getDocument();
final Namespace namespace = document.getRootElement().getNamespace();
final Element ionexDescriptor = getElement(document.getRootElement(), TAG_IONEX_DESCRIPTOR);
final Element latitudeVector = getElement(ionexDescriptor, TAG_LATITUDE_VECTOR);
lat1 = Double.valueOf(latitudeVector.getChildText(TAG_LATITUDE_VECTOR_1ST, namespace));
lat2 = Double.valueOf(latitudeVector.getChildText(TAG_LATITUDE_VECTOR_2ND, namespace));
latDelta = Double.valueOf(latitudeVector.getChildText(TAG_LATITUDE_VECTOR_INCREMENT, namespace));
final Element longitudeVector = getElement(ionexDescriptor, TAG_LONGITUDE_VECTOR);
lon1 = Double.valueOf(longitudeVector.getChildText(TAG_LONGITUDE_VECTOR_1ST, namespace));
lon2 = Double.valueOf(longitudeVector.getChildText(TAG_LONGITUDE_VECTOR_2ND, namespace));
lonDelta = Double.valueOf(longitudeVector.getChildText(TAG_LONGITUDE_VECTOR_INCREMENT, namespace));
final int scalingFactorExponent = Integer.valueOf(ionexDescriptor.getChildText(TAG_SCALING_FACTOR_EXPONENT,
namespace));
scalingFactor = Math.pow(10.0, scalingFactorExponent);
mapData = getDataBlock().getSequence(VTEC_INFO_NAME);
if (mapData == null) {
throw new IllegalStateException(MessageFormat.format(
"SMOS File ''{0}'': Missing VTEC info.", eeFilePair.getDblFile().getPath()));
}
rowCount = (int) (Math.round((lat2 - lat1) / latDelta) + 1);
colCount = (int) (Math.round((lon2 - lon1) / lonDelta) + 1);
}
@Override
public final Area getArea() {
return new Area(new Rectangle2D.Double(lon1, lat2, lon2 - lon1, lat1 - lat2));
}
@Override
public 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));
for (int i = 0; i < mapData.getElementCount(); i++) {
final CompoundData mapCompoundData = mapData.getCompound(i);
final SequenceData mapSequenceData = mapCompoundData.getSequence(VTEC_RECORD_NAME);
final float[] tiePoints = new float[rowCount * colCount];
for (int j = 0; j < mapSequenceData.getElementCount(); j++) {
final CompoundData compoundData = mapSequenceData.getCompound(j);
final SequenceData sequenceData = compoundData.getSequence(VTEC_DATA_NAME);
for (int k = 0; k < sequenceData.getElementCount(); k++) {
tiePoints[j * colCount + k] = sequenceData.getCompound(k).getShort(VTEC_VALUE_NAME);
}
}
final String name = getName(mapCompoundData);
final String description = getDescription(mapCompoundData);
addTiePointGrid(product, name, description, tiePoints);
}
return product;
}
private void addTiePointGrid(Product product, String name, String description, float[] tiePoints) {
final int w = product.getSceneRasterWidth();
final int h = product.getSceneRasterHeight();
final double maxLat = 90.0;
final double maxLon = 180.0;
final double latRange = 180.0;
final double lonRange = 360.0;
final double scaleX = w / lonRange;
final double scaleY = h / latRange;
final float samplingX = (float) Math.abs(lonDelta * scaleX);
final float samplingY = (float) Math.abs(latDelta * scaleY);
final float offsetX = (float) ((maxLon + lon1) * scaleX);
final float offsetY = (float) ((maxLat - lat1) * scaleY);
final TiePointGrid tiePointGrid = new TiePointGrid(name, colCount, rowCount, offsetX, offsetY, samplingX,
samplingY, tiePoints);
tiePointGrid.setScalingFactor(scalingFactor);
tiePointGrid.setDescription(description);
tiePointGrid.setUnit("TECU");
product.addTiePointGrid(tiePointGrid);
}
private String getDescription(CompoundData mapCompoundData) throws IOException {
final CompoundData epoch = mapCompoundData.getCompound(EPOCH_CURRENT_MAP_NAME);
final int days = epoch.getInt(DAYS_NAME);
final int seconds = epoch.getInt(SECONDS_NAME);
final int microseconds = epoch.getInt(MICROSECONDS_NAME);
final String dateTime = DateTimeUtils.cfiDateToUtc(days, seconds, microseconds).toString();
return "Vertical total electron content (TECU) for epoch " + dateTime;
}
private String getName(CompoundData mapCompoundData) throws IOException {
final StringBuilder nameBuilder = new StringBuilder(getDataFormat().getName().substring(16, 22));
final int mapNumber = mapCompoundData.getInt(MAP_NUMBER_NAME);
nameBuilder.append("_").append(mapNumber);
return nameBuilder.toString();
}
}