Merge pull request #1728 from joakim-hove/report-check-time

Report check time
This commit is contained in:
Joakim Hove 2020-04-22 08:21:35 +02:00 committed by GitHub
commit f0eaa8ea99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 269 additions and 52 deletions

View File

@ -264,6 +264,9 @@ void EclipseIO::writeTimeStep(const SummaryState& st,
for (const auto& report : schedule.report_config(report_step)) {
std::stringstream ss;
RptIO::write_report(ss, report.first, report.second, schedule, report_step);
auto log_string = ss.str();
if (!log_string.empty())
OpmLog::note(log_string);
}
}
}

View File

@ -32,19 +32,27 @@ namespace {
constexpr char section_separator { '\n' } ;
constexpr char divider_character { '-' } ;
void left_align(std::string& string, std::size_t width) {
void left_align(std::string& string, std::size_t width, std::size_t = 0) {
if (string.size() < width) {
string.append(std::string(width - string.size(), field_padding));
}
}
void right_align(std::string& string, std::size_t width) {
void left_header(std::string& string, std::size_t width, std::size_t line_number) {
if (line_number == 0) {
left_align(string, width, line_number);
} else {
string.clear();
}
}
void right_align(std::string& string, std::size_t width, std::size_t = 0) {
if (string.size() < width) {
string = std::string(width - string.size(), field_padding) + string;
}
}
void centre_align(std::string& string, std::size_t width) {
void centre_align(std::string& string, std::size_t width, std::size_t = 0) {
if (string.size() < width) {
std::size_t extra_space { width - string.size() } ;
std::size_t shift_one { extra_space % 2 } ;
@ -59,29 +67,39 @@ namespace {
}
}
template<typename T>
const std::string& unimplemented(const T&, std::size_t) {
static const std::string s { } ;
return s;
}
template<typename T>
bool add_separator(const T&, std::size_t line_number) {
return line_number == 0;
}
template<typename T, std::size_t header_height>
struct column {
using fetch_function = std::function<std::string(const T&, std::size_t)>;
using format_function = std::function<void(std::string&, std::size_t)>;
using format_function = std::function<void(std::string&, std::size_t, std::size_t)>;
std::size_t internal_width;
std::array<std::string, header_height> header;
fetch_function fetch;
fetch_function fetch = unimplemented<T>;
format_function format = centre_align;
void print(std::ostream& os, const T& data, std::size_t line_number) const {
std::string string_data { fetch(data, line_number) } ;
format(string_data, internal_width);
format(string_data, internal_width, line_number);
centre_align(string_data, total_width());
os << string_data;
}
void print_header(std::ostream& os, std::size_t row) const {
std::string header_line { header[row] } ;
centre_align(header_line, total_width());
os << header_line;
}
@ -93,6 +111,7 @@ namespace {
template<typename T, std::size_t header_height>
struct table: std::vector<column<T, header_height>> {
using std::vector<column<T, header_height>>::vector;
using separator_function = std::function<bool(const T&, std::size_t)>;
std::size_t total_width() const {
std::size_t r { 1 + this->size() } ;
@ -120,13 +139,14 @@ namespace {
os << field_separator << record_separator;
}
print_divider(os);
}
void print_data(std::ostream& os, const std::vector<T>& lines) const {
std::size_t line_number { 0 } ;
void print_data(std::ostream& os, const std::vector<T>& lines, const separator_function& separator, std::size_t& line_number) const {
for (const auto& line : lines) {
if (separator(line, line_number)) {
print_divider(os);
}
for (const auto& column : *this) {
os << field_separator;
@ -143,17 +163,22 @@ namespace {
template<typename InputType, typename OutputType, std::size_t header_height>
struct subreport {
using transform_function = std::function<std::vector<OutputType>(const InputType&)>;
using separator_function = typename table<OutputType, header_height>::separator_function;
std::string title;
std::string decor;
table<OutputType, header_height> column_definition;
char bottom_border;
transform_function transform;
separator_function separator;
subreport(const std::string& _title, const table<OutputType, header_height>& _coldef, transform_function _tf = &OutputType::transform)
subreport(const std::string& _title, const table<OutputType, header_height>& _coldef, char _bottom_border = '-', separator_function _sf = add_separator<OutputType>, transform_function _tf = &OutputType::transform)
: title { _title }
, decor { underline(title) }
, column_definition { _coldef }
, bottom_border { _bottom_border }
, transform { _tf }
, separator { _sf }
{
centre_align(title, column_definition.total_width());
centre_align(decor, column_definition.total_width());
@ -163,19 +188,23 @@ namespace {
return std::string(string.size(), divider_character);
}
void print(std::ostream& os, const std::vector<InputType>& data) const {
void print(std::ostream& os, const std::vector<InputType>& data, const std::vector<std::pair<int, std::string>>& footnotes) const {
os << title << record_separator;
os << decor << record_separator;
std::size_t line_number { 0 } ;
os << section_separator;
column_definition.print_header(os);
for (const auto element : data) {
column_definition.print_data(os, transform(element));
column_definition.print_data(os, transform(element), separator, line_number);
}
column_definition.print_divider(os);
column_definition.print_divider(os, bottom_border);
for (const auto& fnote: footnotes)
os << fnote.first << ": " << fnote.second << std::endl;
os << section_separator << std::flush;
os << std::endl << std::endl;
}
};
@ -255,7 +284,7 @@ namespace {
}
std::string wellhead_location(std::size_t) const {
auto i { std::to_string(well.getHeadI()) }, j { std::to_string(well.getHeadJ()) } ;
auto i { std::to_string(well.getHeadI() + 1) }, j { std::to_string(well.getHeadJ() + 1) } ;
right_align(i, 3);
right_align(j, 3);
@ -272,13 +301,7 @@ namespace {
ss << well.getPreferredPhase();
return ss.str();
}
const std::string& unimplemented(std::size_t) const {
const static std::string s { } ;
return s;
return ss.str().substr(0, 3);
}
std::string pvt_tab(std::size_t) const {
@ -335,13 +358,11 @@ namespace {
{ 3, { "PVT" , "TAB" , }, &WellWrapper::pvt_tab , },
{ 4, { "WELL" , "DENS" , "CALC" }, &WellWrapper::dens_calc , },
{ 3, { "FIP" , "REG" , }, &WellWrapper::region_number , },
{ 11, { "WELL" , "D-FACTOR?" , "DAY/SM3" }, &WellWrapper::D_factor , },
{ 11, { "WELL" , "D-FACTOR 1" , "DAY/SM3" }, &WellWrapper::D_factor , },
}};
void subreport_well_specification_data(std::ostream& os, const std::vector<Opm::Well>& data) {
well_specification.print(os, data);
os << "? The WELL D-FACTOR is not implemented - and the report will always show the default value 0." << std::endl;
os << std::endl;
well_specification.print(os, data, {{1, "The WELL D-FACTOR is not implemented - and the report will always show the default value 0."}});
}
}
@ -357,7 +378,7 @@ namespace {
}
std::string grid_block(std::size_t) const {
const std::array<int,3> ijk { connection.getI(), connection.getJ(), connection.getK() } ;
const std::array<int,3> ijk { connection.getI() + 1, connection.getJ() + 1, connection.getK() + 1 } ;
auto compose_coordinates = [](std::string& out, int in) -> std::string {
constexpr auto delimiter { ',' } ;
@ -408,9 +429,8 @@ namespace {
return "";
}
const std::string &dfactor(std::size_t) const {
static const std::string s { };
return s;
const std::string dfactor(std::size_t) const {
return "0";
}
static std::vector<WellConnection> transform(const Opm::Well& well) {
@ -426,31 +446,225 @@ namespace {
};
const subreport<Opm::Well, WellConnection, 3> well_connection { "WELL CONNECTION DATA", {
{ 7, {"WELL" ,"NAME" , }, &WellConnection::well_name , left_align },
{ 12, {"GRID" ,"BLOCK" , }, &WellConnection::grid_block , },
{ 3, {"CMPL" ,"NO#" , }, &WellConnection::cmpl_no , right_align },
{ 7, {"CENTRE" ,"DEPTH" ,"METRES" }, &WellConnection::centre_depth , right_align },
{ 3, {"OPEN" ,"SHUT" , }, &WellConnection::open_shut , },
{ 3, {"SAT" ,"TAB" , }, &WellConnection::sat_tab , },
{ 8, {"CONNECTION" ,"FACTOR*" ,"CPM3/D/B" }, &WellConnection::conn_factor , right_align },
{ 6, {"INT" ,"DIAM" ,"METRES" }, &WellConnection::int_diam , right_align },
{ 7, {"K H" ,"VALUE" ,"MD.METRE" }, &WellConnection::kh_value , right_align },
{ 6, {"SKIN" ,"FACTOR" , }, &WellConnection::skin_factor , right_align },
{ 10, {"CONNECTION" ,"D-FACTOR§" ,"DAY/SM3" }, &WellConnection::dfactor , },
{ 23, {"SATURATION SCALING DATA","SWMIN SWMAX SGMIN SGMAX","&" }, &WellConnection::sat_scaling , },
{ 7, {"WELL" ,"NAME" , }, &WellConnection::well_name , left_align },
{ 12, {"GRID" ,"BLOCK" , }, &WellConnection::grid_block , },
{ 3, {"CMPL" ,"NO#" , }, &WellConnection::cmpl_no , right_align },
{ 7, {"CENTRE" ,"DEPTH" ,"METRES" }, &WellConnection::centre_depth , right_align },
{ 3, {"OPEN" ,"SHUT" , }, &WellConnection::open_shut , },
{ 3, {"SAT" ,"TAB" , }, &WellConnection::sat_tab , },
{ 8, {"CONNECTION" ,"FACTOR*" ,"CPM3/D/B" }, &WellConnection::conn_factor , right_align },
{ 6, {"INT" ,"DIAM" ,"METRES" }, &WellConnection::int_diam , right_align },
{ 7, {"K H" ,"VALUE" ,"MD.METRE" }, &WellConnection::kh_value , right_align },
{ 6, {"SKIN" ,"FACTOR" , }, &WellConnection::skin_factor , right_align },
{ 10, {"CONNECTION" ,"D-FACTOR 1" ,"DAY/SM3" }, &WellConnection::dfactor , },
{ 23, {"SATURATION SCALING DATA","SWMIN SWMAX SGMIN SGMAX 2", }, &WellConnection::sat_scaling , },
}};
}
namespace {
struct WellSegment {
const Opm::Well& well;
const Opm::Connection& connection;
const Opm::Segment& segment;
bool branch_separator;
const std::string& well_name(std::size_t) const {
return well.name();
}
std::string connection_grid(std::size_t n) const {
const WellConnection wc { well, connection } ;
return wc.grid_block(n);
}
std::string well_name_seg(std::size_t n) const {
if (n == 0) {
return well_name(n);
} else if (n == 1) {
return Opm::WellSegments::CompPressureDropToString(well.getSegments().compPressureDrop());
} else {
return unimplemented(this, n);
}
}
std::string segment_number(std::size_t) const {
return std::to_string(segment.segmentNumber());
}
std::string branch_id(std::size_t) const {
return std::to_string(segment.branchNumber());
}
std::string branch_number(std::size_t n) const {
if (branch_separator) {
return branch_id(n);
} else {
return unimplemented(this, n);
}
}
std::string connection_depth(std::size_t) const {
return std::to_string(connection.depth()).substr(0, 6);
}
std::string segment_depth(std::size_t) const {
return std::to_string(segment.depth()).substr(0, 6);
}
std::string length_end_segmt(std::size_t) const {
return std::to_string(segment.totalLength()).substr(0, 6);
}
std::string total_length(std::size_t) const {
return std::to_string(segment.totalLength()).substr(0, 6);
}
std::string t_v_depth(std::size_t) const {
return std::to_string(segment.depth()).substr(0, 6);
}
std::string internal_diameter(std::size_t) const {
const auto number { segment.internalDiameter() } ;
if (number != Opm::Segment::invalidValue()) {
return std::to_string(number).substr(0, 6);
} else {
return "0";
}
}
std::string roughness(std::size_t) const {
const auto number { segment.roughness() } ;
if (number != Opm::Segment::invalidValue()) {
return std::to_string(number).substr(0, 8);
} else {
return "0";
}
}
std::string cross_section(std::size_t) const {
const auto number { segment.crossArea() } ;
if (number != Opm::Segment::invalidValue()) {
return std::to_string(number).substr(0, 7);
} else {
return "0";
}
}
std::string volume(std::size_t) const {
return std::to_string(segment.volume()).substr(0, 5);
}
std::string main_inlet(std::size_t) const {
const auto& inlets { segment.inletSegments() } ;
if (inlets.size() != 0) {
return std::to_string(segment.inletSegments().front());
} else {
return "0";
}
}
std::string outlet(std::size_t) const {
return std::to_string(segment.outletSegment());
}
static std::vector<WellSegment> transform(const Opm::Well& well) {
const auto &connections { well.getConnections() } ;
std::vector<WellSegment> out;
int branch_number { 0 } ;
for (const auto& connection : connections) {
const auto& segment { well.getSegments().getFromSegmentNumber(connection.segment()) } ;
const auto& separator { branch_number != segment.branchNumber() } ;
out.push_back({ well, connection, segment, separator });
branch_number = segment.branchNumber();
}
return out;
}
static void ws_format(std::string& string, std::size_t, std::size_t i) {
if (i == 0) {
left_align(string, 8, i);
} else {
right_align(string, 8, i);
}
}
static bool segment_structure_separator(const WellSegment& segment, std::size_t) {
return segment.branch_separator;
}
};
const subreport<Opm::Well, WellSegment, 3> well_multisegment_connection { "MULTI-SEGMENT WELL: CONNECTION DATA", {
{ 8, {"WELL" , "NAME" , }, &WellSegment::well_name , left_header },
{ 9, {"CONNECTION" , "" , }, &WellSegment::connection_grid , },
{ 5, {"SEGMENT" , "NUMBER" , }, &WellSegment::segment_number , right_align },
{ 8, {"BRANCH" , "ID" , }, &WellSegment::branch_id , },
{ 9, {"TUB LENGTH" , "START PERFS", "METRES" }, unimplemented<WellSegment> , right_align },
{ 9, {"TUB LENGTH" , "END PERFS" , "METRES" }, unimplemented<WellSegment> , right_align },
{ 9, {"TUB LENGTH" , "CENTR PERFS", "METRES" }, unimplemented<WellSegment> , right_align },
{ 9, {"TUB LENGTH" , "END SEGMT" , "METRES" }, &WellSegment::length_end_segmt, right_align },
{ 8, {"CONNECTION" , "DEPTH" , "METRES" }, &WellSegment::connection_depth, right_align },
{ 8, {"SEGMENT" , "DEPTH" , "METRES" }, &WellSegment::segment_depth , right_align },
{ 9, {"GRID BLOCK" , "DEPTH" , "METRES" }, unimplemented<WellSegment> , right_align },
}, '='};
const subreport<Opm::Well, WellSegment, 3> well_multisegment_data { "MULTI-SEGMENT WELL: SEGMENT STRUCTURE", {
{ 6, { "WELLNAME" , "AND" , "SEG TYPE" }, &WellSegment::well_name_seg , &WellSegment::ws_format },
{ 3, { "SEG" , "NO" , "" }, &WellSegment::segment_number , right_align },
{ 3, { "BRN" , "NO" , "" }, &WellSegment::branch_number , right_align },
{ 5, { "MAIN" , "INLET" , "SEGMENT" }, &WellSegment::main_inlet , right_align },
{ 5, { "" , "OUTLET" , "SEGMENT" }, &WellSegment::outlet , right_align },
{ 7, { "SEGMENT" , "LENGTH" , "METRES" }, unimplemented<WellSegment> , right_align },
{ 8, { "TOT LENGTH", "TO END" , "METRES" }, &WellSegment::total_length , right_align },
{ 8, { "DEPTH" , "CHANGE" , "METRES" }, unimplemented<WellSegment> , right_align },
{ 8, { "T.V. DEPTH", "AT END" , "METRES" }, &WellSegment::t_v_depth , right_align },
{ 6, { "DIA OR F" , "SCALING" , "METRES" }, &WellSegment::internal_diameter, right_align },
{ 8, { "VFP TAB OR", "ABS ROUGHN" , "METRES" }, &WellSegment::roughness , right_align },
{ 7, { "AREA" , "X-SECTN" , "M**2" }, &WellSegment::cross_section , right_align },
{ 7, { "VOLUME" , "" , "M3" }, &WellSegment::volume , right_align },
{ 8, { "P DROP" , "MULT" , "FACTOR" }, unimplemented<WellSegment> , right_align },
}, '=', &WellSegment::segment_structure_separator};
}
namespace {
void subreport_well_connection_data(std::ostream& os, const std::vector<Opm::Well>& data) {
well_connection.print(os, data);
os << "&: The saturation scaling data has not been implemented in the report and will show blank" << std::endl;
os << "§: Entering the D-FAACTOR with compdat is not supported in opm/flow - the report will always show blank" << std::endl;
os << std::endl;
well_connection.print(os, data, {{1, "The well connection D-FACTOR is not implemented in opm and the report will always show 0."},
{2, "The saturation scaling data has not been implemented in the report and will show blank"}});
}
}
void Opm::RptIO::workers::write_WELSPECS(std::ostream& os, unsigned, const Opm::Schedule& schedule, std::size_t report_step) {
write_report_header(os, schedule, report_step);
auto well_names = schedule.changed_wells(report_step);
if (well_names.empty())
return;
subreport_well_specification_data(os, schedule.getWells(report_step));
subreport_well_connection_data(os, schedule.getWells(report_step));
std::vector<Well> changed_wells;
std::transform(well_names.begin(), well_names.end(), std::back_inserter(changed_wells), [&report_step, &schedule](const std::string& wname) { return schedule.getWell(wname, report_step); });
write_report_header(os, schedule, report_step);
subreport_well_specification_data(os, changed_wells);
subreport_well_connection_data(os, changed_wells);
for (const auto& well : changed_wells) {
if (well.isMultiSegment()) {
well_multisegment_data.print(os, { well }, {});
well_multisegment_connection.print(os, { well }, {});
}
}
}