Example #1
0
 def _create_feature_and_interpretation(model, feature_type, feature_name):
     # includes create_xml() for created organisational objects
     feature_type = feature_type.lower()
     assert feature_type in ['fault', 'horizon', 'geobody']
     if feature_type == 'fault':
         tbf = rqo.TectonicBoundaryFeature(model,
                                           kind='fault',
                                           feature_name=feature_name)
     else:
         tbf = rqo.GeneticBoundaryFeature(model,
                                          kind=feature_type,
                                          feature_name=feature_name)
     tbf.create_xml(reuse=True)
     if feature_type == 'fault':
         fi = rqo.FaultInterpretation(model,
                                      tectonic_boundary_feature=tbf,
                                      is_normal=True)
         # todo: set is_normal correctly
     elif feature_type == 'horizon':
         fi = rqo.HorizonInterpretation(model, genetic_boundary_feature=tbf)
         # todo: support boundary relation list and sequence stratigraphy surface
     else:  # geobody boundary
         fi = rqo.GeobodyBoundaryInterpretation(
             model, genetic_boundary_feature=tbf)
     fi.create_xml(reuse=True)
     return fi.uuid
Example #2
0
def test_GeobodyBoundary(tmp_model):

    gen = rqo.GeneticBoundaryFeature(tmp_model, kind = 'geobody boundary')
    gb = rqo.GeobodyBoundaryInterpretation(tmp_model, genetic_boundary_feature = gen)

    gen.create_xml()
    gb.create_xml()
    gb2 = rqo.GeobodyBoundaryInterpretation(tmp_model, uuid = gb.uuid)
    assert gb == gb2
Example #3
0
def test_Horizon(tmp_model):

    gen = rqo.GeneticBoundaryFeature(tmp_model, kind = 'horizon')
    hor = rqo.HorizonInterpretation(tmp_model,
                                    genetic_boundary_feature = gen,
                                    sequence_stratigraphy_surface = 'maximum flooding')

    gen.create_xml()
    hor.create_xml()

    hor2 = rqo.HorizonInterpretation(tmp_model, uuid = hor.uuid)
    assert hor2.sequence_stratigraphy_surface == hor.sequence_stratigraphy_surface
Example #4
0
def _add_single_surface(model, surf_file, surface_file_format, surface_role, quad_triangles, crs_uuid, rq_class,
                        hdf5_file, h5_mode, make_horizon_interpretations_and_features, ext_uuid):
    _, short_name = os.path.split(surf_file)
    dot = short_name.rfind('.')
    if dot > 0:
        short_name = short_name[:dot]

    log.info('surface ' + short_name + ' processing file: ' + surf_file + ' using format: ' + surface_file_format)
    if rq_class == 'surface':
        if surface_file_format == 'GOCAD-Tsurf':
            surface = rqs.Surface(model,
                                  tsurf_file = surf_file,
                                  surface_role = surface_role,
                                  quad_triangles = quad_triangles)
        else:
            surface = rqs.Surface(model,
                                  mesh_file = surf_file,
                                  mesh_format = surface_file_format,
                                  surface_role = surface_role,
                                  quad_triangles = quad_triangles)
    elif rq_class == 'mesh':
        if surface_file_format == 'GOCAD-Tsurf':
            log.info(f"Cannot convert a GOCAD-Tsurf to mesh, only to TriangulatedSurface - skipping file {surf_file}")
            return model
        else:
            surface = rqs.Mesh(model,
                               mesh_file = surf_file,
                               mesh_format = surface_file_format,
                               mesh_flavour = 'reg&z',
                               surface_role = surface_role,
                               crs_uuid = crs_uuid)
    else:
        log.critical('this is impossible')
    # NB. surface may be either a Surface object or a Mesh object

    log.debug('appending to hdf5 file for surface file: ' + surf_file)
    surface.write_hdf5(hdf5_file, mode = h5_mode)

    if make_horizon_interpretations_and_features:
        feature = rqo.GeneticBoundaryFeature(model, kind = 'horizon', feature_name = short_name)
        feature.create_xml()
        interp = rqo.HorizonInterpretation(model, genetic_boundary_feature = feature, domain = 'depth')
        interp_root = interp.create_xml()
        surface.set_represented_interpretation_root(interp_root)

    surface.create_xml(ext_uuid,
                       add_as_part = True,
                       add_relationships = True,
                       title = short_name + ' sourced from ' + surf_file,
                       originator = None)

    return model
Example #5
0
File: _common.py Project: bp/resqpy
    def create_interpretation_and_feature(self,
                                          kind='horizon',
                                          name=None,
                                          interp_title_suffix=None,
                                          is_normal=True):
        """Creates xml and objects for a represented interpretaion and interpreted feature, if not already present."""

        assert kind in ['horizon', 'fault', 'fracture', 'geobody boundary']
        assert name or self.title, 'title missing'
        if not name:
            name = self.title

        if self.rep_int_root is not None:
            log.debug(
                f'represented interpretation already exisrs for surface {self.title}'
            )
            return
        if kind in ['horizon', 'geobody boundary']:
            feature = rqo.GeneticBoundaryFeature(self.model,
                                                 kind=kind,
                                                 feature_name=name)
            feature.create_xml()
            if kind == 'horizon':
                interp = rqo.HorizonInterpretation(
                    self.model,
                    genetic_boundary_feature=feature,
                    domain='depth')
            else:
                interp = rqo.GeobodyBoundaryInterpretation(
                    self.model,
                    genetic_boundary_feature=feature,
                    domain='depth')
        elif kind in ['fault', 'fracture']:
            feature = rqo.TectonicBoundaryFeature(self.model,
                                                  kind=kind,
                                                  feature_name=name)
            feature.create_xml()
            interp = rqo.FaultInterpretation(
                self.model,
                is_normal=is_normal,
                tectonic_boundary_feature=feature,
                domain='depth')  # might need more arguments
        else:
            log.critical('code failure')
        interp_root = interp.create_xml(title_suffix=interp_title_suffix)
        self.rep_int_root = interp_root
Example #6
0
def _make_k_gcs_from_cip_list(grid, cip_list, feature_name):
    # cip (cell index pair) list contains pairs of natural cell indices for which k connection is required
    # first of pair is layer above (lower k to be precise), second is below (higher k)
    # called by pinchout_connection_set() and k_gap_connection_set() functions

    from resqpy.fault._grid_connection_set import GridConnectionSet

    count = len(cip_list)

    if count == 0:
        return None

    pcs = GridConnectionSet(grid.model)
    pcs.grid_list = [grid]
    pcs.count = count
    pcs.grid_index_pairs = np.zeros((count, 2), dtype=int)
    pcs.cell_index_pairs = np.array(cip_list, dtype=int)
    pcs.face_index_pairs = np.zeros((count, 2),
                                    dtype=int)  # initialize to top faces
    pcs.face_index_pairs[:, 0] = 1  # bottom face of cells above pinchout

    pcs.feature_indices = np.zeros(
        count,
        dtype=int)  # could create seperate features by layer above or below?
    gbf = rqo.GeneticBoundaryFeature(grid.model,
                                     kind='horizon',
                                     feature_name=feature_name)
    gbf_root = gbf.create_xml()
    fi = rqo.HorizonInterpretation(grid.model, genetic_boundary_feature=gbf)
    fi_root = fi.create_xml(gbf_root, title_suffix=None)
    fi_uuid = rqet.uuid_for_part_root(fi_root)

    pcs.feature_list = [('obj_HorizonInterpretation', fi_uuid,
                         str(feature_name))]

    return pcs
Example #7
0
def test_property_collection(example_model_and_crs):
    # Create a WellboreMarkerFrame object
    # Load example model from a fixture
    model, crs = example_model_and_crs

    # Create a trajectory
    well_name = 'Banoffee'
    elevation = 100
    datum = resqpy.well.MdDatum(parent_model=model,
                                crs_uuid=crs.uuid,
                                location=(0, 0, -elevation),
                                md_reference='kelly bushing')
    mds = np.array([300.0, 310.0, 330.0])
    zs = mds - elevation
    source_dataframe = pd.DataFrame({
        'MD': mds,
        'X': [150.0, 165.0, 180.0],
        'Y': [240.0, 260.0, 290.0],
        'Z': zs,
    })
    trajectory = resqpy.well.Trajectory(parent_model=model,
                                        data_frame=source_dataframe,
                                        well_name=well_name,
                                        md_datum=datum,
                                        length_uom='m')
    trajectory.write_hdf5()
    trajectory.create_xml()
    trajectory_uuid = trajectory.uuid

    # Create features and interpretations
    horizon_feature_1 = rqo.GeneticBoundaryFeature(
        parent_model=model, kind='horizon', feature_name='horizon_feature_1')
    horizon_feature_1.create_xml()
    horizon_interp_1 = rqo.HorizonInterpretation(
        parent_model=model,
        title='horizon_interp_1',
        genetic_boundary_feature=horizon_feature_1,
        sequence_stratigraphy_surface='flooding',
        boundary_relation_list=['conformable'])
    horizon_interp_1.create_xml()

    woc_feature_1 = rqo.FluidBoundaryFeature(parent_model=model,
                                             kind='water oil contact',
                                             feature_name='woc_1')
    # fluid boundary feature does not have an associated interpretation
    woc_feature_1.create_xml()

    fault_feature_1 = rqo.TectonicBoundaryFeature(
        parent_model=model, kind='fault', feature_name='fault_feature_1')
    fault_feature_1.create_xml()
    fault_interp_1 = rqo.FaultInterpretation(
        parent_model=model,
        title='fault_interp_1',
        tectonic_boundary_feature=fault_feature_1,
        is_normal=True,
        maximum_throw=15)
    fault_interp_1.create_xml()

    df = pd.DataFrame({
        'MD': [400.0, 410.0, 430.0],
        'Boundary_Feature_Type': ['horizon', 'water oil contact', 'fault'],
        'Marker_Citation_Title':
        ['marker_horizon_1', 'marker_woc_1', 'marker_fault_1'],
        'Interp_Citation_Title': ['horizon_interp_1', None, 'fault_interp_1'],
    })

    # Create a wellbore marker frame from a dataframe
    wellbore_marker_frame = resqpy.well.WellboreMarkerFrame.from_dataframe(
        parent_model=model,
        dataframe=df,
        trajectory_uuid=trajectory_uuid,
        title='WBF1',
        originator='Human',
        extra_metadata={'target_reservoir': 'treacle'})
    wellbore_marker_frame.write_hdf5()
    wellbore_marker_frame.create_xml()

    # create a property collection for the wellbore marker frame and add a couple of properties
    pc = rqp.PropertyCollection(support=wellbore_marker_frame)
    assert pc is not None
    node_prop = np.array([123.45, -456.78, 987.65])
    pc.add_cached_array_to_imported_list(node_prop,
                                         source_info='unit test',
                                         keyword='node prop',
                                         uom='m',
                                         property_kind='length',
                                         indexable_element='nodes')
    interval_prop = np.array([3, 1], dtype=int)
    pc.add_cached_array_to_imported_list(interval_prop,
                                         source_info='unit test',
                                         keyword='interval prop',
                                         discrete=True,
                                         null_value=-1,
                                         property_kind='discrete',
                                         indexable_element='intervals')
    pc.write_hdf5_for_imported_list()
    pc.create_xml_for_imported_list_and_add_parts_to_model()
    del pc

    # reload the property collection
    pc = rqp.PropertyCollection(support=wellbore_marker_frame)
    node_prop_part = model.part(obj_type='ContinuousProperty',
                                title='node prop')
    interval_prop_part = model.part(obj_type='DiscreteProperty',
                                    title='interval prop')

    # check the property arrays
    assert pc is not None
    assert pc.number_of_parts() == 2
    assert node_prop_part is not None
    assert interval_prop_part is not None
    assert node_prop_part in pc.parts()
    assert interval_prop_part in pc.parts()
    assert_array_almost_equal(pc.cached_part_array_ref(node_prop_part),
                              [123.45, -456.78, 987.65])
    int_prop_array = pc.cached_part_array_ref(interval_prop_part)
    assert int_prop_array.size == 2
    assert np.all(int_prop_array == (3, 1))
Example #8
0
def test_find_marker_from_index(example_model_and_crs):
    # --------- Arrange ----------
    # Create a WellboreMarkerFrame object in memory
    # Load example model from a fixture
    model, crs = example_model_and_crs

    # Create a trajectory
    well_name = 'Banoffee'
    elevation = 100
    datum = resqpy.well.MdDatum(parent_model=model,
                                crs_uuid=crs.uuid,
                                location=(0, 0, -elevation),
                                md_reference='kelly bushing')
    mds = np.array([300.0, 310.0, 330.0])
    zs = mds - elevation
    source_dataframe = pd.DataFrame({
        'MD': mds,
        'X': [150.0, 165.0, 180.0],
        'Y': [240.0, 260.0, 290.0],
        'Z': zs,
    })
    trajectory = resqpy.well.Trajectory(parent_model=model,
                                        data_frame=source_dataframe,
                                        well_name=well_name,
                                        md_datum=datum,
                                        length_uom='m')
    trajectory.write_hdf5()
    trajectory.create_xml()
    trajectory_uuid = trajectory.uuid

    # Create features and interpretations
    horizon_feature_1 = rqo.GeneticBoundaryFeature(
        parent_model=model, kind='horizon', feature_name='horizon_feature_1')
    horizon_feature_1.create_xml()
    horizon_interp_1 = rqo.HorizonInterpretation(
        parent_model=model,
        title='horizon_interp_1',
        genetic_boundary_feature=horizon_feature_1,
        sequence_stratigraphy_surface='flooding',
        boundary_relation_list=['conformable'])
    horizon_interp_1.create_xml()

    woc_feature_1 = rqo.FluidBoundaryFeature(parent_model=model,
                                             kind='water oil contact',
                                             feature_name='woc_1')
    # fluid boundary feature does not have an associated interpretation
    woc_feature_1.create_xml()

    fault_feature_1 = rqo.TectonicBoundaryFeature(
        parent_model=model, kind='fault', feature_name='fault_feature_1')
    fault_feature_1.create_xml()
    fault_interp_1 = rqo.FaultInterpretation(
        parent_model=model,
        title='fault_interp_1',
        tectonic_boundary_feature=fault_feature_1,
        is_normal=True,
        maximum_throw=15)
    fault_interp_1.create_xml()

    df = pd.DataFrame({
        'MD': [400.0, 410.0, 430.0],
        'Boundary_Feature_Type': ['horizon', 'water oil contact', 'fault'],
        'Marker_Citation_Title':
        ['marker_horizon_1', 'marker_woc_1', 'marker_fault_1'],
        'Interp_Citation_Title': ['horizon_interp_1', None, 'fault_interp_1'],
    })

    # Create a wellbore marker frame from a dataframe
    wellbore_marker_frame = resqpy.well.WellboreMarkerFrame.from_dataframe(
        parent_model=model,
        dataframe=df,
        trajectory_uuid=trajectory_uuid,
        title='WBF1',
        originator='Human',
        extra_metadata={'target_reservoir': 'treacle'})

    # --------- Act ----------
    # Find marker indices based on interpretation uuids
    found_woc_marker = wellbore_marker_frame.find_marker_from_index(idx=1)
    index_error_result = wellbore_marker_frame.find_marker_from_index(idx=5)

    # --------- Assert ----------
    assert bu.matching_uuids(wellbore_marker_frame.marker_list[1].uuid,
                             found_woc_marker.uuid)
    assert index_error_result is None
Example #9
0
def test_from_dataframe_and_dataframe(example_model_and_crs):
    # Test that a WellboreMarkerFrame object can be correctly instantiated from a source dataframe and verify that the
    # dataframe generated by the dataframe() method matches the source dataframe

    # --------- Arrange ----------
    # Create a WellboreMarkerFrame object in memory
    # Load example model from a fixture
    model, crs = example_model_and_crs
    epc_path = model.epc_file

    # Create a trajectory
    well_name = 'Banoffee'
    elevation = 100
    datum = resqpy.well.MdDatum(parent_model=model,
                                crs_uuid=crs.uuid,
                                location=(0, 0, -elevation),
                                md_reference='kelly bushing')
    mds = np.array([300.0, 310.0, 330.0])
    zs = mds - elevation
    source_dataframe = pd.DataFrame({
        'MD': mds,
        'X': [150.0, 165.0, 180.0],
        'Y': [240.0, 260.0, 290.0],
        'Z': zs,
    })
    trajectory = resqpy.well.Trajectory(parent_model=model,
                                        data_frame=source_dataframe,
                                        well_name=well_name,
                                        md_datum=datum,
                                        length_uom='m')
    trajectory.write_hdf5()
    trajectory.create_xml()
    trajectory_uuid = trajectory.uuid

    # Create features and interpretations
    horizon_feature_1 = rqo.GeneticBoundaryFeature(
        parent_model=model, kind='horizon', feature_name='horizon_feature_1')
    horizon_feature_1.create_xml()
    horizon_interp_1 = rqo.HorizonInterpretation(
        parent_model=model,
        title='horizon_interp_1',
        genetic_boundary_feature=horizon_feature_1,
        sequence_stratigraphy_surface='flooding',
        boundary_relation_list=['conformable'])
    horizon_interp_1.create_xml()

    woc_feature_1 = rqo.FluidBoundaryFeature(parent_model=model,
                                             kind='water oil contact',
                                             feature_name='woc_1')
    # fluid boundary feature does not have an associated interpretation
    woc_feature_1.create_xml()

    fault_feature_1 = rqo.TectonicBoundaryFeature(
        parent_model=model, kind='fault', feature_name='fault_feature_1')
    fault_feature_1.create_xml()
    fault_interp_1 = rqo.FaultInterpretation(
        parent_model=model,
        title='fault_interp_1',
        tectonic_boundary_feature=fault_feature_1,
        is_normal=True,
        maximum_throw=15)
    fault_interp_1.create_xml()

    df = pd.DataFrame({
        'MD': [400.0, 410.0, 430.0],
        'Boundary_Feature_Type': ['horizon', 'water oil contact', 'fault'],
        'Marker_Citation_Title':
        ['marker_horizon_1', 'marker_woc_1', 'marker_fault_1'],
        'Interp_Citation_Title': ['horizon_interp_1', None, 'fault_interp_1'],
    })

    # Create a wellbore marker frame from a dataframe
    wellbore_marker_frame = resqpy.well.WellboreMarkerFrame.from_dataframe(
        parent_model=model,
        dataframe=df,
        trajectory_uuid=trajectory_uuid,
        title='WBF1',
        originator='Human',
        extra_metadata={'target_reservoir': 'treacle'})
    # --------- Act ----------
    # Save to disk
    wellbore_marker_frame.write_hdf5()
    wellbore_marker_frame.create_xml()
    wmf_uuid = wellbore_marker_frame.uuid  # called after create_xml method as it can alter the uuid
    # get the uuids of each of the markers
    marker_uuids = []
    for marker in wellbore_marker_frame.marker_list:
        marker_uuids.append(marker.uuid)
    model.store_epc()
    model.h5_release()

    # Clear memory
    del model, wellbore_marker_frame, datum, trajectory

    # Reload from disk
    model2 = Model(epc_file=epc_path)
    wellbore_marker_frame2 = resqpy.well.WellboreMarkerFrame(
        parent_model=model2, uuid=wmf_uuid)

    # Get the uuids of each of the markers
    marker_uuids2 = []
    for marker in wellbore_marker_frame2.marker_list:
        marker_uuids2.append(marker.uuid)

    # Create a dataframe from the attributes of the new wellbore marker frame object
    df2 = wellbore_marker_frame2.dataframe()
    df2_filtered_cols = df2[[
        'MD', 'Boundary_Feature_Type', 'Marker_Citation_Title',
        'Interp_Citation_Title'
    ]]

    # --------- Assert ----------
    # test that the attributes were reloaded correctly
    assert bu.matching_uuids(wellbore_marker_frame2.trajectory_uuid,
                             trajectory_uuid)
    assert wellbore_marker_frame2.node_count == len(
        wellbore_marker_frame2.node_mds) == len(
            wellbore_marker_frame2.marker_list) == 3
    assert wellbore_marker_frame2.title == 'WBF1'
    assert wellbore_marker_frame2.originator == 'Human'
    assert wellbore_marker_frame2.extra_metadata == {
        'target_reservoir': 'treacle'
    }
    np.testing.assert_almost_equal(wellbore_marker_frame2.node_mds,
                                   np.array([400.0, 410.0, 430.0]))
    for uuid1, uuid2 in zip(marker_uuids, marker_uuids2):
        assert bu.matching_uuids(uuid1, uuid2)
    # test that the generated dataframe contains the same data as the original df
    pd.testing.assert_frame_equal(df, df2_filtered_cols, check_dtype=False)
Example #10
0
def test_load_from_xml(example_model_and_crs):

    # --------- Arrange ----------
    model, crs = example_model_and_crs
    epc_path = model.epc_file
    elevation = 100
    # Create a measured depth datum
    datum = resqpy.well.MdDatum(parent_model=model,
                                crs_uuid=crs.uuid,
                                location=(0, 0, -elevation),
                                md_reference='kelly bushing')
    datum.create_xml()
    mds = np.array([300, 310, 330, 340])
    zs = mds - elevation
    well_name = 'JubJub'
    source_dataframe = pd.DataFrame({
        'MD':
        mds,
        'X': [1, 2, 3, 4],
        'Y': [1, 2, 3, 4],
        'Z':
        zs,
        'WELL': ['JubJub', 'JubJub', 'JubJub', 'JubJub']
    })

    # Create a trajectory from dataframe
    trajectory = resqpy.well.Trajectory(parent_model=model,
                                        data_frame=source_dataframe,
                                        well_name=well_name,
                                        md_datum=datum,
                                        length_uom='m')
    trajectory.write_hdf5()
    trajectory.create_xml()
    trajectory_uuid = trajectory.uuid

    # Create a wellbore marker frame
    wellbore_marker_frame = resqpy.well.WellboreMarkerFrame(
        parent_model=model,
        trajectory_uuid=trajectory_uuid,
        title='WMF1',
        originator='Person1',
        extra_metadata={'target_reservoir': 'r1'})
    wellbore_marker_frame.create_xml()

    # Create several boundary features and interpretations
    horizon_feature_1 = rqo.GeneticBoundaryFeature(
        parent_model=model, kind='horizon', feature_name='horizon_feature_1')
    horizon_feature_1.create_xml()
    horizon_interp_1 = rqo.HorizonInterpretation(
        parent_model=model,
        title='horizon_interp_1',
        genetic_boundary_feature=horizon_feature_1,
        sequence_stratigraphy_surface='flooding',
        boundary_relation_list=['conformable'])
    horizon_interp_1.create_xml()
    horizon_interp_uuid = horizon_interp_1.uuid

    fluid_contact_feature1 = rqo.FluidBoundaryFeature(parent_model=model,
                                                      kind="gas oil contact",
                                                      feature_name='goc_1')
    fluid_contact_feature1.create_xml()

    # --------- Act ----------
    # Create a wellbore marker object
    wellbore_marker_1 = resqpy.well.WellboreMarker(
        parent_model=model,
        parent_frame=wellbore_marker_frame,
        marker_index=0,
        marker_type='horizon',
        interpretation_uuid=horizon_interp_uuid,
        title='Horizon1_marker',
        extra_metadata={'FormationName': 'Banoffee'})
    wellbore_marker_1_uuid = wellbore_marker_1.uuid
    wellbore_marker_2 = resqpy.well.WellboreMarker(
        parent_model=model,
        parent_frame=wellbore_marker_frame,
        marker_index=1,
        marker_type='gas oil contact',
        title='GOC_marker')
    # Create xml for new wellbore markers
    wbm_node_1 = wellbore_marker_1.create_xml(
        parent_node=wellbore_marker_frame.root)
    wbm_node_2 = wellbore_marker_2.create_xml(
        parent_node=wellbore_marker_frame.root)

    # Load a new wellbore marker using a marker node
    wellbore_marker_3 = resqpy.well.WellboreMarker(
        parent_model=model,
        parent_frame=wellbore_marker_frame,
        marker_index=0,
        marker_node=wbm_node_1)

    # --------- Assert ----------
    assert rqet.find_tag_text(root=wbm_node_1,
                              tag_name='GeologicBoundaryKind') == 'horizon'
    assert rqet.find_tag_text(root=wbm_node_2,
                              tag_name='FluidContact') == 'gas oil contact'
    assert wellbore_marker_3 is not None
    assert wellbore_marker_3.title == 'Horizon1_marker'
    assert wellbore_marker_3.marker_type == 'horizon'
    assert bu.matching_uuids(wellbore_marker_3.interpretation_uuid,
                             horizon_interp_uuid)
    assert wellbore_marker_3.extra_metadata == {'FormationName': 'Banoffee'}
    assert bu.matching_uuids(wellbore_marker_3.uuid, wellbore_marker_1_uuid)