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 _load_from_xml(self): """Loads class specific attributes from xml for an existing RESQML object; called from BaseResqpy.""" root_node = self.root assert root_node is not None assert rqet.find_tag_text(root_node, 'OrderingCriteria') == 'age', \ 'stratigraphic column rank interpretation ordering criterion must be age' self.domain = rqet.find_tag_text(root_node, 'Domain') self.feature_uuid = bu.uuid_from_string( rqet.find_nested_tags_text(root_node, ['InterpretedFeature', 'UUID'])) self.has_occurred_during = rqo.extract_has_occurred_during(root_node) self.index = rqet.find_tag_int(root_node, 'Index') self.units = [] for su_node in rqet.list_of_tag(root_node, 'StratigraphicUnits'): index = rqet.find_tag_int(su_node, 'Index') unit_uuid = bu.uuid_from_string( rqet.find_nested_tags_text(su_node, ['Unit', 'UUID'])) assert index is not None and unit_uuid is not None assert self.model.type_of_uuid( unit_uuid, strip_obj=True) == 'StratigraphicUnitInterpretation' self.units.append( (index, StratigraphicUnitInterpretation(self.model, uuid=unit_uuid))) self._sort_units() self.contacts = [] for contact_node in rqet.list_of_tag(root_node, 'ContactInterpretation'): self.contacts.append( BinaryContactInterpretation(self.model, existing_xml_node=contact_node)) self._sort_contacts()
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 uuid_in_part_name(part_name): """Returns uuid as embedded in part name.""" # This might not always work if part_name is None: return None if part_name.endswith('.xml') and len(part_name) >= 40: return bu.uuid_from_string(part_name[-40:-4]) elif part_name.endswith('.xml.rels') and len(part_name) >= 45: return bu.uuid_from_string(part_name[-45:-9]) return None
def force_uuid_equivalence(self, immigrant_uuid, resident_uuid): """Forces immigrant object to be treated as equivalent to (same as) resident object, identified by uuids.""" assert immigrant_uuid is not None and resident_uuid is not None if isinstance(immigrant_uuid, str): immigrant_uuid = bu.uuid_from_string(immigrant_uuid) if isinstance(resident_uuid, str): resident_uuid = bu.uuid_from_string(resident_uuid) if bu.matching_uuids(immigrant_uuid, resident_uuid): return assert immigrant_uuid not in self.map.values() self.map[immigrant_uuid] = resident_uuid
def _load_from_xml(self): """Loads class specific attributes from xml for an existing RESQML object; called from BaseResqpy.""" root_node = self.root assert root_node is not None bottom_ref_uuid = rqet.find_nested_tags_text( root_node, ['ChronostratigraphicBottom', 'UUID']) top_ref_uuid = rqet.find_nested_tags_text( root_node, ['ChronostratigraphicTop', 'UUID']) # todo: find out if these are meant to be references to other stratigraphic unit features or geologic unit features # and if so, instantiate those objects? # for now, simply note the uuids if bottom_ref_uuid is not None: self.bottom_unit_uuid = bu.uuid_from_string(bottom_ref_uuid) if top_ref_uuid is not None: self.top_unit_uuid = bu.uuid_from_string(top_ref_uuid)
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 _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 _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 _set_parent_window_in_grid(set_parent_window, source_grid, grid, fine_coarse): if set_parent_window: pw_grid_uuid = source_grid.uuid if isinstance(set_parent_window, str): if set_parent_window == 'grandparent': assert fine_coarse.within_fine_box is None or (np.all(fine_coarse.within_fine_box[0] == 0) and np.all(fine_coarse.within_fine_box[1]) == source_grid.extent_kji - 1), \ 'attempt to set grandparent window for grid when parent window is present' source_fine_coarse = source_grid.parent_window if source_fine_coarse is not None and ( source_fine_coarse.within_fine_box is not None or source_fine_coarse.within_coarse_box is not None): assert source_fine_coarse.fine_extent_kji == source_fine_coarse.coarse_extent_kji, 'parentage involves refinement or coarsening' if source_fine_coarse.within_fine_box is not None: fine_coarse.within_fine_box = source_fine_coarse.within_fine_box else: fine_coarse.within_fine_box = source_fine_coarse.within_coarse_box pw_grid_uuid = bu.uuid_from_string( rqet.find_nested_tags_text( source_grid.root, ['ParentWindow', 'ParentGrid', 'UUID'])) else: assert set_parent_window == 'parent', 'set_parent_window value not recognized: ' + set_parent_window grid.set_parent(pw_grid_uuid, False, fine_coarse)
def _create_xml_get_p_node(collection, p_uuid): p_node = collection.model.new_obj_node(collection.d_or_c_text + 'Property') if p_uuid is None: p_uuid = bu.uuid_from_string(p_node.attrib['uuid']) else: p_node.attrib['uuid'] = str(p_uuid) return p_node, p_uuid
def uuid_for_part_root(root): """Returns uuid as stored in xml attribs for root.""" if root is None: return None if 'uuid' not in root.attrib.keys(): return None return bu.uuid_from_string(root.attrib['uuid'])
def recursive_uuid_set(node): uuid_set = set() for child in node: uuid_set = uuid_set.union(recursive_uuid_set(child)) if rqet.node_type(node) == 'Hdf5Dataset': h5_uuid = bu.uuid_from_string( rqet.find_nested_tags_text(node, ['HdfProxy', 'UUID'])) uuid_set.add(h5_uuid) return uuid_set
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 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 _create_md_datum_reference(md_datum_root, root=None): """Creates a node refering to an existing measured depth datum and optionally adds as child of root.""" return _create_ref_node('MdDatum', rqet.find_nested_tags_text(md_datum_root, ['Citation', 'Title']), bu.uuid_from_string(md_datum_root.attrib['uuid']), content_type='obj_MdDatum', root=root)
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 _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 _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 __create_wellbore_interpretation_ref_node(self, ds_node): """Create a reference node for the WellboreInterpretation object and add to the DeviationSurvey root node. """ interp_root = None if self.wellbore_interpretation is not None: interp_root = self.wellbore_interpretation.root self.model.create_ref_node('RepresentedInterpretation', rqet.find_nested_tags_text(interp_root, ['Citation', 'Title']), bu.uuid_from_string(interp_root.attrib['uuid']), content_type = 'obj_WellboreInterpretation', root = ds_node) return interp_root
def _add_part_to_dict_get_support_uuid(collection, part): support_uuid = collection.model.supporting_representation_for_part(part) if support_uuid is None: support_uuid = collection.support_uuid elif collection.support_uuid is None: collection.set_support(support_uuid) elif not bu.matching_uuids( support_uuid, collection.support.uuid): # multi-support collection collection.set_support(None) if isinstance(support_uuid, str): support_uuid = bu.uuid_from_string(support_uuid) return support_uuid
def extract_crs_root_and_uuid(self): """Caches uuid for coordinate reference system, as stored in geometry xml sub-tree.""" if self.crs_uuid is None: crs_root = rqet.find_nested_tags(self.node, ['Geometry', 'LocalCrs']) assert crs_root is not None, 'failed to find crs reference in triangulated patch xml' self.crs_uuid = bu.uuid_from_string( rqet.find_tag_text(crs_root, 'UUID')) else: crs_root = self.model.root_for_uuid(self.crs_uuid) return crs_root, self.crs_uuid
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 _load_from_xml(self, marker_node): """Load attributes from xml. This is invoked as part of the init method when an existing uuid is given. Returns: [bool]: True if successful """ assert marker_node is not None # Load XML data uuid_str = marker_node.attrib.get('uuid') if uuid_str: self.uuid = bu.uuid_from_string(uuid_str) citation_tag = rqet.find_nested_tags(root=marker_node, tag_list=['Citation']) assert citation_tag is not None self.title = rqet.find_tag_text(root=citation_tag, tag_name='Title') self.originator = rqet.find_tag_text(root=citation_tag, tag_name='Originator') self.marker_type = None for boundary_feature_type in [ 'GeologicBoundaryKind', 'FluidMarker', 'FluidContact' ]: found_tag_text = rqet.find_tag_text(root=marker_node, tag_name=boundary_feature_type) if found_tag_text is not None: self.marker_type = found_tag_text break assert self.marker_type is not None self.interpretation_uuid = bu.uuid_from_string( rqet.find_nested_tags_text(root=marker_node, tag_list=['Interpretation', 'UUID'])) self.extra_metadata = rqet.load_metadata_from_xml(node=marker_node) return True
def extract_crs_uuid(grid): """Returns uuid for coordinate reference system, as stored in geometry xml tree. returns: uuid.UUID object """ if grid.crs_uuid is not None: return grid.crs_uuid crs_root = grid.resolve_geometry_child('LocalCrs') uuid_str = rqet.find_tag_text(crs_root, 'UUID') if uuid_str: grid.crs_uuid = bu.uuid_from_string(uuid_str) return grid.crs_uuid
def cut_obj_references(root, uuids_to_be_cut): """Deletes any object reference nodes to uuids in given list.""" if root is None or not uuids_to_be_cut: return for child in root: if node_type(child) == 'DataObjectReference': referred_uuid = bu.uuid_from_string( find_tag_text(child, 'UUID', must_exist=True)) for cut_uuid in uuids_to_be_cut: if bu.matching_uuids(referred_uuid, cut_uuid): root.remove(child) break else: cut_obj_references(child, uuids_to_be_cut)
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 __create_wellbore_interpretation_reference_node(self, wbt_node): """Create a reference node to a WellboreInterpretation object and append it to the WellboreTrajectory object's root node. """ interp_root = None if self.wellbore_interpretation is not None: interp_root = self.wellbore_interpretation.root self.model.create_ref_node( 'RepresentedInterpretation', rqet.find_nested_tags_text(interp_root, ['Citation', 'Title']), bu.uuid_from_string(interp_root.attrib['uuid']), content_type='obj_WellboreInterpretation', root=wbt_node) return interp_root
def extract_children(grid): """Looks for LGRs related to this grid and sets the local_grid_uuid_list attribute.""" assert grid.uuid is not None if grid.local_grid_uuid_list is not None: return grid.local_grid_uuid_list grid.local_grid_uuid_list = [] related_grid_roots = grid.model.roots(obj_type = 'IjkGridRepresentation', related_uuid = grid.uuid) if related_grid_roots is not None: for related_root in related_grid_roots: parent_uuid = rqet.find_nested_tags_text(related_root, ['ParentWindow', 'ParentGrid', 'UUID']) if parent_uuid is None: continue parent_uuid = bu.uuid_from_string(parent_uuid) if bu.matching_uuids(grid.uuid, parent_uuid): grid.local_grid_uuid_list.append(parent_uuid) return grid.local_grid_uuid_list
def _create_hdf5_ext(model, add_as_part=True, root=None, title='Hdf Proxy', originator=None, file_name=None, uuid=None): """Creates an hdf5 external node and optionally adds as child of root and/or to parts forest.""" ext = _new_obj_node('EpcExternalPartReference', name_space='eml') assert ext is not None if uuid is not None: # preserve ext uuid if supplied ext.set('uuid', str(uuid)) _create_citation(root=ext, title=title, originator=originator) mime_type = rqet.SubElement(ext, ns['eml'] + 'MimeType') mime_type.set(ns['xsi'] + 'type', ns['xsd'] + 'string') mime_type.text = 'application/x-hdf5' if root is not None: root.append(ext) if add_as_part: ext_uuid = bu.uuid_from_string(ext.attrib['uuid']) model.add_part('obj_EpcExternalPartReference', ext_uuid, ext) if not file_name: file_name = model.h5_file_name(override='full', file_must_exist=False) elif os.sep not in file_name: file_name = os.path.join(model.epc_directory, file_name) assert file_name log.debug(f'creating ext part for hdf5 file: {file_name}') model.h5_dict[ext_uuid.bytes] = file_name if model.main_h5_uuid is None: model.main_h5_uuid = ext_uuid if model.rels_present and file_name: (uuid, rel_tree) = model.rels_forest[rqet.rels_part_name_for_part( rqet.part_name_for_object('obj_EpcExternalPartReference', ext_uuid))] assert (bu.matching_uuids(uuid, ext_uuid)) rel_node = rqet.SubElement(rel_tree.getroot(), ns['rels'] + 'Relationship') rel_node.set('Id', 'Hdf5File') rel_node.set('Type', ns_url['rels_ext'] + 'externalResource') rel_node.set('Target', file_name) rel_node.set('TargetMode', 'External') return ext