ResInsight/ApplicationCode/Commands/CompletionExportCommands/RicWellPathFractureTextReportFeatureImpl.cpp
2019-01-09 15:29:24 +01:00

820 lines
28 KiB
C++

/////////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2018- Equinor ASA
//
// ResInsight 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.
//
// ResInsight 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 at <http://www.gnu.org/licenses/gpl.html>
// for more details.
//
/////////////////////////////////////////////////////////////////////////////////
#include "RicWellPathFractureTextReportFeatureImpl.h"
#include "RiaApplication.h"
#include "RiaRegressionTestRunner.h"
#include "RicExportFractureCompletionsImpl.h"
#include "RicWellPathFractureReportItem.h"
#include "RifEclipseDataTableFormatter.h"
#include "RigCompletionData.h"
#include "RigTransmissibilityEquations.h"
#include "RimEclipseCase.h"
#include "RimEllipseFractureTemplate.h"
#include "RimFileWellPath.h"
#include "RimFractureContainment.h"
#include "RimFractureTemplate.h"
#include "RimFractureTemplateCollection.h"
#include "RimOilField.h"
#include "RimProject.h"
#include "RimStimPlanFractureTemplate.h"
#include "RimTools.h"
#include "RimWellPath.h"
#include "RimWellPathCollection.h"
#include "RimWellPathFracture.h"
#include "RimWellPathFractureCollection.h"
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString orientationText(RimFractureTemplate::FracOrientationEnum orientation)
{
return caf::AppEnum<RimFractureTemplate::FracOrientationEnum>::uiText(orientation);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
RifEclipseOutputTableColumn floatNumberColumn(const QString& text)
{
return RifEclipseOutputTableColumn(text, RifEclipseOutputTableDoubleFormatting(RIF_FLOAT, 3), RIGHT);
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicWellPathFractureTextReportFeatureImpl::wellPathFractureReport(
RimEclipseCase* sourceCase,
const std::vector<RimWellPath*>& wellPaths,
const std::vector<RicWellPathFractureReportItem>& wellPathFractureReportItems) const
{
QString lineStart = "--";
QString text;
QTextStream textStream(&text);
textStream << lineStart
<< "========================================================================================================\n";
textStream << lineStart << " RESINSIGHT DATA\n";
textStream << lineStart << "\n";
std::vector<RimStimPlanFractureTemplate*> stimPlanTemplates;
std::vector<RimEllipseFractureTemplate*> ellipseTemplates;
{
auto proj = RiaApplication::instance()->project();
auto fractureTemplates = proj->activeOilField()->fractureDefinitionCollection()->fractureTemplates();
std::set<QString> usedFractureTemplateNames;
for (const auto& item : wellPathFractureReportItems)
{
usedFractureTemplateNames.insert(item.fractureTemplateName());
}
for (const auto fracTemplate : fractureTemplates)
{
if (usedFractureTemplateNames.find(fracTemplate->name()) == usedFractureTemplateNames.end())
{
continue;
}
auto stimPlanTemplate = dynamic_cast<RimStimPlanFractureTemplate*>(fracTemplate);
if (stimPlanTemplate)
{
stimPlanTemplates.push_back(stimPlanTemplate);
}
auto ellipseTemplate = dynamic_cast<RimEllipseFractureTemplate*>(fracTemplate);
if (ellipseTemplate)
{
ellipseTemplates.push_back(ellipseTemplate);
}
}
}
if (!RiaRegressionTestRunner::instance()->isRunningRegressionTests())
{
if (sourceCase)
{
textStream << lineStart << " Grid Model:\n";
textStream << lineStart << " " << sourceCase->gridFileName() << "\n";
textStream << lineStart << "\n";
}
{
QString tableText = createWellFileLocationText(wellPaths);
textStream << tableText;
textStream << lineStart << "\n";
}
{
QString tableText = createStimPlanFileLocationText(stimPlanTemplates);
textStream << tableText;
textStream << lineStart << "\n";
}
}
{
QString tableText = createEllipseFractureText(ellipseTemplates);
textStream << tableText;
textStream << lineStart << "\n";
}
{
QString tableText = createStimPlanFractureText(stimPlanTemplates);
textStream << tableText;
textStream << lineStart << "\n";
}
{
std::vector<RimFractureTemplate*> fracTemplates;
fracTemplates.insert(fracTemplates.end(), ellipseTemplates.begin(), ellipseTemplates.end());
fracTemplates.insert(fracTemplates.end(), stimPlanTemplates.begin(), stimPlanTemplates.end());
QString tableText = createFractureText(fracTemplates);
textStream << tableText;
textStream << lineStart << "\n";
}
{
std::vector<RimWellPathFracture*> wellPathFractures;
for (const auto& w : wellPaths)
{
for (const auto& frac : w->fractureCollection()->activeFractures())
{
wellPathFractures.push_back(frac);
}
}
std::sort(wellPathFractures.begin(), wellPathFractures.end(), RimWellPathFracture::compareByWellPathNameAndMD);
{
QString tableText = createFractureInstancesText(wellPathFractures);
textStream << tableText;
textStream << lineStart << "\n";
}
{
QString tableText = createFractureCompletionSummaryText(wellPathFractureReportItems);
textStream << tableText;
textStream << lineStart << "\n";
}
{
QString tableText = createFracturePressureDepletionSummaryText(wellPathFractureReportItems);
textStream << tableText;
textStream << lineStart << "\n";
}
{
textStream << lineStart << " Maximum number of connections per well\n";
textStream << lineStart << "\n";
QString tableText = createConnectionsPerWellText(wellPathFractureReportItems);
textStream << tableText;
textStream << lineStart << "\n";
}
}
return text;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
std::vector<RimWellPath*> RicWellPathFractureTextReportFeatureImpl::wellPathsWithActiveFractures()
{
std::vector<RimWellPath*> wellPaths;
auto* wellPathColl = RimTools::wellPathCollection();
if (wellPathColl)
{
for (const auto& wellPath : wellPathColl->wellPaths())
{
if (!wellPath->fractureCollection()->activeFractures().empty())
{
wellPaths.push_back(wellPath);
}
}
}
return wellPaths;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicWellPathFractureTextReportFeatureImpl::createWellFileLocationText(const std::vector<RimWellPath*>& wellPaths) const
{
if (wellPaths.empty()) return "";
QString tableText;
QTextStream stream(&tableText);
RifEclipseDataTableFormatter formatter(stream);
configureFormatter(&formatter);
std::vector<RifEclipseOutputTableColumn> header = {
RifEclipseOutputTableColumn("Well"),
RifEclipseOutputTableColumn("Location"),
};
formatter.header(header);
formatter.addHorizontalLine('-');
if (!wellPaths.empty())
{
for (const auto& wellPath : wellPaths)
{
auto fileWellPath = dynamic_cast<RimFileWellPath*>(wellPath);
if (fileWellPath)
{
formatter.add(wellPath->name());
formatter.add(fileWellPath->filepath());
formatter.rowCompleted();
}
}
}
formatter.tableCompleted();
return tableText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicWellPathFractureTextReportFeatureImpl::createStimPlanFileLocationText(
const std::vector<RimStimPlanFractureTemplate*>& stimPlanTemplates) const
{
if (stimPlanTemplates.empty()) return "";
QString tableText;
QTextStream stream(&tableText);
RifEclipseDataTableFormatter formatter(stream);
configureFormatter(&formatter);
std::vector<RifEclipseOutputTableColumn> header = {
RifEclipseOutputTableColumn("StimPlan Name"),
RifEclipseOutputTableColumn("Location"),
};
formatter.header(header);
formatter.addHorizontalLine('-');
if (!stimPlanTemplates.empty())
{
for (const auto& stimPlanTemplate : stimPlanTemplates)
{
formatter.add(stimPlanTemplate->name());
formatter.add(stimPlanTemplate->fileName());
formatter.rowCompleted();
}
}
formatter.tableCompleted();
return tableText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicWellPathFractureTextReportFeatureImpl::createStimPlanFractureText(
const std::vector<RimStimPlanFractureTemplate*>& stimPlanTemplates) const
{
if (stimPlanTemplates.empty()) return "";
QString tableText;
RiaEclipseUnitTools::UnitSystem unitSystem = stimPlanTemplates.front()->fractureTemplateUnit();
bool isFieldUnits = unitSystem == RiaEclipseUnitTools::UNITS_FIELD;
QTextStream stream(&tableText);
RifEclipseDataTableFormatter formatter(stream);
configureFormatter(&formatter);
std::vector<RifEclipseOutputTableColumn> header = {
RifEclipseOutputTableColumn("StimPlan"),
RifEclipseOutputTableColumn(" "),
floatNumberColumn("WDiam"),
floatNumberColumn("Skin"),
};
formatter.header(header);
// Second header line
{
formatter.add("Template"); // Template
formatter.add("Orientation"); // Orientation
formatter.add(isFieldUnits ? "[in]" : "[m]"); // WDiam
formatter.add("[] "); // Skin
formatter.rowCompleted();
}
formatter.addHorizontalLine('-');
for (const auto& stimPlanTemplate : stimPlanTemplates)
{
formatter.add(stimPlanTemplate->name());
formatter.add(orientationText(stimPlanTemplate->orientationType()));
formatter.add(stimPlanTemplate->wellDiameter());
formatter.add(stimPlanTemplate->skinFactor());
formatter.rowCompleted();
}
formatter.tableCompleted();
return tableText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicWellPathFractureTextReportFeatureImpl::createEllipseFractureText(
const std::vector<RimEllipseFractureTemplate*>& ellipseTemplates) const
{
if (ellipseTemplates.empty()) return "";
QString tableText;
RiaEclipseUnitTools::UnitSystem unitSystem = ellipseTemplates.front()->fractureTemplateUnit();
bool isFieldUnits = unitSystem == RiaEclipseUnitTools::UNITS_FIELD;
QTextStream stream(&tableText);
RifEclipseDataTableFormatter formatter(stream);
configureFormatter(&formatter);
std::vector<RifEclipseOutputTableColumn> header = {
RifEclipseOutputTableColumn("Ellipse"),
RifEclipseOutputTableColumn(" "),
floatNumberColumn("Xf"),
floatNumberColumn("Height"),
floatNumberColumn("Kf"),
floatNumberColumn("Wf"),
floatNumberColumn("WDiam"),
floatNumberColumn("Skin"),
};
formatter.header(header);
// Second header line
{
formatter.add("Template"); // Template
formatter.add("Orientation"); // Orientation
formatter.add(isFieldUnits ? "[ft]" : "[m]"); // Xf
formatter.add(isFieldUnits ? "[ft]" : "[m]"); // Height
formatter.add("[mD]"); // Kf
formatter.add(isFieldUnits ? "[in]" : "[m]"); // Wf
formatter.add(isFieldUnits ? "[ft]" : "[m]"); // WDiam
formatter.add("[] "); // Skin
formatter.rowCompleted();
}
formatter.addHorizontalLine('-');
for (const auto& ellipseTemplate : ellipseTemplates)
{
formatter.add(ellipseTemplate->name());
formatter.add(orientationText(ellipseTemplate->orientationType()));
formatter.add(ellipseTemplate->halfLength());
formatter.add(ellipseTemplate->height());
formatter.add(RigTransmissibilityEquations::permeability(ellipseTemplate->conductivity(), ellipseTemplate->width()));
formatter.add(ellipseTemplate->width());
formatter.add(ellipseTemplate->wellDiameter());
formatter.add(ellipseTemplate->skinFactor());
formatter.rowCompleted();
}
formatter.tableCompleted();
return tableText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString
RicWellPathFractureTextReportFeatureImpl::createFractureText(const std::vector<RimFractureTemplate*>& fractureTemplates) const
{
if (fractureTemplates.empty()) return "";
QString tableText;
QTextStream stream(&tableText);
RifEclipseDataTableFormatter formatter(stream);
configureFormatter(&formatter);
std::vector<RifEclipseOutputTableColumn> header = {
RifEclipseOutputTableColumn(" "),
floatNumberColumn("Top"),
floatNumberColumn("Bot"),
floatNumberColumn("Fault"),
floatNumberColumn("Height"),
floatNumberColumn("Half Length"),
floatNumberColumn("DFac"),
floatNumberColumn("Conductivity"),
};
formatter.header(header);
// Second header line
{
formatter.add("Template");
formatter.add("Cont");
formatter.add("Cont");
formatter.add("Truncation");
formatter.add("Scale");
formatter.add("Scale");
formatter.add("Scale");
formatter.add("Scale");
formatter.rowCompleted();
}
formatter.addHorizontalLine('-');
for (const auto& fracTemplate : fractureTemplates)
{
formatter.add(fracTemplate->name());
if (fracTemplate->fractureContainment()->isEnabled())
{
formatter.add(fracTemplate->fractureContainment()->topKLayer());
formatter.add(fracTemplate->fractureContainment()->baseKLayer());
}
else
{
formatter.add("N/A");
formatter.add("N/A");
}
if (fracTemplate->fractureContainment()->minimumFaultThrow() >= 0.0)
{
formatter.add(fracTemplate->fractureContainment()->minimumFaultThrow());
}
else
{
formatter.add("N/A");
}
double halfLengthScale, heightScale, dfactorScale, conductivityScale;
fracTemplate->scaleFactors(&halfLengthScale, &heightScale, &dfactorScale, &conductivityScale);
formatter.add(heightScale);
formatter.add(halfLengthScale);
formatter.add(dfactorScale);
formatter.add(conductivityScale);
formatter.rowCompleted();
}
formatter.tableCompleted();
return tableText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicWellPathFractureTextReportFeatureImpl::createFractureInstancesText(
const std::vector<RimWellPathFracture*>& fractures) const
{
if (fractures.empty()) return "";
RiaEclipseUnitTools::UnitSystem unitSystem = fractures.front()->fractureUnit(); // Fix
bool isFieldUnits = unitSystem == RiaEclipseUnitTools::UNITS_FIELD;
QString tableText;
QTextStream stream(&tableText);
RifEclipseDataTableFormatter formatter(stream);
configureFormatter(&formatter);
std::vector<RifEclipseOutputTableColumn> header = {
RifEclipseOutputTableColumn(""),
RifEclipseOutputTableColumn(""),
RifEclipseOutputTableColumn(""),
floatNumberColumn("MD"),
floatNumberColumn("Dip"),
floatNumberColumn("Tilt"),
floatNumberColumn("LPerf"),
floatNumberColumn("PerfEff"),
floatNumberColumn("Wdia"),
RifEclipseOutputTableColumn(
"Dfac", RifEclipseOutputTableDoubleFormatting(RifEclipseOutputTableDoubleFormat::RIF_SCIENTIFIC), RIGHT),
};
formatter.header(header);
// Second header line
{
formatter.add("Well");
formatter.add("Fracture");
formatter.add("Template");
formatter.add(""); // MD
formatter.add(""); // Dip
formatter.add(""); // Tilt
formatter.add(isFieldUnits ? "[ft]" : "[m]"); // LPerf
formatter.add("[]"); // PerfEff
formatter.add(isFieldUnits ? "[ft]" : "[m]"); // WDia
formatter.add("[...]"); // Dfac
formatter.rowCompleted();
}
formatter.addHorizontalLine('-');
for (const auto& fracture : fractures)
{
fracture->ensureValidNonDarcyProperties();
QString wellName;
RimWellPath* wellPath = nullptr;
fracture->firstAncestorOrThisOfType(wellPath);
if (wellPath)
{
wellName = wellPath->name();
}
formatter.add(wellName);
formatter.add(fracture->name());
if (fracture->fractureTemplate())
{
formatter.add(fracture->fractureTemplate()->name());
}
else
{
formatter.add("N/A");
}
formatter.add(fracture->fractureMD());
formatter.add(fracture->dip());
formatter.add(fracture->tilt());
if (fracture->fractureTemplate() &&
fracture->fractureTemplate()->orientationType() == RimFractureTemplate::ALONG_WELL_PATH)
{
formatter.add(fracture->perforationLength());
}
else
{
formatter.add("N/A");
}
formatter.add(fracture->perforationEfficiency());
formatter.add(fracture->wellRadius() * 2.0);
if (fracture->fractureTemplate() && fracture->fractureTemplate()->isNonDarcyFlowEnabled())
{
formatter.add(fracture->nonDarcyProperties().dFactor);
}
else
{
formatter.add("N/A");
}
formatter.rowCompleted();
}
formatter.tableCompleted();
return tableText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicWellPathFractureTextReportFeatureImpl::createFractureCompletionSummaryText(
const std::vector<RicWellPathFractureReportItem>& wellPathFractureReportItems) const
{
QString tableText;
RiaEclipseUnitTools::UnitSystem unitSystem = wellPathFractureReportItems.front().unitSystem();
bool isFieldUnits = unitSystem == RiaEclipseUnitTools::UNITS_FIELD;
QTextStream stream(&tableText);
RifEclipseDataTableFormatter formatter(stream);
configureFormatter(&formatter);
const QString meanText = "Mean";
std::vector<RifEclipseOutputTableColumn> header = {
RifEclipseOutputTableColumn(""), // Well
RifEclipseOutputTableColumn(""), // Fracture
RifEclipseOutputTableColumn(""), // Template
floatNumberColumn(""), // Tr
floatNumberColumn(""), //#con
floatNumberColumn(""), // Fcd
RifEclipseOutputTableColumn("", RifEclipseOutputTableDoubleFormatting(RIF_FLOAT, 1), RIGHT), // Area
RifEclipseOutputTableColumn(meanText, RifEclipseOutputTableDoubleFormatting(RIF_FLOAT, 1), RIGHT), // KfWf
RifEclipseOutputTableColumn(meanText, RifEclipseOutputTableDoubleFormatting(RIF_FLOAT, 1), RIGHT), // Kf
floatNumberColumn(meanText), // wf
RifEclipseOutputTableColumn(meanText, RifEclipseOutputTableDoubleFormatting(RIF_FLOAT, 1), RIGHT), // xf
RifEclipseOutputTableColumn(meanText, RifEclipseOutputTableDoubleFormatting(RIF_FLOAT, 1), RIGHT), // H
floatNumberColumn(meanText), // Km
};
formatter.header(header);
// Second header line
{
formatter.add("");
formatter.add("");
formatter.add("");
formatter.add("Tr"); // Tr
formatter.add("#con"); // #con
formatter.add("Fcd"); // Fcd
formatter.add("Area"); // Area
formatter.add("KfWf"); // KfWf
formatter.add("Kf"); // Kf
formatter.add("wf"); // wf
formatter.add("Xf"); // Xf
formatter.add("H"); // H
formatter.add("Km"); // Km
formatter.rowCompleted();
}
// Third header line
{
formatter.add("Well");
formatter.add("Fracture");
formatter.add("Template");
formatter.add(isFieldUnits ? "[cP.rb/day/psi]" : "[cP.rm3/day/bars]"); // Tr
formatter.add(""); // #con
formatter.add("[]"); // Fcd
formatter.add(isFieldUnits ? "[ft2]" : "[m2]"); // Area
formatter.add(isFieldUnits ? "[mDft]" : "[mDm]"); // KfWf
formatter.add("[mD]"); // Kf
formatter.add(isFieldUnits ? "[ft]" : "[m]"); // wf
formatter.add(isFieldUnits ? "[ft]" : "[m]"); // Xf
formatter.add(isFieldUnits ? "[ft]" : "[m]"); // H
formatter.add("[mD]"); // Km
formatter.rowCompleted();
}
formatter.addHorizontalLine('-');
for (const auto& reportItem : wellPathFractureReportItems)
{
formatter.add(reportItem.wellPathNameForExport());
formatter.add(reportItem.fractureName());
formatter.add(reportItem.fractureTemplateName());
formatter.add(reportItem.transmissibility());
formatter.add(reportItem.connectionCount());
formatter.add(reportItem.fcd());
formatter.add(reportItem.area());
formatter.add(reportItem.kfwf()); // KfWf
formatter.add(reportItem.kf()); // Kf
formatter.add(reportItem.wf()); // wf
formatter.add(reportItem.xf()); // Xf
formatter.add(reportItem.h()); // H
formatter.add(reportItem.km()); // Km
formatter.rowCompleted();
}
formatter.tableCompleted();
return tableText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicWellPathFractureTextReportFeatureImpl::createFracturePressureDepletionSummaryText(
const std::vector<RicWellPathFractureReportItem>& wellPathFractureReportItems) const
{
QString tableText;
QTextStream stream(&tableText);
RifEclipseDataTableFormatter formatter(stream);
configureFormatter(&formatter);
std::vector<RifEclipseOutputTableColumn> header = {RifEclipseOutputTableColumn("Well"),
RifEclipseOutputTableColumn("Fracture"),
RifEclipseOutputTableColumn("Actual WBHP"),
RifEclipseOutputTableColumn("Min Pressure Drop"),
RifEclipseOutputTableColumn("Max Pressure Drop")};
bool createdTable = false;
for (const auto& reportItem : wellPathFractureReportItems)
{
if (reportItem.performPressureDepletionScaling())
{
if (!createdTable)
{
formatter.comment(QString("Pressure Depletion Time step: %1").arg(reportItem.pressureDepletionTimeStepString()));
formatter.comment(QString("WBHP Source: %1").arg(reportItem.pressureDepletionWBHPString()));
formatter.comment(QString("User Defined WBHP: %1").arg(reportItem.pressureDepletionUserWBHP()));
formatter.header(header);
formatter.addHorizontalLine('-');
createdTable = true;
}
formatter.add(reportItem.wellPathNameForExport());
formatter.add(reportItem.fractureName());
formatter.add(reportItem.pressureDepletionActualWBHP());
formatter.add(reportItem.pressureDepletionMinPressureDrop());
formatter.add(reportItem.pressureDepletionMaxPressureDrop());
formatter.rowCompleted();
}
}
if (createdTable)
{
formatter.tableCompleted();
}
return tableText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
QString RicWellPathFractureTextReportFeatureImpl::createConnectionsPerWellText(
const std::vector<RicWellPathFractureReportItem>& wellPathFractureReportItems) const
{
QString tableText;
QTextStream stream(&tableText);
RifEclipseDataTableFormatter formatter(stream);
configureFormatter(&formatter);
std::vector<RifEclipseOutputTableColumn> header = {RifEclipseOutputTableColumn("Well"), floatNumberColumn("ConnCount")};
formatter.header(header);
formatter.addHorizontalLine('-');
std::map<QString /*Well*/, size_t> wellConnectionCounts;
for (const auto& reportItem : wellPathFractureReportItems)
{
QString wellPathName = reportItem.wellPathNameForExport();
if (wellConnectionCounts.find(wellPathName) == wellConnectionCounts.end())
{
wellConnectionCounts.insert(std::make_pair(wellPathName, 0));
}
wellConnectionCounts[wellPathName] += reportItem.connectionCount();
}
for (const auto& connCount : wellConnectionCounts)
{
formatter.add(connCount.first);
formatter.add(connCount.second);
formatter.rowCompleted();
}
formatter.tableCompleted();
return tableText;
}
//--------------------------------------------------------------------------------------------------
///
//--------------------------------------------------------------------------------------------------
void RicWellPathFractureTextReportFeatureImpl::configureFormatter(RifEclipseDataTableFormatter* formatter) const
{
if (!formatter) return;
formatter->setColumnSpacing(3);
formatter->setTableRowPrependText("-- ");
formatter->setTableRowLineAppendText("");
}