Commit 90eccc1e authored by Lefebvre, Jordan's avatar Lefebvre, Jordan
Browse files

Resolving #13. Implementing hysplit concentration file stream and test.

parent 99e6ea75
Pipeline #10625 failed with stage
in 3 minutes and 59 seconds
......@@ -566,6 +566,11 @@ int eafstream::bytesRead() const
return mBytesRead;
}//bytesRead
int eafstream::bytesWritten() const
{
return mBytesWritten;
}
int eafstream::readHeader()
{
mHeader = readInt();
......@@ -577,6 +582,8 @@ int eafstream::readHeader()
void eafstream::writeHeader(int header)
{
writeInt(header);
// don't count header in bytes written
mBytesWritten -= int_size;
}
int eafstream::header() const
......@@ -598,6 +605,7 @@ int eafstream::readFooter()
void eafstream::writeFooter(int footer)
{
writeInt(footer);
mBytesWritten = 0;
}
int eafstream::footer() const
......
......@@ -95,11 +95,17 @@ public:
std::string readString(int size);
void writeString(const std::string& var);
/**
* \brief Returns the number of bytes read since the last headers marker
* \brief Returns the number of bytes read since the last header marker
* \return int
*/
int bytesRead() const;
/**
* \brief Returns the number of bytes written since the last header marker
* \return int
*/
int bytesWritten() const;
/**
* @brief readHeader Reads and returns the fortran header record
* @return int
......
......@@ -22,6 +22,14 @@ void HysplitCDump::dateTime(int &year, int &month, int &day, int &hour) const
hour = mHour;
}
void HysplitCDump::setDateTime(int year, int month, int day, int hour)
{
mYear = year;
mMonth = month;
mDay = day;
mHour = hour;
}
int HysplitCDump::forecastHour() const
{
return mForecastHour;
......@@ -37,7 +45,7 @@ int HysplitCDump::numLocations() const
return int(mStartLocations.size());
}
void HysplitCDump::locations(int i, int &year, int &month, int &day, int &hour, float &lat, float &lon, float &z, int &minutes) const
void HysplitCDump::location(int i, int &year, int &month, int &day, int &hour, float &lat, float &lon, float &z, int &minutes) const
{
radix_check(i < mStartLocations.size());
radix_check(i >= 0);
......@@ -124,6 +132,10 @@ void HysplitCDump::setCornerLon(float cLon)
mCLon = cLon;
}
int HysplitCDump::numLevels() const
{
return int(mLevels.size());
}
void HysplitCDump::addLevel(int altitude)
{
mLevels.push_back(altitude);
......@@ -239,6 +251,10 @@ void HysplitCDump::setNumNonZeroPoints(int timeIndex, int pollutantIndex, int le
radix_check(pollutantIndex >= 0);
radix_check(levelIndex >= 0);
// pollutants and levels should be set before number of points
radix_check(pollutantIndex < mPollutants.size());
radix_check(levelIndex < mLevels.size());
// resize according to timeIndex
if(timeIndex >= mXList.size())
{
......
......@@ -4,6 +4,7 @@
#include <string>
#include <sstream>
#include <vector>
#include <memory>
#include "radixdl/visibility.hh"
......@@ -13,6 +14,7 @@ namespace radix
class RADIX_PUBLIC HysplitCDump
{
public:
typedef std::shared_ptr<HysplitCDump> SP;
/**
* @brief The Location struct
* Contains date (year, month, day)
......@@ -89,10 +91,11 @@ public:
std::string id() const;
void setId(const std::string &id);
void dateTime(int &year, int &month, int &day, int &hour) const;
void setDateTime(int year, int month, int day, int hour);
int forecastHour() const;
void setForecastHour(int forecastHour);
int numLocations() const;
void locations(int i, int &year, int &month, int& day, int &hour
void location(int i, int &year, int &month, int& day, int &hour
, float &lat, float &lon, float &z
, int &minutes) const;
......@@ -112,6 +115,7 @@ public:
float cornerLon() const;
void setCornerLon(float cLon);
int numLevels() const;
void addLevel(int altitude);
int level(int index) const;
......
......@@ -178,11 +178,15 @@ bool HysplitCDumpStream<data_type>::write_to(const std::string& file) const
}
record_length = id.size() + sizeof(int)*7;
int year, month, day, hour, forecastHour, minutes, numLocations, packing = 1;
mData->dateTime(year, month, day, hour, forecastHour);
mData->dateTime(year, month, day, hour);
forecastHour = mData->forecastHour();
numLocations = mData->numLocations();
radix_tagged_line("record_length=" << record_length);
fstr.writeHeader(record_length);
fstr.writeString(id);
fstr << year << month << day << hour << forecastHour << numLocations << packing;
radix_tagged_line("bytes_written=" << fstr.bytesWritten());
fstr.writeFooter(record_length);
float lat, lon, z;
......@@ -202,30 +206,29 @@ bool HysplitCDumpStream<data_type>::write_to(const std::string& file) const
deltaLon = mData->deltaLon();
cLat = mData->cornerLat();
cLon = mData->cornerLon();
{
// force string to be only 4 characters
char cid[5];
sprintf(cid, "%4s", id.c_str());
cid[4] = '\0'; // null terminate
id = cid;
}
record_length = sizeof(int)*2+sizeof(float)*4;
fstr.writeHeader(record_length);
fstr << numLat << numLon << deltaLat << deltaLon << cLat << cLon;
fstr.writeFooter(record_length);
int numLevels = mData->numLevels();
record_length = int(sizeof(int))*numLevels;
record_length = int(sizeof(int))+int(sizeof(int))*numLevels;
radix_tagged_line("record_length=" << record_length);
fstr.writeHeader(record_length);
fstr << numLevels;
for(int i = 0; i < numLevels; ++i)
{
fstr << mData->level(i);
}
radix_tagged_line("bytes_written=" << fstr.bytesWritten());
fstr.writeFooter(record_length);
int numPollutants = mData->numPollutants();
record_length = numPollutants*4;
record_length = int(sizeof(int))+numPollutants*4;
radix_tagged_line("record_length=" << record_length);
fstr.writeHeader(record_length);
fstr << numPollutants;
std::vector<std::string> local_pols;
for(int i = 0; i < numPollutants; ++i)
{
......@@ -238,7 +241,7 @@ bool HysplitCDumpStream<data_type>::write_to(const std::string& file) const
fstr.writeString(pol);
local_pols.push_back(pol);
}
radix_tagged_line("bytes_written=" << fstr.bytesWritten());
fstr.writeFooter(record_length);
int numStartTimes = mData->numStartTimes();
......@@ -249,14 +252,18 @@ bool HysplitCDumpStream<data_type>::write_to(const std::string& file) const
{
mData->startTime(timeIndex, year, month, day, hour, minutes, forecastHour);
record_length = sizeof(int)*6;
radix_tagged_line("record_length=" << record_length);
fstr.writeHeader(record_length);
fstr << year << month << day << hour << minutes << forecastHour;
radix_tagged_line("bytes_written=" << fstr.bytesWritten());
fstr.writeFooter(record_length);
mData->endTime(timeIndex, year, month, day, hour, minutes, forecastHour);
record_length = sizeof(int)*6;
radix_tagged_line("record_length=" << record_length);
fstr.writeHeader(record_length);
fstr << year << month << day << hour << minutes << forecastHour;
radix_tagged_line("bytes_written=" << fstr.bytesWritten());
fstr.writeFooter(record_length);
for(int i = 0; i < numPollutants; ++i)
......@@ -268,6 +275,10 @@ bool HysplitCDumpStream<data_type>::write_to(const std::string& file) const
record_length = 4 + int(sizeof(int)) * 2
+ int(sizeof(short))*2*nxyp
+ int(sizeof(float))*nxyp;
radix_tagged_line("record_length=" << record_length
<< " pol=" << local_pols[size_t(i)]
<< " z=" << level
<< " nxyp=" << nxyp);
fstr.writeHeader(record_length);
fstr.writeString(local_pols[size_t(i)]);
fstr << level << nxyp;
......@@ -278,10 +289,12 @@ bool HysplitCDumpStream<data_type>::write_to(const std::string& file) const
mData->point(timeIndex, i, j, np, xi, yi, c);
fstr << xi << yi << c;
}
radix_tagged_line("bytes_written=" << fstr.bytesWritten());
fstr.writeFooter(record_length);
}
}
}
fstr.close();
result = true;
return result;
}
......
......@@ -2,3 +2,4 @@ INCLUDE(GoogleTest)
ADD_GOOGLE_TEST(tstCSVFile.cc NP 1)
ADD_GOOGLE_TEST(tstEafstream.cc NP 1)
ADD_GOOGLE_TEST(tstHysplitCDump.cc NP 1)
#include "gtest/gtest.h"
#include "radixio/hysplitcdump.hh"
using namespace radix;
TEST(RadixIO, HysplitCDump)
{
std::string file("cdump.bin");
HysplitCDump::SP cd1 = std::make_shared<HysplitCDump>();
// build an initial object
{
cd1->setId("TCDump"); // this should get truncated to 4 characters
cd1->setDateTime(1951, 11, 19, 17);
cd1->setForecastHour(12);
cd1->addLocation(1951, 11, 19, 17, 37.15f, -116.13f, 1284.7f, 0);
// grid 100x100 points spanning 15x10
cd1->setNumLon(10);
cd1->setNumLat(15); // use different number to ensure no typos
cd1->setDeltaLat(0.015f);
cd1->setDeltaLon(0.01f); // same as comment above
cd1->setCornerLat(32.15f);
cd1->setCornerLon(-123.63f);
// altitudes
cd1->addLevel(0);
cd1->addLevel(100);
cd1->addLevel(1000);
cd1->addLevel(5400);
//pollutants
cd1->addPollutant("P001.1"); // should be truncated to P001
cd1->addPollutant("P099");
// start and end times
cd1->addStartTime(1951, 11, 19, 17, 0, 0);
cd1->addEndTime( 1951, 11, 19, 23, 0, 0);
cd1->addStartTime(1951, 11, 19, 23, 0, 0);
cd1->addEndTime( 1951, 11, 20, 05, 0, 0);
// set non-zero points time pol level np
cd1->setNumNonZeroPoints(0, 0, 0, 2);
cd1->setNumNonZeroPoints(0, 0, 1, 2);
cd1->setNumNonZeroPoints(0, 0, 2, 2);
cd1->setNumNonZeroPoints(0, 0, 3, 2);
// set points time pol level np
cd1->setPoint( 0, 0, 0, 0, 49, 49, 1.f);
cd1->setPoint( 0, 0, 0, 1, 49, 50, 1.5f);
cd1->setPoint( 0, 0, 1, 0, 48, 44, 0.1f);
cd1->setPoint( 0, 0, 1, 1, 49, 50, 0.5f);
cd1->setPoint( 0, 0, 2, 0, 40, 40, 0.01f);
cd1->setPoint( 0, 0, 2, 1, 40, 50, 0.05f);
cd1->setPoint( 0, 0, 3, 0, 60, 50, 0.02f);
cd1->setPoint( 0, 0, 3, 1, 60, 55, 0.07f);
cd1->setNumNonZeroPoints(0, 1, 0, 2);
cd1->setNumNonZeroPoints(0, 1, 1, 2);
cd1->setNumNonZeroPoints(0, 1, 2, 2);
cd1->setNumNonZeroPoints(0, 1, 3, 2);
// set points time pol level np
cd1->setPoint( 0, 1, 0, 0, 49, 49, 1.f);
cd1->setPoint( 0, 1, 0, 1, 49, 50, 1.5f);
cd1->setPoint( 0, 1, 1, 0, 48, 44, 0.1f);
cd1->setPoint( 0, 1, 1, 1, 49, 50, 0.5f);
cd1->setPoint( 0, 1, 2, 0, 40, 40, 0.01f);
cd1->setPoint( 0, 1, 2, 1, 40, 50, 0.05f);
cd1->setPoint( 0, 1, 3, 0, 60, 50, 0.02f);
cd1->setPoint( 0, 1, 3, 1, 60, 55, 0.07f);
cd1->setNumNonZeroPoints(1, 0, 0, 2);
cd1->setNumNonZeroPoints(1, 0, 1, 2);
cd1->setNumNonZeroPoints(1, 0, 2, 2);
cd1->setNumNonZeroPoints(1, 0, 3, 2);
// set points time pol level np
cd1->setPoint( 1, 0, 0, 0, 49, 49, 1.f);
cd1->setPoint( 1, 0, 0, 1, 49, 50, 1.5f);
cd1->setPoint( 1, 0, 1, 0, 48, 44, 0.1f);
cd1->setPoint( 1, 0, 1, 1, 49, 50, 0.5f);
cd1->setPoint( 1, 0, 2, 0, 40, 40, 0.01f);
cd1->setPoint( 1, 0, 2, 1, 40, 50, 0.05f);
cd1->setPoint( 1, 0, 3, 0, 60, 50, 0.02f);
cd1->setPoint( 1, 0, 3, 1, 60, 55, 0.07f);
// pol #2 doesn't have any data for second time
cd1->setNumNonZeroPoints(1, 1, 0, 0);
cd1->setNumNonZeroPoints(1, 1, 1, 0);
cd1->setNumNonZeroPoints(1, 1, 2, 0);
cd1->setNumNonZeroPoints(1, 1, 3, 0);
// write to file
HysplitCDumpStream<HysplitCDump::SP> stream(cd1);
stream.write_to(file);
}
{
HysplitCDump::SP cd2 = std::make_shared<HysplitCDump>();
// load the file
HysplitCDumpStream<HysplitCDump::SP> stream(cd2);
stream.read_from(file);
EXPECT_EQ(cd1->id().substr(0,4), cd2->id());
int y1, y2, m1, m2, d1, d2, h1, h2, f1, f2;
cd1->dateTime(y1, m1, d1, h1);
cd2->dateTime(y2, m2, d2, h2);
EXPECT_EQ(y1, y2);
EXPECT_EQ(m1, m2);
EXPECT_EQ(d1, d2);
EXPECT_EQ(h1, h2);
f1 = cd1->forecastHour();
f2 = cd2->forecastHour();
EXPECT_EQ(f1, f2);
EXPECT_EQ(cd1->numLocations(), cd2->numLocations());
int min1, min2;
float lat1, lat2, lon1, lon2, z1, z2;
int numLocations = cd1->numLocations();
for(int i = 0; i < numLocations; ++i)
{
cd1->location(i, y1, m1, d1, h1, lat1, lon1, z1, min1);
cd2->location(i, y2, m2, d2, h2, lat2, lon2, z2, min2);
EXPECT_EQ(y1, y2);
EXPECT_EQ(m1, m2);
EXPECT_EQ(d1, d2);
EXPECT_EQ(h1, h2);
EXPECT_FLOAT_EQ(lat1, lat2);
EXPECT_FLOAT_EQ(lon1, lon2);
EXPECT_FLOAT_EQ(z1, z2);
EXPECT_EQ(min1, min2);
}
EXPECT_EQ(cd1->numLat(), cd2->numLat());
EXPECT_EQ(cd1->numLon(), cd2->numLon());
EXPECT_FLOAT_EQ(cd1->deltaLat(), cd2->deltaLat());
EXPECT_FLOAT_EQ(cd1->deltaLon(), cd2->deltaLon());
EXPECT_FLOAT_EQ(cd1->cornerLat(), cd2->cornerLat());
EXPECT_FLOAT_EQ(cd1->cornerLon(), cd2->cornerLon());
EXPECT_EQ(cd1->numLevels(), cd2->numLevels());
int numLevels = cd1->numLevels();
for(int i = 0; i < numLevels; ++i)
{
EXPECT_EQ(cd1->level(i), cd2->level(i));
}
EXPECT_EQ(cd1->numPollutants(), cd2->numPollutants());
int numPols = cd1->numPollutants();
for(int i = 0; i < numPols; ++i)
{
EXPECT_EQ(cd1->pollutant(i).substr(0,4), cd2->pollutant(i));
}
EXPECT_EQ(cd1->numStartTimes(), cd2->numStartTimes());
int numStartTimes = cd1->numStartTimes();
for(int i = 0; i < numStartTimes; ++i)
{
cd1->startTime(i, y1, m1, d1, h1, min1, f1);
cd2->startTime(i, y2, m2, d2, h2, min2, f2);
EXPECT_EQ(y1, y2);
EXPECT_EQ(m1, m2);
EXPECT_EQ(d1, d2);
EXPECT_EQ(h1, h2);
EXPECT_EQ(min1, min2);
EXPECT_EQ(f1, f2);
}
EXPECT_EQ(cd1->numEndTimes(), cd2->numEndTimes());
int numEndTimes = cd1->numEndTimes();
for(int i = 0; i < numEndTimes; ++i)
{
cd1->endTime(i, y1, m1, d1, h1, min1, f1);
cd2->endTime(i, y2, m2, d2, h2, min2, f2);
EXPECT_EQ(y1, y2);
EXPECT_EQ(m1, m2);
EXPECT_EQ(d1, d2);
EXPECT_EQ(h1, h2);
EXPECT_EQ(min1, min2);
EXPECT_EQ(f1, f2);
}
for(int ti = 0; ti < numStartTimes; ++ti)
{
for(int pi = 0; pi < numPols; ++pi)
{
for(int li = 0; li < numLevels; ++li)
{
EXPECT_EQ(cd1->numNonZeroPoints(ti,pi,li)
, cd2->numNonZeroPoints(ti,pi,li));
int nxyp = cd1->numNonZeroPoints(ti,pi,li);
for(int ni = 0; ni < nxyp; ++ni)
{
short xi1, xi2, yi1, yi2;
float c1, c2;
cd1->point(ti,pi,li,ni,xi1,yi1,c1);
cd2->point(ti,pi,li,ni,xi2,yi2,c2);
EXPECT_EQ(xi1, xi2);
EXPECT_EQ(yi1, yi2);
EXPECT_FLOAT_EQ(c1, c2);
}
}
}
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment