/*
* Copyright 1998-2009 University Corporation for Atmospheric Research/Unidata
*
* Portions of this software were developed by the Unidata Program at the
* University Corporation for Atmospheric Research.
*
* Access and use of this software shall impose the following obligations
* and understandings on the user. The user is granted the right, without
* any fee or cost, to use, copy, modify, alter, enhance and distribute
* this software, and any derivative works thereof, and its supporting
* documentation for any purpose whatsoever, provided that this entire
* notice appears in all copies of the software, derivative works and
* supporting documentation. Further, UCAR requests that the user credit
* UCAR/Unidata in any publications that result from the use of this
* software or in any product that includes this software. The names UCAR
* and/or Unidata, however, may not be used in any advertising or publicity
* to endorse or promote any products or commercial entity unless specific
* written permission is obtained from UCAR/Unidata. The user also
* understands that UCAR/Unidata is not obligated to provide the user with
* any support, consulting, training or assistance of any kind with regard
* to the use, operation and performance of this software nor to provide
* the user with any updates, revisions, new versions or "bug fixes."
*
* THIS SOFTWARE IS PROVIDED BY UCAR/UNIDATA "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL UCAR/UNIDATA BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
* FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
* WITH THE ACCESS, USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// $Id: TestDmspIosp.java 51 2006-07-12 17:13:13Z caron $
package ucar.nc2.iosp.dmsp;
import junit.framework.TestCase;
import ucar.ma2.IndexIterator;
import ucar.ma2.InvalidRangeException;
import ucar.nc2.*;
import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
/**
* A description
* <p/>
* User: edavis
* Date: Aug 10, 2004
* Time: 5:50:02 PM
*/
public class TestDmspIosp extends TestCase
{
private String testFilePath = TestAll.cdmLocalTestDataDir + "dmsp";
private String testDataFileName = "F14200307192230.n.OIS";
private String testDataFileFileIdAttValue = "/dmsp/moby-1-3/subscriptions/IBAMA/1353226646955.tmp";
private String testDataFileDatasetIdAttValue = "DMSP F14 OLS LS & TS";
private int testDataFileNumBytesPerRecordAttValue = 3040;
private int testDataFileNumHeaderRecordsAttValue = 1;
private int testDataFileNumDataRecordsAttValue = 691;
private int testDataFileNumSamplesPerBandDimAttValue = 1465;
private String testDataFileSuborbitHistoryAttValue = "F14200307192230.OIS (1,691)";
private String testDataFileProcessingSystemAttValue = "v2.1b";
private String testDataFileProcessingDateAttValue = "2003-07-19T19:33:23.000GMT";
//"Sat Jul 19 19:33:23 2003";
private String testDataFileSpacecraftIdAttValue = "F14";
private String testDataFileNoradIdAttValue = "24753";
private double testDataFileAscendingNodeAttValue = 320.55;
private double testDataFileNodeHeadingAttValue = 8.64;
private String numDataRecordsDimName = "numScans";
private String numSamplesPerBandDimName = "numSamplesPerScan";
private String fileIdAttName = "fileId";
private String datasetIdAttName = "datasetId";
private String suborbitHistoryAttName = "suborbitHistory";
private String processingSystemAttName = "processingSystem";
private String processingDateAttName = "processingDate";
private String spacecraftIdAttName = "spacecraftId";
private String noradIdAttName = "noradId";
private String ascendingNodeAttName = "ascendingNode";
private String nodeHeadingAttName = "nodeHeading";
private DMSPHeader meHeader = null;
private ucar.unidata.io.RandomAccessFile meRaf = null;
private NetcdfFile meNcf = null;
public TestDmspIosp( String name )
{
super( name );
}
public void testDateFormatHandler()
{
String isoDateFormatString = "yyyy-MM-dd";
String isoTimeFormatString = "HH:mm:ss.SSSz";
String isoDateTimeFormatString = "yyyy-MM-dd\'T\'HH:mm:ss.SSSz";
String altDateTimeFormatString = "EEE MMM dd HH:mm:ss yyyy";
int targetDate1Year = 2003;
int targetDate1Month = 6; // July
int targetDate1Day = 19;
int targetDate1Hour = 19;
int targetDate1Minute = 33;
int targetDate1Second = 23;
int targetDate1Milisecond = 0;
String targetDate1ISODateString = "2003-07-19";
String targetDate1ISODateTimeString = "2003-07-19T19:33:23.000GMT";
String targetDate1AltDateTimeString = "Sat Jul 19 19:33:23 2003";
Calendar calendar = Calendar.getInstance( TimeZone.getTimeZone( "GMT" ), Locale.US );
calendar.set( targetDate1Year, targetDate1Month, targetDate1Day,
targetDate1Hour, targetDate1Minute, targetDate1Second );
calendar.set( Calendar.MILLISECOND, targetDate1Milisecond );
Date targetDate1 = calendar.getTime();
Date testDate = null;
String testDateTimeString = null;
// Test that alternate date/time format string is as expected.
assertTrue( "Alternate date/time format string <" + DMSPHeader.DateFormatHandler.ALT_DATE_TIME.getDateTimeFormatString() + "> not as expected <" + altDateTimeFormatString + ">.",
DMSPHeader.DateFormatHandler.ALT_DATE_TIME.getDateTimeFormatString().equals( altDateTimeFormatString ) );
// Test that alternate date/time format string handler parses date/time string properly.
try
{
testDate = DMSPHeader.DateFormatHandler.ALT_DATE_TIME.getDateFromDateTimeString( targetDate1AltDateTimeString );
}
catch ( ParseException e )
{
assertTrue( "Unexpected ParseException while parsing date/time string <" + targetDate1AltDateTimeString + ">: " + e.getMessage(),
false );
}
assertTrue( "Alternate date/time <" + testDate + "> not as expected <" + targetDate1.toString() + ">.",
testDate.equals( targetDate1 ) );
// Test that alternate date/time format string handler formats date/time properly.
testDateTimeString = DMSPHeader.DateFormatHandler.ALT_DATE_TIME.getDateTimeStringFromDate( targetDate1 );
assertTrue( "Date/time string <" + testDateTimeString + "> not as expected <" + targetDate1AltDateTimeString + ">.",
testDateTimeString.equals( targetDate1AltDateTimeString ) );
}
/**
* Test ...
*/
public void testDimAndAtt() throws IOException {
setupReadDmspAsNetcdf( this.testFilePath, this.testDataFileName);
assertTrue( "Created NetcdfFile is null.", meNcf != null );
// // Test some header information not available from NetcdfFile.
// assertTrue( "Number of bytes per records <" + meHeader.getRecordSizeInBytes() + "> not as expected <" + this.testDataFileNumBytesPerRecordAttValue + ">.",
// meHeader.getRecordSizeInBytes() == this.testDataFileNumBytesPerRecordAttValue );
// assertTrue( "Number of header records <" + meHeader.getNumHeaderRecords() + "> not as expected <" + this.testDataFileNumHeaderRecordsAttValue + ">.",
// meHeader.getNumHeaderRecords() == this.testDataFileNumHeaderRecordsAttValue );
// Test for the dimensions of the NetcdfFile.
Dimension curDim = meNcf.getRootGroup().findDimension( this.numDataRecordsDimName);
assertTrue( "Number of data records <" + curDim.getLength() + "> not as expected <" + this.testDataFileNumDataRecordsAttValue + ">.",
curDim.getLength() == this.testDataFileNumDataRecordsAttValue );
curDim = meNcf.getRootGroup().findDimension( this.numSamplesPerBandDimName);
assertTrue( "Number of bytes per records <" + curDim.getLength() + "> not as expected <" + this.testDataFileNumSamplesPerBandDimAttValue + ">.",
curDim.getLength() == this.testDataFileNumSamplesPerBandDimAttValue );
// Test for the attributes of the NetcdfFile.
Attribute curAtt = meNcf.getRootGroup().findAttribute( this.fileIdAttName);
assertTrue( "FileId attribute <" + curAtt.getStringValue() + "> not as expected <" + this.testDataFileFileIdAttValue + ">.",
curAtt.getStringValue().equals( this.testDataFileFileIdAttValue ));
curAtt = meNcf.getRootGroup().findAttribute( this.datasetIdAttName);
assertTrue( "DatasetId attribute <" + curAtt.getStringValue() + "> not as expected <" + this.testDataFileDatasetIdAttValue + ">.",
curAtt.getStringValue().equals( this.testDataFileDatasetIdAttValue ));
curAtt = meNcf.getRootGroup().findAttribute( this.suborbitHistoryAttName);
assertTrue( "SuborbitHistory attribute <" + curAtt.getStringValue() + "> not as expected <" + this.testDataFileSuborbitHistoryAttValue + ">.",
curAtt.getStringValue().equals( this.testDataFileSuborbitHistoryAttValue ));
curAtt = meNcf.getRootGroup().findAttribute( this.processingSystemAttName);
assertTrue( "ProcessingSystem attribute <" + curAtt.getStringValue() + "> not as expected <" + this.testDataFileProcessingSystemAttValue + ">.",
curAtt.getStringValue().equals( this.testDataFileProcessingSystemAttValue ));
curAtt = meNcf.getRootGroup().findAttribute( this.processingDateAttName);
assertTrue( "ProcessingDate attribute <" + curAtt.getStringValue() + "> not as expected <" + this.testDataFileProcessingDateAttValue + ">.",
curAtt.getStringValue().equals( this.testDataFileProcessingDateAttValue ));
curAtt = meNcf.getRootGroup().findAttribute( this.spacecraftIdAttName);
assertTrue( "SpacecraftId attribute <" + curAtt.getStringValue() + "> not as expected <" + this.testDataFileSpacecraftIdAttValue + ">.",
curAtt.getStringValue().equals( this.testDataFileSpacecraftIdAttValue ));
curAtt = meNcf.getRootGroup().findAttribute( this.noradIdAttName);
assertTrue( "ProcessingDate attribute <" + curAtt.getStringValue() + "> not as expected <" + this.testDataFileNoradIdAttValue + ">.",
curAtt.getStringValue().equals( this.testDataFileNoradIdAttValue ));
curAtt = meNcf.getRootGroup().findAttribute( this.ascendingNodeAttName);
assertTrue( "AscendingNode attribute <" + curAtt.getNumericValue().doubleValue() + "> not as expected <" + this.testDataFileAscendingNodeAttValue + ">.",
curAtt.getNumericValue().doubleValue() == testDataFileAscendingNodeAttValue);
curAtt = meNcf.getRootGroup().findAttribute( this.nodeHeadingAttName);
assertTrue( "NodeHeading attribute <" + curAtt.getNumericValue().doubleValue() + "> not as expected <" + this.testDataFileNodeHeadingAttValue + ">.",
curAtt.getNumericValue().doubleValue() == testDataFileNodeHeadingAttValue);
meNcf.close();
}
public void testReadEpoch() throws IOException {
setupReadDmspAsNetcdf( this.testFilePath, this.testDataFileName);
// Test reading year.
ucar.ma2.Array year = null;
try
{
year = meNcf.findVariable( "year").read();
}
catch ( IOException e )
{
assertTrue( "Unexpected IOException reading \"year\" variable: " + e.getMessage(),
false );
}
int val = 0;
IndexIterator iter = year.getIndexIterator();
while (iter.hasNext()) {
val = iter.getIntNext();
assertTrue( "Value of variable \"year\" <" + val + "> not expected <2003>.",
val == 2003 );
}
// Test reading dayOfYear.
ucar.ma2.Array dayOfYear = null;
try
{
dayOfYear = meNcf.findVariable( "dayOfYear").read();
}
catch ( IOException e )
{
assertTrue( "Unexpected IOException reading \"dayOfYear\" variable: " + e.getMessage(),
false );
}
val = 0;
iter = dayOfYear.getIndexIterator();
while (iter.hasNext()) {
val = iter.getIntNext();
assertTrue( "Value of variable \"dayOfYear\" <" + val + "> not expected <200>.",
val == 200 );
}
// Test reading dayOfYear.
ucar.ma2.Array secondsOfDay = null;
try
{
secondsOfDay = meNcf.findVariable( "secondsOfDay").read();
}
catch ( IOException e )
{
assertTrue( "Unexpected IOException reading \"secondsOfDay\" variable: " + e.getMessage(),
false );
}
double prevVal = 0;
double curVal = 0;
double timeInterval = 0;
double timeIntervalGuess = 0.42;
double delta = 0.01;
iter = secondsOfDay.getIndexIterator();
if ( iter.hasNext())
{
prevVal = iter.getDoubleNext();
int timeStep = 1;
while (iter.hasNext())
{
curVal = iter.getDoubleNext();
timeInterval = curVal - prevVal;
StringBuffer tmpMsg = new StringBuffer( "Variable \"secondsOfDay\": [" )
.append( timeStep ).append( "]=<" ).append( curVal).append( ">, [")
.append( (timeStep-1) ).append( "]=<" ).append( prevVal ).append( "> difference <")
.append( timeInterval).append( "> not within delta <" ).append( delta )
.append( "> of expected <" ).append( timeIntervalGuess ).append( ">." );
assertTrue( tmpMsg.toString(),
timeInterval >= timeIntervalGuess - delta && timeInterval <= timeIntervalGuess + delta );
prevVal = curVal;
timeStep++;
}
}
meNcf.close();
}
public void testLatLonCalcAndCache() throws IOException {
setupReadDmspAsNetcdf( this.testFilePath, this.testDataFileName);
Variable latVar = meNcf.findVariable( "latitude" );
ucar.ma2.Array latitude = null;
try
{
latitude = latVar.read();
}
catch ( IOException e )
{
assertTrue( "Unexpected IOException reading \"latitude\" variable: " + e.getMessage(),
false );
}
// Test that difference between neighboring pixels in first scan is small
IndexIterator iter = latitude.getIndexIterator();
float curVal = 0.0F;
float diff = 0.0F;
float biggestDiff = 0.0F;
float smallestDiff = 0.0F;
float prevVal = iter.getFloatNext();
int cnt = 1;
while (iter.hasNext() && cnt < 1465) {
curVal = iter.getFloatNext();
diff = curVal - prevVal;
if ( cnt == 1)
{
biggestDiff = diff;
smallestDiff = diff;
}
else
{
if ( diff > biggestDiff ) biggestDiff = diff;
if ( diff < smallestDiff ) smallestDiff = diff;
}
//System.out.println( curVal + " : " + diff);
prevVal = curVal;
cnt++;
}
//System.out.println( "\nBiggest Diff=" + biggestDiff);
//System.out.println( "Smallest Diff=" + smallestDiff);
assertTrue( "Biggest difference in latitude between neighboring pixels of the first scan <" + biggestDiff + "> bigger than expected <0.004>.",
biggestDiff < 0.004);
assertTrue( "Smallest difference in latitude between neighboring pixels of the first scan <" + smallestDiff + "> smaller than expected <0.002>.",
smallestDiff > 0.002);
// Now test that the user isn't getting the cached data.
float lat1 = latitude.getFloat( latitude.getIndex().set( 0,0) );
latitude.setFloat( latitude.getIndex().set( 0,0), lat1 + 100.0F);
ucar.ma2.Array latPointAfterModify = null;
try
{
latPointAfterModify = latVar.read( "0:0:1,0:0:1" );
}
catch ( InvalidRangeException e )
{
assertTrue( "Unexpected InvalidRangeException reading \"latitude\" variable: " + e.getMessage(),
false );
}
catch ( IOException e )
{
assertTrue( "Unexpected IOException reading \"latitude\" variable: " + e.getMessage(),
false );
}
float lat1After = latPointAfterModify.getFloat( latPointAfterModify.getIndex().set( 0, 0 ) );
assertTrue( "Value of lat[0,0] <" + lat1 + "> changed <" + lat1After + ">",
lat1 == lat1After );
meNcf.close();
}
// From: John Caron
// Date: 9 May 2006
// I just tracked down an insidious bug where Array.section() was used
// instead of Array.sectionNoReduce(). The difference is that section()
// will eliminate any dimension of length =1, thus reducing the rank.
//
// I.e., if a user requests one point in a particular dimension, that
// dimension will be removed.
public void testSectionVsSectionNoReduce() throws IOException {
setupReadDmspAsNetcdf( this.testFilePath, this.testDataFileName);
Variable yearVar = meNcf.findVariable( "year" );
assertTrue( "Year variable not of rank one.",
yearVar.getRank() == 1 );
Variable visVar = meNcf.findVariable( "visibleImagery" );
assertTrue( "Visible imagery variable not of rank two.",
visVar.getRank() == 2 );
Variable irVar = meNcf.findVariable( "infraredImagery" );
assertTrue( "Infrared imagery variable not of rank two.",
irVar.getRank() == 2 );
long visSize = visVar.getSize();
long irSize = irVar.getSize();
assertTrue( "Visible and infrared imagery variables are different sizes (" + visSize + " vs " + irSize + ".",
visSize == irSize );
// Read in year variable with section not for single point.
ucar.ma2.Array yearArray = null;
try
{
yearArray = yearVar.read( "0:1:1" );
}
catch ( InvalidRangeException e )
{
assertTrue( "Unexpected InvalidRangeException reading \"year\" variable: " + e.getMessage(),
false );
}
catch ( IOException e )
{
assertTrue( "Unexpected IOException reading \"year\" variable: " + e.getMessage(),
false );
}
int yearRank = yearArray.getRank();
assertTrue( "Year array not rank 1 <" + yearRank + ">",
yearRank == 1 );
// Read in visible imagery with only one point selected in one dimension.
ucar.ma2.Array visArray = null;
try
{
visArray = visVar.read( "0:0:1,0:1:1");
}
catch ( InvalidRangeException e )
{
assertTrue( "Unexpected InvalidRangeException reading \"visibleImagery\" variable: " + e.getMessage(),
false );
}
catch ( IOException e )
{
assertTrue( "Unexpected IOException reading \"visibleImagery\" variable: " + e.getMessage(),
false );
}
int visRank = visArray.getRank();
assertTrue( "Latitude array rank not 2 <" + visRank + ">.",
visRank ==2);
meNcf.close();
}
private void setupReadDmspAsNetcdf( String testFilePath, String testDataFileName )
{
// Register the DMSP IOServiceProvider.
try
{
NetcdfFile.registerIOProvider( DMSPiosp.class );
}
catch ( IllegalAccessException e )
{
assertTrue( "Unexpected IllegalAccessException registering DMSPiosp: " + e.getMessage(),
false );
}
catch ( InstantiationException e )
{
assertTrue( "Unexpected InstantiationException registering DMSPiosp: " + e.getMessage(),
false );
}
// Make sure test DMSP file exists and such.
File testFile = new File( testFilePath, testDataFileName );
assertTrue( "Test file <" + testFile.getAbsolutePath() + "> does not exist.",
testFile.exists() );
assertTrue( "Test file <" + testFile.getAbsolutePath() + "> cannot be read.",
testFile.canRead() );
assertTrue( "Test file <" + testFile.getAbsolutePath() + "> is a directory.",
! testFile.isDirectory() );
// Open test DMSP file as NetCDF file.
try
{
meNcf = NetcdfFile.open( testFilePath + "/" + testDataFileName );
}
catch ( IOException e )
{
assertTrue( "Unexpected IOException opening DMSP file <" + testFile.getAbsolutePath() + ">: " + e.getMessage(),
false );
}
}
}
/*
* $Log: TestDmspIosp.java,v $
* Revision 1.5 2006/05/31 19:04:41 edavis
* Fix bug with use of section() instead of sectionNoReduce().
* Also, fix so that copy of cached data is returned to user instead of backing store.
*
* Revision 1.4 2005/07/25 00:07:13 caron
* cache debugging
*
* Revision 1.3 2004/10/14 00:13:01 edavis
* Comment out some print statements.
*
* Revision 1.2 2004/10/13 15:30:35 edavis
* Some clean up and add test for latitude/longitude calculation.
*
* Revision 1.1 2004/10/06 21:47:06 edavis
* Initial tests for ucar.nc2.iosp.dmsp classes.
*
*/