From 3dd8aad70b3818a745bf9d36efa47743d07674db Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Mon, 14 Sep 2015 16:32:10 +0200 Subject: [PATCH] Changed MultiRecordTable implementation: - Will not use any getFlatXxx() methods. - Will fetch item0 and items1 for reference Rs value and table data respectively. --- .../EclipseState/Tables/MultiRecordTable.cpp | 124 +++----- .../EclipseState/Tables/MultiRecordTable.hpp | 16 +- .../EclipseState/Tables/PvtgOuterTable.hpp | 27 +- .../EclipseState/Tables/PvtoOuterTable.hpp | 10 +- .../EclipseState/Tables/tests/CMakeLists.txt | 2 +- .../Tables/tests/MultiRecordTableTests.cpp | 117 +++++++ testdata/integration_tests/TABLES/PVTO1.DATA | 44 +++ testdata/integration_tests/TABLES/PVTO2.DATA | 296 ++++++++++++++++++ 8 files changed, 519 insertions(+), 117 deletions(-) create mode 100644 opm/parser/eclipse/EclipseState/Tables/tests/MultiRecordTableTests.cpp create mode 100644 testdata/integration_tests/TABLES/PVTO1.DATA create mode 100644 testdata/integration_tests/TABLES/PVTO2.DATA diff --git a/opm/parser/eclipse/EclipseState/Tables/MultiRecordTable.cpp b/opm/parser/eclipse/EclipseState/Tables/MultiRecordTable.cpp index cb33effc8..89039b7ff 100644 --- a/opm/parser/eclipse/EclipseState/Tables/MultiRecordTable.cpp +++ b/opm/parser/eclipse/EclipseState/Tables/MultiRecordTable.cpp @@ -16,6 +16,7 @@ You should have received a copy of the GNU General Public License along with OPM. If not, see . */ +#include #include namespace Opm { @@ -23,112 +24,65 @@ namespace Opm { * \brief Returns the number of tables which can be found in a * given keyword. */ + size_t MultiRecordTable::numTables(Opm::DeckKeywordConstPtr keyword) { - size_t result = 0; - - // first, go to the first record of the specified table. For this, - // we need to skip the right number of empty records... - for (size_t recordIdx = 0; - recordIdx < keyword->size(); - ++ recordIdx) - { - if (getNumFlatItems(keyword->getRecord(recordIdx)) == 0) - // each table ends with an empty record - ++ result; - } - - // the last empty record of a keyword seems to go MIA for some - // strange reason... - ++result; - - return result; + auto ranges = recordRanges(keyword); + return ranges.size(); } + +std::vector > MultiRecordTable::recordRanges(Opm::DeckKeywordConstPtr keyword) { + std::vector > ranges; + size_t startRecord = 0; + size_t recordIndex = 0; + while (recordIndex < keyword->size()) { + auto item = keyword->getRecord(recordIndex)->getItem(0); + if (item->size( ) == 0) { + ranges.push_back( std::make_pair( startRecord , recordIndex ) ); + startRecord = recordIndex + 1; + } + recordIndex++; + } + ranges.push_back( std::make_pair( startRecord , recordIndex ) ); + return ranges; +} + + // create table from first few items of multiple records void MultiRecordTable::init(Opm::DeckKeywordConstPtr keyword, const std::vector &columnNames, - size_t tableIdx, - size_t firstEntityOffset) + size_t tableIdx) { + auto ranges = recordRanges(keyword); + if (tableIdx >= ranges.size()) + throw std::invalid_argument("Asked for table: " + std::to_string( tableIdx ) + " in keyword + " + keyword->name() + " which only has " + std::to_string( ranges.size() ) + " tables"); + createColumns(columnNames); + m_recordRange = ranges[ tableIdx ]; + for (size_t rowIdx = m_recordRange.first; rowIdx < m_recordRange.second; rowIdx++) { + Opm::DeckRecordConstPtr deckRecord = keyword->getRecord(rowIdx); + Opm::DeckItemConstPtr indexItem = deckRecord->getItem(0); + Opm::DeckItemConstPtr dataItem = deckRecord->getItem(1); - // first, go to the first record of the specified table. For this, - // we need to skip the right number of empty records... - size_t curTableIdx = 0; - for (m_firstRecordIdx = 0; - curTableIdx < tableIdx; - ++ m_firstRecordIdx) - { - if (getNumFlatItems(keyword->getRecord(m_firstRecordIdx)) == 0) - // next table starts with an empty record - ++ curTableIdx; - } - - if (curTableIdx != tableIdx) { - throw std::runtime_error("keyword does not specify enough tables"); - } - - // find the number of records in the table - for (m_numRecords = 0; - m_firstRecordIdx + m_numRecords < keyword->size() - && getNumFlatItems(keyword->getRecord(m_firstRecordIdx + m_numRecords)) != 0; - ++ m_numRecords) - { - } - - for (size_t rowIdx = m_firstRecordIdx; rowIdx < m_firstRecordIdx + m_numRecords; ++ rowIdx) { - // extract the actual data from the records of the keyword of - // the deck - Opm::DeckRecordConstPtr deckRecord = - keyword->getRecord(rowIdx); - - if ( (getNumFlatItems(deckRecord) - firstEntityOffset) < numColumns()) - throw std::runtime_error("Number of columns in the data file is" - "inconsistent with the ones specified"); - - for (size_t colIdx = 0; colIdx < numColumns(); ++colIdx) { - size_t deckItemIdx = colIdx + firstEntityOffset; - m_columns[colIdx].push_back(getFlatSiDoubleData(deckRecord, deckItemIdx)); - m_valueDefaulted[colIdx].push_back(getFlatIsDefaulted(deckRecord, deckItemIdx)); + m_columns[0].push_back(indexItem->getSIDouble(0)); + m_valueDefaulted[0].push_back(indexItem->defaultApplied(0)); + for (size_t colIdx = 1; colIdx < numColumns(); ++colIdx) { + m_columns[colIdx].push_back(dataItem->getSIDouble(colIdx - 1)); + m_valueDefaulted[colIdx].push_back(dataItem->defaultApplied(colIdx - 1)); } } } size_t MultiRecordTable::firstRecordIndex() const { - return m_firstRecordIdx; + return m_recordRange.first; } size_t MultiRecordTable::numRecords() const { - return m_numRecords; + return m_recordRange.second - m_recordRange.first; } -size_t MultiRecordTable::getNumFlatItems(Opm::DeckRecordConstPtr deckRecord) -{ - int result = 0; - for (unsigned i = 0; i < deckRecord->size(); ++ i) { - Opm::DeckItemConstPtr item(deckRecord->getItem(i)); - if (item->size() == 0 || item->defaultApplied(0)) - return result; - result += item->size(); - } - return result; -} - -double MultiRecordTable::getFlatSiDoubleData(Opm::DeckRecordConstPtr deckRecord, unsigned flatItemIdx) const -{ - unsigned itemFirstFlatIdx = 0; - for (unsigned i = 0; i < deckRecord->size(); ++ i) { - Opm::DeckItemConstPtr item = deckRecord->getItem(i); - if (itemFirstFlatIdx + item->size() > flatItemIdx) - return item->getSIDouble(flatItemIdx - itemFirstFlatIdx); - else - itemFirstFlatIdx += item->size(); - } - - throw std::range_error("Tried to access out-of-range flat item"); -} } diff --git a/opm/parser/eclipse/EclipseState/Tables/MultiRecordTable.hpp b/opm/parser/eclipse/EclipseState/Tables/MultiRecordTable.hpp index dbaa4c9a0..3e50af39c 100644 --- a/opm/parser/eclipse/EclipseState/Tables/MultiRecordTable.hpp +++ b/opm/parser/eclipse/EclipseState/Tables/MultiRecordTable.hpp @@ -44,8 +44,7 @@ namespace Opm { */ void init(Opm::DeckKeywordConstPtr keyword, const std::vector &columnNames, - size_t tableIndex, - size_t firstEntityOffset); + size_t tableIndex); public: MultiRecordTable() = default; @@ -54,9 +53,8 @@ namespace Opm { // DO NOT TRY TO CALL THIS METHOD! it is only for the unit tests! void initFORUNITTESTONLY(Opm::DeckKeywordConstPtr keyword, const std::vector &columnNames, - size_t tableIndex, - size_t firstEntityOffset) - { init(keyword, columnNames, tableIndex, firstEntityOffset); } + size_t tableIndex) + { init(keyword, columnNames, tableIndex); } #endif /*! @@ -64,7 +62,7 @@ namespace Opm { * given keyword. */ static size_t numTables(Opm::DeckKeywordConstPtr keyword); - + static std::vector > recordRanges(Opm::DeckKeywordConstPtr keyword); /*! * \brief Return the index of the first record which applies * for this table object. @@ -78,11 +76,7 @@ namespace Opm { size_t numRecords() const; private: - static size_t getNumFlatItems(Opm::DeckRecordConstPtr deckRecord); - double getFlatSiDoubleData(Opm::DeckRecordConstPtr deckRecord, unsigned flatItemIdx) const; - - size_t m_firstRecordIdx; - size_t m_numRecords; + std::pair m_recordRange; }; typedef std::shared_ptr MultiRecordTablePtr; diff --git a/opm/parser/eclipse/EclipseState/Tables/PvtgOuterTable.hpp b/opm/parser/eclipse/EclipseState/Tables/PvtgOuterTable.hpp index bf6fe80ec..c9e9e0962 100644 --- a/opm/parser/eclipse/EclipseState/Tables/PvtgOuterTable.hpp +++ b/opm/parser/eclipse/EclipseState/Tables/PvtgOuterTable.hpp @@ -40,10 +40,9 @@ namespace Opm { */ void init(Opm::DeckKeywordConstPtr keyword, size_t tableIdx) { - ParentType::init(keyword, - std::vector{"P", "RV", "BG", "MUG"}, - tableIdx, - /*firstEntryOffset=*/0); + MultiRecordTable::init(keyword, + std::vector{"P", "RV", "BG", "MUG"}, + tableIdx); MultiRecordTable::checkNonDefaultable("P"); MultiRecordTable::checkMonotonic("P", /*isAscending=*/true); @@ -53,24 +52,24 @@ namespace Opm { } public: - using ParentType::numTables; - using ParentType::numRows; - using ParentType::numColumns; - using ParentType::evaluate; - using ParentType::firstRecordIndex; - using ParentType::numRecords; + using MultiRecordTable::numTables; + using MultiRecordTable::numRows; + using MultiRecordTable::numColumns; + using MultiRecordTable::evaluate; + using MultiRecordTable::firstRecordIndex; + using MultiRecordTable::numRecords; const std::vector &getPressureColumn() const - { return ParentType::getColumn(0); } + { return MultiRecordTable::getColumn(0); } const std::vector &getOilSolubilityColumn() const - { return ParentType::getColumn(1); } + { return MultiRecordTable::getColumn(1); } const std::vector &getGasFormationFactorColumn() const - { return ParentType::getColumn(2); } + { return MultiRecordTable::getColumn(2); } const std::vector &getGasViscosityColumn() const - { return ParentType::getColumn(3); } + { return MultiRecordTable::getColumn(3); } }; } diff --git a/opm/parser/eclipse/EclipseState/Tables/PvtoOuterTable.hpp b/opm/parser/eclipse/EclipseState/Tables/PvtoOuterTable.hpp index c306df59b..8ea7772d1 100644 --- a/opm/parser/eclipse/EclipseState/Tables/PvtoOuterTable.hpp +++ b/opm/parser/eclipse/EclipseState/Tables/PvtoOuterTable.hpp @@ -37,15 +37,13 @@ namespace Opm { /*! * \brief Read the per record table of the PVTO keyword and * provide some convenience methods for it. - * - * The first value of the record (-> Rs) is skipped. */ void init(Opm::DeckKeywordConstPtr keyword, int tableIdx) { - ParentType::init(keyword, - std::vector{"RS", "P", "BO", "MU"}, - tableIdx, - /*firstEntryOffset=*/0); + MultiRecordTable::init(keyword, + std::vector{"RS", "P", "BO", "MU"}, + tableIdx); + MultiRecordTable::checkNonDefaultable("RS"); MultiRecordTable::checkMonotonic("RS", /*isAscending=*/true); diff --git a/opm/parser/eclipse/EclipseState/Tables/tests/CMakeLists.txt b/opm/parser/eclipse/EclipseState/Tables/tests/CMakeLists.txt index 20adb309b..ad12aa2de 100644 --- a/opm/parser/eclipse/EclipseState/Tables/tests/CMakeLists.txt +++ b/opm/parser/eclipse/EclipseState/Tables/tests/CMakeLists.txt @@ -1,4 +1,4 @@ -foreach(tapp TableManagerTests TabdimsTests) +foreach(tapp TableManagerTests TabdimsTests MultiRecordTableTests) opm_add_test(run${tapp} SOURCES ${tapp}.cpp LIBRARIES opmparser ${Boost_LIBRARIES}) endforeach() diff --git a/opm/parser/eclipse/EclipseState/Tables/tests/MultiRecordTableTests.cpp b/opm/parser/eclipse/EclipseState/Tables/tests/MultiRecordTableTests.cpp new file mode 100644 index 000000000..6c02c0a2a --- /dev/null +++ b/opm/parser/eclipse/EclipseState/Tables/tests/MultiRecordTableTests.cpp @@ -0,0 +1,117 @@ +/* + Copyright (C) 2013 by Andreas Lauser + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . + */ + +#define BOOST_TEST_MODULE MultiRecordTableTests + +#include +#include +#include + +#include +#include +#include +#include + +// generic table classes +#include +#include +#include +#include + +// keyword specific table classes +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +using namespace Opm; + + +BOOST_AUTO_TEST_CASE( MultiRecordNumTables1 ) { + ParserPtr parser(new Parser()); + boost::filesystem::path deckFile("testdata/integration_tests/TABLES/PVTO1.DATA"); + ParseMode parseMode; + DeckPtr deck = parser->parseFile(deckFile.string(), parseMode); + BOOST_CHECK_EQUAL( MultiRecordTable::numTables( deck->getKeyword()) , 1); + + auto ranges = MultiRecordTable::recordRanges( deck->getKeyword() ); + auto range = ranges[0]; + BOOST_CHECK_EQUAL( range.first , 0 ); + BOOST_CHECK_EQUAL( range.second , 2 ); +} + + +BOOST_AUTO_TEST_CASE( MultiRecordNumTables2 ) { + ParserPtr parser(new Parser()); + boost::filesystem::path deckFile("testdata/integration_tests/TABLES/PVTO2.DATA"); + ParseMode parseMode; + DeckPtr deck = parser->parseFile(deckFile.string(), parseMode); + BOOST_CHECK_EQUAL( MultiRecordTable::numTables( deck->getKeyword()) , 3); + + auto ranges = MultiRecordTable::recordRanges( deck->getKeyword() ); + auto range1 = ranges[0]; + BOOST_CHECK_EQUAL( range1.first , 0 ); + BOOST_CHECK_EQUAL( range1.second , 41 ); + + auto range2 = ranges[1]; + BOOST_CHECK_EQUAL( range2.first , 42 ); + BOOST_CHECK_EQUAL( range2.second , 43 ); + + auto range3 = ranges[2]; + BOOST_CHECK_EQUAL( range3.first , 44 ); + BOOST_CHECK_EQUAL( range3.second , 46 ); +} + +BOOST_AUTO_TEST_CASE( MultiRecordNumTables3 ) { + const char *deckData = + "TABDIMS\n" + "1 2 /\n" + "\n" + "PVTO\n" + " 1 2 3 4" + " 5 6 7/\n" + " 8 9 10 11 /\n" + "/\n" + "12 13 14 15\n" + " 16 17 18/\n" + "19 20 21 22/\n" + "/\n"; + + Opm::ParserPtr parser(new Opm::Parser); + Opm::DeckConstPtr deck(parser->parseString(deckData, Opm::ParseMode())); + + auto ranges = MultiRecordTable::recordRanges( deck->getKeyword() ); + BOOST_CHECK_EQUAL( 2 ,ranges.size() ); + + auto range1 = ranges[0]; + BOOST_CHECK_EQUAL( range1.first , 0 ); + BOOST_CHECK_EQUAL( range1.second , 2 ); + + auto range2 = ranges[1]; + BOOST_CHECK_EQUAL( range2.first , 3 ); + BOOST_CHECK_EQUAL( range2.second , 5 ); +} diff --git a/testdata/integration_tests/TABLES/PVTO1.DATA b/testdata/integration_tests/TABLES/PVTO1.DATA new file mode 100644 index 000000000..01e8f531f --- /dev/null +++ b/testdata/integration_tests/TABLES/PVTO1.DATA @@ -0,0 +1,44 @@ +RUNSPEC + +TITLE + SIMPLE TEST + +DIMENS + 9 9 2 / + +OIL + +WATER + +GAS + +DISGAS + +VAPOIL + +METRIC + +EQLDIMS + 1 100 2 1 1 / +TABDIMS + 1 1 33 60 16 60 / + +PROPS =============================================================== +PVTO + +-- RSO PRESSURE B-OIL VISCOSITY +-- (BAR) (CP) + + 20.59 50.00 1.10615 1.180 + 75.00 1.10164 1.247 + 100.00 1.09744 1.315 + 125.00 1.09351 1.384 + 150.00 1.08984 1.453 / + + 28.19 70.00 1.12522 1.066 + 95.00 1.12047 1.124 + 120.00 1.11604 1.182 + 145.00 1.11191 1.241 + 170.00 1.10804 1.300 / +/ + diff --git a/testdata/integration_tests/TABLES/PVTO2.DATA b/testdata/integration_tests/TABLES/PVTO2.DATA new file mode 100644 index 000000000..9e94920bf --- /dev/null +++ b/testdata/integration_tests/TABLES/PVTO2.DATA @@ -0,0 +1,296 @@ +RUNSPEC + +TITLE + SIMPLE TEST + +DIMENS + 9 9 2 / + +OIL + +WATER + +GAS + +DISGAS + +VAPOIL + +METRIC + +EQLDIMS + 1 100 2 1 1 / +TABDIMS + 1 3 33 60 16 60 / + +PROPS =============================================================== +PVTO + +-- RSO PRESSURE B-OIL VISCOSITY +-- (BAR) (CP) + + 20.59 50.00 1.10615 1.180 + 75.00 1.10164 1.247 + 100.00 1.09744 1.315 + 125.00 1.09351 1.384 + 150.00 1.08984 1.453 / + + 28.19 70.00 1.12522 1.066 + 95.00 1.12047 1.124 + 120.00 1.11604 1.182 + 145.00 1.11191 1.241 + 170.00 1.10804 1.300 / + + 36.01 90.00 1.14458 0.964 + 115.00 1.13959 1.014 + 140.00 1.13494 1.064 + 165.00 1.13060 1.115 + 190.00 1.12653 1.166 / + + 44.09 110.00 1.16437 0.880 + 135.00 1.15915 0.924 + 160.00 1.15428 0.968 + 185.00 1.14973 1.012 + 210.00 1.14547 1.056 / + + 52.46 130.00 1.18467 0.805 + 155.00 1.17921 0.843 + 180.00 1.17413 0.882 + 205.00 1.16937 0.920 + 230.00 1.16491 0.959 / + + 61.13 150.00 1.20555 0.746 + 175.00 1.19985 0.780 + 200.00 1.19454 0.814 + 225.00 1.18958 0.849 + 250.00 1.18492 0.883 / + + 70.14 170.00 1.22704 0.698 + 195.00 1.22111 0.729 + 220.00 1.21558 0.759 + 245.00 1.21040 0.790 + 270.00 1.20555 0.821 / + + 79.50 190.00 1.24922 0.658 + 215.00 1.24305 0.686 + 240.00 1.23729 0.714 + 265.00 1.23190 0.742 + 290.00 1.22685 0.770 / + + 89.24 210.00 1.27214 0.637 + 235.00 1.26573 0.664 + 260.00 1.25974 0.693 + 285.00 1.25414 0.725 + 310.00 1.24888 0.760 / + + 99.39 230.00 1.29586 0.622 + 255.00 1.28921 0.641 + 280.00 1.28300 0.661 + 305.00 1.27718 0.680 + 330.00 1.27171 0.699 / + + 110.41 250.80 1.32148 0.610 + 275.80 1.31457 0.628 + 300.80 1.30812 0.647 + 325.80 1.30207 0.665 + 350.80 1.29638 0.682 / + + 120.32 268.42 1.34449 0.576 + 293.42 1.33735 0.593 + 318.42 1.33068 0.609 + 343.42 1.32442 0.626 + 368.42 1.31853 0.642 / + + 130.23 285.33 1.36737 0.5335 + 310.33 1.36001 0.5487 + 335.33 1.35313 0.5638 + 360.33 1.34667 0.5787 + 385.33 1.34059 0.5934 / + + 140.12 301.59 1.39015 0.4956 + 326.59 1.38257 0.5094 + 351.59 1.37548 0.5230 + 376.59 1.36882 0.5365 + 401.59 1.36255 0.5498 / + + 150.01 317.23 1.41282 0.4614 + 342.23 1.40503 0.4739 + 367.23 1.39773 0.4863 + 392.23 1.39088 0.4986 + 417.23 1.38443 0.5107 / + + 159.89 332.29 1.43539 0.43042 + 357.29 1.42739 0.44183 + 382.29 1.41990 0.45312 + 407.29 1.41286 0.46430 + 432.29 1.40622 0.47537 / + + 169.76 346.80 1.45788 0.41191 + 371.80 1.44967 0.42260 + 396.80 1.44198 0.43318 + 421.80 1.43475 0.44365 + 446.80 1.42794 0.45402 / + + 179.63 360.80 1.48028 0.39503 + 385.80 1.47187 0.40508 + 410.80 1.46398 0.41502 + 435.80 1.45657 0.42487 + 460.80 1.44958 0.43461 / + + 189.48 374.31 1.50260 0.37959 + 399.31 1.49399 0.38907 + 424.31 1.48591 0.39845 + 449.31 1.47832 0.40773 + 474.31 1.47116 0.41692 / + + 199.34 387.36 1.52484 0.36543 + 412.36 1.51603 0.37439 + 437.36 1.50777 0.38326 + 462.36 1.50000 0.39203 + 487.36 1.49267 0.40072 / + + 209.18 399.99 1.54700 0.35239 + 424.99 1.53800 0.36089 + 449.99 1.52956 0.36929 + 474.99 1.52161 0.37762 + 499.99 1.51411 0.38585 / + + 219.02 412.21 1.56910 0.34035 + 437.21 1.55991 0.34843 + 462.21 1.55128 0.35642 + 487.21 1.54316 0.36433 + 512.21 1.53549 0.37216 / + + 228.85 424.05 1.59112 0.32921 + 449.05 1.58174 0.33691 + 474.05 1.57294 0.34453 + 499.05 1.56464 0.35206 + 524.05 1.55681 0.35952 / + + 238.67 435.53 1.61307 0.31888 + 460.53 1.60351 0.32623 + 485.53 1.59453 0.33350 + 510.53 1.58606 0.34070 + 535.53 1.57807 0.34782 / + + 248.48 446.68 1.63496 0.30927 + 471.68 1.62522 0.31630 + 496.68 1.61606 0.32326 + 521.68 1.60743 0.33014 + 546.68 1.59927 0.33695 / + + 258.29 457.51 1.65678 0.30032 + 482.51 1.64686 0.30706 + 507.51 1.63753 0.31373 + 532.51 1.62873 0.32032 + 557.51 1.62042 0.32685 / + + 268.09 468.04 1.67853 0.29196 + 493.04 1.66843 0.29843 + 518.04 1.65893 0.30483 + 543.04 1.64997 0.31117 + 568.04 1.64150 0.31743 / + + 277.89 478.30 1.70022 0.28414 + 503.30 1.68994 0.29037 + 528.30 1.68028 0.29652 + 553.30 1.67116 0.30261 + 578.30 1.66253 0.30864 / + + 287.68 488.30 1.72184 0.27681 + 513.30 1.71139 0.28281 + 538.30 1.70156 0.28874 + 563.30 1.69228 0.29460 + 588.30 1.68350 0.30040 / + + 297.46 498.06 1.74339 0.26994 + 523.06 1.73277 0.27572 + 548.06 1.72278 0.28144 + 573.06 1.71334 0.28709 + 598.06 1.70442 0.29269 / + + 307.23 507.59 1.76487 0.26347 + 532.59 1.75409 0.26906 + 557.59 1.74393 0.27458 + 582.59 1.73434 0.28004 + 607.59 1.72527 0.28544 / + + 317.00 516.92 1.78628 0.25738 + 541.92 1.77533 0.26279 + 566.92 1.76502 0.26812 + 591.92 1.75528 0.27340 + 616.92 1.74606 0.27863 / + + 326.76 526.06 1.80761 0.25165 + 551.06 1.79651 0.25688 + 576.06 1.78604 0.26204 + 601.06 1.77615 0.26716 + 626.06 1.76679 0.27221 / + + 336.51 535.02 1.82887 0.24623 + 560.02 1.81761 0.25130 + 585.02 1.80699 0.25631 + 610.02 1.79696 0.26126 + 635.02 1.78746 0.26616 / + + 346.26 543.83 1.85005 0.24112 + 568.83 1.83864 0.24603 + 593.83 1.82787 0.25089 + 618.83 1.81770 0.25570 + 643.83 1.80806 0.26045 / + + 356.00 552.49 1.87115 0.23628 + 577.49 1.85959 0.24105 + 602.49 1.84868 0.24577 + 627.49 1.83836 0.25043 + 652.49 1.82858 0.25505 / + + 365.73 561.04 1.89217 0.23170 + 586.04 1.88046 0.23634 + 611.04 1.86940 0.24092 + 636.04 1.85895 0.24546 + 661.04 1.84904 0.24994 / + + 375.46 569.48 1.91309 0.22736 + 594.48 1.90124 0.23187 + 619.48 1.89004 0.23633 + 644.48 1.87946 0.24074 + 669.48 1.86942 0.24510 / + + 385.18 577.82 1.93391 0.22325 + 602.82 1.92192 0.22764 + 627.82 1.91060 0.23198 + 652.82 1.89988 0.23627 + 677.82 1.88971 0.24052 / + + 394.89 586.09 1.95464 0.21934 + 611.09 1.94252 0.22362 + 636.09 1.93106 0.22785 + 661.09 1.92021 0.23204 + 686.09 1.90993 0.23617 / + + 404.60 594.29 1.97527 0.21564 + 619.29 1.96301 0.21981 + 644.29 1.95143 0.22393 + 669.29 1.94046 0.22801 + 694.29 1.93005 0.23204 / --40 +/ --41 + 404.60 594.29 1.97527 0.21564 + 619.29 1.96301 0.21981 + 644.29 1.95143 0.22393 + 669.29 1.94046 0.22801 + 694.29 1.93005 0.23204 / --42 +/ --43 + 404.60 594.29 1.97527 0.21564 + 619.29 1.96301 0.21981 + 644.29 1.95143 0.22393 + 669.29 1.94046 0.22801 + 694.29 1.93005 0.23204 / --44 + + 404.60 594.29 1.97527 0.21564 + 619.29 1.96301 0.21981 + 644.29 1.95143 0.22393 + 669.29 1.94046 0.22801 + 694.29 1.93005 0.23204 / --45 +/ --46 +