Example #1
0
def test_format_table_simple_raises():
    with pytest.raises(ValueError) as err:
        data_table.format_table([['Col 1', 'Col 2'], [
            1,
        ]])
    assert err.value.args[
        0] == 'Rows not of equal length but lengths of {1, 2}'
Example #2
0
def write_parameter_section_to_las(
        logical_file: LogicalFile.LogicalFile,
        ostream: typing.TextIO,
    ) -> None:
    """Write the ``PARAMETER`` tables to LAS."""
    las_mnem_map: typing.Dict[str, UnitValueDescription] = collections.OrderedDict()
    for position_eflr in logical_file.eflrs:
        if position_eflr.eflr.set.type == b'PARAMETER':
            # print('TRACE:', position_eflr.eflr.str_long())
            for obj in position_eflr.eflr.objects:
                units = obj[b'VALUES'].units.decode('ascii')
                value = stringify.stringify_object_by_type(obj[b'VALUES'].value).strip()
                descr = stringify.stringify_object_by_type(obj[b'LONG-NAME'].value).strip()
                # NOTE: Overwriting is possible here.
                las_mnem_map[obj.name.I.decode('ascii')] = UnitValueDescription(units, value, descr)
    table = [
        ['#MNEM.UNIT', 'Value', 'Description'],
        ['#---------', '-----', '-----------'],
    ]
    # pprint.pprint(las_mnem_map)
    for k in las_mnem_map:
        table.append(
            [f'{k:<4}.{las_mnem_map[k].unit:<4}', las_mnem_map[k].value, f': {las_mnem_map[k].description}']
        )
    rows = data_table.format_table(table, pad='  ', left_flush=True)
    ostream.write('~Parameter Information Section\n')
    for row in rows:
        ostream.write(row)
        ostream.write('\n')
Example #3
0
def _scan_log_pass_content(
        logical_index: LogicalFile.LogicalIndex,
        logical_file_index: int,
        fout: typing.TextIO,
        *,
        frame_slice: Slice.Slice) -> None:
    """Scan the LogPass."""
    assert logical_index[logical_file_index].has_log_pass
    logical_file = logical_index[logical_file_index]
    lp: LogPass.LogPass = logical_file.log_pass
    frame_array: LogPass.FrameArray
    for fa, frame_array in enumerate(lp.frame_arrays):
        with _output_section_header_trailer(f'Frame Array [{fa}/{len(lp.frame_arrays)}]', '^', os=fout):
            fout.write(str(frame_array))
            fout.write('\n')
            num_frames = logical_file.populate_frame_array(
                frame_array,
                frame_slice,
            )
            if num_frames > 0:
                x_axis: XAxis.XAxis = logical_index[logical_file_index].iflr_position_map[frame_array.ident]
                _write_x_axis_summary(x_axis, fout)
                if x_axis.summary.spacing is not None:
                    interval = f'{x_axis.summary.spacing.median:0.3f}'
                else:
                    interval = 'N/A'
                fout.write(
                    f'Frames [{len(x_axis)}]'
                    f' from: {float(x_axis[0].x_axis):0.3f}'
                    f' to {float(x_axis[-1].x_axis):0.3f}'
                    f' Interval: {interval}'
                    f' {frame_array.x_axis.units}'
                )
                fout.write('\n')
                fout.write(
                    f'Frame spacing: {frame_slice.long_str(len(x_axis))}'
                    f' number of frames: {num_frames}'
                    f' numpy size: {frame_array.sizeof_array:,d} bytes'
                )
                fout.write('\n')
                frame_table = [['Channel', 'Size', 'Absent', 'Min', 'Mean', 'Std.Dev.', 'Max', 'Units', 'dtype']]
                for channel in frame_array.channels:
                    channel_ident = channel.ident.I.decode("ascii")
                    # arr = channel.array
                    arr = AbsentValue.mask_absent_values(channel.array)
                    frame_table.append(
                        [channel_ident, arr.size,
                         # NOTE: Not the masked array!
                         AbsentValue.count_of_absent_values(channel.array),
                         arr.min(), arr.mean(),
                         arr.std(), arr.max(), channel.units, arr.dtype]
                    )
                fout.write('\n'.join(data_table.format_table(frame_table, heading_underline='-', pad='   ')))
                fout.write('\n')
            else:
                fout.write('No frames.')
            fout.write('\n')
Example #4
0
def test_format_table_simple():
    formatted_table = data_table.format_table(SIMPLE_TABLE)
    expected = """Col 1 Col 2
    1     2
    3     4
    5     6"""
    # print(formatted_table)
    assert formatted_table == [
        'Col 1 Col 2', '    1     2', '    3     4', '    5     6'
    ]
    assert '\n'.join(formatted_table) == expected
Example #5
0
def test_format_table_simple_pad():
    formatted_table = data_table.format_table(SIMPLE_TABLE, pad=' | ')
    expected = """Col 1 | Col 2
    1 |     2
    3 |     4
    5 |     6"""
    # print(formatted_table)
    assert formatted_table == [
        'Col 1 | Col 2', '    1 |     2', '    3 |     4', '    5 |     6'
    ]
    assert '\n'.join(formatted_table) == expected
Example #6
0
def test_format_table_simple_floats():
    formatted_table = data_table.format_table(SIMPLE_TABLE_WITH_FLOATS)
    expected = """Col 1 Col 2
1.000 2.000
3.000 4.000
5.000 6.000"""
    # print(formatted_table)
    assert formatted_table == [
        'Col 1 Col 2', '1.000 2.000', '3.000 4.000', '5.000 6.000'
    ]
    # print('\n'.join(formatted_table))
    assert '\n'.join(formatted_table) == expected
Example #7
0
def test_format_table_simple_sphinx():
    formatted_table = data_table.format_table(SIMPLE_TABLE,
                                              heading_underline='=')
    expected = """Col 1 Col 2
===== =====
    1     2
    3     4
    5     6"""
    # print(formatted_table)
    assert formatted_table == [
        'Col 1 Col 2', '===== =====', '    1     2', '    3     4',
        '    5     6'
    ]
    assert '\n'.join(formatted_table) == expected
Example #8
0
def _write_las_header(input_file: str,
                      logical_file: LogicalFile.LogicalFile,
                      logical_file_number: int,
                      frame_array_ident: str,
                      ostream: typing.TextIO) -> None:
    """Writes the LAS opening such as:

    ~Version Information Section
    VERS.           2.0                           : CWLS Log ASCII Standard - VERSION 2.0
    WRAP.           NO                            : One Line per depth step
    PROD.           TotalDepth                    : LAS Producer
    PROG.           TotalDepth.RP66V1.ToLAS 0.1.1 : LAS Program name and version
    CREA.           2012-11-14 10:50              : LAS Creation date [YYYY-MMM-DD hh:mm]
    DLIS_CREA.      2012-11-10 22:06              : DLIS Creation date and time [YYYY-MMM-DD hh:mm]
    SOURCE.         SOME-FILE-NAME.dlis           : DLIS File Name
    FILE-ID.        SOME-FILE-ID                  : File Identification from the FILE-HEADER Logical Record
    LOGICAL-FILE.   3                             : Logical File number in the DLIS file
    FRAME-ARRAY.    60B                           : Identity of the Frame Array in the Logical File

    Reference: [LAS2.0 Las2_Update_Feb2017.pdf Section 5.3 ~V (Version Information)]
    """
    now = datetime.datetime.utcnow()
    date_time = logical_file.defining_origin[b'CREATION-TIME'].value[0]
    dt = date_time.as_datetime()
    fhlr: EFLR.ExplicitlyFormattedLogicalRecord = logical_file.file_header_logical_record
    file_id = fhlr.objects[0][b'ID'].value[0].decode('ascii').strip()
    table: typing.List[typing.List[str]] = [
        ['VERS.', '2.0', ': CWLS Log ASCII Standard - VERSION 2.0'],
        ['WRAP.', 'NO', ': One Line per depth step'],
        ['PROD.', 'TotalDepth', ': LAS Producer'],
        ['PROG.', f'TotalDepth.RP66V1.ToLAS {LAS_PRODUCER_VERSION}', ': LAS Program name and version'],
        ['CREA.', f'{now.strftime(LAS_DATETIME_FORMAT_UTC)}', f': LAS Creation date [{LAS_DATE_FORMAT_TEXT}]'],
        [
            f'DLIS_CREA.',
            f'{dt.strftime(LAS_DATETIME_FORMAT_UTC)}', f': DLIS Creation date and time [{LAS_DATE_FORMAT_TEXT}]'
        ],
        ['SOURCE.', f'{os.path.basename(input_file)}', ': DLIS File Name'],
        ['FILE-ID.', f'{file_id}', ': File Identification Number'],
        ['LOGICAL-FILE.', f'{logical_file_number:d}', ': Logical File number in the DLIS file'],
    ]
    if frame_array_ident:
        table.append(
            ['FRAME-ARRAY.', f'{frame_array_ident}', ': Identity of the Frame Array in the Logical File'],
        )
    rows = data_table.format_table(table, pad='  ', left_flush=True)
    ostream.write('~Version Information Section\n')
    for row in rows:
        ostream.write(row)
        ostream.write('\n')
Example #9
0
def write_well_information_to_las(
        logical_file: LogicalFile.LogicalFile,
        frame_array: typing.Union[LogPass.FrameArray, None],
        frame_slice: typing.Union[Slice.Slice, Slice.Sample],
        ostream: typing.TextIO,
    ) -> None:
    """Writes the well information section.

    Reference: ``[LAS2.0 Las2_Update_Feb2017.pdf Section 5.4 ~W (Well Information)]``
    """
    # Tuple of (units, value, description)
    las_map: typing.Dict[str, UnitValueDescription] = extract_well_information_from_origin(logical_file)
    _add_start_stop_step_to_dictionary(logical_file, frame_array, frame_slice, las_map)
    eflr: EFLR.ExplicitlyFormattedLogicalRecord
    for _lrsh_position, eflr in logical_file.eflrs:
        if eflr.set.type in DLIS_TO_WELL_INFORMATION_LAS_EFLR_MAPPING:
            bytes_index_map: typing.Dict[bytes, int] = EFLR.reduced_object_map(eflr)
            for row_key in DLIS_TO_WELL_INFORMATION_LAS_EFLR_MAPPING[eflr.set.type]:
                if row_key in bytes_index_map:
                    obj = eflr[bytes_index_map[row_key]]
                    # ORIGIN is only key/value so does not have LONG-NAME
                    # PARAMETER does have LONG-NAME
                    units = obj[b'VALUES'].units.decode('ascii')
                    value = stringify.stringify_object_by_type(obj[b'VALUES'].value).strip()
                    descr = stringify.stringify_object_by_type(obj[b'LONG-NAME'].value).strip()
                    # NOTE: Overwriting is possible here.
                    las_map[row_key.decode('ascii')] = UnitValueDescription(units, value, descr)
    table = [
        ['#MNEM.UNIT', 'DATA', 'DESCRIPTION',],
        ['#----.----', '----', '-----------',],
    ]
    for k in WELL_INFORMATION_KEYS:
        if k in las_map:
            row = [f'{k:4}.{las_map[k].unit:4}', f'{las_map[k].value}', f': {las_map[k].description}',]
        else:
            row = [f'{k:4}.{"":4}', '', ':']
        table.append(row)
    rows = data_table.format_table(table, pad='  ', left_flush=True)
    ostream.write('~Well Information Section\n')
    for row in rows:
        ostream.write(row)
        ostream.write('\n')
Example #10
0
def scan_RP66V1_file_data_content(fobj: typing.BinaryIO, fout: typing.TextIO,
                                  *, rp66v1_path: str, frame_slice: Slice.Slice, eflr_as_table: bool) -> None:
    """
    Scans all of every EFLR and IFLR in the file using a ScanFile object.
    """
    with LogicalFile.LogicalIndex(fobj) as logical_index:
        with _output_section_header_trailer('RP66V1 File Data Summary', '*', os=fout):
            fout.write(str(logical_index.storage_unit_label))
            fout.write('\n')
            logical_file: LogicalFile.LogicalFile
            for lf, logical_file in enumerate(logical_index.logical_files):
                with _output_section_header_trailer(f'Logical File [{lf}/{len(logical_index.logical_files)}]', '=', os=fout):
                    fout.write(str(logical_file))
                    fout.write('\n')
                    eflr_position: LogicalFile.PositionEFLR
                    for e, eflr_position in enumerate(logical_file.eflrs):
                        header = f'EFLR [{e}/{len(logical_file.eflrs)}] at {str(eflr_position.lrsh_position)}'
                        with _output_section_header_trailer(header, '-', os=fout):
                            # fout.write(str(eflr_position.eflr))
                            # fout.write('\n')
                            if eflr_as_table:
                                if eflr_position.eflr.is_key_value():
                                    eflr_str_table = eflr_position.eflr.key_values(
                                        stringify_function=stringify.stringify_object_by_type,
                                        sort=True
                                    )
                                else:
                                    eflr_str_table = eflr_position.eflr.table_as_strings(
                                        stringify_function=stringify.stringify_object_by_type,
                                        sort=True
                                    )
                                fout.write('\n'.join(data_table.format_table(eflr_str_table, heading_underline='-')))
                                fout.write('\n')
                            else:
                                fout.write(eflr_position.eflr.str_long())
                            fout.write('\n')
                    # Now the LogPass(s)
                    if logical_file.has_log_pass:
                        with _output_section_header_trailer('Log Pass', '-', os=fout):
                            _scan_log_pass_content(logical_index, lf, fout, frame_slice=frame_slice)
                    else:
                        fout.write('NO Log Pass for this Logical Record\n')
Example #11
0
def write_curve_section_to_las(
        frame_array: LogPass.FrameArray,
        channels: typing.Set[str],
        ostream: typing.TextIO,
    ) -> None:
    """Write the ``~Curve Information Section`` to the LAS file."""
    ostream.write('~Curve Information Section\n')
    table = [
        ['#MNEM.UNIT', 'Curve Description'],
        ['#---------', '-----------------'],
    ]
    for c, channel in enumerate(frame_array.channels):
        if len(channels) == 0 or c == 0 or channel.ident.I.decode("ascii") in channels:
            desc = ' '.join([
                f': {channel.long_name.decode("ascii")}',
                f'Rep Code: {RepCode.REP_CODE_INT_TO_STR[channel.rep_code]}',
                f'Dimensions: {channel.dimensions}'
            ])
            table.append([f'{channel.ident.I.decode("ascii"):<4}.{channel.units.decode("ascii"):<4}', desc])
    rows = data_table.format_table(table, pad='  ', left_flush=True)
    for row in rows:
        ostream.write(row)
        ostream.write('\n')
Example #12
0
def main() -> int:
    """Main entry point."""
    description = """usage: %(prog)s [options] file
Reads RP66V1 file(s) and writes them out as LAS files."""
    print('Cmd: %s' % ' '.join(sys.argv))

    parser = cmn_cmd_opts.path_in_out(
        description, prog='TotalDepth.RP66V1.ToLAS.main', version=__version__, epilog=__rights__
    )
    cmn_cmd_opts.add_log_level(parser, level=20)
    cmn_cmd_opts.add_multiprocessing(parser)
    Slice.add_frame_slice_to_argument_parser(parser, use_what=True)
    process.add_process_logger_to_argument_parser(parser)
    gnuplot.add_gnuplot_to_argument_parser(parser)
    parser.add_argument(
        '--array-reduction', type=str,
        help='Method to reduce multidimensional channel data to a single value. [default: %(default)s]',
        default='first',
        choices=list(sorted(ARRAY_REDUCTIONS)),
        )
    parser.add_argument(
        '--channels', type=str,
        help='Comma separated list of channels to write out (X axis is always included).'
             ' Use \'?\' to see what channels exist without writing anything. [default: "%(default)s"]',
        default='',
        )
    parser.add_argument('--field-width', type=int,
                        help='Field width for array data [default: %(default)s].', default=16)
    parser.add_argument('--float-format', type=str,
                        help='Floating point format for array data [default: "%(default)s"].', default='.3f')
    args = parser.parse_args()
    cmn_cmd_opts.set_log_level(args)
    # print('args:', args)
    # return 0
    # Your code here
    clk_start = time.perf_counter()
    ret_val = 0
    result: typing.Dict[str, LASWriteResult] = {}
    # if os.path.isfile(args.path_in) and (args.frame_slice.strip() == '?' or args.channels.strip() == '?'):
    if args.frame_slice.strip() == '?' or args.channels.strip() == '?':
        dump_frames_and_or_channels(args.path_in, args.recurse, args.frame_slice.strip(), args.channels.strip())
    else:
        channel_set = set()
        for ch in args.channels.strip().split(','):
            if ch.strip() != '':
                channel_set.add(ch.strip())
        if cmn_cmd_opts.multiprocessing_requested(args) and os.path.isdir(args.path_in):
            result = convert_rp66v1_dir_or_file_to_las_multiprocessing(
                args.path_in,
                args.path_out,
                args.recurse,
                args.array_reduction,
                Slice.create_slice_or_sample(args.frame_slice),
                channel_set,
                args.field_width,
                args.float_format,
                args.jobs,
            )
        else:
            if args.log_process > 0.0:
                with process.log_process(args.log_process):
                    result = convert_rp66v1_dir_or_file_to_las(
                        args.path_in,
                        args.path_out,
                        args.recurse,
                        args.array_reduction,
                        Slice.create_slice_or_sample(args.frame_slice),
                        channel_set,
                        args.field_width,
                        args.float_format,
                    )
            else:
                result = convert_rp66v1_dir_or_file_to_las(
                    args.path_in,
                    args.path_out,
                    args.recurse,
                    args.array_reduction,
                    Slice.create_slice_or_sample(args.frame_slice),
                    channel_set,
                    args.field_width,
                    args.float_format,
                )
    clk_exec = time.perf_counter() - clk_start
    # Report output
    if result:
        size_index = size_input = 0
        files_processed = 0
        table = [
            ['Input', 'Output', 'LAS Count', 'Time', 'Ratio', 'ms/Mb', 'Exception', 'Path']
        ]
        for path in sorted(result.keys()):
            las_result = result[path]
            # print('TRACE: las_result', las_result)
            if las_result.size_input > 0:
                ms_mb = las_result.time * 1000 / (las_result.size_input / 1024 ** 2)
                ratio = las_result.size_output / las_result.size_input
                out = [
                    f'{las_result.size_input:,d}',
                    f'{las_result.size_output:,d}',
                    f'{las_result.las_count:,d}',
                    f'{las_result.time:.3f}',
                    f'{ratio:.1%}',
                    f'{ms_mb:.1f}',
                    f'{str(las_result.exception)}',
                    f'"{path}"',
                ]
                table.append(out)
                # print(' '.join(out))
                size_input += result[path].size_input
                size_index += result[path].size_output
                files_processed += 1
                if las_result.exception:
                    ret_val = 1
        for row in data_table.format_table(table, pad=' ', heading_underline='-'):
            print(row)
        try:
            if args.gnuplot:
                plot_gnuplot(result, args.gnuplot)
        except Exception as err:  # pragma: no cover
            logger.exception(str(err))
            ret_val = 2
        print('Execution time = %8.3f (S)' % clk_exec)
        if size_input > 0:
            ms_mb = clk_exec * 1000 / (size_input/ 1024**2)
            ratio = size_index / size_input
        else:
            ms_mb = 0.0
            ratio = 0.0
        print(f'Out of  {len(result):,d} processed {files_processed:,d} files of total size {size_input:,d} input bytes')
        print(f'Wrote {size_index:,d} output bytes, ratio: {ratio:8.3%} at {ms_mb:.1f} ms/Mb')
    else:
        print(f'Execution time: {clk_exec:.3f} (s)')
    print('Bye, bye!')
    return ret_val
Example #13
0
def main() -> int:
    description = """usage: %(prog)s [options] file
Scans a RP66V1 file or directory and saves the index as a pickled file."""
    print('Cmd: %s' % ' '.join(sys.argv))
    parser = cmn_cmd_opts.path_in_out(
        description, prog='TotalDepth.RP66V1.IndexPickle.main', version=__version__, epilog=__rights__
    )
    cmn_cmd_opts.add_log_level(parser, level=20)
    cmn_cmd_opts.add_multiprocessing(parser)
    parser.add_argument('--read-back', action='store_true', help='Read and time the output. [default: %(default)s]')
    process.add_process_logger_to_argument_parser(parser)
    gnuplot.add_gnuplot_to_argument_parser(parser)
    args = parser.parse_args()
    # print('args:', args)
    # return 0
    cmn_cmd_opts.set_log_level(args)
    # Your code here
    clk_start = time.perf_counter()
    ret_val = 0
    if cmn_cmd_opts.multiprocessing_requested(args) and os.path.isdir(args.path_in):
        result: typing.Dict[str, IndexResult] = index_dir_multiprocessing(
            args.path_in,
            args.path_out,
            args.jobs,
            args.recurse,
            args.read_back,
        )
    else:
        if args.log_process > 0.0:
            with process.log_process(args.log_process):
                result: typing.Dict[str, IndexResult] = index_dir_or_file(
                    args.path_in,
                    args.path_out,
                    args.recurse,
                    args.read_back,
                )
        else:
            result: typing.Dict[str, IndexResult] = index_dir_or_file(
                args.path_in,
                args.path_out,
                args.recurse,
                args.read_back,
            )
    clk_exec = time.perf_counter() - clk_start
    size_index = size_input = 0
    files_processed = 0
    try:
        path_prefix = os.path.commonpath(result.keys())
        len_path_prefix = len(path_prefix)
        table: typing.List[typing.List[str]] = [
            [
                'Size (b)', 'Index (b)', 'Ratio (%)',
                'Index (s)', 'Index (ms/Mb)',
                'Write (s)', 'Write (ms/Mb)',
                'Read (s)', 'Read (ms/Mb)',
                'Except',
                'Path',
            ]
        ]
        for path in sorted(result.keys()):
            idx_result = result[path]
            if not idx_result.ignored and idx_result.size_input > 0:
                ms_mb_index = idx_result.time_index * 1000 / (idx_result.size_input / 1024 ** 2)
                ms_mb_write = idx_result.time_write * 1000 / (idx_result.size_input / 1024 ** 2)
                ms_mb_read = idx_result.time_read * 1000 / (idx_result.size_input / 1024 ** 2)
                ratio = idx_result.size_index / idx_result.size_input
                table.append(
                    [
                        f'{idx_result.size_input:,d}', f'{idx_result.size_index:,d}', f'{ratio:.3%}',
                        f'{idx_result.time_index:.3f}', f'{ms_mb_index:.1f}',
                        f'{idx_result.time_write:.3f}', f'{ms_mb_write:.1f}',
                        f'{idx_result.time_read:.3f}', f'{ms_mb_read:.2f}',
                        f'{str(idx_result.exception):5}',
                        f'{path[len_path_prefix+1:]}',
                    ]
                )
                size_input += result[path].size_input
                size_index += result[path].size_index
                files_processed += 1
                if idx_result.exception:  # pragma: no cover
                    ret_val = 1
        print(f'Common path prefix: {path_prefix}')
        print('\n'.join(data_table.format_table(table, pad=' | ', heading_underline='-')))
        if args.gnuplot:
            try:
                plot_gnuplot(result, args.gnuplot)
            except IOError:  # pragma: no cover
                logger.exception('Plotting with gnuplot failed.')
                ret_val = 2
    except Exception as err:  # pragma: no cover
        logger.exception(str(err))
        ret_val = 3
    print('Execution time = %8.3f (S)' % clk_exec)
    if size_input > 0:
        ms_mb = clk_exec * 1000 / (size_input/ 1024**2)
        ratio = size_index / size_input
    else:  # pragma: no cover
        ms_mb = 0.0
        ratio = 0.0
    print(f'Out of  {len(result):,d} processed {files_processed:,d} files of total size {size_input:,d} input bytes')
    print(f'Wrote {size_index:,d} output bytes, ratio: {ratio:8.3%} at {ms_mb:.1f} ms/Mb')
    print('Bye, bye!')
    return ret_val