/*
* 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 org.junit.experimental.categories.Category;
import ucar.ma2.IndexIterator;
import ucar.ma2.InvalidRangeException;
import ucar.nc2.*;
import ucar.unidata.util.test.category.NeedsCdmUnitTest;
import ucar.unidata.util.test.TestDir;
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;
public class TestDmspIosp extends TestCase {
private String testFilePath = TestDir.cdmUnitTestDir + "formats/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.000Z";
//"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 ...
*/
@Category(NeedsCdmUnitTest.class)
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();
}
@Category(NeedsCdmUnitTest.class)
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();
}
@Category(NeedsCdmUnitTest.class)
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.
@Category(NeedsCdmUnitTest.class)
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.
*
*/