From 2bee1e4f99dd03c8103b4d89c6d1905c8c5247e4 Mon Sep 17 00:00:00 2001 From: Robert Smallshire Date: Sun, 14 Jun 2015 17:20:29 +0200 Subject: [PATCH] Adds inline/xline range support to extract_trace_header_3d. Adds extract_xline_3d --- segpy-ext/segpy-numpy/segpy_numpy/extract.py | 158 ++++++++++++++++--- 1 file changed, 140 insertions(+), 18 deletions(-) diff --git a/segpy-ext/segpy-numpy/segpy_numpy/extract.py b/segpy-ext/segpy-numpy/segpy_numpy/extract.py index f783efb..d6dbc2f 100644 --- a/segpy-ext/segpy-numpy/segpy_numpy/extract.py +++ b/segpy-ext/segpy-numpy/segpy_numpy/extract.py @@ -13,15 +13,45 @@ class DimensionalityError: # TODO: Add inline_numbers and xline_numbers arguments -def extract_trace_header_field_3d(reader, fields, null=None): +def extract_trace_header_field_3d(reader_3d, fields, inline_numbers=None, xline_numbers=None, null=None): """Extract a single trace header field from all trace headers as an array. Args: - reader: A SegYReader3D + reader_3d: A SegYReader3D - fields: A an iterable series where each item is either the string name of a field - or an object with a 'name' attribute which is the name of a field, such as a - NamedField. + fields: A an iterable series where each item is either the name of a field as a string + or an object such as a NamedField with a 'name' attribute which in turn is the name + of a field as a string, such as a NamedField. + + inline_numbers: The inline numbers for which traces are to be extracted. + This argument can be specified in three ways: + + None (the default) - All traces within the each crossline will be be extracted. + + sequence - When a sequence, such as a range or a list is provided only those traces at + inline numbers corresponding to the items in the sequence will be extracted. The + traces will always be extracted in increasing numeric order and duplicate entries + will be ignored. For example inline_numbers=range(100, 200, 2) will extract alternate + traces from inline number 100 to inline number 198 inclusive. + + slice - When a slice object is provided the slice will be applied to the sequence of all + inline numbers. For example inline_numbers=slice(100, -100) will omit the first + one hundred and the last one hundred traces, irrespective of their numbers. + + xline_numbers: The crossline numbers at which traces are to be extracted. + This argument can be specified in three ways: + + None (the default) - All traces at within each inline will be be extracted. + + sequence - When a sequence, such as a range or a list is provided only those traces at + crossline numbers corresponding to the items in the sequence will be extracted. The + traces will always be extracted in increasing numeric order and duplicate entries + will be ignored. For example xline_numbers=range(100, 200, 2) will extract alternate + traces from crossline number 100 to crossline number 198 inclusive. + + slice - When a slice object is provided the slice will be applied to the sequence of all + crossline numbers. For example xline_numbers=slice(100, -100) will omit the first + one hundred and the last one hundred traces, irrespective of their numbers. null: An optional null value for missing traces. The null value must be convertible to all field value types. @@ -37,14 +67,17 @@ def extract_trace_header_field_3d(reader, fields, null=None): """ field_names = [_extract_field_name(field) for field in fields] + inline_numbers = ensure_superset(reader_3d.inline_numbers(), inline_numbers) + xline_numbers = ensure_superset(reader_3d.xline_numbers(), xline_numbers) + shape = (len(inline_numbers), len(xline_numbers)) + class SubHeader(metaclass=SubFormatMeta, - parent_format=reader.trace_header_format_class, + parent_format=reader_3d.trace_header_format_class, parent_field_names=field_names): pass - sub_header_packer = make_header_packer(SubHeader, reader.endian) + sub_header_packer = make_header_packer(SubHeader, reader_3d.endian) TraceHeaderArrays = namedtuple('TraceHeaderArrays', field_names) - shape = (reader.num_inlines(), reader.num_xlines()) arrays = (_make_array(shape, make_dtype(getattr(SubHeader, field_name).value_type.SEG_Y_TYPE), @@ -53,16 +86,16 @@ def extract_trace_header_field_3d(reader, fields, null=None): trace_header_arrays = TraceHeaderArrays(*arrays) - for inline_xline in reader.inline_xline_numbers(): - inline_number, xline_number = inline_xline - trace_index = reader.trace_index(inline_xline) - trace_header = reader.trace_header(trace_index, sub_header_packer) - inline_index = reader.inline_numbers().index(inline_number) - xline_index = reader.xline_numbers().index(xline_number) + for inline_index, inline_number in enumerate(inline_numbers): + for xline_index, xline_number in enumerate(xline_numbers): + inline_xline_number = (inline_number, xline_number) + if reader_3d.has_trace_index(inline_xline_number): + trace_index = reader_3d.trace_index((inline_number, xline_number)) + trace_header = reader_3d.trace_header(trace_index, sub_header_packer) - for field_name, a in zip(field_names, trace_header_arrays): - field_value = getattr(trace_header, field_name) - a[inline_index, xline_index] = field_value + for field_name, a in zip(field_names, trace_header_arrays): + field_value = getattr(trace_header, field_name) + a[inline_index, xline_index] = field_value return trace_header_arrays @@ -151,7 +184,7 @@ def extract_inline_3d(reader_3d, inline_number, xline_numbers=None, sample_numbe a regular array will be returned. The first (slowest changing) index will correspond to the traces (index zero will correspond to the first crossline number). The second (fastest changing) index will correspond to the samples (index zero will - correspond to the first sample number. + correspond to the first sample number). """ if inline_number not in reader_3d.inline_numbers(): raise ValueError("Inline number {} not present in {}".format(inline_number, reader_3d)) @@ -195,6 +228,95 @@ def _populate_inline_array_over_sample_range(reader, inline_number, xline_number array[xline_index, :] = trace_samples[source_slice] +def extract_xline_3d(reader_3d, xline_number, inline_numbers=None, sample_numbers=None, null=None): + """Extract an inline as a two-dimensional array. + + Args: + reader: A SegYReader3D object. + + xline_number: The number of the xline to be extracted. + + inline_numbers: The inline numbers within the crossline at which traces are to be extracted. + This argument can be specified in three ways: + + None (the default) - All traces within the crossline will be be extracted. + + sequence - When a sequence, such as a range or a list is provided only those traces at + inline numbers corresponding to the items in the sequence will be extracted. The + traces will always be extracted in increasing numeric order and duplicate entries + will be ignored. For example inline_numbers=range(100, 200, 2) will extract alternate + traces from inline number 100 to inline number 198 inclusive. + + slice - When a slice object is provided the slice will be applied to the sequence of all + inline numbers. For example inline_numbers=slice(100, -100) will omit the first + one hundred and the last one hundred traces, irrespective of their numbers. + + sample_numbers: The sample numbers within each trace at which samples are to be extracted. + This argument can be specified in three ways: + + None (the default) - All samples within the trace will be be extracted. + + sequence - When a sequence, such as a range or a list is provided only those samples at + sample numbers corresponding to the items in the sequence will be extracted. The + samples will always be extracted in increasing numeric order and duplicate entries + will be ignored. For example sample_numbers=range(100, 200, 2) will extract alternate + samples from sample number 100 to sample number 198 inclusive. + + slice - When a slice object is provided the slice will be applied to the sequence of all + sample numbers. For example sample_numbers=slice(100, -100) will omit the first + one hundred and the last one hundred samples, irrespective of their numbers. + + null: A null value. When None is specified as the null value a masked array will be returned. + + Returns: + A two-dimensional array. If null is None a masked array will be returned, otherwise + a regular array will be returned. The first (slowest changing) index will correspond + to the traces (index zero will correspond to the first inline number). The + second (fastest changing) index will correspond to the samples (index zero will + correspond to the first sample number). + """ + if xline_number not in reader_3d.xline_numbers(): + raise ValueError("Crossline number {} not present in {}".format(xline_number, reader_3d)) + + inline_numbers = ensure_superset(reader_3d.inline_numbers(), inline_numbers) + sample_numbers = ensure_superset(range(0, reader_3d.max_num_trace_samples()), sample_numbers) + shape = (len(inline_numbers), len(sample_numbers)) + dtype = make_dtype(reader_3d.data_sample_format) + array = _make_array(shape, dtype, null) + + if isinstance(sample_numbers, range): + _populate_xline_array_over_sample_range(reader_3d, xline_number, inline_numbers, sample_numbers, array) + else: + _populate_xline_array_numbered_samples(reader_3d, xline_number, inline_numbers, sample_numbers, array) + + return array + + +def _populate_xline_array_numbered_samples(reader, xline_number, inline_numbers, sample_numbers, array): + for inline_index, inline_number in enumerate(inline_numbers): + inline_xline_number = (inline_number, xline_number) + if reader.has_trace_index(inline_xline_number): + trace_index = reader.trace_index(inline_xline_number) + num_trace_samples = reader.num_trace_samples(trace_index) + trace_sample_start = sample_numbers[0] + trace_sample_stop = min(sample_numbers[-1] + 1, num_trace_samples) + trace_samples = reader.trace_samples(trace_index, trace_sample_start, trace_sample_stop) + for sample_index, sample_number in enumerate(sample_numbers): + array[inline_index, sample_index] = trace_samples[sample_number - trace_sample_start] + + +def _populate_xline_array_over_sample_range(reader, xline_number, inline_numbers, sample_numbers, array): + for inline_index, inline_number in enumerate(inline_numbers): + inline_xline_number = (inline_number, xline_number) + if reader.has_trace_index(inline_xline_number): + trace_index = reader.trace_index(inline_xline_number) + num_trace_samples = reader.num_trace_samples(trace_index) + trace_sample_stop = min(sample_numbers.stop, num_trace_samples) + trace_samples = reader.trace_samples(trace_index, sample_numbers.start, trace_sample_stop) + source_slice = slice(sample_numbers.start, trace_sample_stop, sample_numbers.step) + array[inline_index, :] = trace_samples[source_slice] + + def _make_array(shape, dtype, null=None): """Make an array""" if null is None: