Merge branch 'dev' into hdf-prototype

This commit is contained in:
Magne Sjaastad
2017-08-14 10:47:44 +02:00
443 changed files with 20467 additions and 3429 deletions

View File

@@ -37,6 +37,7 @@
#include "RigEclipseCaseData.h"
#include "RigMainGrid.h"
#include "RigSingleWellResultsData.h"
#include "RigEclipseResultInfo.h"
#include "cafProgressInfo.h"
@@ -203,8 +204,6 @@ RifReaderEclipseOutput::RifReaderEclipseOutput()
m_fileName.clear();
m_filesWithSameBaseName.clear();
m_timeSteps.clear();
m_eclipseCase = NULL;
m_ecl_init_file = NULL;
@@ -252,8 +251,8 @@ bool RifReaderEclipseOutput::transferGeometry(const ecl_grid_type* mainEclGrid,
return false;
}
RigActiveCellInfo* activeCellInfo = eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS);
RigActiveCellInfo* fractureActiveCellInfo = eclipseCase->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS);
RigActiveCellInfo* activeCellInfo = eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL);
RigActiveCellInfo* fractureActiveCellInfo = eclipseCase->activeCellInfo(RiaDefines::FRACTURE_MODEL);
CVF_ASSERT(activeCellInfo && fractureActiveCellInfo);
@@ -455,7 +454,7 @@ void RifReaderEclipseOutput::setHdf5FileName(const QString& fileName)
{
CVF_ASSERT(m_eclipseCase);
RigCaseCellResultsData* matrixModelResults = m_eclipseCase->results(RifReaderInterface::MATRIX_RESULTS);
RigCaseCellResultsData* matrixModelResults = m_eclipseCase->results(RiaDefines::MATRIX_MODEL);
CVF_ASSERT(matrixModelResults);
if (fileName.isEmpty())
@@ -471,9 +470,11 @@ void RifReaderEclipseOutput::setHdf5FileName(const QString& fileName)
RiaLogging::info("HDF: Removing all existing Sour Sim data ...");
matrixModelResults->eraseAllSourSimData();
if (m_dynamicResultsAccess.isNull())
std::vector<QDateTime> dateTimes;
std::vector<double> daysSinceSimulationStart;
if (m_dynamicResultsAccess.notNull())
{
m_timeSteps.clear();
m_dynamicResultsAccess->timeSteps(&dateTimes, &daysSinceSimulationStart);
}
std::unique_ptr<RifHdf5ReaderInterface> myReader;
@@ -489,27 +490,27 @@ void RifReaderEclipseOutput::setHdf5FileName(const QString& fileName)
}
std::vector<QDateTime> hdfTimeSteps = myReader->timeSteps();
if (m_timeSteps.size() > 0)
if (dateTimes.size() > 0)
{
if (hdfTimeSteps.size() != m_timeSteps.size())
if (hdfTimeSteps.size() != dateTimes.size())
{
RiaLogging::error("HDF: Time step count does not match");
RiaLogging::error(QString("HDF: Eclipse count %1").arg(m_timeSteps.size()));
RiaLogging::error(QString("HDF: Eclipse count %1").arg(dateTimes.size()));
RiaLogging::error(QString("HDF: HDF count %1").arg(hdfTimeSteps.size()));
return;
}
bool isTimeStampsEqual = true;
for (size_t i = 0; i < m_timeSteps.size(); i++)
for (size_t i = 0; i < dateTimes.size(); i++)
{
if (hdfTimeSteps[i].date() != m_timeSteps[i].date())
if (hdfTimeSteps[i].date() != dateTimes[i].date())
{
RiaLogging::error("HDF: Time steps does not match");
QString dateStr("yyyy.MMM.ddd hh:mm");
RiaLogging::error(QString("HDF: Eclipse date %1").arg(m_timeSteps[i].toString(dateStr)));
RiaLogging::error(QString("HDF: Eclipse date %1").arg(dateTimes[i].toString(dateStr)));
RiaLogging::error(QString("HDF: HDF date %1").arg(hdfTimeSteps[i].toString(dateStr)));
isTimeStampsEqual = false;
@@ -521,28 +522,40 @@ void RifReaderEclipseOutput::setHdf5FileName(const QString& fileName)
else
{
// Use time steps from HDF to define the time steps
m_timeSteps = hdfTimeSteps;
dateTimes = hdfTimeSteps;
QDateTime firstDate = hdfTimeSteps[0];
for (auto d : hdfTimeSteps)
{
daysSinceSimulationStart.push_back(firstDate.daysTo(d));
}
}
std::vector<int> reportNumbers;
if (m_dynamicResultsAccess.notNull())
std::vector<RigEclipseTimeStepInfo> timeStepInfos;
{
reportNumbers = m_dynamicResultsAccess->reportNumbers();
}
else
{
for (size_t i = 0; i < m_timeSteps.size(); i++)
std::vector<int> reportNumbers;
if (m_dynamicResultsAccess.notNull())
{
reportNumbers.push_back(static_cast<int>(i));
reportNumbers = m_dynamicResultsAccess->reportNumbers();
}
else
{
for (size_t i = 0; i < dateTimes.size(); i++)
{
reportNumbers.push_back(static_cast<int>(i));
}
}
timeStepInfos = RigEclipseTimeStepInfo::createTimeStepInfos(dateTimes, reportNumbers, daysSinceSimulationStart);
}
QStringList resultNames = myReader->propertyNames();
for (int i = 0; i < resultNames.size(); ++i)
{
size_t resIndex = matrixModelResults->addEmptyScalarResult(RimDefines::SOURSIMRL, resultNames[i], false);
matrixModelResults->setTimeStepDates(resIndex, m_timeSteps, m_daysSinceSimulationStart, reportNumbers);
size_t resIndex = matrixModelResults->addEmptyScalarResult(RiaDefines::SOURSIMRL, resultNames[i], false);
matrixModelResults->setTimeStepInfos(resIndex, timeStepInfos);
}
m_hdfReaderInterface = std::move(myReader);
@@ -718,8 +731,8 @@ bool RifReaderEclipseOutput::readActiveCellInfo()
return false;
}
RigActiveCellInfo* activeCellInfo = m_eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS);
RigActiveCellInfo* fractureActiveCellInfo = m_eclipseCase->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS);
RigActiveCellInfo* activeCellInfo = m_eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL);
RigActiveCellInfo* fractureActiveCellInfo = m_eclipseCase->activeCellInfo(RiaDefines::FRACTURE_MODEL);
activeCellInfo->setReservoirCellCount(reservoirCellCount);
fractureActiveCellInfo->setReservoirCellCount(reservoirCellCount);
@@ -782,8 +795,10 @@ void RifReaderEclipseOutput::buildMetaData()
progInfo.setNextProgressIncrement(m_filesWithSameBaseName.size());
RigCaseCellResultsData* matrixModelResults = m_eclipseCase->results(RifReaderInterface::MATRIX_RESULTS);
RigCaseCellResultsData* fractureModelResults = m_eclipseCase->results(RifReaderInterface::FRACTURE_RESULTS);
RigCaseCellResultsData* matrixModelResults = m_eclipseCase->results(RiaDefines::MATRIX_MODEL);
RigCaseCellResultsData* fractureModelResults = m_eclipseCase->results(RiaDefines::FRACTURE_MODEL);
std::vector<RigEclipseTimeStepInfo> timeStepInfos;
// Create access object for dynamic results
m_dynamicResultsAccess = createDynamicResultsAccess();
@@ -793,9 +808,7 @@ void RifReaderEclipseOutput::buildMetaData()
progInfo.incrementProgress();
// Get time steps
m_dynamicResultsAccess->timeSteps(&m_timeSteps, &m_daysSinceSimulationStart);
std::vector<int> reportNumbers = m_dynamicResultsAccess->reportNumbers();
timeStepInfos = createFilteredTimeStepInfos();
QStringList resultNames;
std::vector<size_t> resultNamesDataItemCounts;
@@ -803,41 +816,41 @@ void RifReaderEclipseOutput::buildMetaData()
{
QStringList matrixResultNames = validKeywordsForPorosityModel(resultNames, resultNamesDataItemCounts,
m_eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS),
m_eclipseCase->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS),
RifReaderInterface::MATRIX_RESULTS, m_dynamicResultsAccess->timeStepCount());
m_eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL),
m_eclipseCase->activeCellInfo(RiaDefines::FRACTURE_MODEL),
RiaDefines::MATRIX_MODEL, m_dynamicResultsAccess->timeStepCount());
for (int i = 0; i < matrixResultNames.size(); ++i)
{
size_t resIndex = matrixModelResults->addEmptyScalarResult(RimDefines::DYNAMIC_NATIVE, matrixResultNames[i], false);
matrixModelResults->setTimeStepDates(resIndex, m_timeSteps, m_daysSinceSimulationStart, reportNumbers);
size_t resIndex = matrixModelResults->addEmptyScalarResult(RiaDefines::DYNAMIC_NATIVE, matrixResultNames[i], false);
matrixModelResults->setTimeStepInfos(resIndex, timeStepInfos);
}
}
{
QStringList fractureResultNames = validKeywordsForPorosityModel(resultNames, resultNamesDataItemCounts,
m_eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS),
m_eclipseCase->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS),
RifReaderInterface::FRACTURE_RESULTS, m_dynamicResultsAccess->timeStepCount());
m_eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL),
m_eclipseCase->activeCellInfo(RiaDefines::FRACTURE_MODEL),
RiaDefines::FRACTURE_MODEL, m_dynamicResultsAccess->timeStepCount());
for (int i = 0; i < fractureResultNames.size(); ++i)
{
size_t resIndex = fractureModelResults->addEmptyScalarResult(RimDefines::DYNAMIC_NATIVE, fractureResultNames[i], false);
fractureModelResults->setTimeStepDates(resIndex, m_timeSteps, m_daysSinceSimulationStart, reportNumbers);
size_t resIndex = fractureModelResults->addEmptyScalarResult(RiaDefines::DYNAMIC_NATIVE, fractureResultNames[i], false);
fractureModelResults->setTimeStepInfos(resIndex, timeStepInfos);
}
}
// Default units type is METRIC
RigEclipseCaseData::UnitsType unitsType = RigEclipseCaseData::UNITS_METRIC;
RiaEclipseUnitTools::UnitSystem unitsType = RiaEclipseUnitTools::UNITS_METRIC;
{
int unitsTypeValue = m_dynamicResultsAccess->readUnitsType();
if (unitsTypeValue == 2)
{
unitsType = RigEclipseCaseData::UNITS_FIELD;
unitsType = RiaEclipseUnitTools::UNITS_FIELD;
}
else if (unitsTypeValue == 3)
{
unitsType = RigEclipseCaseData::UNITS_LAB;
unitsType = RiaEclipseUnitTools::UNITS_LAB;
}
}
@@ -859,59 +872,40 @@ void RifReaderEclipseOutput::buildMetaData()
RifEclipseOutputFileTools::findKeywordsAndItemCount(filesUsedToFindAvailableKeywords, &resultNames, &resultNamesDataItemCounts);
std::vector<QDateTime> staticDate;
std::vector<double> staticDay;
std::vector<int> staticReportNumber;
std::vector<RigEclipseTimeStepInfo> staticTimeStepInfo;
if (!timeStepInfos.empty())
{
if ( m_timeSteps.size() > 0 )
{
staticDate.push_back(m_timeSteps.front());
}
if (m_daysSinceSimulationStart.size() > 0)
{
staticDay.push_back(m_daysSinceSimulationStart.front());
}
std::vector<int> reportNumbers;
if (m_dynamicResultsAccess.notNull())
{
reportNumbers = m_dynamicResultsAccess->reportNumbers();
}
if ( reportNumbers.size() > 0 )
{
staticReportNumber.push_back(reportNumbers.front());
}
staticTimeStepInfo.push_back(timeStepInfos.front());
}
{
QStringList matrixResultNames = validKeywordsForPorosityModel(resultNames, resultNamesDataItemCounts,
m_eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS),
m_eclipseCase->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS),
RifReaderInterface::MATRIX_RESULTS, 1);
m_eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL),
m_eclipseCase->activeCellInfo(RiaDefines::FRACTURE_MODEL),
RiaDefines::MATRIX_MODEL, 1);
// Add ACTNUM
matrixResultNames += "ACTNUM";
for (int i = 0; i < matrixResultNames.size(); ++i)
{
size_t resIndex = matrixModelResults->addEmptyScalarResult(RimDefines::STATIC_NATIVE, matrixResultNames[i], false);
matrixModelResults->setTimeStepDates(resIndex, staticDate, staticDay, staticReportNumber);
size_t resIndex = matrixModelResults->addEmptyScalarResult(RiaDefines::STATIC_NATIVE, matrixResultNames[i], false);
matrixModelResults->setTimeStepInfos(resIndex, staticTimeStepInfo);
}
}
{
QStringList fractureResultNames = validKeywordsForPorosityModel(resultNames, resultNamesDataItemCounts,
m_eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS),
m_eclipseCase->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS),
RifReaderInterface::FRACTURE_RESULTS, 1);
m_eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL),
m_eclipseCase->activeCellInfo(RiaDefines::FRACTURE_MODEL),
RiaDefines::FRACTURE_MODEL, 1);
// Add ACTNUM
fractureResultNames += "ACTNUM";
for (int i = 0; i < fractureResultNames.size(); ++i)
{
size_t resIndex = fractureModelResults->addEmptyScalarResult(RimDefines::STATIC_NATIVE, fractureResultNames[i], false);
fractureModelResults->setTimeStepDates(resIndex, staticDate, staticDay, staticReportNumber);
size_t resIndex = fractureModelResults->addEmptyScalarResult(RiaDefines::STATIC_NATIVE, fractureResultNames[i], false);
fractureModelResults->setTimeStepInfos(resIndex, staticTimeStepInfo);
}
}
}
@@ -948,7 +942,7 @@ RifEclipseRestartDataAccess* RifReaderEclipseOutput::createDynamicResultsAccess(
//--------------------------------------------------------------------------------------------------
/// Get all values of a given static result as doubles
//--------------------------------------------------------------------------------------------------
bool RifReaderEclipseOutput::staticResult(const QString& result, PorosityModelResultType matrixOrFracture, std::vector<double>* values)
bool RifReaderEclipseOutput::staticResult(const QString& result, RiaDefines::PorosityModelType matrixOrFracture, std::vector<double>* values)
{
CVF_ASSERT(values);
@@ -999,7 +993,7 @@ void RifReaderEclipseOutput::sourSimRlResult(const QString& result, size_t stepI
size_t activeCellCount = cvf::UNDEFINED_SIZE_T;
{
RigActiveCellInfo* fracActCellInfo = m_eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS);
RigActiveCellInfo* fracActCellInfo = m_eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL);
fracActCellInfo->gridActiveCellCounts(0, activeCellCount);
}
@@ -1017,10 +1011,7 @@ void RifReaderEclipseOutput::sourSimRlResult(const QString& result, size_t stepI
//--------------------------------------------------------------------------------------------------
/// Get dynamic result at given step index. Will concatenate values for the main grid and all sub grids.
//--------------------------------------------------------------------------------------------------
bool RifReaderEclipseOutput::dynamicResult(const QString& result,
PorosityModelResultType matrixOrFracture,
size_t stepIndex,
std::vector<double>* values)
bool RifReaderEclipseOutput::dynamicResult(const QString& result, RiaDefines::PorosityModelType matrixOrFracture, size_t stepIndex, std::vector<double>* values)
{
@@ -1031,8 +1022,10 @@ bool RifReaderEclipseOutput::dynamicResult(const QString& result,
if (m_dynamicResultsAccess.notNull())
{
size_t indexOnFile = timeStepIndexOnFile(stepIndex);
std::vector<double> fileValues;
if (!m_dynamicResultsAccess->results(result, stepIndex, m_eclipseCase->mainGrid()->gridCount(), &fileValues))
if (!m_dynamicResultsAccess->results(result, indexOnFile, m_eclipseCase->mainGrid()->gridCount(), &fileValues))
{
return false;
}
@@ -1160,8 +1153,8 @@ RigWellResultPoint RifReaderEclipseOutput::createWellResultPoint(const RigGridBa
double fieldGasToOilEquivalent = 1.0e6/5800; // Mega ft^3 to BOE
double metricGasToOilEquivalent = 1.0/1.0e3; // Sm^3 Gas to Sm^3 oe
if (m_eclipseCase->unitsType() == RigEclipseCaseData::UNITS_FIELD) gasRate = fieldGasToOilEquivalent * gasRate;
if (m_eclipseCase->unitsType() == RigEclipseCaseData::UNITS_METRIC) gasRate = metricGasToOilEquivalent * gasRate;
if (m_eclipseCase->unitsType() == RiaEclipseUnitTools::UNITS_FIELD) gasRate = fieldGasToOilEquivalent * gasRate;
if (m_eclipseCase->unitsType() == RiaEclipseUnitTools::UNITS_METRIC) gasRate = metricGasToOilEquivalent * gasRate;
resultPoint.m_gasRate = gasRate;
}
@@ -1830,7 +1823,16 @@ void RifReaderEclipseOutput::readWellCells(const ecl_grid_type* mainEclGrid, boo
}
wellResults->computeMappingFromResultTimeIndicesToWellTimeIndices(m_timeSteps);
std::vector<QDateTime> filteredTimeSteps;
{
std::vector<RigEclipseTimeStepInfo> filteredTimeStepInfos = createFilteredTimeStepInfos();
for (auto a : filteredTimeStepInfos)
{
filteredTimeSteps.push_back(a.m_date);
}
}
wellResults->computeMappingFromResultTimeIndicesToWellTimeIndices(filteredTimeSteps);
wells.push_back(wellResults.p());
@@ -1850,7 +1852,7 @@ QStringList RifReaderEclipseOutput::validKeywordsForPorosityModel(const QStringL
const std::vector<size_t>& keywordDataItemCounts,
const RigActiveCellInfo* matrixActiveCellInfo,
const RigActiveCellInfo* fractureActiveCellInfo,
PorosityModelResultType porosityModel,
RiaDefines::PorosityModelType porosityModel,
size_t timeStepCount) const
{
CVF_ASSERT(matrixActiveCellInfo);
@@ -1860,7 +1862,7 @@ QStringList RifReaderEclipseOutput::validKeywordsForPorosityModel(const QStringL
return QStringList();
}
if (porosityModel == RifReaderInterface::FRACTURE_RESULTS)
if (porosityModel == RiaDefines::FRACTURE_MODEL)
{
if (fractureActiveCellInfo->reservoirActiveCellCount() == 0)
{
@@ -1896,14 +1898,14 @@ QStringList RifReaderEclipseOutput::validKeywordsForPorosityModel(const QStringL
size_t sumFractureMatrixActiveCellCount = matrixActiveCellInfo->reservoirActiveCellCount() + fractureActiveCellInfo->reservoirActiveCellCount();
size_t timeStepsMatrixAndFractureRest = keywordDataItemCount % sumFractureMatrixActiveCellCount;
if (porosityModel == RifReaderInterface::MATRIX_RESULTS && timeStepsMatrixRest == 0)
if (porosityModel == RiaDefines::MATRIX_MODEL && timeStepsMatrixRest == 0)
{
if (keywordDataItemCount <= timeStepCount * std::max(matrixActiveCellInfo->reservoirActiveCellCount(), sumFractureMatrixActiveCellCount))
{
validKeyword = true;
}
}
else if (porosityModel == RifReaderInterface::FRACTURE_RESULTS && fractureActiveCellInfo->reservoirActiveCellCount() > 0 && timeStepsFractureRest == 0)
else if (porosityModel == RiaDefines::FRACTURE_MODEL && fractureActiveCellInfo->reservoirActiveCellCount() > 0 && timeStepsFractureRest == 0)
{
if (keywordDataItemCount <= timeStepCount * std::max(fractureActiveCellInfo->reservoirActiveCellCount(), sumFractureMatrixActiveCellCount))
{
@@ -1949,19 +1951,47 @@ QStringList RifReaderEclipseOutput::validKeywordsForPorosityModel(const QStringL
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseOutput::extractResultValuesBasedOnPorosityModel(PorosityModelResultType matrixOrFracture, std::vector<double>* destinationResultValues, const std::vector<double>& sourceResultValues)
std::vector<RigEclipseTimeStepInfo> RifReaderEclipseOutput::createFilteredTimeStepInfos()
{
std::vector<RigEclipseTimeStepInfo> timeStepInfos;
if (m_dynamicResultsAccess.notNull())
{
std::vector<QDateTime> timeStepsOnFile;
std::vector<double> daysSinceSimulationStartOnFile;
std::vector<int> reportNumbersOnFile;
m_dynamicResultsAccess->timeSteps(&timeStepsOnFile, &daysSinceSimulationStartOnFile);
reportNumbersOnFile = m_dynamicResultsAccess->reportNumbers();
for (size_t i = 0; i < timeStepsOnFile.size(); i++)
{
if (this->isTimeStepIncludedByFilter(i))
{
timeStepInfos.push_back(RigEclipseTimeStepInfo(timeStepsOnFile[i], reportNumbersOnFile[i], daysSinceSimulationStartOnFile[i]));
}
}
}
return timeStepInfos;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RifReaderEclipseOutput::extractResultValuesBasedOnPorosityModel(RiaDefines::PorosityModelType matrixOrFracture, std::vector<double>* destinationResultValues, const std::vector<double>& sourceResultValues)
{
if (sourceResultValues.size() == 0) return;
RigActiveCellInfo* fracActCellInfo = m_eclipseCase->activeCellInfo(RifReaderInterface::FRACTURE_RESULTS);
RigActiveCellInfo* fracActCellInfo = m_eclipseCase->activeCellInfo(RiaDefines::FRACTURE_MODEL);
if (matrixOrFracture == RifReaderInterface::MATRIX_RESULTS && fracActCellInfo->reservoirActiveCellCount() == 0)
if (matrixOrFracture == RiaDefines::MATRIX_MODEL && fracActCellInfo->reservoirActiveCellCount() == 0)
{
destinationResultValues->insert(destinationResultValues->end(), sourceResultValues.begin(), sourceResultValues.end());
}
else
{
RigActiveCellInfo* actCellInfo = m_eclipseCase->activeCellInfo(RifReaderInterface::MATRIX_RESULTS);
RigActiveCellInfo* actCellInfo = m_eclipseCase->activeCellInfo(RiaDefines::MATRIX_MODEL);
size_t sourceStartPosition = 0;
@@ -1973,7 +2003,7 @@ void RifReaderEclipseOutput::extractResultValuesBasedOnPorosityModel(PorosityMod
actCellInfo->gridActiveCellCounts(i, matrixActiveCellCount);
fracActCellInfo->gridActiveCellCounts(i, fractureActiveCellCount);
if (matrixOrFracture == RifReaderInterface::MATRIX_RESULTS)
if (matrixOrFracture == RiaDefines::MATRIX_MODEL)
{
destinationResultValues->insert(destinationResultValues->end(),
sourceResultValues.begin() + sourceStartPosition,
@@ -2008,14 +2038,6 @@ void RifReaderEclipseOutput::openInitFile()
}
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<QDateTime> RifReaderEclipseOutput::timeSteps()
{
return m_timeSteps;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------