#include "radixio/arldatastream.hh" #include "radixbug/bug.hh" #include "radixcore/stringfunctions.hh" #include "radixio/eafstream.hh" #include "radixmath/util.hh" #include namespace radix { class ARLDataStream::PImpl { public: std::string file; std::shared_ptr stream; int recordSize = 0; }; void ARLDataStream::expand(const std::string& val, ARLIndexHeader& index) { if (val.size() < indexHeaderLength) { throw std::runtime_error( "Incorrect size for string expansion to ARLIndexHeader."); } index.year = std::atoi(val.substr(0, 2).c_str()); index.month = std::atoi(val.substr(2, 2).c_str()); index.day = std::atoi(val.substr(4, 2).c_str()); index.hour = std::atoi(val.substr(6, 2).c_str()); index.ic = std::atoi(val.substr(8, 2).c_str()); index.il = std::atoi(val.substr(10, 2).c_str()); index.cgrid = val.substr(12, 2).c_str(); index.kvar = val.substr(14, 4); index.nexp = std::atoi(val.substr(18, 4).c_str()); index.prec = float(std::atof(val.substr(22, 14).c_str())); index.var1 = float(std::atof(val.substr(36, 14).c_str())); } void ARLDataStream::expand(const std::string& val, const ARLIndexHeader& index, ARLRecordHeader& header) { if (val.size() < recordHeaderLength) { throw std::runtime_error( "Incorrect size for string expansion to ARLHeader."); } header.model_id = val.substr(0, 4); header.icx = std::atoi(val.substr(4, 3).c_str()); header.mn = std::atoi(val.substr(7, 2).c_str()); header.pole_lat = float(std::atof(val.substr(9, 7).c_str())); header.pole_lon = float(std::atof(val.substr(16, 7).c_str())); header.ref_lat = float(std::atof(val.substr(23, 7).c_str())); header.ref_lon = float(std::atof(val.substr(30, 7).c_str())); header.size = float(std::atof(val.substr(37, 7).c_str())); header.orient = float(std::atof(val.substr(44, 7).c_str())); header.tang_lat = float(std::atof(val.substr(51, 7).c_str())); header.sync_xp = float(std::atof(val.substr(58, 7).c_str())); header.sync_yp = float(std::atof(val.substr(65, 7).c_str())); header.sync_lat = float(std::atof(val.substr(72, 7).c_str())); header.sync_lon = float(std::atof(val.substr(79, 7).c_str())); header.dummy = float(std::atof(val.substr(86, 7).c_str())); header.nx = std::atoi(val.substr(93, 3).c_str()); header.ny = std::atoi(val.substr(96, 3).c_str()); header.nz = std::atoi(val.substr(99, 3).c_str()); header.z_flag = std::atoi(val.substr(102, 2).c_str()); header.lenh = std::atoi(val.substr(104, 4).c_str()); int knx = ordinal(index.cgrid[0]); int kny = ordinal(index.cgrid[1]); // Check for the grid domain extending beyond 3 digits if (knx >= 64 || kny >= 64) { header.nx = (knx - 64) * 1000 + header.nx; header.ny = (kny - 64) * 1000 + header.ny; } } ARLDataStream::ARLDataStream(const std::string& file) : p(new PImpl(), [](PImpl* impl) { delete impl; }) { p->file = file; p->stream = std::make_shared( p->file.c_str(), std::ios::in | std::ios::binary); if (!p->stream->is_open()) { radix_line("Failed to open ARL file: " << file); } } bool ARLDataStream::read_index_header(ARLIndexHeader& iheader) { std::string headerString = p->stream->readString(indexHeaderLength); expand(headerString, iheader); radix_line("Read index header: year = " << iheader.year); radix_line(" month = " << iheader.month); radix_line(" day = " << iheader.day); radix_line(" hour = " << iheader.hour); radix_line(" variable = " << iheader.kvar); radix_line(" scaling exponent = " << iheader.nexp); radix_line(" initial value = " << iheader.var1); radix_line(headerString); return true; } bool ARLDataStream::read_next_index_header(ARLIndexHeader& iheader) { int bytesToSkip = roundUpInt(p->stream->bytesRead(), p->recordSize) - p->stream->bytesRead(); p->stream->skipBytes(bytesToSkip); return read_index_header(iheader); } bool ARLDataStream::read_record_header(const ARLIndexHeader& iheader, ARLRecordHeader& rheader) { std::string headerString = p->stream->readString(recordHeaderLength); expand(headerString, iheader, rheader); // Calculate and save record size p->recordSize = (rheader.nx * rheader.ny) + indexHeaderLength; radix_line(" Read record header: model = " << rheader.model_id); radix_line(" nx = " << rheader.nx); radix_line(" ny = " << rheader.ny); radix_line(" nz = " << rheader.nz); radix_line(" Size of each record = " << p->recordSize); radix_line(headerString); return true; } bool ARLDataStream::read_record(const ARLIndexHeader& iheader, const ARLRecordHeader& rheader, std::vector >& record) { // Set up the vector size record.resize(rheader.nx); for (std::vector& vec : record) { vec.resize(rheader.ny); } // Calculate the scaling factor double scaleFactor = pow(2.0, 7.0 - (double)iheader.nexp), lastValue = 0.0; radix_line(" Reading record data:"); for (int y = 0; y < rheader.ny; ++y) { for (int x = 0; x < rheader.nx; ++x) { // Read the raw value unsigned char ch = (unsigned char)p->stream->readChar(); int packedValue = ch - 127; // int packedValue = p->stream->readChar() - 127; // Calculate the unpacked value double unpackedValue = 0.0; // Get the correct 'last value' if we are at a 0 index if (x == 0) { if (y == 0) { lastValue = iheader.var1; } else { lastValue = record[x][y - 1]; } } unpackedValue = (packedValue / scaleFactor) + lastValue; record[x][y] = unpackedValue; lastValue = unpackedValue; if ((x < 2 && y < 2) || ((rheader.nx - x < 3) && (rheader.ny - y < 3))) { radix_line(" [" << x << "," << y << "]: packed = " << packedValue << ", unpacked = " << unpackedValue); } } } return true; } /** * @brief The ARLRecord::PImpl class */ class ARLRecord::PImpl { public: }; ARLRecord::ARLRecord() : p(new ARLRecord::PImpl(), [](ARLRecord::PImpl* impl) { delete impl; }) { } ARLRecord::ARLRecord(const ARLRecord& orig) : p(new ARLRecord::PImpl(), [](ARLRecord::PImpl* impl) { delete impl; }) { } } // namespace radix