def _load_from_xml(self): root_node = self.root assert root_node is not None flavour = rqet.node_type(root_node) assert flavour in ['obj_LocalDepth3dCrs', 'obj_LocalTime3dCrs' ], f'bad crs node type: {flavour}' if flavour == 'obj_LocalTime3dCrs': self.time_units = rqet.find_tag_text(root_node, 'TimeUom') assert self.time_units else: self.time_units = None self.xy_units = rqet.find_tag_text(root_node, 'ProjectedUom') self.axis_order = rqet.find_tag_text(root_node, 'ProjectedAxisOrder') self.z_units = rqet.find_tag_text(root_node, 'VerticalUom') self.z_inc_down = rqet.find_tag_bool(root_node, 'ZIncreasingDownward') self.x_offset = rqet.find_tag_float(root_node, 'XOffset') self.y_offset = rqet.find_tag_float(root_node, 'YOffset') self.z_offset = rqet.find_tag_float(root_node, 'ZOffset') self.rotation = rqet.find_tag_float(root_node, 'ArealRotation') rotation_node = rqet.find_tag(root_node, 'ArealRotation') self.rotation_units = rotation_node.attrib.get('uom') parent_xy_crs = rqet.find_tag(root_node, 'ProjectedCrs') if parent_xy_crs is not None and rqet.node_type( parent_xy_crs) == 'ProjectedCrsEpsgCode': self.epsg_code = rqet.find_tag_text( parent_xy_crs, 'EpsgCode') # should be an integer? else: self.epsg_code = None
def _load_from_xml(self, bci_node): """Populates this binary contact interpretation based on existing xml. arguments: bci_node (lxml.etree._Element): the root xml node for the binary contact interpretation sub-tree """ assert bci_node is not None self.contact_relationship = rqet.find_tag_text(bci_node, 'ContactRelationship') assert self.contact_relationship in valid_contact_relationships, \ f'missing or invalid contact relationship {self.contact_relationship} in xml for binary contact interpretation' self.index = rqet.find_tag_int(bci_node, 'Index') assert self.index is not None, 'missing index in xml for binary contact interpretation' self.part_of_uuid = bu.uuid_from_string(rqet.find_nested_tags_text(bci_node, ['PartOf', 'UUID'])) sr_node = rqet.find_tag(bci_node, 'Subject') assert sr_node is not None, 'missing subject in xml for binary contact interpretation' self.subject_uuid = bu.uuid_from_string(rqet.find_tag_text(sr_node, 'UUID')) assert self.subject_uuid is not None self.subject_contact_side = rqet.find_tag_text(sr_node, 'Qualifier') self.subject_contact_mode = rqet.find_tag_text(sr_node, 'SecondaryQualifier') dor_node = rqet.find_tag(bci_node, 'DirectObject') assert dor_node is not None, 'missing direct object in xml for binary contact interpretation' self.direct_object_uuid = bu.uuid_from_string(rqet.find_tag_text(dor_node, 'UUID')) assert self.direct_object_uuid is not None self.direct_object_contact_side = rqet.find_tag_text(dor_node, 'Qualifier') self.direct_object_contact_mode = rqet.find_tag_text(dor_node, 'SecondaryQualifier') self.verb = rqet.find_tag_text(bci_node, 'Verb') assert self.verb in valid_contact_verbs, \ f'missing or invalid contact verb {self.verb} in xml for binary contact interpretation'
def _add_part_to_dict_get_property_kind(xml_node, citation_title): perm_synonyms = ['permeability rock', 'rock permeability'] (p_kind_from_keyword, facet_type, facet) = property_kind_and_facet_from_keyword(citation_title) prop_kind_node = rqet.find_tag(xml_node, 'PropertyKind') assert (prop_kind_node is not None) kind_node = rqet.find_tag(prop_kind_node, 'Kind') property_kind_uuid = None # only used for bespoke (local) property kinds if kind_node is not None: property_kind = kind_node.text # could check for consistency with that derived from citation title lpk_node = None else: lpk_node = rqet.find_tag(prop_kind_node, 'LocalPropertyKind') if lpk_node is not None: property_kind = rqet.find_tag_text(lpk_node, 'Title') property_kind_uuid = rqet.find_tag_text(lpk_node, 'UUID') assert property_kind is not None and len(property_kind) > 0 if (p_kind_from_keyword and p_kind_from_keyword != property_kind and (p_kind_from_keyword not in ['cell length', 'length', 'thickness'] or property_kind not in ['cell length', 'length', 'thickness'])): if property_kind not in perm_synonyms or p_kind_from_keyword not in perm_synonyms: log.warning( f'property kind {property_kind} not the expected {p_kind_from_keyword} for keyword {citation_title}' ) return property_kind, property_kind_uuid, lpk_node
def _load_from_xml(self): assert self.root is not None # polyline xml node is specified poly_root = self.root self.title = rqet.citation_title_for_node(poly_root) self.extra_metadata = rqet.load_metadata_from_xml(self.root) self.isclosed = rqet.bool_from_text( rqet.node_text(rqet.find_tag(poly_root, 'IsClosed'))) assert self.isclosed is not None # Required field patch_node = rqet.find_tag(poly_root, 'NodePatch') assert patch_node is not None # Required field geometry_node = rqet.find_tag(patch_node, 'Geometry') assert geometry_node is not None # Required field self.crs_uuid = bu.uuid_from_string( rqet.find_nested_tags_text(geometry_node, ['LocalCrs', 'UUID'])) assert self.crs_uuid is not None # Required field points_node = rqet.find_tag(geometry_node, 'Points') assert points_node is not None # Required field load_hdf5_array(self, points_node, 'coordinates', tag='Coordinates') self.nodepatch = (rqet.find_tag_int(patch_node, 'PatchIndex'), rqet.find_tag_int(patch_node, 'Count')) assert not any( map(lambda x: x is None, self.nodepatch)) # Required fields - assert neither are None self.rep_int_root = self.model.referenced_node( rqet.find_tag(poly_root, 'RepresentedInterpretation'))
def _process_complex_types(schema, complex_types): for completon in rqet.list_of_tag(schema, 'complexType'): name = completon.attrib['name'] doc = rqet.find_nested_tags_text(completon, ['annotation', 'documentation']) content = rqet.find_tag(completon, 'complexContent') extension = rqet.find_tag(content, 'extension') if extension is None: e_base = None else: e_base = extension.attrib['base'] content = extension if content is None: content = completon sequence = rqet.find_tag(content, 'sequence') if sequence is None: sequence = content element_list = [] e_nodes = rqet.list_of_tag(sequence, 'element') if e_nodes is not None: for element in e_nodes: e_name = element.attrib['name'] flavour = element.attrib[ 'type'] # could strip prefix here? min_occurs = element.get('minOccurs') max_occurs = element.get('maxOccurs') element_list.append( (e_name, flavour, min_occurs, max_occurs)) complex_types[name] = (e_base, element_list, doc)
def _referenced_node(model, ref_node, consolidate=False): """For a given xml reference node, returns the node for the object referred to, if present.""" # log.debug(f'ref node called for: {ref_node}') if ref_node is None: return None # content_type = rqet.find_tag_text(ref_node, 'ContentType') # log.debug(f'ref node title: {rqet.citation_title_for_node(rqet.find_tag(ref_node, "Title"))}') uuid = bu.uuid_from_string(rqet.find_tag_text(ref_node, 'UUID')) # log.debug(f'ref node uuid: {uuid}') if uuid is None: return None # return model.root_for_part(model.parts_list_of_type(type_of_interest = content_type, uuid = uuid)) if consolidate and model.consolidation is not None and uuid in model.consolidation.map: resident_uuid = model.consolidation.map[uuid] if resident_uuid is None: return None node = model.root_for_part(model.part_for_uuid(resident_uuid)) if node is not None: # patch resident uuid and title into ref node! uuid_node = rqet.find_tag(ref_node, 'UUID') uuid_node.text = str(resident_uuid) title_node = rqet.find_tag(ref_node, 'Title') if title_node is not None: title = rqet.citation_title_for_node(node) if title: title_node.text = str(title) else: node = model.root_for_part(model.part_for_uuid(uuid)) # log.debug(f'ref_node return node: {node}') return node
def _title_for_root(model, root=None): """Returns the Title text from the Citation within the given root node.""" title = rqet.find_tag(rqet.find_tag(root, 'Citation'), 'Title') if title is None: return None return title.text
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)
def extract_grid_parent(grid): """Returns the uuid of the parent grid for the supplied grid""" if grid.extent_kji is None: grid.extract_extent_kji() if grid.parent_grid_uuid is not None: return grid.parent_grid_uuid grid.parent_window = None # FineCoarse cell index mapping info with respect to parent grid.is_refinement = None pw_node = rqet.find_tag(grid.root, 'ParentWindow') if pw_node is None: return None # load a FineCoarse object as parent_window attribute and set parent_grid_uuid attribute grid.parent_grid_uuid = bu.uuid_from_string(rqet.find_nested_tags_text(pw_node, ['ParentGrid', 'UUID'])) assert grid.parent_grid_uuid is not None parent_grid_root = grid.model.root(uuid = grid.parent_grid_uuid) if parent_grid_root is None: log.warning('parent grid not present in model, unable to treat as local grid') return None # etxract parent grid extent directly from xml to avoid risk of circular references parent_grid_extent_kji = np.array((rqet.find_tag_int( parent_grid_root, 'Nk'), rqet.find_tag_int(parent_grid_root, 'Nj'), rqet.find_tag_int(parent_grid_root, 'Ni')), dtype = int) parent_initials = [] intervals_count_list = [] parent_count_list_list = [] child_count_list_list = [] child_weight_list_list = [] refining_flag = None # gets set True if local grid is a refinement, False if a coarsening parent_box = np.zeros((2, 3), dtype = int) for axis in range(3): refining_flag = __process_axis(axis, child_count_list_list, child_weight_list_list, grid, intervals_count_list, parent_box, parent_count_list_list, parent_grid_extent_kji, parent_initials, pw_node, refining_flag) cell_overlap_node = rqet.find_tag(pw_node, 'CellOverlap') if cell_overlap_node is not None: log.warning('ignoring cell overlap information in grid relationship') omit_node = rqet.find_tag(pw_node, 'OmitParentCells') if omit_node is not None: log.warning('unable to handle parent cell omissions in local grid definition – ignoring') # todo: handle omissions if refining_flag is None: log.warning('local grid has no refinement nor coarsening – treating as a refined grid') refining_flag = True grid.is_refinement = refining_flag if refining_flag: # local grid is a refinement __extract_refined_parent(child_count_list_list, child_weight_list_list, grid, intervals_count_list, parent_box, parent_count_list_list) else: # local grid is a coarsening __extract_coarsening_parent(child_count_list_list, child_weight_list_list, grid, intervals_count_list, parent_box, parent_count_list_list) grid.parent_window.assert_valid() return grid.parent_grid_uuid
def extract_crs_uuid(self): """Returns uuid for coordinate reference system, as stored in reference node of this md datum's xml tree.""" if self.crs_uuid is not None: return self.crs_uuid crs_root = rqet.find_tag(self.root, 'LocalCrs') uuid_str = rqet.find_tag(crs_root, 'UUID').text self.crs_uuid = bu.uuid_from_string(uuid_str) return self.crs_uuid
def create_xml(self, parent_node, title='wellbore marker'): """Creates the xml tree for this wellbore marker. arguments: parent_node (xml node): the root node of the WellboreMarkerFrame object to which the newly created node will be appended title (string, optional): the citation title of the newly created node note: if not None, self.title will be used instead of "wellbore marker" returns: the newly created xml node """ assert self.uuid is not None wbm_node = self.model.new_obj_node('WellboreMarker', is_top_lvl_obj=False) wbm_node.set('uuid', str(self.uuid)) # Citation block if self.title is not None: title = self.title citation = self.model.create_citation(root=wbm_node, title=title, originator=self.originator) # Add sub-elements to root node for k, v in WellboreMarker.boundary_feature_dict.items(): if self.marker_type in v: boundary_kind = k break wbm_gb_node = rqet.SubElement(wbm_node, ns['resqml2'] + boundary_kind) # wbm_gb_node.set(ns['xsi'] + 'type', ns['xsd'] + 'string') wbm_gb_node.set(ns['xsi'] + 'type', ns['resqml2'] + 'GeologicBoundaryKind') wbm_gb_node.text = str(self.marker_type) if self.interpretation_uuid is not None: interp_content_type = 'obj_' + self.marker_type.capitalize( ) + 'Interpretation' interp_root = self.model.root_for_uuid( uuid=self.interpretation_uuid) self.model.create_ref_node( flavour='Interpretation', title=rqet.find_tag(rqet.find_tag(interp_root, 'Citation'), 'Title').text, uuid=self.interpretation_uuid, content_type=interp_content_type, root=wbm_node) # Extra metadata if hasattr(self, 'extra_metadata') and self.extra_metadata: rqet.create_metadata_xml(node=wbm_node, extra_metadata=self.extra_metadata) if parent_node is not None: parent_node.append(wbm_node) return wbm_node
def _load_from_xml(self): root_node = self.root self.is_abstract = rqet.find_tag_bool(root_node, 'IsAbstract') self.naming_system = rqet.find_tag_text(root_node, 'NamingSystem') self.example_uom = rqet.find_tag_text(root_node, 'RepresentativeUom') ppk_node = rqet.find_tag(root_node, 'ParentPropertyKind') assert ppk_node is not None ppk_kind_node = rqet.find_tag(ppk_node, 'Kind') assert ppk_kind_node is not None, 'only standard property kinds supported as parent kind' self.parent_kind = ppk_kind_node.text
def _add_part_to_dict_get_count_and_indexable(xml_node): count_node = rqet.find_tag(xml_node, 'Count') assert count_node is not None count = int(count_node.text) indexable_node = rqet.find_tag(xml_node, 'IndexableElement') assert indexable_node is not None indexable = indexable_node.text return count, indexable
def _add_part_to_dict_get_timeseries(xml_node): time_series_uuid = None time_index = None time_node = rqet.find_tag(xml_node, 'TimeIndex') if time_node is not None: time_index = int(rqet.find_tag(time_node, 'Index').text) time_series_uuid = bu.uuid_from_string( rqet.find_tag(rqet.find_tag(time_node, 'TimeSeries'), 'UUID').text) return time_series_uuid, time_index
def _load_related_datum(self): """Return related MdDatum object from XML if present.""" md_datum_uuid = bu.uuid_from_string(rqet.find_tag(rqet.find_tag(self.root, 'MdDatum'), 'UUID')) if md_datum_uuid is not None: md_datum_part = 'obj_MdDatum_' + str(md_datum_uuid) + '.xml' md_datum = MdDatum(self.model, md_datum_root = self.model.root_for_part(md_datum_part, is_rels = False)) else: md_datum = None return md_datum
def _load_from_xml(self): md_datum_root = self.root assert md_datum_root is not None location_node = rqet.find_tag(md_datum_root, 'Location') self.location = (rqet.find_tag_float(location_node, 'Coordinate1'), rqet.find_tag_float(location_node, 'Coordinate2'), rqet.find_tag_float(location_node, 'Coordinate3')) self.md_reference = rqet.node_text( rqet.find_tag(md_datum_root, 'MdReference')).strip().lower() assert self.md_reference in valid_md_reference_list self.crs_uuid = self.extract_crs_uuid()
def _h5_uuid_and_path_for_node(model, node, tag='Values'): """Returns a (hdf5_uuid, hdf5_internal_path) pair for an xml array node.""" child = rqet.find_tag(node, tag) if child is None: return None assert rqet.node_type(child) == 'Hdf5Dataset' h5_path = rqet.find_tag(child, 'PathInHdfFile').text h5_uuid = bu.uuid_from_string( rqet.find_nested_tags_text(child, ['HdfProxy', 'UUID'])) return (h5_uuid, h5_path)
def _crs_m_or_ft( crs_node): # NB. models not-so-rarely use metres for xy and feet for z if crs_node is None: return None xy_units = rqet.find_tag(crs_node, 'ProjectedUom').text.lower() z_units = rqet.find_tag(crs_node, 'VerticalUom').text.lower() if xy_units == 'm' and z_units == 'm': return 'm' if xy_units == 'ft' and z_units == 'ft': return 'ft' return None
def _add_part_to_dict_get_minmax(xml_node): minimum = None min_node = rqet.find_tag(xml_node, 'MinimumValue') if min_node is not None: minimum = min_node.text # NB: left as text maximum = None max_node = rqet.find_tag(xml_node, 'MaximumValue') if max_node is not None: maximum = max_node.text # NB: left as text return minimum, maximum
def create_xml(self, ext_uuid=None, add_as_part=True, add_relationships=True, title='wellbore marker framework', originator=None): """Creates the xml tree for this wellbore marker frame and optionally adds as a part to the model.""" assert type(add_as_part) is bool if not self.title: self.title = title if ext_uuid is None: ext_uuid = self.model.h5_uuid() wbm_node = super().create_xml(originator=originator, add_as_part=False) node_count, nodeMd, md_values_node = self.__add_sub_elements_to_root_node( wbm_node=wbm_node) self.model.create_hdf5_dataset_ref(ext_uuid, self.uuid, 'Mds', root=md_values_node) if self.trajectory is not None: traj_root = self.trajectory.root self.model.create_ref_node( 'Trajectory', rqet.find_tag(rqet.find_tag(traj_root, 'Citation'), 'Title').text, bu.uuid_from_string(traj_root.attrib['uuid']), content_type='obj_WellboreTrajectoryRepresentation', root=wbm_node) else: log.error('trajectory object is missing and must be included') # fill wellbore marker if self.marker_list is not None: for marker in self.marker_list: title = self.__get_wbm_node_title(marker) wbm_node_obj = marker.create_xml(parent_node=wbm_node, title=title) assert wbm_node_obj is not None # add as part self.__add_as_part_and_add_relationships( wbm_node=wbm_node, ext_uuid=ext_uuid, add_as_part=add_as_part, add_relationships=add_relationships) return wbm_node
def _add_part_to_dict_get_facet(xml_node): facet_type = None facet = None facet_node = rqet.find_tag( xml_node, 'Facet') # todo: handle more than one facet for a property if facet_node is not None: facet_type = rqet.find_tag(facet_node, 'Facet').text facet = rqet.find_tag(facet_node, 'Value').text if facet_type is not None and facet_type == '': facet_type = None if facet is not None and facet == '': facet = None return facet_type, facet
def triangles_and_points(self): """Returns arrays representing the patch. Returns: Tuple (triangles, points): * triangles (int array of shape[:, 3]): integer indices into points array, being the nodes of the corners of the triangles * points (float array of shape[:, 3]): flat array of xyz points, indexed by triangles """ if self.triangles is not None: return (self.triangles, self.points) assert self.triangle_count is not None and self.node_count is not None geometry_node = rqet.find_tag(self.node, 'Geometry') assert geometry_node is not None p_root = rqet.find_tag(geometry_node, 'Points') assert p_root is not None, 'Points xml node not found for triangle patch' assert rqet.node_type(p_root) == 'Point3dHdf5Array' h5_key_pair = self.model.h5_uuid_and_path_for_node(p_root, tag='Coordinates') if h5_key_pair is None: return (None, None) try: self.model.h5_array_element(h5_key_pair, cache_array=True, object=self, array_attribute='points', dtype='float') except Exception: log.error('hdf5 points failure for triangle patch ' + str(self.patch_index)) raise triangles_node = rqet.find_tag(self.node, 'Triangles') h5_key_pair = self.model.h5_uuid_and_path_for_node(triangles_node) if h5_key_pair is None: log.warning('No Triangles found in xml for patch index: ' + str(self.patch_index)) return (None, None) try: self.model.h5_array_element(h5_key_pair, cache_array=True, object=self, array_attribute='triangles', dtype='int') except Exception: log.error('hdf5 triangles failure for triangle patch ' + str(self.patch_index)) raise return (self.triangles, self.points)
def __create_deviation_survey_reference_node(self, wbt_node): """ Create a reference node to a DeviationSurvey object and append it to the WellboreTrajectory object's root node. """ if self.deviation_survey is not None: ds_root = self.deviation_survey.root_node self.model.create_ref_node( 'DeviationSurvey', rqet.find_tag(rqet.find_tag(ds_root, 'Citation'), 'Title').text, bu.uuid_from_string(ds_root.attrib['uuid']), content_type='obj_DeviationSurveyRepresentation', root=wbt_node)
def extract_extent_kji(grid): """Returns the grid extent; for IJK grids this is a 3 integer numpy array, order is Nk, Nj, Ni. returns: numpy int array of shape (3,) being number of cells in k, j & i axes respectively; the return value is cached in attribute extent_kji, which can alternatively be referenced directly by calling code as the value is set from xml on initialisation """ if grid.extent_kji is not None: return grid.extent_kji grid.extent_kji = np.ones(3, dtype = 'int') # todo: handle other varieties of grid grid.extent_kji[0] = int(rqet.find_tag(grid.root, 'Nk').text) grid.extent_kji[1] = int(rqet.find_tag(grid.root, 'Nj').text) grid.extent_kji[2] = int(rqet.find_tag(grid.root, 'Ni').text) return grid.extent_kji
def cases(self): """Returns a list of simulation case strings as found in the main xml file.""" if self.case_list is not None: return self.case_list try: xml_file = os.path.join(self.path, 'main.xml') if self.zipped: with zf.ZipFile(self.zip_file) as zfp: with zfp.open(xml_file) as fp: tree = rqet.parse(fp) root = tree.getroot() else: assert os.path.exists( xml_file), 'could not find vdb main xml file: ' + xml_file with open(xml_file, 'r') as fp: tree = rqet.parse(fp) root = tree.getroot() caselist = rqet.list_of_tag(rqet.find_tag(root, 'CASELIST'), 'CASE') self.case_list = [] for case in caselist: self.case_list.append(str(case.attrib['Name']).strip()) if self.use_case is None and len(self.case_list): self.use_case = self.case_list[0] except Exception: log.exception('failed to extract case list') return self.case_list
def __init__(self, model, uuid=None, title=None, originator=None, extra_metadata=None): """Load an existing resqml object, or create new. Args: model (resqpy.model.Model): Parent model uuid (str, optional): Load from existing uuid (if given), else create new. title (str, optional): Citation title originator (str, optional): Creator of object. By default, uses user id. """ self.model = model self.title = title #: Citation title self.originator = originator #: Creator of object. By default, user id. self.extra_metadata = {} if extra_metadata: self.extra_metadata = extra_metadata self._standardise_extra_metadata( ) # has side effect of making a copy if uuid is None: self.uuid = bu.new_uuid() #: Unique identifier else: self.uuid = uuid root_node = self.root citation_node = rqet.find_tag(root_node, 'Citation') if citation_node is not None: self.title = rqet.find_tag_text(citation_node, 'Title') self.originator = rqet.find_tag_text(citation_node, 'Originator') self.extra_metadata = rqet.load_metadata_from_xml(root_node) self._load_from_xml()
def _load_from_xml(self): """Loads class specific attributes from xml for an existing RESQML object; called from BaseResqpy.""" super()._load_from_xml() root_node = self.root assert root_node is not None feature_uuid = bu.uuid_from_string( rqet.find_nested_tags_text(root_node, ['InterpretedFeature', 'UUID'])) if feature_uuid is not None: self.geologic_unit_feature = StratigraphicUnitFeature( self.model, uuid=feature_uuid, title=self.model.title(uuid=feature_uuid)) # load deposition mode and min & max thicknesses (& uom), if present self.deposition_mode = rqet.find_tag_text(root_node, 'DepositionMode') for min_max in ['Min', 'Max']: thick_node = rqet.find_tag(root_node, min_max + 'Thickness') if thick_node is not None: thick = float(thick_node.text) if min_max == 'Min': self.min_thickness = thick else: self.max_thickness = thick thick_uom = thick_node.attrib[ 'uom'] # todo: check this is correct uom representation if self.thickness_uom is None: self.thickness_uom = thick_uom else: assert thick_uom == self.thickness_uom, 'inconsistent length units of measure for stratigraphic thicknesses'
def grid_flavour(grid_root): """Returns a string indicating type of grid geometry, currently 'IjkGrid' or 'IjkBlockGrid'.""" if grid_root is None: return None em = rqet.load_metadata_from_xml(grid_root) flavour = em.get('grid_flavour') if flavour is None: node_type = rqet.node_type(grid_root, strip_obj = True) if node_type == 'IjkGridRepresentation': if rqet.find_tag(grid_root, 'Geometry') is not None: flavour = 'IjkGrid' else: flavour = 'IjkBlockGrid' # this might cause issues elif node_type == 'UnstructuredGridRepresentation': cell_shape = rqet.find_nested_tags_text(grid_root, ['Geometry', 'CellShape']) if cell_shape is None or cell_shape == 'polyhedral': flavour = 'UnstructuredGrid' elif cell_shape == 'tetrahedral': flavour = 'TetraGrid' elif cell_shape == 'hexahedral': flavour = 'HexaGrid' elif cell_shape == 'pyramidal': flavour = 'PyramidGrid' elif cell_shape == 'prism': flavour = 'PrismGrid' return flavour
def _load_from_xml(self): root_node = self.root self.domain = rqet.find_tag_text(root_node, 'Domain') interp_feature_ref_node = rqet.find_tag(root_node, 'InterpretedFeature') assert interp_feature_ref_node is not None self.feature_root = self.model.referenced_node(interp_feature_ref_node) if self.feature_root is not None: self.tectonic_boundary_feature = TectonicBoundaryFeature(self.model, uuid = self.feature_root.attrib['uuid'], feature_name = self.model.title_for_root( self.feature_root)) self.main_has_occurred_during = extract_has_occurred_during(root_node) self.is_listric = rqet.find_tag_bool(root_node, 'IsListric') self.is_normal = (self.is_listric is None) self.maximum_throw = rqet.find_tag_float(root_node, 'MaximumThrow') # todo: check that type="eml:LengthMeasure" is simple float self.mean_azimuth = rqet.find_tag_float(root_node, 'MeanAzimuth') self.mean_dip = rqet.find_tag_float(root_node, 'MeanDip') throw_interpretation_nodes = rqet.list_of_tag(root_node, 'ThrowInterpretation') if throw_interpretation_nodes is not None and len(throw_interpretation_nodes): self.throw_interpretation_list = [] for ti_node in throw_interpretation_nodes: hod_pair = extract_has_occurred_during(ti_node) throw_kind_list = rqet.list_of_tag(ti_node, 'Throw') for tk_node in throw_kind_list: self.throw_interpretation_list.append((tk_node.text, hod_pair))
def __load_from_xml_refz(self, support_geom_node): self.flavour = 'ref&z' # assert rqet.node_type(support_geom_node) == 'Point3dFromRepresentationLatticeArray' # only this supported for now self.ref_uuid = rqet.find_nested_tags_text( support_geom_node, ['SupportingRepresentation', 'UUID']) assert self.ref_uuid, 'missing supporting representation info in xml for z-value mesh' self.ref_mesh = Mesh(self.model, uuid=self.ref_uuid) assert self.nj == self.ref_mesh.nj and self.ni == self.ref_mesh.ni # only this supported for now niosr_node = rqet.find_tag(support_geom_node, 'NodeIndicesOnSupportingRepresentation') start_value = rqet.find_tag_int(niosr_node, 'StartValue') assert start_value == 0, 'only full use of supporting mesh catered for at present' offset_nodes = rqet.list_of_tag( niosr_node, 'Offset') # first occurrence for FastestAxis, ie. I; 2nd for J assert len( offset_nodes ) == 2, 'missing (or too many) offset nodes in xml for regular mesh (lattice)' for j_or_i in range(2): # 0 = J, 1 = I assert rqet.node_type( offset_nodes[j_or_i] ) == 'IntegerConstantArray', 'variable step not catered for' assert rqet.find_tag_int( offset_nodes[j_or_i], 'Value') == 1, 'step other than 1 not catered for' count = rqet.find_tag_int(offset_nodes[j_or_i], 'Count') assert count == (self.nj, self.ni)[j_or_i] - 1, \ 'unexpected value for count in xml spacing info for regular mesh (lattice)'