Beispiel #1
0
def test_wellbore_interp_title(tmp_model):
    # Create a feature and interp objects
    feature_name = 'well A'
    well_feature = rqo.WellboreFeature(tmp_model, feature_name = feature_name)
    well_feature.create_xml()
    well_interp_1 = rqo.WellboreInterpretation(tmp_model, wellbore_feature = well_feature, is_drilled = True)
    well_interp_1.create_xml()

    # Create a duplicate object, loading from XML
    well_interp_2 = rqo.WellboreInterpretation(tmp_model, uuid = well_interp_1.uuid)

    # Check feature name is present
    assert well_interp_1.title == feature_name
    assert well_interp_2.title == feature_name
Beispiel #2
0
    def create_feature_and_interpretation(self):
        """Instantiate new empty WellboreFeature and WellboreInterpretation objects, if a wellboreinterpretation does

        not already exist.

        Uses the trajectory citation title as the well name
        """

        log.debug("Creating a new WellboreInterpretation..")
        log.debug(
            f"WellboreFeature exists: {self.wellbore_feature is not None}")
        log.debug(
            f"WellboreInterpretation exists: {self.wellbore_interpretation is not None}"
        )

        if self.wellbore_interpretation is None:
            log.info(
                f"Creating WellboreInterpretation and WellboreFeature with name {self.title}"
            )
            self.wellbore_feature = rqo.WellboreFeature(
                parent_model=self.model, feature_name=self.title)
            self.wellbore_interpretation = rqo.WellboreInterpretation(
                parent_model=self.model,
                wellbore_feature=self.wellbore_feature)
            self.feature_and_interpretation_to_be_written = True
        else:
            raise ValueError(
                "Cannot add WellboreFeature, trajectory already has an associated WellboreInterpretation"
            )
Beispiel #3
0
    def _load_from_xml(self):
        """Loads the trajectory object from an xml node (and associated hdf5 data)."""

        node = self.root
        assert node is not None
        self.start_md = float(
            rqet.node_text(rqet.find_tag(node, 'StartMd')).strip())
        self.finish_md = float(
            rqet.node_text(rqet.find_tag(node, 'FinishMd')).strip())
        self.md_uom = rqet.length_units_from_node(rqet.find_tag(node, 'MdUom'))
        self.md_domain = rqet.node_text(rqet.find_tag(node, 'MdDomain'))
        geometry_node = rqet.find_tag(node, 'Geometry')
        self.crs_uuid = bu.uuid_from_string(
            rqet.find_nested_tags_text(geometry_node, ['LocalCrs', 'UUID']))
        self.knot_count = int(
            rqet.node_text(rqet.find_tag(geometry_node, 'KnotCount')).strip())
        self.line_kind_index = int(
            rqet.node_text(rqet.find_tag(geometry_node,
                                         'LineKindIndex')).strip())
        mds_node = rqet.find_tag(geometry_node, 'ControlPointParameters')
        if mds_node is not None:  # not required for vertical or z linear cubic spline
            load_hdf5_array(self, mds_node, 'measured_depths')
        control_points_node = rqet.find_tag(geometry_node, 'ControlPoints')
        load_hdf5_array(self,
                        control_points_node,
                        'control_points',
                        tag='Coordinates')
        tangents_node = rqet.find_tag(geometry_node, 'TangentVectors')
        if tangents_node is not None:
            load_hdf5_array(self,
                            tangents_node,
                            'tangent_vectors',
                            tag='Coordinates')
        relatives_model = self.model  # if hdf5_source_model is None else hdf5_source_model
        # md_datum - separate part, referred to in this tree
        md_datum_uuid = bu.uuid_from_string(
            rqet.find_nested_tags_text(node, ['MdDatum', 'UUID']))
        assert md_datum_uuid is not None, 'failed to fetch uuid of md datum for trajectory'
        md_datum_part = relatives_model.part_for_uuid(md_datum_uuid)
        assert md_datum_part, 'md datum part not found in model'
        self.md_datum = MdDatum(
            self.model, uuid=relatives_model.uuid_for_part(md_datum_part))
        ds_uuid = bu.uuid_from_string(
            rqet.find_nested_tags_text(node, ['DeviationSurvey', 'UUID']))
        if ds_uuid is not None:  # this will probably not work when relatives model is different from self.model
            ds_uuid = self.model.uuid(obj_type='DeviationSurveyRepresentation',
                                      uuid=ds_uuid)  # check part is present
            if ds_uuid is not None:
                self.deviation_survey = DeviationSurvey(self.model,
                                                        uuid=ds_uuid)
        interp_uuid = rqet.find_nested_tags_text(
            node, ['RepresentedInterpretation', 'UUID'])
        if interp_uuid is None:
            self.wellbore_interpretation = None
        else:
            self.wellbore_interpretation = rqo.WellboreInterpretation(
                self.model, uuid=interp_uuid)
Beispiel #4
0
    def _load_related_wellbore_interp(self):
        """Return related wellbore interp object from XML if present."""

        interp_uuid = rqet.find_nested_tags_text(self.root, ['RepresentedInterpretation', 'UUID'])
        if interp_uuid is None:
            represented_interp = None
        else:
            represented_interp = rqo.WellboreInterpretation(self.model, uuid = interp_uuid)
        return represented_interp
Beispiel #5
0
def _iter_wellbore_interpretations(model):
    """Iterable of all WellboreInterpretations associated with the model."""

    import resqpy.organize as rqo  # imported here for speed, module is not always needed

    uuids = _uuids(model, obj_type='WellboreInterpretation')
    if uuids:
        for uuid in uuids:
            yield rqo.WellboreInterpretation(model, uuid=uuid)
Beispiel #6
0
    def create_feature_and_interpretation(self):
        """Instantiate new empty WellboreFeature and WellboreInterpretation objects, if a wellboreinterpretation does

        not already exist.

        Uses the wellboreframe citation title as the well name
        """

        if self.wellbore_interpretation is None:
            log.info(
                f"Creating WellboreInterpretation and WellboreFeature with name {self.title}"
            )
            self.wellbore_feature = rqo.WellboreFeature(
                parent_model=self.model, feature_name=self.title)
            self.wellbore_interpretation = rqo.WellboreInterpretation(
                parent_model=self.model,
                wellbore_feature=self.wellbore_feature)
            self.feature_and_interpretation_to_be_written = True
        else:
            log.info("WellboreInterpretation already exists")
Beispiel #7
0
    def _load_from_xml(self):
        """Loads the wellbore frame object from an xml node (and associated hdf5 data)."""

        # NB: node is the root level xml node, not a node in the md list!

        node = self.root
        assert node is not None

        trajectory_uuid = bu.uuid_from_string(
            rqet.find_nested_tags_text(node, ['Trajectory', 'UUID']))
        assert trajectory_uuid is not None, 'wellbore frame trajectory reference not found in xml'
        if self.trajectory is None:
            self.trajectory = resqpy.well.Trajectory(self.model,
                                                     uuid=trajectory_uuid)
        else:
            assert bu.matching_uuids(
                self.trajectory.uuid,
                trajectory_uuid), 'wellbore frame trajectory uuid mismatch'

        self.node_count = rqet.find_tag_int(node, 'NodeCount')
        assert self.node_count is not None, 'node count not found in xml for wellbore frame'
        assert self.node_count > 1, 'fewer than 2 nodes for wellbore frame'

        mds_node = rqet.find_tag(node, 'NodeMd')
        assert mds_node is not None, 'wellbore frame measured depths hdf5 reference not found in xml'
        load_hdf5_array(self, mds_node, 'node_mds')

        assert self.node_mds is not None and self.node_mds.ndim == 1 and self.node_mds.size == self.node_count

        interp_uuid = rqet.find_nested_tags_text(
            node, ['RepresentedInterpretation', 'UUID'])
        if interp_uuid is None:
            self.wellbore_interpretation = None
        else:
            self.wellbore_interpretation = rqo.WellboreInterpretation(
                self.model, uuid=interp_uuid)

        # Create well log collection of all log data
        self.logs = rqp.WellLogCollection(frame=self)
Beispiel #8
0
def add_wells_from_ascii_file(model,
                              crs_uuid,
                              trajectory_file,
                              comment_character='#',
                              space_separated_instead_of_csv=False,
                              well_col='WELL',
                              md_col='MD',
                              x_col='X',
                              y_col='Y',
                              z_col='Z',
                              length_uom='m',
                              md_domain=None,
                              drilled=False):
    """Creates new md datum, trajectory, interpretation and feature objects for each well in an ascii file.

    arguments:
       crs_uuid (uuid.UUID): the unique identifier of the coordinate reference system applicable to the x,y,z data;
          if None, a default crs will be created, making use of the length_uom and z_inc_down arguments
       trajectory_file (string): the path of the ascii file holding the well trajectory data to be loaded
       comment_character (string, default '#'): character deemed to introduce a comment in the trajectory file
       space_separated_instead_of_csv (boolean, default False): if True, the columns in the trajectory file are space
          separated; if False, comma separated
       well_col (string, default 'WELL'): the heading for the column containing well names
       md_col (string, default 'MD'): the heading for the column containing measured depths
       x_col (string, default 'X'): the heading for the column containing X (usually easting) data
       y_col (string, default 'Y'): the heading for the column containing Y (usually northing) data
       z_col (string, default 'Z'): the heading for the column containing Z (depth or elevation) data
       length_uom (string, default 'm'): the units of measure for the measured depths; should be 'm' or 'ft'
       md_domain (string, optional): the source of the original deviation data; may be 'logger' or 'driller'
       drilled (boolean, default False): True should be used for wells that have been drilled; False otherwise (planned,
          proposed, or a location being studied)
       z_inc_down (boolean, default True): indicates whether z values increase with depth; only used in the creation
          of a default coordinate reference system; ignored if crs_uuid is not None

    returns:
       tuple of lists of objects: (feature_list, interpretation_list, trajectory_list, md_datum_list),

    notes:
       ascii file must be table with first line being column headers, with columns for WELL, MD, X, Y & Z;
       actual column names can be set with optional arguments;
       all the objects are added to the model, with array data being written to the hdf5 file for the trajectories;
       the md_domain and drilled values are stored in the RESQML metadata but are only for human information and do not
       generally affect computations
    """

    assert md_col and x_col and y_col and z_col
    md_col = str(md_col)
    x_col = str(x_col)
    y_col = str(y_col)
    z_col = str(z_col)
    if crs_uuid is None:
        crs_uuid = model.crs_uuid
    assert crs_uuid is not None, 'coordinate reference system not found when trying to add wells'

    try:
        df = pd.read_csv(trajectory_file,
                         comment=comment_character,
                         delim_whitespace=space_separated_instead_of_csv)
        if df is None:
            raise Exception
    except Exception:
        log.error('failed to read ascii deviation survey file: ' +
                  str(trajectory_file))
        raise
    if well_col and well_col not in df.columns:
        log.warning('well column ' + str(well_col) +
                    ' not found in ascii trajectory file: ' +
                    str(trajectory_file))
        well_col = None
    if well_col is None:
        for col in df.columns:
            if str(col).upper().startswith('WELL'):
                well_col = str(col)
                break
    else:
        well_col = str(well_col)
    assert well_col
    unique_wells = set(df[well_col])
    if len(unique_wells) == 0:
        log.warning('no well data found in ascii trajectory file: ' +
                    str(trajectory_file))
        # note: empty lists will be returned, below

    feature_list = []
    interpretation_list = []
    trajectory_list = []
    md_datum_list = []

    for well_name in unique_wells:

        log.debug('importing well: ' + str(well_name))
        # create single well data frame (assumes measured depths increasing)
        well_df = df[df[well_col] == well_name]
        # create a measured depth datum for the well and add as part
        first_row = well_df.iloc[0]
        if first_row[md_col] == 0.0:
            md_datum = MdDatum(model,
                               crs_uuid=crs_uuid,
                               location=(first_row[x_col], first_row[y_col],
                                         first_row[z_col]))
        else:
            md_datum = MdDatum(model,
                               crs_uuid=crs_uuid,
                               location=(first_row[x_col], first_row[y_col],
                                         0.0))  # sea level datum
        md_datum.create_xml(title=str(well_name))
        md_datum_list.append(md_datum)

        # create a well feature and add as part
        feature = rqo.WellboreFeature(model, feature_name=well_name)
        feature.create_xml()
        feature_list.append(feature)

        # create interpretation and add as part
        interpretation = rqo.WellboreInterpretation(model,
                                                    is_drilled=drilled,
                                                    wellbore_feature=feature)
        interpretation.create_xml(title_suffix=None)
        interpretation_list.append(interpretation)

        # create trajectory, write arrays to hdf5 and add as part
        trajectory = Trajectory(model,
                                md_datum=md_datum,
                                data_frame=well_df,
                                length_uom=length_uom,
                                md_domain=md_domain,
                                represented_interp=interpretation,
                                well_name=well_name)
        trajectory.write_hdf5()
        trajectory.create_xml(title=well_name)
        trajectory_list.append(trajectory)

    return (feature_list, interpretation_list, trajectory_list, md_datum_list)