From 3fc2651730c2cb06ad1e9d33bbf49275f98c2272 Mon Sep 17 00:00:00 2001 From: Emily Boudreaux Date: Sat, 15 Feb 2025 07:27:47 -0500 Subject: [PATCH] feat(opatIO): added min viable version of opatIO opatIO can now read tables properly and retreive them in a useful manner. Future aditions will be the ability to lookup "closest" tables and a pretty printer for tables. --- src/mapping/private/mapping_private | 0 src/mapping/public/mapping_public | 0 src/opatIO/private/opatIO.cpp | 255 ++++++++++++++++------------ src/opatIO/public/opatIO.h | 31 ++-- 4 files changed, 169 insertions(+), 117 deletions(-) delete mode 100644 src/mapping/private/mapping_private delete mode 100644 src/mapping/public/mapping_public diff --git a/src/mapping/private/mapping_private b/src/mapping/private/mapping_private deleted file mode 100644 index e69de29..0000000 diff --git a/src/mapping/public/mapping_public b/src/mapping/public/mapping_public deleted file mode 100644 index e69de29..0000000 diff --git a/src/opatIO/private/opatIO.cpp b/src/opatIO/private/opatIO.cpp index 67900ba..29f0d08 100644 --- a/src/opatIO/private/opatIO.cpp +++ b/src/opatIO/private/opatIO.cpp @@ -4,8 +4,12 @@ #include #include #include -#include -#include +#include +#include +#include +#include +#include +#include // Constructor OpatIO::OpatIO() {} @@ -41,7 +45,7 @@ void OpatIO::unload() { tableIndex.clear(); while (!tableQueue.empty()) { - tableQueue.pop(); + tableQueue.pop_front(); } loaded = false; @@ -63,125 +67,168 @@ void OpatIO::readTableIndex(std::ifstream &file) { if (file.gcount() != static_cast(header.numTables * sizeof(TableIndex))) { throw std::runtime_error("Error reading table index from file: " + filename); } + buildTableIDToComposition(); } -// // Check if a table is in the queue -// bool OpatIO::isTableInQueue(double X, double Z) { -// for (const auto &table : tableQueue) { -// if (table.X == X && table.Z == Z) { -// return true; -// } -// } -// return false; -// } +void OpatIO::buildTableIDToComposition(){ + tableIDToComposition.clear(); + int tableID = 0; + std::pair comp; + for (const auto &index : tableIndex) { + comp.first = index.X; + comp.second = index.Z; + tableIDToComposition.emplace(tableID, comp); + tableID++; + } + XZLookupEpsilon(); +} -// // Get a table from the queue -// OPATTable OpatIO::getTableFromQueue(double X, double Z) { -// std::queue tempQueue; -// OPATTable result; +void OpatIO::XZLookupEpsilon() { + /* + Get 10% of the minimum spacing between XZ values + in the tableIDToComposition map. This can be used + to set the comparison distance when doing a reverse + lookup (composition -> tableID) + */ + std::vector Xvalues, Zvalues; + double epsilonX, epsilonZ, xgap, zgap; -// while (!tableQueue.empty()) { -// OPATTable table = tableQueue.front(); -// tableQueue.pop(); -// if (table.X == X && table.Z == Z) { -// result = table; -// } -// tempQueue.push(table); -// } + // Start these out as larger than they will ever be + epsilonX = 1; + epsilonZ = 1; + for (const auto& pair : tableIDToComposition) { + Xvalues.push_back(pair.second.first); + Zvalues.push_back(pair.second.second); + } -// tableQueue = tempQueue; -// return result; -// } + // Sorting is required for this algorithm. + std::sort(Xvalues.begin(), Xvalues.end()); + std::sort(Zvalues.begin(), Zvalues.end()); -// // Add a table to the queue -// void OpatIO::addTableToQueue(OPATTable table) { -// if (tableQueue.size() >= maxQueueDepth) { -// removeTableFromQueue(); -// } -// tableQueue.push(table); -// } + for (size_t i = 1; i < Xvalues.size(); ++i) { + xgap = Xvalues[i] - Xvalues[i - 1]; + zgap = Zvalues[i] - Zvalues[i - 1]; + if (xgap > 0 && xgap < epsilonX) { + epsilonX = xgap; + } + if (zgap > 0 && zgap < epsilonZ) { + epsilonZ = zgap; + } + } + // 0.1 to extract 10% of min distance. + XZepsilon = {0.1*epsilonX, 0.1*epsilonZ}; +} -// // Remove a table from the queue -// void OpatIO::removeTableFromQueue() { -// if (!tableQueue.empty()) { -// tableQueue.pop(); -// } -// } +int OpatIO::lookupTableID(double X, double Z){ + bool XOkay; + bool ZOkay; + int tableID = 0; + for (const auto &tableMap : tableIDToComposition){ + XOkay = std::fabs(tableMap.second.first - X) < XZepsilon.first; + ZOkay = std::fabs(tableMap.second.second - Z) < XZepsilon.second; + if (XOkay and ZOkay){ + return tableID; + } + tableID++; + } + return -1; +} -// // Flush the queue -// void OpatIO::flushQueue() { -// while (!tableQueue.empty()) { -// tableQueue.pop(); -// } -// } +// Get a table from the queue +OPATTable OpatIO::getTableFromQueue(int tableID) { + for (const auto &table : tableQueue) { + if (table.first == tableID) { + return table.second; + } + } + throw std::out_of_range("Table not found!"); +} -// // Get the OPAT version -// uint16_t OpatIO::getOPATVersion() { -// return header.version; -// } +// Add a table to the queue +void OpatIO::addTableToQueue(int tableID, OPATTable table) { + if (static_cast(tableQueue.size()) >= maxQDepth) { + removeTableFromQueue(); + } + std::pair IDTablePair = {tableID, table}; + tableQueue.push_back(IDTablePair); +} -// // Get the table ID for given X and Z -// uint16_t OpatIO::getTableID(double X, double Z) { -// for (const auto &index : tableIndex) { -// if (index.X == X && index.Z == Z) { -// return index.tableID; -// } -// } -// throw std::runtime_error("Table ID not found for given X and Z"); -// } +// Remove a table from the queue +void OpatIO::removeTableFromQueue() { + if (!tableQueue.empty()) { + tableQueue.pop_front(); + } +} -// // Get the byte start for a given table ID -// uint64_t OpatIO::getTableByteStart(uint16_t tableID) { -// for (const auto &index : tableIndex) { -// if (index.tableID == tableID) { -// return index.byteStart; -// } -// } -// throw std::runtime_error("Byte start not found for given table ID"); -// } +// Flush the queue +void OpatIO::flushQueue() { + while (!tableQueue.empty()) { + tableQueue.pop_back(); + tableQueue.pop_front(); + } +} -// // Get the byte end for a given table ID -// uint64_t OpatIO::getTableByteEnd(uint16_t tableID) { -// for (const auto &index : tableIndex) { -// if (index.tableID == tableID) { -// return index.byteEnd; -// } -// } -// throw std::runtime_error("Byte end not found for given table ID"); -// } +// Get the OPAT version +uint16_t OpatIO::getOPATVersion() { + return header.version; +} -// // Get a table for given X and Z -// OPATTable OpatIO::getTable(double X, double Z) { -// if (isTableInQueue(X, Z)) { -// return getTableFromQueue(X, Z); -// } +// Get a table for given X and Z +OPATTable OpatIO::getTable(double X, double Z) { + int tableID = lookupTableID(X, Z); + if (tableID == -1) { + throw std::out_of_range("X Z Pair Not found!"); + } + try { + return getTableFromQueue(tableID); + } + catch(const std::out_of_range &e) { + return getTable(tableID); + } +} -// uint16_t tableID = getTableID(X, Z); -// return getTable(tableID); -// } +OPATTable OpatIO::getTable(int tableID) { + std::ifstream file(filename, std::ios::binary); + if (!file.is_open()) { + throw std::runtime_error("Could not open file: " + filename); + } -// // Get a table for given table ID -// OPATTable OpatIO::getTable(uint16_t tableID) { -// std::ifstream file(filename, std::ios::binary); -// if (!file.is_open()) { -// throw std::runtime_error("Could not open file: " + filename); -// } + uint64_t byteStart = tableIndex[tableID].byteStart; -// uint64_t byteStart = getTableByteStart(tableID); -// uint64_t byteEnd = getTableByteEnd(tableID); -// uint64_t tableSize = byteEnd - byteStart; + file.seekg(byteStart, std::ios::beg); -// file.seekg(byteStart, std::ios::beg); -// OPATTable table; -// file.read(reinterpret_cast(&table), tableSize); -// if (file.gcount() != tableSize) { -// throw std::runtime_error("Error reading table from file: " + filename); -// } + OPATTable table; -// addTableToQueue(table); -// file.close(); -// return table; -// } + // Step 1: Read N_R and N_T + file.read(reinterpret_cast(&table.N_R), sizeof(uint32_t)); + file.read(reinterpret_cast(&table.N_T), sizeof(uint32_t)); + + + // Resize vectors to hold the correct number of elements + table.logR.resize(table.N_R); + table.logT.resize(table.N_T); + table.logKappa.resize(table.N_R, std::vector(table.N_T)); + + // Step 2: Read logR values + file.read(reinterpret_cast(table.logR.data()), table.N_R * sizeof(double)); + + // Step 3: Read logT values + file.read(reinterpret_cast(table.logT.data()), table.N_T * sizeof(double)); + + // Step 4: Read logKappa values (flattened row-major order) + for (size_t i = 0; i < table.N_R; ++i) { + + file.read(reinterpret_cast(table.logKappa[i].data()), table.N_T * sizeof(double)); + } + + if (!file) { + throw std::runtime_error("Error reading table from file: " + filename); + } + + addTableToQueue(tableID, table); + file.close(); + return table; +} // Set the maximum queue depth void OpatIO::setMaxQDepth(int depth) { diff --git a/src/opatIO/public/opatIO.h b/src/opatIO/public/opatIO.h index 30c4ba5..70feda9 100644 --- a/src/opatIO/public/opatIO.h +++ b/src/opatIO/public/opatIO.h @@ -5,7 +5,9 @@ #include #include #include -#include +#include +#include +#include struct Header { char magic[4]; @@ -37,11 +39,15 @@ struct OPATTable { std::vector> logKappa; }; +class opatIOTest; // Friend for gtest + class OpatIO { private: Header header; std::vector tableIndex; - std::queue tableQueue; + std::deque> tableQueue; + std::map> tableIDToComposition; + std::pair XZepsilon; int maxQDepth = 10; std::string filename; bool loaded = false; @@ -49,26 +55,21 @@ private: void readHeader(std::ifstream &file); void readTableIndex(std::ifstream &file); - bool isTableInQueue(double X, double Z); - OPATTable getTableFromQueue(double X, double Z); - void addTableToQueue(OPATTable table); + OPATTable getTableFromQueue(int tableID); + void addTableToQueue(int tableID, OPATTable table); void removeTableFromQueue(); - void flushQueue(); - uint16_t getOPATVersion(); - - uint16_t getTableID(double X, double Z); - uint64_t getTableByteStart(uint16_t tableID); - uint64_t getTableByteEnd(uint16_t tableID); + OPATTable getTable(int tableID); + void XZLookupEpsilon(); + void buildTableIDToComposition(); public: OpatIO(); OpatIO(std::string filename); ~OpatIO(); - OPATTable getTable(double X, double, double C=0, double O=0); - OPATTable getTable(uint16_t tableID); + OPATTable getTable(double X, double Z); void setMaxQDepth(int depth); int getMaxQDepth(); void setFilename(std::string filename); @@ -87,6 +88,10 @@ public: std::vector getClosestXTables(double X, double ZExact, double C=0, double O=0, int numTables=1); std::vector getClosestZTables(double XExact, double Z, double C=0, double O=0, int numTables=1); std::vector getClosestTables(double X, double Z, double C=0, double O=0, int numTables=1); + + int lookupTableID(double X, double Z); + int lookupClosestTableID(double X, double Z); + uint16_t getOPATVersion(); };