resqpy 4.14.1__py3-none-any.whl → 5.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- resqpy/__init__.py +1 -1
 - resqpy/fault/_gcs_functions.py +10 -10
 - resqpy/fault/_grid_connection_set.py +277 -113
 - resqpy/grid/__init__.py +2 -3
 - resqpy/grid/_defined_geometry.py +3 -3
 - resqpy/grid/_extract_functions.py +2 -1
 - resqpy/grid/_grid.py +95 -12
 - resqpy/grid/_grid_types.py +22 -7
 - resqpy/grid/_points_functions.py +1 -1
 - resqpy/grid/_regular_grid.py +6 -2
 - resqpy/grid_surface/__init__.py +17 -38
 - resqpy/grid_surface/_blocked_well_populate.py +5 -5
 - resqpy/grid_surface/_find_faces.py +1349 -253
 - resqpy/lines/_polyline.py +24 -33
 - resqpy/model/_catalogue.py +9 -0
 - resqpy/model/_forestry.py +18 -14
 - resqpy/model/_hdf5.py +11 -3
 - resqpy/model/_model.py +85 -10
 - resqpy/model/_xml.py +38 -13
 - resqpy/multi_processing/wrappers/grid_surface_mp.py +92 -37
 - resqpy/olio/read_nexus_fault.py +8 -2
 - resqpy/olio/relperm.py +1 -1
 - resqpy/olio/transmission.py +8 -8
 - resqpy/olio/triangulation.py +36 -30
 - resqpy/olio/vector_utilities.py +340 -6
 - resqpy/olio/volume.py +0 -20
 - resqpy/olio/wellspec_keywords.py +19 -13
 - resqpy/olio/write_hdf5.py +1 -1
 - resqpy/olio/xml_et.py +12 -0
 - resqpy/property/__init__.py +6 -4
 - resqpy/property/_collection_add_part.py +4 -3
 - resqpy/property/_collection_create_xml.py +4 -2
 - resqpy/property/_collection_get_attributes.py +4 -0
 - resqpy/property/attribute_property_set.py +311 -0
 - resqpy/property/grid_property_collection.py +11 -11
 - resqpy/property/property_collection.py +79 -31
 - resqpy/property/property_common.py +3 -8
 - resqpy/rq_import/_add_surfaces.py +34 -14
 - resqpy/rq_import/_grid_from_cp.py +2 -2
 - resqpy/rq_import/_import_nexus.py +75 -48
 - resqpy/rq_import/_import_vdb_all_grids.py +64 -52
 - resqpy/rq_import/_import_vdb_ensemble.py +12 -13
 - resqpy/surface/_mesh.py +4 -0
 - resqpy/surface/_surface.py +593 -118
 - resqpy/surface/_tri_mesh.py +22 -12
 - resqpy/surface/_tri_mesh_stencil.py +4 -4
 - resqpy/surface/_triangulated_patch.py +71 -51
 - resqpy/time_series/_any_time_series.py +7 -4
 - resqpy/time_series/_geologic_time_series.py +1 -1
 - resqpy/unstructured/_hexa_grid.py +6 -2
 - resqpy/unstructured/_prism_grid.py +13 -5
 - resqpy/unstructured/_pyramid_grid.py +6 -2
 - resqpy/unstructured/_tetra_grid.py +6 -2
 - resqpy/unstructured/_unstructured_grid.py +6 -2
 - resqpy/well/_blocked_well.py +1986 -1946
 - resqpy/well/_deviation_survey.py +3 -3
 - resqpy/well/_md_datum.py +11 -21
 - resqpy/well/_trajectory.py +10 -5
 - resqpy/well/_wellbore_frame.py +10 -2
 - resqpy/well/blocked_well_frame.py +3 -3
 - resqpy/well/well_object_funcs.py +7 -9
 - resqpy/well/well_utils.py +33 -0
 - {resqpy-4.14.1.dist-info → resqpy-5.1.5.dist-info}/METADATA +8 -9
 - {resqpy-4.14.1.dist-info → resqpy-5.1.5.dist-info}/RECORD +66 -66
 - {resqpy-4.14.1.dist-info → resqpy-5.1.5.dist-info}/WHEEL +1 -1
 - resqpy/grid/_moved_functions.py +0 -15
 - {resqpy-4.14.1.dist-info → resqpy-5.1.5.dist-info}/LICENSE +0 -0
 
    
        resqpy/well/_blocked_well.py
    CHANGED
    
    | 
         @@ -10,6 +10,7 @@ log = logging.getLogger(__name__) 
     | 
|
| 
       10 
10 
     | 
    
         
             
            import math as maths
         
     | 
| 
       11 
11 
     | 
    
         
             
            import numpy as np
         
     | 
| 
       12 
12 
     | 
    
         
             
            import pandas as pd
         
     | 
| 
      
 13 
     | 
    
         
            +
            import warnings
         
     | 
| 
       13 
14 
     | 
    
         
             
            from functools import partial
         
     | 
| 
       14 
15 
     | 
    
         | 
| 
       15 
16 
     | 
    
         
             
            import resqpy.crs as crs
         
     | 
| 
         @@ -136,12 +137,13 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       136 
137 
     | 
    
         
             
                    self.wellbore_interpretation = None  #: associated wellbore interpretation object
         
     | 
| 
       137 
138 
     | 
    
         
             
                    self.wellbore_feature = None  #: associated wellbore feature object
         
     | 
| 
       138 
139 
     | 
    
         
             
                    self.well_name = None  #: name of well to import from ascii file formats
         
     | 
| 
      
 140 
     | 
    
         
            +
                    self.cell_index_dtype = np.int32  #: set to int64 if any grid has more than 2^31 - 1 cells, otherwise int32
         
     | 
| 
       139 
141 
     | 
    
         | 
| 
       140 
142 
     | 
    
         
             
                    self.cell_interval_map = None  # maps from cell index to interval (ie. node) index; populated on demand
         
     | 
| 
       141 
143 
     | 
    
         | 
| 
       142 
144 
     | 
    
         
             
                    self.property_collection = None
         
     | 
| 
       143 
145 
     | 
    
         
             
                    #: all logs associated with the blockedwellbore; an instance of :class:`resqpy.property.WellIntervalPropertyCollection`
         
     | 
| 
       144 
     | 
    
         
            -
                    self. 
     | 
| 
      
 146 
     | 
    
         
            +
                    self._logs = None  # use of .logs is deprecated
         
     | 
| 
       145 
147 
     | 
    
         
             
                    self.cellind_null = -1
         
     | 
| 
       146 
148 
     | 
    
         
             
                    self.gridind_null = -1
         
     | 
| 
       147 
149 
     | 
    
         
             
                    self.facepair_null = -1
         
     | 
| 
         @@ -150,11 +152,11 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       150 
152 
     | 
    
         
             
                    # this is the default as indicated on page 139 (but not p. 180) of the RESQML Usage Gude v2.0.1
         
     | 
| 
       151 
153 
     | 
    
         
             
                    # also assumes K is generally increasing downwards
         
     | 
| 
       152 
154 
     | 
    
         
             
                    # see DevOps backlog item 269001 discussion for more information
         
     | 
| 
       153 
     | 
    
         
            -
                    #     self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype =  
     | 
| 
       154 
     | 
    
         
            -
                    self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype =  
     | 
| 
      
 155 
     | 
    
         
            +
                    #     self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype = np.int8)
         
     | 
| 
      
 156 
     | 
    
         
            +
                    self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype = np.int8)  # order: top, base, J-, I+, J+, I-
         
     | 
| 
       155 
157 
     | 
    
         
             
                    # and the inverse, maps from 0..5 to (axis, p01)
         
     | 
| 
       156 
     | 
    
         
            -
                    #     self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype =  
     | 
| 
       157 
     | 
    
         
            -
                    self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype =  
     | 
| 
      
 158 
     | 
    
         
            +
                    #     self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype = np.int8)
         
     | 
| 
      
 159 
     | 
    
         
            +
                    self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype = np.int8)
         
     | 
| 
       158 
160 
     | 
    
         
             
                    # note: the rework_face_pairs() method, below, overwrites the face indices based on I, J cell indices
         
     | 
| 
       159 
161 
     | 
    
         | 
| 
       160 
162 
     | 
    
         
             
                    super().__init__(model = parent_model,
         
     | 
| 
         @@ -190,160 +192,17 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       190 
192 
     | 
    
         
             
                            self.title = well_name
         
     | 
| 
       191 
193 
     | 
    
         
             
                    # else an empty object is returned
         
     | 
| 
       192 
194 
     | 
    
         | 
| 
       193 
     | 
    
         
            -
                 
     | 
| 
       194 
     | 
    
         
            -
             
     | 
| 
       195 
     | 
    
         
            -
             
     | 
| 
       196 
     | 
    
         
            -
                     
     | 
| 
       197 
     | 
    
         
            -
             
     | 
| 
       198 
     | 
    
         
            -
                         
     | 
| 
       199 
     | 
    
         
            -
                     
     | 
| 
       200 
     | 
    
         
            -
                        grid_final = grid
         
     | 
| 
       201 
     | 
    
         
            -
                    return grid_final
         
     | 
| 
       202 
     | 
    
         
            -
             
     | 
| 
       203 
     | 
    
         
            -
                def __check_cellio_init_okay(self, cellio_file, well_name, grid):
         
     | 
| 
       204 
     | 
    
         
            -
                    """Checks if BlockedWell object initialization from a cellio file is okay."""
         
     | 
| 
       205 
     | 
    
         
            -
             
     | 
| 
       206 
     | 
    
         
            -
                    okay = self.import_from_rms_cellio(cellio_file, well_name, grid)
         
     | 
| 
       207 
     | 
    
         
            -
                    if not okay:
         
     | 
| 
       208 
     | 
    
         
            -
                        self.node_count = 0
         
     | 
| 
       209 
     | 
    
         
            -
             
     | 
| 
       210 
     | 
    
         
            -
                def _load_from_xml(self):
         
     | 
| 
       211 
     | 
    
         
            -
                    """Loads the blocked wellbore object from an xml node (and associated hdf5 data)."""
         
     | 
| 
       212 
     | 
    
         
            -
             
     | 
| 
       213 
     | 
    
         
            -
                    node = self.root
         
     | 
| 
       214 
     | 
    
         
            -
                    assert node is not None
         
     | 
| 
       215 
     | 
    
         
            -
             
     | 
| 
       216 
     | 
    
         
            -
                    self.__find_trajectory_uuid(node = node)
         
     | 
| 
       217 
     | 
    
         
            -
             
     | 
| 
       218 
     | 
    
         
            -
                    self.node_count = rqet.find_tag_int(node, 'NodeCount')
         
     | 
| 
       219 
     | 
    
         
            -
                    assert self.node_count is not None and self.node_count >= 2, 'problem with blocked well node count'
         
     | 
| 
       220 
     | 
    
         
            -
             
     | 
| 
       221 
     | 
    
         
            -
                    mds_node = rqet.find_tag(node, 'NodeMd')
         
     | 
| 
       222 
     | 
    
         
            -
                    assert mds_node is not None, 'blocked well node measured depths hdf5 reference not found in xml'
         
     | 
| 
       223 
     | 
    
         
            -
                    rqwu.load_hdf5_array(self, mds_node, 'node_mds')
         
     | 
| 
       224 
     | 
    
         
            -
             
     | 
| 
       225 
     | 
    
         
            -
                    # Statement below has no effect, is this a bug?
         
     | 
| 
       226 
     | 
    
         
            -
                    self.node_mds is not None and self.node_mds.ndim == 1 and self.node_mds.size == self.node_count
         
     | 
| 
       227 
     | 
    
         
            -
             
     | 
| 
       228 
     | 
    
         
            -
                    self.cell_count = rqet.find_tag_int(node, 'CellCount')
         
     | 
| 
       229 
     | 
    
         
            -
                    assert self.cell_count is not None and self.cell_count > 0
         
     | 
| 
       230 
     | 
    
         
            -
             
     | 
| 
       231 
     | 
    
         
            -
                    # todo: remove this if block once RMS export issue resolved
         
     | 
| 
       232 
     | 
    
         
            -
                    if self.cell_count == self.node_count:
         
     | 
| 
       233 
     | 
    
         
            -
                        extended_mds = np.empty((self.node_mds.size + 1,))
         
     | 
| 
       234 
     | 
    
         
            -
                        extended_mds[:-1] = self.node_mds
         
     | 
| 
       235 
     | 
    
         
            -
                        extended_mds[-1] = self.node_mds[-1] + 1.0
         
     | 
| 
       236 
     | 
    
         
            -
                        self.node_mds = extended_mds
         
     | 
| 
       237 
     | 
    
         
            -
                        self.node_count += 1
         
     | 
| 
       238 
     | 
    
         
            -
             
     | 
| 
       239 
     | 
    
         
            -
                    assert self.cell_count < self.node_count
         
     | 
| 
       240 
     | 
    
         
            -
             
     | 
| 
       241 
     | 
    
         
            -
                    self.__find_ci_node_and_load_hdf5_array(node = node)
         
     | 
| 
       242 
     | 
    
         
            -
             
     | 
| 
       243 
     | 
    
         
            -
                    self.__find_fi_node_and_load_hdf5_array(node)
         
     | 
| 
       244 
     | 
    
         
            -
             
     | 
| 
       245 
     | 
    
         
            -
                    unique_grid_indices = self.__find_gi_node_and_load_hdf5_array(node = node)
         
     | 
| 
       246 
     | 
    
         
            -
             
     | 
| 
       247 
     | 
    
         
            -
                    self.__find_grid_node(node = node, unique_grid_indices = unique_grid_indices)
         
     | 
| 
       248 
     | 
    
         
            -
             
     | 
| 
       249 
     | 
    
         
            -
                    interp_uuid = rqet.find_nested_tags_text(node, ['RepresentedInterpretation', 'UUID'])
         
     | 
| 
       250 
     | 
    
         
            -
                    if interp_uuid is None:
         
     | 
| 
       251 
     | 
    
         
            -
                        self.wellbore_interpretation = None
         
     | 
| 
       252 
     | 
    
         
            -
                    else:
         
     | 
| 
       253 
     | 
    
         
            -
                        self.wellbore_interpretation = rqo.WellboreInterpretation(self.model, uuid = interp_uuid)
         
     | 
| 
       254 
     | 
    
         
            -
             
     | 
| 
       255 
     | 
    
         
            -
                    # Create blocked well log collection of all log data
         
     | 
| 
       256 
     | 
    
         
            -
                    self.logs = rqp.WellIntervalPropertyCollection(frame = self)
         
     | 
| 
       257 
     | 
    
         
            -
             
     | 
| 
       258 
     | 
    
         
            -
                    # Set up matches between cell_indices and grid_indices
         
     | 
| 
       259 
     | 
    
         
            -
                    self.cell_grid_link = self.map_cell_and_grid_indices()
         
     | 
| 
       260 
     | 
    
         
            -
             
     | 
| 
       261 
     | 
    
         
            -
                def __find_trajectory_uuid(self, node):
         
     | 
| 
       262 
     | 
    
         
            -
                    """Find and verify the uuid of the trajectory associated with the BlockedWell object."""
         
     | 
| 
       263 
     | 
    
         
            -
             
     | 
| 
       264 
     | 
    
         
            -
                    trajectory_uuid = bu.uuid_from_string(rqet.find_nested_tags_text(node, ['Trajectory', 'UUID']))
         
     | 
| 
       265 
     | 
    
         
            -
                    assert trajectory_uuid is not None, 'blocked well trajectory reference not found in xml'
         
     | 
| 
       266 
     | 
    
         
            -
                    if self.trajectory is None:
         
     | 
| 
       267 
     | 
    
         
            -
                        self.trajectory = rqw.Trajectory(self.model, uuid = trajectory_uuid)
         
     | 
| 
       268 
     | 
    
         
            -
                    else:
         
     | 
| 
       269 
     | 
    
         
            -
                        assert bu.matching_uuids(self.trajectory.uuid, trajectory_uuid), 'blocked well trajectory uuid mismatch'
         
     | 
| 
       270 
     | 
    
         
            -
             
     | 
| 
       271 
     | 
    
         
            -
                def __find_ci_node_and_load_hdf5_array(self, node):
         
     | 
| 
       272 
     | 
    
         
            -
                    """Find the BlockedWell object's cell indices hdf5 reference node and load the array."""
         
     | 
| 
       273 
     | 
    
         
            -
             
     | 
| 
       274 
     | 
    
         
            -
                    ci_node = rqet.find_tag(node, 'CellIndices')
         
     | 
| 
       275 
     | 
    
         
            -
                    assert ci_node is not None, 'blocked well cell indices hdf5 reference not found in xml'
         
     | 
| 
       276 
     | 
    
         
            -
                    rqwu.load_hdf5_array(self, ci_node, 'cell_indices', dtype = int)
         
     | 
| 
       277 
     | 
    
         
            -
                    assert (self.cell_indices is not None and self.cell_indices.ndim == 1 and
         
     | 
| 
       278 
     | 
    
         
            -
                            self.cell_indices.size == self.cell_count), 'mismatch in number of cell indices for blocked well'
         
     | 
| 
       279 
     | 
    
         
            -
                    self.cellind_null = rqet.find_tag_int(ci_node, 'NullValue')
         
     | 
| 
       280 
     | 
    
         
            -
                    if self.cellind_null is None:
         
     | 
| 
       281 
     | 
    
         
            -
                        self.cellind_null = -1  # if no Null found assume -1 default
         
     | 
| 
       282 
     | 
    
         
            -
             
     | 
| 
       283 
     | 
    
         
            -
                def __find_fi_node_and_load_hdf5_array(self, node):
         
     | 
| 
       284 
     | 
    
         
            -
                    """Find the BlockedWell object's face indices hdf5 reference node and load the array."""
         
     | 
| 
       285 
     | 
    
         
            -
             
     | 
| 
       286 
     | 
    
         
            -
                    fi_node = rqet.find_tag(node, 'LocalFacePairPerCellIndices')
         
     | 
| 
       287 
     | 
    
         
            -
                    assert fi_node is not None, 'blocked well face indices hdf5 reference not found in xml'
         
     | 
| 
       288 
     | 
    
         
            -
                    rqwu.load_hdf5_array(self, fi_node, 'raw_face_indices', dtype = 'int')
         
     | 
| 
       289 
     | 
    
         
            -
                    assert self.raw_face_indices is not None, 'failed to load face indices for blocked well'
         
     | 
| 
       290 
     | 
    
         
            -
                    assert self.raw_face_indices.size == 2 * self.cell_count, 'mismatch in number of cell faces for blocked well'
         
     | 
| 
       291 
     | 
    
         
            -
                    if self.raw_face_indices.ndim > 1:
         
     | 
| 
       292 
     | 
    
         
            -
                        self.raw_face_indices = self.raw_face_indices.reshape((self.raw_face_indices.size,))
         
     | 
| 
       293 
     | 
    
         
            -
                    mask = np.where(self.raw_face_indices == -1)
         
     | 
| 
       294 
     | 
    
         
            -
                    self.raw_face_indices[mask] = 0
         
     | 
| 
       295 
     | 
    
         
            -
                    self.face_pair_indices = self.face_index_inverse_map[self.raw_face_indices]
         
     | 
| 
       296 
     | 
    
         
            -
                    self.face_pair_indices[mask] = (-1, -1)
         
     | 
| 
       297 
     | 
    
         
            -
                    self.face_pair_indices = self.face_pair_indices.reshape((-1, 2, 2))
         
     | 
| 
       298 
     | 
    
         
            -
                    del self.raw_face_indices
         
     | 
| 
       299 
     | 
    
         
            -
                    self.facepair_null = rqet.find_tag_int(fi_node, 'NullValue')
         
     | 
| 
       300 
     | 
    
         
            -
                    if self.facepair_null is None:
         
     | 
| 
       301 
     | 
    
         
            -
                        self.facepair_null = -1
         
     | 
| 
       302 
     | 
    
         
            -
             
     | 
| 
       303 
     | 
    
         
            -
                def __find_gi_node_and_load_hdf5_array(self, node):
         
     | 
| 
       304 
     | 
    
         
            -
                    """Find the BlockedWell object's grid indices hdf5 reference node and load the array."""
         
     | 
| 
       305 
     | 
    
         
            -
             
     | 
| 
       306 
     | 
    
         
            -
                    gi_node = rqet.find_tag(node, 'GridIndices')
         
     | 
| 
       307 
     | 
    
         
            -
                    assert gi_node is not None, 'blocked well grid indices hdf5 reference not found in xml'
         
     | 
| 
       308 
     | 
    
         
            -
                    rqwu.load_hdf5_array(self, gi_node, 'grid_indices', dtype = 'int')
         
     | 
| 
       309 
     | 
    
         
            -
                    # assert self.grid_indices is not None and self.grid_indices.ndim == 1 and self.grid_indices.size == self.node_count - 1
         
     | 
| 
       310 
     | 
    
         
            -
                    # temporary code to handle blocked wells with incorrectly shaped grid indices wrt. nodes
         
     | 
| 
       311 
     | 
    
         
            -
                    assert self.grid_indices is not None and self.grid_indices.ndim == 1
         
     | 
| 
       312 
     | 
    
         
            -
                    if self.grid_indices.size != self.node_count - 1:
         
     | 
| 
       313 
     | 
    
         
            -
                        if self.grid_indices.size == self.cell_count and self.node_count == 2 * self.cell_count:
         
     | 
| 
       314 
     | 
    
         
            -
                            log.warning(f'handling node duplication or missing unblocked intervals in blocked well: {self.title}')
         
     | 
| 
       315 
     | 
    
         
            -
             
     | 
| 
       316 
     | 
    
         
            -
                            expanded_grid_indices = np.full(self.node_count - 1, -1, dtype = int)
         
     | 
| 
       317 
     | 
    
         
            -
                            expanded_grid_indices[::2] = self.grid_indices
         
     | 
| 
       318 
     | 
    
         
            -
                            self.grid_indices = expanded_grid_indices
         
     | 
| 
       319 
     | 
    
         
            -
                        else:
         
     | 
| 
       320 
     | 
    
         
            -
                            raise ValueError(
         
     | 
| 
       321 
     | 
    
         
            -
                                f'incorrect grid indices size with respect to node count in blocked well: {self.title}')
         
     | 
| 
       322 
     | 
    
         
            -
                    # end of temporary code
         
     | 
| 
       323 
     | 
    
         
            -
                    unique_grid_indices = np.unique(self.grid_indices)  # sorted list of unique values
         
     | 
| 
       324 
     | 
    
         
            -
                    self.gridind_null = rqet.find_tag_int(gi_node, 'NullValue')
         
     | 
| 
       325 
     | 
    
         
            -
                    if self.gridind_null is None:
         
     | 
| 
       326 
     | 
    
         
            -
                        self.gridind_null = -1  # if no Null found assume -1 default
         
     | 
| 
       327 
     | 
    
         
            -
                    return unique_grid_indices
         
     | 
| 
       328 
     | 
    
         
            -
             
     | 
| 
       329 
     | 
    
         
            -
                def __find_grid_node(self, node, unique_grid_indices):
         
     | 
| 
       330 
     | 
    
         
            -
                    """Find the BlockedWell object's grid reference node(s)."""
         
     | 
| 
       331 
     | 
    
         
            -
                    grid_node_list = rqet.list_of_tag(node, 'Grid')
         
     | 
| 
       332 
     | 
    
         
            -
                    assert len(grid_node_list) > 0, 'blocked well grid reference(s) not found in xml'
         
     | 
| 
       333 
     | 
    
         
            -
                    assert unique_grid_indices[0] >= -1 and unique_grid_indices[-1] < len(
         
     | 
| 
       334 
     | 
    
         
            -
                        grid_node_list), 'blocked well grid index out of range'
         
     | 
| 
       335 
     | 
    
         
            -
                    assert np.count_nonzero(
         
     | 
| 
       336 
     | 
    
         
            -
                        self.grid_indices >= 0) == self.cell_count, 'mismatch in number of blocked well intervals'
         
     | 
| 
       337 
     | 
    
         
            -
                    self.grid_list = []
         
     | 
| 
       338 
     | 
    
         
            -
                    for grid_ref_node in grid_node_list:
         
     | 
| 
       339 
     | 
    
         
            -
                        grid_node = self.model.referenced_node(grid_ref_node)
         
     | 
| 
       340 
     | 
    
         
            -
                        assert grid_node is not None, 'grid referenced in blocked well xml is not present in model'
         
     | 
| 
       341 
     | 
    
         
            -
                        grid_uuid = rqet.uuid_for_part_root(grid_node)
         
     | 
| 
       342 
     | 
    
         
            -
                        grid_obj = self.model.grid(uuid = grid_uuid, find_properties = False)
         
     | 
| 
       343 
     | 
    
         
            -
                        self.grid_list.append(grid_obj)
         
     | 
| 
      
 195 
     | 
    
         
            +
                @property
         
     | 
| 
      
 196 
     | 
    
         
            +
                def logs(self):
         
     | 
| 
      
 197 
     | 
    
         
            +
                    """Returns blocked well property collection of all well log properties."""
         
     | 
| 
      
 198 
     | 
    
         
            +
                    warnings.warn('DEPRECATED: use of BlockedWell.logs attribute is deprecated, use property collection instead')
         
     | 
| 
      
 199 
     | 
    
         
            +
                    if self._logs is None:
         
     | 
| 
      
 200 
     | 
    
         
            +
                        self._logs = rqp.WellIntervalPropertyCollection(frame = self)
         
     | 
| 
      
 201 
     | 
    
         
            +
                    return self._logs
         
     | 
| 
       344 
202 
     | 
    
         | 
| 
       345 
203 
     | 
    
         
             
                def extract_property_collection(self, refresh = False):
         
     | 
| 
       346 
204 
     | 
    
         
             
                    """Returns a property collection for the blocked well."""
         
     | 
| 
      
 205 
     | 
    
         
            +
             
     | 
| 
       347 
206 
     | 
    
         
             
                    if self.property_collection is None or refresh:
         
     | 
| 
       348 
207 
     | 
    
         
             
                        self.property_collection = rqp.PropertyCollection(support = self)
         
     | 
| 
       349 
208 
     | 
    
         
             
                    return self.property_collection
         
     | 
| 
         @@ -407,6 +266,7 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       407 
266 
     | 
    
         | 
| 
       408 
267 
     | 
    
         
             
                def interval_for_cell(self, cell_index):
         
     | 
| 
       409 
268 
     | 
    
         
             
                    """Returns the interval index for a given cell index (identical if there are no unblocked intervals)."""
         
     | 
| 
      
 269 
     | 
    
         
            +
             
     | 
| 
       410 
270 
     | 
    
         
             
                    assert 0 <= cell_index < self.cell_count
         
     | 
| 
       411 
271 
     | 
    
         
             
                    if self.node_count == self.cell_count + 1:
         
     | 
| 
       412 
272 
     | 
    
         
             
                        return cell_index
         
     | 
| 
         @@ -424,20 +284,10 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       424 
284 
     | 
    
         
             
                        (float, float) being the entry and exit measured depths for the cell, along the trajectory;
         
     | 
| 
       425 
285 
     | 
    
         
             
                        uom is held in trajectory object
         
     | 
| 
       426 
286 
     | 
    
         
             
                    """
         
     | 
| 
      
 287 
     | 
    
         
            +
             
     | 
| 
       427 
288 
     | 
    
         
             
                    interval = self.interval_for_cell(cell_index)
         
     | 
| 
       428 
289 
     | 
    
         
             
                    return (self.node_mds[interval], self.node_mds[interval + 1])
         
     | 
| 
       429 
290 
     | 
    
         | 
| 
       430 
     | 
    
         
            -
                def _set_cell_interval_map(self):
         
     | 
| 
       431 
     | 
    
         
            -
                    """Sets up an index mapping from blocked cell index to interval index, accounting for unblocked intervals."""
         
     | 
| 
       432 
     | 
    
         
            -
                    self.cell_interval_map = np.zeros(self.cell_count, dtype = int)
         
     | 
| 
       433 
     | 
    
         
            -
                    ci = 0
         
     | 
| 
       434 
     | 
    
         
            -
                    for ii in range(self.node_count - 1):
         
     | 
| 
       435 
     | 
    
         
            -
                        if self.grid_indices[ii] < 0:
         
     | 
| 
       436 
     | 
    
         
            -
                            continue
         
     | 
| 
       437 
     | 
    
         
            -
                        self.cell_interval_map[ci] = ii
         
     | 
| 
       438 
     | 
    
         
            -
                        ci += 1
         
     | 
| 
       439 
     | 
    
         
            -
                    assert ci == self.cell_count
         
     | 
| 
       440 
     | 
    
         
            -
             
     | 
| 
       441 
291 
     | 
    
         
             
                def cell_indices_kji0(self):
         
     | 
| 
       442 
292 
     | 
    
         
             
                    """Returns a numpy int array of shape (N, 3) of cells visited by well, for a single grid situation.
         
     | 
| 
       443 
293 
     | 
    
         | 
| 
         @@ -456,7 +306,7 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       456 
306 
     | 
    
         
             
                    grid_for_cell_list = []
         
     | 
| 
       457 
307 
     | 
    
         
             
                    grid_indices = self.compressed_grid_indices()
         
     | 
| 
       458 
308 
     | 
    
         
             
                    assert len(grid_indices) == self.cell_count
         
     | 
| 
       459 
     | 
    
         
            -
                    cell_indices = np.empty((self.cell_count, 3), dtype =  
     | 
| 
      
 309 
     | 
    
         
            +
                    cell_indices = np.empty((self.cell_count, 3), dtype = np.int32)
         
     | 
| 
       460 
310 
     | 
    
         
             
                    for cell_number in range(self.cell_count):
         
     | 
| 
       461 
311 
     | 
    
         
             
                        grid = self.grid_list[grid_indices[cell_number]]
         
     | 
| 
       462 
312 
     | 
    
         
             
                        grid_for_cell_list.append(grid)
         
     | 
| 
         @@ -488,7 +338,7 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       488 
338 
     | 
    
         | 
| 
       489 
339 
     | 
    
         
             
                    if cells_kji0 is None or len(cells_kji0) == 0:
         
     | 
| 
       490 
340 
     | 
    
         
             
                        return None
         
     | 
| 
       491 
     | 
    
         
            -
                    well_box = np.empty((2, 3), dtype =  
     | 
| 
      
 341 
     | 
    
         
            +
                    well_box = np.empty((2, 3), dtype = np.int32)
         
     | 
| 
       492 
342 
     | 
    
         
             
                    well_box[0] = np.min(cells_kji0, axis = 0)
         
     | 
| 
       493 
343 
     | 
    
         
             
                    well_box[1] = np.max(cells_kji0, axis = 0)
         
     | 
| 
       494 
344 
     | 
    
         
             
                    return well_box
         
     | 
| 
         @@ -716,16 +566,6 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       716 
566 
     | 
    
         | 
| 
       717 
567 
     | 
    
         
             
                    return self
         
     | 
| 
       718 
568 
     | 
    
         | 
| 
       719 
     | 
    
         
            -
                def __derive_from_wellspec_check_well_name(self, well_name):
         
     | 
| 
       720 
     | 
    
         
            -
                    """Set the well name to be used in the wellspec file."""
         
     | 
| 
       721 
     | 
    
         
            -
                    if well_name:
         
     | 
| 
       722 
     | 
    
         
            -
                        self.well_name = well_name
         
     | 
| 
       723 
     | 
    
         
            -
                    else:
         
     | 
| 
       724 
     | 
    
         
            -
                        well_name = self.well_name
         
     | 
| 
       725 
     | 
    
         
            -
                    if not self.title:
         
     | 
| 
       726 
     | 
    
         
            -
                        self.title = well_name
         
     | 
| 
       727 
     | 
    
         
            -
                    return well_name
         
     | 
| 
       728 
     | 
    
         
            -
             
     | 
| 
       729 
569 
     | 
    
         
             
                def derive_from_cell_list(self, cell_kji0_list, well_name, grid, length_uom = None):
         
     | 
| 
       730 
570 
     | 
    
         
             
                    """Populate empty blocked well from numpy int array of shape (N, 3) being list of cells."""
         
     | 
| 
       731 
571 
     | 
    
         | 
| 
         @@ -847,9 +687,9 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       847 
687 
     | 
    
         
             
                    self.node_count = len(trajectory_mds)
         
     | 
| 
       848 
688 
     | 
    
         
             
                    self.node_mds = np.array(trajectory_mds)
         
     | 
| 
       849 
689 
     | 
    
         
             
                    self.cell_count = len(blocked_cells_kji0)
         
     | 
| 
       850 
     | 
    
         
            -
                    self.grid_indices = np.array(blocked_intervals, dtype =  
     | 
| 
       851 
     | 
    
         
            -
                    self.cell_indices = grid.natural_cell_indices(np.array(blocked_cells_kji0))
         
     | 
| 
       852 
     | 
    
         
            -
                    self.face_pair_indices = np.array(blocked_face_pairs, dtype =  
     | 
| 
      
 690 
     | 
    
         
            +
                    self.grid_indices = np.array(blocked_intervals, dtype = np.int32)  # NB. only supporting one grid at the moment
         
     | 
| 
      
 691 
     | 
    
         
            +
                    self.cell_indices = grid.natural_cell_indices(np.array(blocked_cells_kji0)).astype(self.cell_index_dtype)
         
     | 
| 
      
 692 
     | 
    
         
            +
                    self.face_pair_indices = np.array(blocked_face_pairs, dtype = np.int8)
         
     | 
| 
       853 
693 
     | 
    
         
             
                    self.grid_list = [grid]
         
     | 
| 
       854 
694 
     | 
    
         | 
| 
       855 
695 
     | 
    
         
             
                    trajectory_points, trajectory_mds = BlockedWell.__add_tail_to_trajectory_if_necessary(
         
     | 
| 
         @@ -866,258 +706,38 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       866 
706 
     | 
    
         | 
| 
       867 
707 
     | 
    
         
             
                    return self
         
     | 
| 
       868 
708 
     | 
    
         | 
| 
       869 
     | 
    
         
            -
                 
     | 
| 
       870 
     | 
    
         
            -
             
     | 
| 
       871 
     | 
    
         
            -
             
     | 
| 
       872 
     | 
    
         
            -
             
     | 
| 
       873 
     | 
    
         
            -
             
     | 
| 
       874 
     | 
    
         
            -
             
     | 
| 
       875 
     | 
    
         
            -
                     
     | 
| 
       876 
     | 
    
         
            -
                    cell_kji0[:] -= 1
         
     | 
| 
       877 
     | 
    
         
            -
                    return cell_kji0
         
     | 
| 
       878 
     | 
    
         
            -
             
     | 
| 
       879 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       880 
     | 
    
         
            -
                def __verify_grid_name(grid_name_to_check, row, skipped_warning_grid, well_name):
         
     | 
| 
       881 
     | 
    
         
            -
                    """Check whether the grid associated with a row of the dataframe matches the expected grid name."""
         
     | 
| 
       882 
     | 
    
         
            -
                    skip_row = False
         
     | 
| 
       883 
     | 
    
         
            -
                    if grid_name_to_check and pd.notna(row['GRID']) and grid_name_to_check != str(row['GRID']).upper():
         
     | 
| 
       884 
     | 
    
         
            -
                        other_grid = str(row['GRID'])
         
     | 
| 
       885 
     | 
    
         
            -
                        if skipped_warning_grid != other_grid:
         
     | 
| 
       886 
     | 
    
         
            -
                            log.warning('skipping perforation(s) in grid ' + other_grid + ' for well ' + str(well_name))
         
     | 
| 
       887 
     | 
    
         
            -
                            skipped_warning_grid = other_grid
         
     | 
| 
       888 
     | 
    
         
            -
                            skip_row = True
         
     | 
| 
       889 
     | 
    
         
            -
                    return skipped_warning_grid, skip_row
         
     | 
| 
       890 
     | 
    
         
            -
             
     | 
| 
       891 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       892 
     | 
    
         
            -
                def __calculate_entry_and_exit_axes_polarities_and_points(angles_present, row, cp, well_name, df, i, cell_kji0,
         
     | 
| 
       893 
     | 
    
         
            -
                                                                          blocked_cells_kji0, use_face_centres, xy_units, z_units):
         
     | 
| 
       894 
     | 
    
         
            -
                    if angles_present:
         
     | 
| 
       895 
     | 
    
         
            -
                        entry_axis, entry_polarity, entry_xyz, exit_axis, exit_polarity, exit_xyz =  \
         
     | 
| 
       896 
     | 
    
         
            -
                        BlockedWell.__calculate_entry_and_exit_axes_polarities_and_points_using_angles(
         
     | 
| 
       897 
     | 
    
         
            -
                            row = row, cp = cp, well_name = well_name, xy_units = xy_units, z_units = z_units)
         
     | 
| 
       898 
     | 
    
         
            -
                    else:
         
     | 
| 
       899 
     | 
    
         
            -
                        # fabricate entry and exit axes and polarities based on indices alone
         
     | 
| 
       900 
     | 
    
         
            -
                        # note: could use geometry but here a cheap rough-and-ready approach is used
         
     | 
| 
       901 
     | 
    
         
            -
                        log.debug('row ' + str(i) + ': using cell moves')
         
     | 
| 
       902 
     | 
    
         
            -
                        entry_axis, entry_polarity, exit_axis, exit_polarity = BlockedWell.__calculate_entry_and_exit_axes_polarities_and_points_using_indices(
         
     | 
| 
       903 
     | 
    
         
            -
                            df = df, i = i, cell_kji0 = cell_kji0, blocked_cells_kji0 = blocked_cells_kji0)
         
     | 
| 
       904 
     | 
    
         
            -
             
     | 
| 
       905 
     | 
    
         
            -
                    entry_xyz, exit_xyz = BlockedWell.__override_vector_based_xyz_entry_and_exit_points_if_necessary(
         
     | 
| 
       906 
     | 
    
         
            -
                        use_face_centres = use_face_centres,
         
     | 
| 
       907 
     | 
    
         
            -
                        entry_axis = entry_axis,
         
     | 
| 
       908 
     | 
    
         
            -
                        exit_axis = exit_axis,
         
     | 
| 
       909 
     | 
    
         
            -
                        entry_polarity = entry_polarity,
         
     | 
| 
       910 
     | 
    
         
            -
                        exit_polarity = exit_polarity,
         
     | 
| 
       911 
     | 
    
         
            -
                        cp = cp)
         
     | 
| 
      
 709 
     | 
    
         
            +
                def import_from_rms_cellio(self,
         
     | 
| 
      
 710 
     | 
    
         
            +
                                           cellio_file,
         
     | 
| 
      
 711 
     | 
    
         
            +
                                           well_name,
         
     | 
| 
      
 712 
     | 
    
         
            +
                                           grid,
         
     | 
| 
      
 713 
     | 
    
         
            +
                                           include_overburden_unblocked_interval = False,
         
     | 
| 
      
 714 
     | 
    
         
            +
                                           set_tangent_vectors = False):
         
     | 
| 
      
 715 
     | 
    
         
            +
                    """Populates empty blocked well from RMS cell I/O data; creates simulation trajectory and md datum.
         
     | 
| 
       912 
716 
     | 
    
         | 
| 
       913 
     | 
    
         
            -
                     
     | 
| 
      
 717 
     | 
    
         
            +
                    arguments:
         
     | 
| 
      
 718 
     | 
    
         
            +
                       cellio_file (string): path of RMS ascii export file holding blocked well cell I/O data; cell entry and
         
     | 
| 
      
 719 
     | 
    
         
            +
                          exit points are expected
         
     | 
| 
      
 720 
     | 
    
         
            +
                       well_name (string): the name of the well as used in the cell I/O file
         
     | 
| 
      
 721 
     | 
    
         
            +
                       grid (grid.Grid object): the grid object which the cell indices in the cell I/O data relate to
         
     | 
| 
      
 722 
     | 
    
         
            +
                       set_tangent_vectors (boolean, default False): if True, tangent vectors will be computed from the well
         
     | 
| 
      
 723 
     | 
    
         
            +
                          trajectory's control points
         
     | 
| 
       914 
724 
     | 
    
         | 
| 
       915 
     | 
    
         
            -
             
     | 
| 
       916 
     | 
    
         
            -
             
     | 
| 
       917 
     | 
    
         
            -
                    """ 
     | 
| 
      
 725 
     | 
    
         
            +
                    returns:
         
     | 
| 
      
 726 
     | 
    
         
            +
                       self if successful; None otherwise
         
     | 
| 
      
 727 
     | 
    
         
            +
                    """
         
     | 
| 
       918 
728 
     | 
    
         | 
| 
       919 
     | 
    
         
            -
                     
     | 
| 
       920 
     | 
    
         
            -
             
     | 
| 
       921 
     | 
    
         
            -
                    if inclination < 0.001:
         
     | 
| 
       922 
     | 
    
         
            -
                        azimuth = 0.0
         
     | 
| 
      
 729 
     | 
    
         
            +
                    if well_name:
         
     | 
| 
      
 730 
     | 
    
         
            +
                        self.well_name = well_name
         
     | 
| 
       923 
731 
     | 
    
         
             
                    else:
         
     | 
| 
       924 
     | 
    
         
            -
                         
     | 
| 
       925 
     | 
    
         
            -
             
     | 
| 
       926 
     | 
    
         
            -
             
     | 
| 
       927 
     | 
    
         
            -
                    if xy_units != z_units:
         
     | 
| 
       928 
     | 
    
         
            -
                        well_vector[2] = wam.convert_lengths(well_vector[2], xy_units, z_units)
         
     | 
| 
       929 
     | 
    
         
            -
                        well_vector = vec.unit_vector(well_vector) * 10000.0
         
     | 
| 
       930 
     | 
    
         
            -
                    # todo: the following might be producing NaN's when vector passes precisely through an edge
         
     | 
| 
       931 
     | 
    
         
            -
                    (entry_axis, entry_polarity, entry_xyz, exit_axis, exit_polarity, exit_xyz) =  \
         
     | 
| 
       932 
     | 
    
         
            -
                        rqwu.find_entry_and_exit(cp, -well_vector, well_vector, well_name)
         
     | 
| 
       933 
     | 
    
         
            -
                    return entry_axis, entry_polarity, entry_xyz, exit_axis, exit_polarity, exit_xyz
         
     | 
| 
      
 732 
     | 
    
         
            +
                        well_name = self.well_name
         
     | 
| 
      
 733 
     | 
    
         
            +
                    if not self.title:
         
     | 
| 
      
 734 
     | 
    
         
            +
                        self.title = well_name
         
     | 
| 
       934 
735 
     | 
    
         | 
| 
       935 
     | 
    
         
            -
             
     | 
| 
       936 
     | 
    
         
            -
             
     | 
| 
       937 
     | 
    
         
            -
                     
     | 
| 
       938 
     | 
    
         
            -
             
     | 
| 
       939 
     | 
    
         
            -
                     
     | 
| 
       940 
     | 
    
         
            -
                        i, cell_kji0, entry_axis, entry_polarity, df)
         
     | 
| 
       941 
     | 
    
         
            -
             
     | 
| 
       942 
     | 
    
         
            -
                    return entry_axis, entry_polarity, exit_axis, exit_polarity
         
     | 
| 
       943 
     | 
    
         
            -
             
     | 
| 
       944 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       945 
     | 
    
         
            -
                def __fabricate_entry_axis_and_polarity_using_indices(i, cell_kji0, blocked_cells_kji0):
         
     | 
| 
       946 
     | 
    
         
            -
                    """Fabricate entry and exit axes and polarities based on indices alone.
         
     | 
| 
       947 
     | 
    
         
            -
             
     | 
| 
       948 
     | 
    
         
            -
                    note:
         
     | 
| 
       949 
     | 
    
         
            -
                        could use geometry but here a cheap rough-and-ready approach is used
         
     | 
| 
       950 
     | 
    
         
            -
                    """
         
     | 
| 
       951 
     | 
    
         
            -
             
     | 
| 
       952 
     | 
    
         
            -
                    if i == 0:
         
     | 
| 
       953 
     | 
    
         
            -
                        entry_axis, entry_polarity = 0, 0  # K-
         
     | 
| 
       954 
     | 
    
         
            -
                    else:
         
     | 
| 
       955 
     | 
    
         
            -
                        entry_move = cell_kji0 - blocked_cells_kji0[-1]
         
     | 
| 
       956 
     | 
    
         
            -
                        log.debug(f'entry move: {entry_move}')
         
     | 
| 
       957 
     | 
    
         
            -
                        if entry_move[1] == 0 and entry_move[2] == 0:  # K move
         
     | 
| 
       958 
     | 
    
         
            -
                            entry_axis = 0
         
     | 
| 
       959 
     | 
    
         
            -
                            entry_polarity = 0 if entry_move[0] >= 0 else 1
         
     | 
| 
       960 
     | 
    
         
            -
                        elif abs(entry_move[1]) > abs(entry_move[2]):  # J dominant move
         
     | 
| 
       961 
     | 
    
         
            -
                            entry_axis = 1
         
     | 
| 
       962 
     | 
    
         
            -
                            entry_polarity = 0 if entry_move[1] >= 0 else 1
         
     | 
| 
       963 
     | 
    
         
            -
                        else:  # I dominant move
         
     | 
| 
       964 
     | 
    
         
            -
                            entry_axis = 2
         
     | 
| 
       965 
     | 
    
         
            -
                            entry_polarity = 0 if entry_move[2] >= 0 else 1
         
     | 
| 
       966 
     | 
    
         
            -
                    return entry_axis, entry_polarity
         
     | 
| 
       967 
     | 
    
         
            -
             
     | 
| 
       968 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       969 
     | 
    
         
            -
                def __fabricate_exit_axis_and_polarity_using_indices(i, cell_kji0, entry_axis, entry_polarity, df):
         
     | 
| 
       970 
     | 
    
         
            -
                    if i == len(df) - 1:
         
     | 
| 
       971 
     | 
    
         
            -
                        exit_axis, exit_polarity = entry_axis, 1 - entry_polarity
         
     | 
| 
       972 
     | 
    
         
            -
                    else:
         
     | 
| 
       973 
     | 
    
         
            -
                        next_cell_kji0 = BlockedWell.__cell_kji0_from_df(df, i + 1)
         
     | 
| 
       974 
     | 
    
         
            -
                        if next_cell_kji0 is None:
         
     | 
| 
       975 
     | 
    
         
            -
                            exit_axis, exit_polarity = entry_axis, 1 - entry_polarity
         
     | 
| 
       976 
     | 
    
         
            -
                        else:
         
     | 
| 
       977 
     | 
    
         
            -
                            exit_move = next_cell_kji0 - cell_kji0
         
     | 
| 
       978 
     | 
    
         
            -
                            log.debug(f'exit move: {exit_move}')
         
     | 
| 
       979 
     | 
    
         
            -
                            if exit_move[1] == 0 and exit_move[2] == 0:  # K move
         
     | 
| 
       980 
     | 
    
         
            -
                                exit_axis = 0
         
     | 
| 
       981 
     | 
    
         
            -
                                exit_polarity = 1 if exit_move[0] >= 0 else 0
         
     | 
| 
       982 
     | 
    
         
            -
                            elif abs(exit_move[1]) > abs(exit_move[2]):  # J dominant move
         
     | 
| 
       983 
     | 
    
         
            -
                                exit_axis = 1
         
     | 
| 
       984 
     | 
    
         
            -
                                exit_polarity = 1 if exit_move[1] >= 0 else 0
         
     | 
| 
       985 
     | 
    
         
            -
                            else:  # I dominant move
         
     | 
| 
       986 
     | 
    
         
            -
                                exit_axis = 2
         
     | 
| 
       987 
     | 
    
         
            -
                                exit_polarity = 1 if exit_move[2] >= 0 else 0
         
     | 
| 
       988 
     | 
    
         
            -
                    return exit_axis, exit_polarity
         
     | 
| 
       989 
     | 
    
         
            -
             
     | 
| 
       990 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       991 
     | 
    
         
            -
                def __override_vector_based_xyz_entry_and_exit_points_if_necessary(use_face_centres, entry_axis, exit_axis,
         
     | 
| 
       992 
     | 
    
         
            -
                                                                                   entry_polarity, exit_polarity, cp):
         
     | 
| 
       993 
     | 
    
         
            -
                    """Override the vector based xyz entry and exit with face centres."""
         
     | 
| 
       994 
     | 
    
         
            -
             
     | 
| 
       995 
     | 
    
         
            -
                    if use_face_centres:  # override the vector based xyz entry and exit points with face centres
         
     | 
| 
       996 
     | 
    
         
            -
                        if entry_axis == 0:
         
     | 
| 
       997 
     | 
    
         
            -
                            entry_xyz = np.mean(cp[entry_polarity, :, :], axis = (0, 1))
         
     | 
| 
       998 
     | 
    
         
            -
                        elif entry_axis == 1:
         
     | 
| 
       999 
     | 
    
         
            -
                            entry_xyz = np.mean(cp[:, entry_polarity, :], axis = (0, 1))
         
     | 
| 
       1000 
     | 
    
         
            -
                        else:
         
     | 
| 
       1001 
     | 
    
         
            -
                            entry_xyz = np.mean(cp[:, :, entry_polarity], axis = (0, 1))  # entry_axis == 2, ie. I
         
     | 
| 
       1002 
     | 
    
         
            -
                        if exit_axis == 0:
         
     | 
| 
       1003 
     | 
    
         
            -
                            exit_xyz = np.mean(cp[exit_polarity, :, :], axis = (0, 1))
         
     | 
| 
       1004 
     | 
    
         
            -
                        elif exit_axis == 1:
         
     | 
| 
       1005 
     | 
    
         
            -
                            exit_xyz = np.mean(cp[:, exit_polarity, :], axis = (0, 1))
         
     | 
| 
       1006 
     | 
    
         
            -
                        else:
         
     | 
| 
       1007 
     | 
    
         
            -
                            exit_xyz = np.mean(cp[:, :, exit_polarity], axis = (0, 1))  # exit_axis == 2, ie. I
         
     | 
| 
       1008 
     | 
    
         
            -
                        return entry_xyz, exit_xyz
         
     | 
| 
       1009 
     | 
    
         
            -
             
     | 
| 
       1010 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1011 
     | 
    
         
            -
                def __add_interval(previous_xyz, entry_axis, entry_polarity, entry_xyz, exit_axis, exit_polarity, exit_xyz,
         
     | 
| 
       1012 
     | 
    
         
            -
                                   cell_kji0, trajectory_mds, trajectory_points, blocked_intervals, blocked_cells_kji0,
         
     | 
| 
       1013 
     | 
    
         
            -
                                   blocked_face_pairs, xy_units, z_units, length_uom):
         
     | 
| 
       1014 
     | 
    
         
            -
                    if previous_xyz is None:  # first entry
         
     | 
| 
       1015 
     | 
    
         
            -
                        log.debug('adding mean sea level trajectory start')
         
     | 
| 
       1016 
     | 
    
         
            -
                        previous_xyz = entry_xyz.copy()
         
     | 
| 
       1017 
     | 
    
         
            -
                        previous_xyz[2] = 0.0  # use depth zero as md datum
         
     | 
| 
       1018 
     | 
    
         
            -
                        trajectory_mds.append(0.0)
         
     | 
| 
       1019 
     | 
    
         
            -
                        trajectory_points.append(previous_xyz)
         
     | 
| 
       1020 
     | 
    
         
            -
                    if not vec.isclose(previous_xyz, entry_xyz, tolerance = 0.05):  # add an unblocked interval
         
     | 
| 
       1021 
     | 
    
         
            -
                        log.debug('adding unblocked interval')
         
     | 
| 
       1022 
     | 
    
         
            -
                        trajectory_points.append(entry_xyz)
         
     | 
| 
       1023 
     | 
    
         
            -
                        new_md = trajectory_mds[-1] + BlockedWell._md_length(entry_xyz - previous_xyz, xy_units, z_units,
         
     | 
| 
       1024 
     | 
    
         
            -
                                                                             length_uom)
         
     | 
| 
       1025 
     | 
    
         
            -
                        trajectory_mds.append(new_md)
         
     | 
| 
       1026 
     | 
    
         
            -
                        blocked_intervals.append(-1)  # unblocked interval
         
     | 
| 
       1027 
     | 
    
         
            -
                        previous_xyz = entry_xyz
         
     | 
| 
       1028 
     | 
    
         
            -
                    log.debug('adding blocked interval for cell kji0: ' + str(cell_kji0))
         
     | 
| 
       1029 
     | 
    
         
            -
                    trajectory_points.append(exit_xyz)
         
     | 
| 
       1030 
     | 
    
         
            -
                    new_md = trajectory_mds[-1] + BlockedWell._md_length(exit_xyz - previous_xyz, xy_units, z_units, length_uom)
         
     | 
| 
       1031 
     | 
    
         
            -
                    trajectory_mds.append(new_md)
         
     | 
| 
       1032 
     | 
    
         
            -
                    blocked_intervals.append(0)  # blocked interval
         
     | 
| 
       1033 
     | 
    
         
            -
                    previous_xyz = exit_xyz
         
     | 
| 
       1034 
     | 
    
         
            -
                    blocked_cells_kji0.append(cell_kji0)
         
     | 
| 
       1035 
     | 
    
         
            -
                    blocked_face_pairs.append(((entry_axis, entry_polarity), (exit_axis, exit_polarity)))
         
     | 
| 
       1036 
     | 
    
         
            -
             
     | 
| 
       1037 
     | 
    
         
            -
                    return previous_xyz, trajectory_mds, trajectory_points, blocked_intervals, blocked_cells_kji0, blocked_face_pairs
         
     | 
| 
       1038 
     | 
    
         
            -
             
     | 
| 
       1039 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1040 
     | 
    
         
            -
                def _md_length(xyz_vector, xy_units, z_units, length_uom):
         
     | 
| 
       1041 
     | 
    
         
            -
                    if length_uom == xy_units and length_uom == z_units:
         
     | 
| 
       1042 
     | 
    
         
            -
                        return vec.naive_length(xyz_vector)
         
     | 
| 
       1043 
     | 
    
         
            -
                    x = wam.convert_lengths(xyz_vector[0], xy_units, length_uom)
         
     | 
| 
       1044 
     | 
    
         
            -
                    y = wam.convert_lengths(xyz_vector[1], xy_units, length_uom)
         
     | 
| 
       1045 
     | 
    
         
            -
                    z = wam.convert_lengths(xyz_vector[2], z_units, length_uom)
         
     | 
| 
       1046 
     | 
    
         
            -
                    return vec.naive_length((x, y, z))
         
     | 
| 
       1047 
     | 
    
         
            -
             
     | 
| 
       1048 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1049 
     | 
    
         
            -
                def __add_tail_to_trajectory_if_necessary(blocked_count, exit_axis, exit_polarity, cell_kji0, grid,
         
     | 
| 
       1050 
     | 
    
         
            -
                                                          trajectory_points, trajectory_mds):
         
     | 
| 
       1051 
     | 
    
         
            -
                    """Add tail to trajcetory if last segment terminates at bottom face in bottom layer."""
         
     | 
| 
       1052 
     | 
    
         
            -
             
     | 
| 
       1053 
     | 
    
         
            -
                    if blocked_count > 0 and exit_axis == 0 and exit_polarity == 1 and cell_kji0[
         
     | 
| 
       1054 
     | 
    
         
            -
                            0] == grid.nk - 1 and grid.k_direction_is_down:
         
     | 
| 
       1055 
     | 
    
         
            -
                        tail_length = 10.0  # metres or feet
         
     | 
| 
       1056 
     | 
    
         
            -
                        tail_xyz = trajectory_points[-1].copy()
         
     | 
| 
       1057 
     | 
    
         
            -
                        tail_xyz[2] += tail_length * (1.0 if grid.z_inc_down() else -1.0)
         
     | 
| 
       1058 
     | 
    
         
            -
                        trajectory_points.append(tail_xyz)
         
     | 
| 
       1059 
     | 
    
         
            -
                        new_md = trajectory_mds[-1] + tail_length
         
     | 
| 
       1060 
     | 
    
         
            -
                        trajectory_mds.append(new_md)
         
     | 
| 
       1061 
     | 
    
         
            -
             
     | 
| 
       1062 
     | 
    
         
            -
                    return trajectory_points, trajectory_mds
         
     | 
| 
       1063 
     | 
    
         
            -
             
     | 
| 
       1064 
     | 
    
         
            -
                def __add_as_properties_if_specified(self,
         
     | 
| 
       1065 
     | 
    
         
            -
                                                     add_as_properties,
         
     | 
| 
       1066 
     | 
    
         
            -
                                                     df,
         
     | 
| 
       1067 
     | 
    
         
            -
                                                     length_uom,
         
     | 
| 
       1068 
     | 
    
         
            -
                                                     time_index = None,
         
     | 
| 
       1069 
     | 
    
         
            -
                                                     time_series_uuid = None):
         
     | 
| 
       1070 
     | 
    
         
            -
                    # if add_as_properties is True and present as a list of wellspec column names, both the blocked well and
         
     | 
| 
       1071 
     | 
    
         
            -
                    # the properties will have their hdf5 data written, xml created and be added as parts to the model
         
     | 
| 
       1072 
     | 
    
         
            -
             
     | 
| 
       1073 
     | 
    
         
            -
                    if add_as_properties and len(df.columns) > 3:
         
     | 
| 
       1074 
     | 
    
         
            -
                        # NB: atypical writing of hdf5 data and xml creation in order to support related properties
         
     | 
| 
       1075 
     | 
    
         
            -
                        self.write_hdf5()
         
     | 
| 
       1076 
     | 
    
         
            -
                        self.create_xml()
         
     | 
| 
       1077 
     | 
    
         
            -
                        if isinstance(add_as_properties, list):
         
     | 
| 
       1078 
     | 
    
         
            -
                            for col in add_as_properties:
         
     | 
| 
       1079 
     | 
    
         
            -
                                assert col in df.columns[3:]  # could just skip missing columns
         
     | 
| 
       1080 
     | 
    
         
            -
                            property_columns = add_as_properties
         
     | 
| 
       1081 
     | 
    
         
            -
                        else:
         
     | 
| 
       1082 
     | 
    
         
            -
                            property_columns = df.columns[3:]
         
     | 
| 
       1083 
     | 
    
         
            -
                        self.add_df_properties(df,
         
     | 
| 
       1084 
     | 
    
         
            -
                                               property_columns,
         
     | 
| 
       1085 
     | 
    
         
            -
                                               length_uom = length_uom,
         
     | 
| 
       1086 
     | 
    
         
            -
                                               time_index = time_index,
         
     | 
| 
       1087 
     | 
    
         
            -
                                               time_series_uuid = time_series_uuid)
         
     | 
| 
       1088 
     | 
    
         
            -
             
     | 
| 
       1089 
     | 
    
         
            -
                def import_from_rms_cellio(self,
         
     | 
| 
       1090 
     | 
    
         
            -
                                           cellio_file,
         
     | 
| 
       1091 
     | 
    
         
            -
                                           well_name,
         
     | 
| 
       1092 
     | 
    
         
            -
                                           grid,
         
     | 
| 
       1093 
     | 
    
         
            -
                                           include_overburden_unblocked_interval = False,
         
     | 
| 
       1094 
     | 
    
         
            -
                                           set_tangent_vectors = False):
         
     | 
| 
       1095 
     | 
    
         
            -
                    """Populates empty blocked well from RMS cell I/O data; creates simulation trajectory and md datum.
         
     | 
| 
       1096 
     | 
    
         
            -
             
     | 
| 
       1097 
     | 
    
         
            -
                    arguments:
         
     | 
| 
       1098 
     | 
    
         
            -
                       cellio_file (string): path of RMS ascii export file holding blocked well cell I/O data; cell entry and
         
     | 
| 
       1099 
     | 
    
         
            -
                          exit points are expected
         
     | 
| 
       1100 
     | 
    
         
            -
                       well_name (string): the name of the well as used in the cell I/O file
         
     | 
| 
       1101 
     | 
    
         
            -
                       grid (grid.Grid object): the grid object which the cell indices in the cell I/O data relate to
         
     | 
| 
       1102 
     | 
    
         
            -
                       set_tangent_vectors (boolean, default False): if True, tangent vectors will be computed from the well
         
     | 
| 
       1103 
     | 
    
         
            -
                          trajectory's control points
         
     | 
| 
       1104 
     | 
    
         
            -
             
     | 
| 
       1105 
     | 
    
         
            -
                    returns:
         
     | 
| 
       1106 
     | 
    
         
            -
                       self if successful; None otherwise
         
     | 
| 
       1107 
     | 
    
         
            -
                    """
         
     | 
| 
       1108 
     | 
    
         
            -
             
     | 
| 
       1109 
     | 
    
         
            -
                    if well_name:
         
     | 
| 
       1110 
     | 
    
         
            -
                        self.well_name = well_name
         
     | 
| 
       1111 
     | 
    
         
            -
                    else:
         
     | 
| 
       1112 
     | 
    
         
            -
                        well_name = self.well_name
         
     | 
| 
       1113 
     | 
    
         
            -
                    if not self.title:
         
     | 
| 
       1114 
     | 
    
         
            -
                        self.title = well_name
         
     | 
| 
       1115 
     | 
    
         
            -
             
     | 
| 
       1116 
     | 
    
         
            -
                    grid_name = rqet.citation_title_for_node(grid.root)
         
     | 
| 
       1117 
     | 
    
         
            -
                    length_uom = grid.z_units()
         
     | 
| 
       1118 
     | 
    
         
            -
                    grid_z_inc_down = crs.Crs(grid.model, uuid = grid.crs_uuid).z_inc_down
         
     | 
| 
       1119 
     | 
    
         
            -
                    log.debug('grid z increasing downwards: ' + str(grid_z_inc_down) + '(type: ' + str(type(grid_z_inc_down)) + ')')
         
     | 
| 
       1120 
     | 
    
         
            -
                    cellio_z_inc_down = None
         
     | 
| 
      
 736 
     | 
    
         
            +
                    grid_name = rqet.citation_title_for_node(grid.root)
         
     | 
| 
      
 737 
     | 
    
         
            +
                    length_uom = grid.z_units()
         
     | 
| 
      
 738 
     | 
    
         
            +
                    grid_z_inc_down = crs.Crs(grid.model, uuid = grid.crs_uuid).z_inc_down
         
     | 
| 
      
 739 
     | 
    
         
            +
                    log.debug('grid z increasing downwards: ' + str(grid_z_inc_down) + '(type: ' + str(type(grid_z_inc_down)) + ')')
         
     | 
| 
      
 740 
     | 
    
         
            +
                    cellio_z_inc_down = None
         
     | 
| 
       1121 
741 
     | 
    
         | 
| 
       1122 
742 
     | 
    
         
             
                    try:
         
     | 
| 
       1123 
743 
     | 
    
         
             
                        assert ' ' not in well_name, 'cannot import for well name containing spaces'
         
     | 
| 
         @@ -1195,9 +815,10 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       1195 
815 
     | 
    
         
             
                            self.node_count = len(trajectory_mds)
         
     | 
| 
       1196 
816 
     | 
    
         
             
                            self.node_mds = np.array(trajectory_mds)
         
     | 
| 
       1197 
817 
     | 
    
         
             
                            self.cell_count = len(blocked_cells_kji0)
         
     | 
| 
       1198 
     | 
    
         
            -
                             
     | 
| 
       1199 
     | 
    
         
            -
             
     | 
| 
       1200 
     | 
    
         
            -
                            self.cell_indices = grid.natural_cell_indices(np.array(blocked_cells_kji0))
         
     | 
| 
      
 818 
     | 
    
         
            +
                            # NB. only supporting one grid at the moment
         
     | 
| 
      
 819 
     | 
    
         
            +
                            self.grid_indices = np.array(blocked_intervals, dtype = np.int32)
         
     | 
| 
      
 820 
     | 
    
         
            +
                            self.cell_indices = grid.natural_cell_indices(np.array(blocked_cells_kji0)).astype(
         
     | 
| 
      
 821 
     | 
    
         
            +
                                self.cell_index_dtype)
         
     | 
| 
       1201 
822 
     | 
    
         
             
                            self.face_pair_indices = np.array(blocked_face_pairs)
         
     | 
| 
       1202 
823 
     | 
    
         
             
                            self.grid_list = [grid]
         
     | 
| 
       1203 
824 
     | 
    
         | 
| 
         @@ -1208,70 +829,6 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       1208 
829 
     | 
    
         | 
| 
       1209 
830 
     | 
    
         
             
                    return self
         
     | 
| 
       1210 
831 
     | 
    
         | 
| 
       1211 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1212 
     | 
    
         
            -
                def __verify_header_lines_in_cellio_file(fp, well_name, cellio_file):
         
     | 
| 
       1213 
     | 
    
         
            -
                    """Find and verify the information in the header lines for the specified well in the RMS cellio file."""
         
     | 
| 
       1214 
     | 
    
         
            -
                    while True:
         
     | 
| 
       1215 
     | 
    
         
            -
                        kf.skip_blank_lines_and_comments(fp)
         
     | 
| 
       1216 
     | 
    
         
            -
                        line = fp.readline()  # file format version number?
         
     | 
| 
       1217 
     | 
    
         
            -
                        assert line, 'well ' + str(well_name) + ' not found in file ' + str(cellio_file)
         
     | 
| 
       1218 
     | 
    
         
            -
                        fp.readline()  # 'Undefined'
         
     | 
| 
       1219 
     | 
    
         
            -
                        words = fp.readline().split()
         
     | 
| 
       1220 
     | 
    
         
            -
                        assert len(words), 'missing header info in cell I/O file'
         
     | 
| 
       1221 
     | 
    
         
            -
                        if words[0].upper() == well_name.upper():
         
     | 
| 
       1222 
     | 
    
         
            -
                            break
         
     | 
| 
       1223 
     | 
    
         
            -
                        while not kf.blank_line(fp):
         
     | 
| 
       1224 
     | 
    
         
            -
                            fp.readline()  # skip to block of data for next well
         
     | 
| 
       1225 
     | 
    
         
            -
                    header_lines = int(fp.readline().strip())
         
     | 
| 
       1226 
     | 
    
         
            -
                    for _ in range(header_lines):
         
     | 
| 
       1227 
     | 
    
         
            -
                        fp.readline()
         
     | 
| 
       1228 
     | 
    
         
            -
             
     | 
| 
       1229 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1230 
     | 
    
         
            -
                def __parse_non_blank_line_in_cellio_file(line, grid, cellio_z_inc_down, grid_z_inc_down):
         
     | 
| 
       1231 
     | 
    
         
            -
                    """Parse each non-blank line in the RMS cellio file for the relevant parameters."""
         
     | 
| 
       1232 
     | 
    
         
            -
             
     | 
| 
       1233 
     | 
    
         
            -
                    words = line.split()
         
     | 
| 
       1234 
     | 
    
         
            -
                    assert len(words) >= 9, 'not enough items on data line in cell I/O file, minimum 9 expected'
         
     | 
| 
       1235 
     | 
    
         
            -
                    i1, j1, k1 = int(words[0]), int(words[1]), int(words[2])
         
     | 
| 
       1236 
     | 
    
         
            -
                    cell_kji0 = np.array((k1 - 1, j1 - 1, i1 - 1), dtype = int)
         
     | 
| 
       1237 
     | 
    
         
            -
                    assert np.all(0 <= cell_kji0) and np.all(
         
     | 
| 
       1238 
     | 
    
         
            -
                        cell_kji0 < grid.extent_kji), 'cell I/O cell index not within grid extent'
         
     | 
| 
       1239 
     | 
    
         
            -
                    entry_xyz = np.array((float(words[3]), float(words[4]), float(words[5])))
         
     | 
| 
       1240 
     | 
    
         
            -
                    exit_xyz = np.array((float(words[6]), float(words[7]), float(words[8])))
         
     | 
| 
       1241 
     | 
    
         
            -
                    if cellio_z_inc_down is None:
         
     | 
| 
       1242 
     | 
    
         
            -
                        cellio_z_inc_down = bool(entry_xyz[2] + exit_xyz[2] > 0.0)
         
     | 
| 
       1243 
     | 
    
         
            -
                    if cellio_z_inc_down != grid_z_inc_down:
         
     | 
| 
       1244 
     | 
    
         
            -
                        entry_xyz[2] = -entry_xyz[2]
         
     | 
| 
       1245 
     | 
    
         
            -
                        exit_xyz[2] = -exit_xyz[2]
         
     | 
| 
       1246 
     | 
    
         
            -
                    return cell_kji0, entry_xyz, exit_xyz
         
     | 
| 
       1247 
     | 
    
         
            -
             
     | 
| 
       1248 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1249 
     | 
    
         
            -
                def __calculate_cell_cp_center_and_vectors(grid, cell_kji0, entry_xyz, exit_xyz, well_name):
         
     | 
| 
       1250 
     | 
    
         
            -
                    # calculate the i,j,k coordinates that represent the corner points and center of a perforation cell
         
     | 
| 
       1251 
     | 
    
         
            -
                    # calculate the entry and exit vectors for the perforation cell
         
     | 
| 
       1252 
     | 
    
         
            -
             
     | 
| 
       1253 
     | 
    
         
            -
                    cp = grid.corner_points(cell_kji0 = cell_kji0, cache_resqml_array = False)
         
     | 
| 
       1254 
     | 
    
         
            -
                    assert not np.any(np.isnan(
         
     | 
| 
       1255 
     | 
    
         
            -
                        cp)), 'missing geometry for perforation cell(kji0) ' + str(cell_kji0) + ' for well ' + str(well_name)
         
     | 
| 
       1256 
     | 
    
         
            -
                    cell_centre = np.mean(cp, axis = (0, 1, 2))
         
     | 
| 
       1257 
     | 
    
         
            -
                    # let's hope everything is in the same coordinate reference system!
         
     | 
| 
       1258 
     | 
    
         
            -
                    entry_vector = 100.0 * (entry_xyz - cell_centre)
         
     | 
| 
       1259 
     | 
    
         
            -
                    exit_vector = 100.0 * (exit_xyz - cell_centre)
         
     | 
| 
       1260 
     | 
    
         
            -
                    return cp, cell_centre, entry_vector, exit_vector
         
     | 
| 
       1261 
     | 
    
         
            -
             
     | 
| 
       1262 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1263 
     | 
    
         
            -
                def __check_number_of_blocked_well_intervals(blocked_cells_kji0, well_name, grid_name):
         
     | 
| 
       1264 
     | 
    
         
            -
                    """Check that at least one interval is blocked for the specified well."""
         
     | 
| 
       1265 
     | 
    
         
            -
             
     | 
| 
       1266 
     | 
    
         
            -
                    blocked_count = len(blocked_cells_kji0)
         
     | 
| 
       1267 
     | 
    
         
            -
                    if blocked_count == 0:
         
     | 
| 
       1268 
     | 
    
         
            -
                        log.warning(f"No intervals blocked for well {well_name} in grid"
         
     | 
| 
       1269 
     | 
    
         
            -
                                    f"{f' {grid_name}' if grid_name is not None else ''}.")
         
     | 
| 
       1270 
     | 
    
         
            -
                        return None
         
     | 
| 
       1271 
     | 
    
         
            -
                    else:
         
     | 
| 
       1272 
     | 
    
         
            -
                        log.info(f"{blocked_count} interval{rqwu._pl(blocked_count)} blocked for well {well_name} in"
         
     | 
| 
       1273 
     | 
    
         
            -
                                 f" grid{f' {grid_name}' if grid_name is not None else ''}.")
         
     | 
| 
       1274 
     | 
    
         
            -
             
     | 
| 
       1275 
832 
     | 
    
         
             
                def dataframe(self,
         
     | 
| 
       1276 
833 
     | 
    
         
             
                              i_col = 'IW',
         
     | 
| 
       1277 
834 
     | 
    
         
             
                              j_col = 'JW',
         
     | 
| 
         @@ -1410,20 +967,21 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       1410 
967 
     | 
    
         
             
                       time_series_uuid (UUID, optional): the uuid of the time series for time dependent properties being added
         
     | 
| 
       1411 
968 
     | 
    
         | 
| 
       1412 
969 
     | 
    
         
             
                    notes:
         
     | 
| 
       1413 
     | 
    
         
            -
                       units of length along wellbore will be those of the trajectory's length_uom (also applies to K.H values) unless
         
     | 
| 
       1414 
     | 
    
         
            -
             
     | 
| 
       1415 
     | 
    
         
            -
                       the constraints are applied independently for each row and a row is excluded if it fails any constraint;
         
     | 
| 
       1416 
     | 
    
         
            -
                       the min_k0 and max_k0 arguments do not stop later rows within the layer range from being included;
         
     | 
| 
       1417 
     | 
    
         
            -
                       the min_length and min_kh limits apply to individual cell intervals and thus depend on cell size;
         
     | 
| 
       1418 
     | 
    
         
            -
                       the water and oil saturation limits are for saturations at a single time and affect whether the interval
         
     | 
| 
       1419 
     | 
    
         
            -
             
     | 
| 
       1420 
     | 
    
         
            -
                        
     | 
| 
       1421 
     | 
    
         
            -
             
     | 
| 
       1422 
     | 
    
         
            -
                        
     | 
| 
       1423 
     | 
    
         
            -
                        
     | 
| 
       1424 
     | 
    
         
            -
             
     | 
| 
       1425 
     | 
    
         
            -
                       add_as_properties  
     | 
| 
       1426 
     | 
    
         
            -
                        
     | 
| 
      
 970 
     | 
    
         
            +
                       - units of length along wellbore will be those of the trajectory's length_uom (also applies to K.H values) unless
         
     | 
| 
      
 971 
     | 
    
         
            +
                         the length_uom argument is used;
         
     | 
| 
      
 972 
     | 
    
         
            +
                       - the constraints are applied independently for each row and a row is excluded if it fails any constraint;
         
     | 
| 
      
 973 
     | 
    
         
            +
                       - the min_k0 and max_k0 arguments do not stop later rows within the layer range from being included;
         
     | 
| 
      
 974 
     | 
    
         
            +
                       - the min_length and min_kh limits apply to individual cell intervals and thus depend on cell size;
         
     | 
| 
      
 975 
     | 
    
         
            +
                       - the water and oil saturation limits are for saturations at a single time and affect whether the interval
         
     | 
| 
      
 976 
     | 
    
         
            +
                         is included in the dataframe
         
     | 
| 
      
 977 
     | 
    
         
            +
                       – to turn perforations off and on over time create a time series dependent bunch of boolean properties on
         
     | 
| 
      
 978 
     | 
    
         
            +
                         the blocked well, with title 'STAT' or local property kind 'well connection open';
         
     | 
| 
      
 979 
     | 
    
         
            +
                       - the saturation limits do not stop deeper intervals with qualifying saturations from being included;
         
     | 
| 
      
 980 
     | 
    
         
            +
                       - the k0_list, perforation_list and region_list arguments should be set to None to disable the
         
     | 
| 
      
 981 
     | 
    
         
            +
                         corresponding functionality, if set to an empty list, no rows will be included in the dataframe;
         
     | 
| 
      
 982 
     | 
    
         
            +
                       - if add_as_properties is True, the blocked well must already have been added as a part to the model;
         
     | 
| 
      
 983 
     | 
    
         
            +
                       - add_as_properties and use_properties cannot both be True;
         
     | 
| 
      
 984 
     | 
    
         
            +
                       - add_as_properties and use_properties are only currently functional for single grid blocked wells;
         
     | 
| 
       1427 
985 
     | 
    
         | 
| 
       1428 
986 
     | 
    
         
             
                    :meta common:
         
     | 
| 
       1429 
987 
     | 
    
         
             
                    """
         
     | 
| 
         @@ -1503,7 +1061,7 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       1503 
1061 
     | 
    
         
             
                        for grid in self.grid_list:
         
     | 
| 
       1504 
1062 
     | 
    
         
             
                            grid.cache_all_geometry_arrays()
         
     | 
| 
       1505 
1063 
     | 
    
         | 
| 
       1506 
     | 
    
         
            -
                    k_face_check = np.zeros((2, 2), dtype =  
     | 
| 
      
 1064 
     | 
    
         
            +
                    k_face_check = np.zeros((2, 2), dtype = np.int8)
         
     | 
| 
       1507 
1065 
     | 
    
         
             
                    k_face_check[1, 1] = 1  # now represents entry, exit of K-, K+
         
     | 
| 
       1508 
1066 
     | 
    
         
             
                    k_face_check_end = k_face_check.copy()
         
     | 
| 
       1509 
1067 
     | 
    
         
             
                    k_face_check_end[1] = -1  # entry through K-, terminating (TD) within cell
         
     | 
| 
         @@ -1637,41 +1195,46 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       1637 
1195 
     | 
    
         
             
                        if skip_interval_due_to_min_kh:
         
     | 
| 
       1638 
1196 
     | 
    
         
             
                            continue
         
     | 
| 
       1639 
1197 
     | 
    
         | 
| 
       1640 
     | 
    
         
            -
                        length, radw_i, skin_i, radb, wi, wbc  
     | 
| 
       1641 
     | 
    
         
            -
             
     | 
| 
       1642 
     | 
    
         
            -
             
     | 
| 
       1643 
     | 
    
         
            -
             
     | 
| 
       1644 
     | 
    
         
            -
             
     | 
| 
       1645 
     | 
    
         
            -
             
     | 
| 
       1646 
     | 
    
         
            -
             
     | 
| 
       1647 
     | 
    
         
            -
             
     | 
| 
       1648 
     | 
    
         
            -
             
     | 
| 
       1649 
     | 
    
         
            -
             
     | 
| 
      
 1198 
     | 
    
         
            +
                        length, radw_i, skin_i, radb, wi, wbc, stat_i =  \
         
     | 
| 
      
 1199 
     | 
    
         
            +
                            BlockedWell.__get_pc_arrays_for_interval(pc = pc,
         
     | 
| 
      
 1200 
     | 
    
         
            +
                                                                     pc_timeless = pc_timeless,
         
     | 
| 
      
 1201 
     | 
    
         
            +
                                                                     pc_titles = pc_titles,
         
     | 
| 
      
 1202 
     | 
    
         
            +
                                                                     ci = ci,
         
     | 
| 
      
 1203 
     | 
    
         
            +
                                                                     length = length,
         
     | 
| 
      
 1204 
     | 
    
         
            +
                                                                     radw = radw,
         
     | 
| 
      
 1205 
     | 
    
         
            +
                                                                     skin = skin,
         
     | 
| 
      
 1206 
     | 
    
         
            +
                                                                     stat = stat,
         
     | 
| 
      
 1207 
     | 
    
         
            +
                                                                     length_uom = length_uom,
         
     | 
| 
      
 1208 
     | 
    
         
            +
                                                                     grid = grid,
         
     | 
| 
      
 1209 
     | 
    
         
            +
                                                                     traj_crs = traj_crs)
         
     | 
| 
       1650 
1210 
     | 
    
         
             
                        if skin_i is None:
         
     | 
| 
       1651 
1211 
     | 
    
         
             
                            skin_i = 0.0
         
     | 
| 
       1652 
1212 
     | 
    
         
             
                        if radw_i is None:
         
     | 
| 
       1653 
1213 
     | 
    
         
             
                            radw_i = (0.33 if length_uom == 'ft' else 0.1)
         
     | 
| 
       1654 
     | 
    
         
            -
             
     | 
| 
       1655 
     | 
    
         
            -
             
     | 
| 
       1656 
     | 
    
         
            -
             
     | 
| 
       1657 
     | 
    
         
            -
             
     | 
| 
       1658 
     | 
    
         
            -
             
     | 
| 
       1659 
     | 
    
         
            -
             
     | 
| 
       1660 
     | 
    
         
            -
             
     | 
| 
       1661 
     | 
    
         
            -
             
     | 
| 
       1662 
     | 
    
         
            -
             
     | 
| 
       1663 
     | 
    
         
            -
             
     | 
| 
       1664 
     | 
    
         
            -
             
     | 
| 
       1665 
     | 
    
         
            -
             
     | 
| 
       1666 
     | 
    
         
            -
             
     | 
| 
       1667 
     | 
    
         
            -
             
     | 
| 
       1668 
     | 
    
         
            -
             
     | 
| 
       1669 
     | 
    
         
            -
             
     | 
| 
       1670 
     | 
    
         
            -
             
     | 
| 
       1671 
     | 
    
         
            -
             
     | 
| 
       1672 
     | 
    
         
            -
             
     | 
| 
       1673 
     | 
    
         
            -
             
     | 
| 
       1674 
     | 
    
         
            -
             
     | 
| 
      
 1214 
     | 
    
         
            +
                        if stat_i is None:
         
     | 
| 
      
 1215 
     | 
    
         
            +
                            stat_i = stat
         
     | 
| 
      
 1216 
     | 
    
         
            +
             
     | 
| 
      
 1217 
     | 
    
         
            +
                        radb, wi, wbc =  \
         
     | 
| 
      
 1218 
     | 
    
         
            +
                            BlockedWell.__get_well_inflow_parameters_for_interval(do_well_inflow = do_well_inflow,
         
     | 
| 
      
 1219 
     | 
    
         
            +
                                                                                  isotropic_perm = isotropic_perm,
         
     | 
| 
      
 1220 
     | 
    
         
            +
                                                                                  ntg_is_one = ntg_is_one,
         
     | 
| 
      
 1221 
     | 
    
         
            +
                                                                                  k_i = k_i,
         
     | 
| 
      
 1222 
     | 
    
         
            +
                                                                                  k_j = k_j,
         
     | 
| 
      
 1223 
     | 
    
         
            +
                                                                                  k_k = k_k,
         
     | 
| 
      
 1224 
     | 
    
         
            +
                                                                                  sine_anglv = sine_anglv,
         
     | 
| 
      
 1225 
     | 
    
         
            +
                                                                                  cosine_anglv = cosine_anglv,
         
     | 
| 
      
 1226 
     | 
    
         
            +
                                                                                  sine_angla = sine_angla,
         
     | 
| 
      
 1227 
     | 
    
         
            +
                                                                                  cosine_angla = cosine_angla,
         
     | 
| 
      
 1228 
     | 
    
         
            +
                                                                                  grid = grid,
         
     | 
| 
      
 1229 
     | 
    
         
            +
                                                                                  cell_kji0 = cell_kji0,
         
     | 
| 
      
 1230 
     | 
    
         
            +
                                                                                  radw = radw_i,
         
     | 
| 
      
 1231 
     | 
    
         
            +
                                                                                  radb = radb,
         
     | 
| 
      
 1232 
     | 
    
         
            +
                                                                                  wi = wi,
         
     | 
| 
      
 1233 
     | 
    
         
            +
                                                                                  wbc = wbc,
         
     | 
| 
      
 1234 
     | 
    
         
            +
                                                                                  skin = skin_i,
         
     | 
| 
      
 1235 
     | 
    
         
            +
                                                                                  kh = kh,
         
     | 
| 
      
 1236 
     | 
    
         
            +
                                                                                  length_uom = length_uom,
         
     | 
| 
      
 1237 
     | 
    
         
            +
                                                                                  column_list = column_list)
         
     | 
| 
       1675 
1238 
     | 
    
         | 
| 
       1676 
1239 
     | 
    
         
             
                        xyz = self.__get_xyz_for_interval(doing_xyz = doing_xyz,
         
     | 
| 
       1677 
1240 
     | 
    
         
             
                                                          length_mode = length_mode,
         
     | 
| 
         @@ -1703,7 +1266,7 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       1703 
1266 
     | 
    
         
             
                                                                             kh = kh,
         
     | 
| 
       1704 
1267 
     | 
    
         
             
                                                                             xyz = xyz,
         
     | 
| 
       1705 
1268 
     | 
    
         
             
                                                                             md = md,
         
     | 
| 
       1706 
     | 
    
         
            -
                                                                             stat =  
     | 
| 
      
 1269 
     | 
    
         
            +
                                                                             stat = stat_i,
         
     | 
| 
       1707 
1270 
     | 
    
         
             
                                                                             part_perf_fraction = part_perf_fraction,
         
     | 
| 
       1708 
1271 
     | 
    
         
             
                                                                             radb = radb,
         
     | 
| 
       1709 
1272 
     | 
    
         
             
                                                                             wi = wi,
         
     | 
| 
         @@ -1751,6 +1314,7 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       1751 
1314 
     | 
    
         
             
                                                   fraction of wellbore frame interval in cell,
         
     | 
| 
       1752 
1315 
     | 
    
         
             
                                                   fraction of cell's wellbore interval in wellbore frame interval)
         
     | 
| 
       1753 
1316 
     | 
    
         
             
                    """
         
     | 
| 
      
 1317 
     | 
    
         
            +
             
     | 
| 
       1754 
1318 
     | 
    
         
             
                    return bwf.blocked_well_frame_contributions_list(self, wbf)
         
     | 
| 
       1755 
1319 
     | 
    
         | 
| 
       1756 
1320 
     | 
    
         
             
                def add_properties_from_wellbore_frame(self,
         
     | 
| 
         @@ -1815,1469 +1379,2055 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       1815 
1379 
     | 
    
         
             
                                                                               set_perforation_fraction = set_perforation_fraction,
         
     | 
| 
       1816 
1380 
     | 
    
         
             
                                                                               set_frame_interval = set_frame_interval)
         
     | 
| 
       1817 
1381 
     | 
    
         | 
| 
       1818 
     | 
    
         
            -
                def  
     | 
| 
       1819 
     | 
    
         
            -
             
     | 
| 
       1820 
     | 
    
         
            -
             
     | 
| 
       1821 
     | 
    
         
            -
             
     | 
| 
       1822 
     | 
    
         
            -
             
     | 
| 
       1823 
     | 
    
         
            -
             
     | 
| 
       1824 
     | 
    
         
            -
             
     | 
| 
       1825 
     | 
    
         
            -
             
     | 
| 
       1826 
     | 
    
         
            -
                    return interval_count
         
     | 
| 
       1827 
     | 
    
         
            -
             
     | 
| 
       1828 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1829 
     | 
    
         
            -
                def __prop_array(uuid_or_dict, grid):
         
     | 
| 
       1830 
     | 
    
         
            -
                    assert uuid_or_dict is not None and grid is not None
         
     | 
| 
       1831 
     | 
    
         
            -
                    if isinstance(uuid_or_dict, dict):
         
     | 
| 
       1832 
     | 
    
         
            -
                        prop_uuid = uuid_or_dict[grid.uuid]
         
     | 
| 
       1833 
     | 
    
         
            -
                    else:
         
     | 
| 
       1834 
     | 
    
         
            -
                        prop_uuid = uuid_or_dict  # uuid either in form of string or uuid.UUID
         
     | 
| 
       1835 
     | 
    
         
            -
                    return grid.property_collection.single_array_ref(uuid = prop_uuid)
         
     | 
| 
       1836 
     | 
    
         
            -
             
     | 
| 
       1837 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1838 
     | 
    
         
            -
                def __get_ref_vector(grid, grid_crs, cell_kji0, mode):
         
     | 
| 
       1839 
     | 
    
         
            -
                    # returns unit vector with true direction, ie. accounts for differing xy & z units in grid's crs
         
     | 
| 
       1840 
     | 
    
         
            -
                    # gravity = np.array((0.0, 0.0, 1.0))
         
     | 
| 
       1841 
     | 
    
         
            -
                    if mode == 'normal well i+':
         
     | 
| 
       1842 
     | 
    
         
            -
                        return None  # ANGLA only: option for no projection onto a plane
         
     | 
| 
       1843 
     | 
    
         
            -
                    ref_vector = None
         
     | 
| 
       1844 
     | 
    
         
            -
                    # options for anglv or angla reference: 'z down', 'z+', 'k down', 'k+', 'normal ij', 'normal ij down'
         
     | 
| 
       1845 
     | 
    
         
            -
                    if mode == 'z+':
         
     | 
| 
       1846 
     | 
    
         
            -
                        ref_vector = np.array((0.0, 0.0, 1.0))
         
     | 
| 
       1847 
     | 
    
         
            -
                    elif mode == 'z down':
         
     | 
| 
       1848 
     | 
    
         
            -
                        if grid_crs.z_inc_down:
         
     | 
| 
       1849 
     | 
    
         
            -
                            ref_vector = np.array((0.0, 0.0, 1.0))
         
     | 
| 
       1850 
     | 
    
         
            -
                        else:
         
     | 
| 
       1851 
     | 
    
         
            -
                            ref_vector = np.array((0.0, 0.0, -1.0))
         
     | 
| 
       1852 
     | 
    
         
            -
                    else:
         
     | 
| 
       1853 
     | 
    
         
            -
                        cell_axial_vectors = grid.interface_vectors_kji(cell_kji0)
         
     | 
| 
       1854 
     | 
    
         
            -
                        if grid_crs.xy_units != grid_crs.z_units:
         
     | 
| 
       1855 
     | 
    
         
            -
                            wam.convert_lengths(cell_axial_vectors[..., 2], grid_crs.z_units, grid_crs.xy_units)
         
     | 
| 
       1856 
     | 
    
         
            -
                        if mode in ['k+', 'k down']:
         
     | 
| 
       1857 
     | 
    
         
            -
                            ref_vector = vec.unit_vector(cell_axial_vectors[0])
         
     | 
| 
       1858 
     | 
    
         
            -
                            if mode == 'k down' and not grid.k_direction_is_down:
         
     | 
| 
       1859 
     | 
    
         
            -
                                ref_vector = -ref_vector
         
     | 
| 
       1860 
     | 
    
         
            -
                        else:  # normal to plane of ij axes
         
     | 
| 
       1861 
     | 
    
         
            -
                            ref_vector = vec.unit_vector(vec.cross_product(cell_axial_vectors[1], cell_axial_vectors[2]))
         
     | 
| 
       1862 
     | 
    
         
            -
                            if mode == 'normal ij down':
         
     | 
| 
       1863 
     | 
    
         
            -
                                if grid_crs.z_inc_down:
         
     | 
| 
       1864 
     | 
    
         
            -
                                    if ref_vector[2] < 0.0:
         
     | 
| 
       1865 
     | 
    
         
            -
                                        ref_vector = -ref_vector
         
     | 
| 
       1866 
     | 
    
         
            -
                                else:
         
     | 
| 
       1867 
     | 
    
         
            -
                                    if ref_vector[2] > 0.0:
         
     | 
| 
       1868 
     | 
    
         
            -
                                        ref_vector = -ref_vector
         
     | 
| 
       1869 
     | 
    
         
            -
                        if ref_vector is None or ref_vector[2] == 0.0:
         
     | 
| 
       1870 
     | 
    
         
            -
                            if grid_crs.z_inc_down:
         
     | 
| 
       1871 
     | 
    
         
            -
                                ref_vector = np.array((0.0, 0.0, 1.0))
         
     | 
| 
       1872 
     | 
    
         
            -
                            else:
         
     | 
| 
       1873 
     | 
    
         
            -
                                ref_vector = np.array((0.0, 0.0, -1.0))
         
     | 
| 
       1874 
     | 
    
         
            -
                    return ref_vector
         
     | 
| 
       1875 
     | 
    
         
            -
             
     | 
| 
       1876 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1877 
     | 
    
         
            -
                def __verify_angle_references(anglv_ref, angla_plane_ref):
         
     | 
| 
       1878 
     | 
    
         
            -
                    """Verify that the references for anglv and angla are one of the acceptable options."""
         
     | 
| 
       1879 
     | 
    
         
            -
             
     | 
| 
       1880 
     | 
    
         
            -
                    assert anglv_ref in ['gravity', 'z down', 'z+', 'k down', 'k+', 'normal ij', 'normal ij down']
         
     | 
| 
       1881 
     | 
    
         
            -
                    if anglv_ref == 'gravity':
         
     | 
| 
       1882 
     | 
    
         
            -
                        anglv_ref = 'z down'
         
     | 
| 
       1883 
     | 
    
         
            -
                    if angla_plane_ref is None:
         
     | 
| 
       1884 
     | 
    
         
            -
                        angla_plane_ref = anglv_ref
         
     | 
| 
       1885 
     | 
    
         
            -
                    assert angla_plane_ref in [
         
     | 
| 
       1886 
     | 
    
         
            -
                        'gravity', 'z down', 'z+', 'k down', 'k+', 'normal ij', 'normal ij down', 'normal well i+'
         
     | 
| 
       1887 
     | 
    
         
            -
                    ]
         
     | 
| 
       1888 
     | 
    
         
            -
                    if angla_plane_ref == 'gravity':
         
     | 
| 
       1889 
     | 
    
         
            -
                        angla_plane_ref = 'z down'
         
     | 
| 
       1890 
     | 
    
         
            -
                    return anglv_ref, angla_plane_ref
         
     | 
| 
       1891 
     | 
    
         
            -
             
     | 
| 
       1892 
     | 
    
         
            -
                @staticmethod
         
     | 
| 
       1893 
     | 
    
         
            -
                def __verify_saturation_ranges_and_property_uuids(max_satw, min_sato, max_satg, satw_uuid, sato_uuid, satg_uuid):
         
     | 
| 
       1894 
     | 
    
         
            -
                    # verify that the fluid saturation limits fall within 0.0 to 1.0 and that the uuid of the required
         
     | 
| 
       1895 
     | 
    
         
            -
                    # saturation property array has been specified.
         
     | 
| 
       1896 
     | 
    
         
            -
             
     | 
| 
       1897 
     | 
    
         
            -
                    if max_satw is not None and max_satw >= 1.0:
         
     | 
| 
       1898 
     | 
    
         
            -
                        max_satw = None
         
     | 
| 
       1899 
     | 
    
         
            -
                    if min_sato is not None and min_sato <= 0.0:
         
     | 
| 
       1900 
     | 
    
         
            -
                        min_sato = None
         
     | 
| 
       1901 
     | 
    
         
            -
                    if max_satg is not None and max_satg >= 1.0:
         
     | 
| 
       1902 
     | 
    
         
            -
                        max_satg = None
         
     | 
| 
       1903 
     | 
    
         
            -
             
     | 
| 
       1904 
     | 
    
         
            -
                    phase_list = ['water', 'oil', 'gas']
         
     | 
| 
       1905 
     | 
    
         
            -
                    phase_saturation_limits_list = [max_satw, min_sato, max_satg]
         
     | 
| 
       1906 
     | 
    
         
            -
                    uuids_list = [satw_uuid, sato_uuid, satg_uuid]
         
     | 
| 
       1907 
     | 
    
         
            -
             
     | 
| 
       1908 
     | 
    
         
            -
                    for phase, phase_limit, uuid in zip(phase_list, phase_saturation_limits_list, uuids_list):
         
     | 
| 
       1909 
     | 
    
         
            -
                        if phase_limit is not None:
         
     | 
| 
       1910 
     | 
    
         
            -
                            assert uuid is not None, f'{phase} saturation limit specified without saturation property array'
         
     | 
| 
      
 1382 
     | 
    
         
            +
                def add_df_properties(self,
         
     | 
| 
      
 1383 
     | 
    
         
            +
                                      df,
         
     | 
| 
      
 1384 
     | 
    
         
            +
                                      columns,
         
     | 
| 
      
 1385 
     | 
    
         
            +
                                      length_uom = None,
         
     | 
| 
      
 1386 
     | 
    
         
            +
                                      time_index = None,
         
     | 
| 
      
 1387 
     | 
    
         
            +
                                      time_series_uuid = None,
         
     | 
| 
      
 1388 
     | 
    
         
            +
                                      realization = None):
         
     | 
| 
      
 1389 
     | 
    
         
            +
                    """Creates a property part for each column in the dataframe, based on the dataframe values.
         
     | 
| 
       1911 
1390 
     | 
    
         | 
| 
       1912 
     | 
    
         
            -
                     
     | 
| 
      
 1391 
     | 
    
         
            +
                    arguments:
         
     | 
| 
      
 1392 
     | 
    
         
            +
                        df (pd.DataFrame): dataframe containing the columns that will be converted to properties
         
     | 
| 
      
 1393 
     | 
    
         
            +
                        columns (List[str]): list of the column names that will be converted to properties
         
     | 
| 
      
 1394 
     | 
    
         
            +
                        length_uom (str, optional): the length unit of measure
         
     | 
| 
      
 1395 
     | 
    
         
            +
                        time_index (int, optional): if adding a timestamp to the property, this is the timestamp
         
     | 
| 
      
 1396 
     | 
    
         
            +
                            index of the TimeSeries timestamps attribute
         
     | 
| 
      
 1397 
     | 
    
         
            +
                        time_series_uuid (uuid.UUID, optional): if adding a timestamp to the property, this is
         
     | 
| 
      
 1398 
     | 
    
         
            +
                            the uuid of the TimeSeries object
         
     | 
| 
      
 1399 
     | 
    
         
            +
                        realization (int, optional): if present, is used as the realization number for all the
         
     | 
| 
      
 1400 
     | 
    
         
            +
                            properties
         
     | 
| 
       1913 
1401 
     | 
    
         | 
| 
       1914 
     | 
    
         
            -
             
     | 
| 
       1915 
     | 
    
         
            -
             
     | 
| 
       1916 
     | 
    
         
            -
                                                                       use_properties, skin, stat, radw):
         
     | 
| 
       1917 
     | 
    
         
            -
                    """Determine which extra columns, if any, should be added as properties to the dataframe.
         
     | 
| 
      
 1402 
     | 
    
         
            +
                    returns:
         
     | 
| 
      
 1403 
     | 
    
         
            +
                        None
         
     | 
| 
       1918 
1404 
     | 
    
         | 
| 
       1919 
     | 
    
         
            -
                     
     | 
| 
       1920 
     | 
    
         
            -
                         
     | 
| 
      
 1405 
     | 
    
         
            +
                    notes:
         
     | 
| 
      
 1406 
     | 
    
         
            +
                        the column name is used as the property citation title;
         
     | 
| 
      
 1407 
     | 
    
         
            +
                        the blocked well must already exist as a part in the model;
         
     | 
| 
      
 1408 
     | 
    
         
            +
                        this method currently only handles single grid situations;
         
     | 
| 
      
 1409 
     | 
    
         
            +
                        dataframe rows must be in the same order as the cells in the blocked well
         
     | 
| 
       1921 
1410 
     | 
    
         
             
                    """
         
     | 
| 
       1922 
1411 
     | 
    
         | 
| 
       1923 
     | 
    
         
            -
                     
     | 
| 
       1924 
     | 
    
         
            -
             
     | 
| 
       1925 
     | 
    
         
            -
             
     | 
| 
       1926 
     | 
    
         
            -
             
     | 
| 
       1927 
     | 
    
         
            -
             
     | 
| 
       1928 
     | 
    
         
            -
             
     | 
| 
       1929 
     | 
    
         
            -
             
     | 
| 
       1930 
     | 
    
         
            -
                     
     | 
| 
       1931 
     | 
    
         
            -
             
     | 
| 
       1932 
     | 
    
         
            -
                    assert not (add_as_properties and use_properties)
         
     | 
| 
      
 1412 
     | 
    
         
            +
                    # todo: enhance to handle multiple grids
         
     | 
| 
      
 1413 
     | 
    
         
            +
                    assert len(self.grid_list) == 1
         
     | 
| 
      
 1414 
     | 
    
         
            +
                    if columns is None or len(columns) == 0 or len(df) == 0:
         
     | 
| 
      
 1415 
     | 
    
         
            +
                        return
         
     | 
| 
      
 1416 
     | 
    
         
            +
                    if length_uom is None:
         
     | 
| 
      
 1417 
     | 
    
         
            +
                        length_uom = self.trajectory.md_uom
         
     | 
| 
      
 1418 
     | 
    
         
            +
                    extra_pc = rqp.PropertyCollection()
         
     | 
| 
      
 1419 
     | 
    
         
            +
                    extra_pc.set_support(support = self)
         
     | 
| 
      
 1420 
     | 
    
         
            +
                    assert len(df) == self.cell_count
         
     | 
| 
       1933 
1421 
     | 
    
         | 
| 
       1934 
     | 
    
         
            -
                     
     | 
| 
       1935 
     | 
    
         
            -
                         
     | 
| 
      
 1422 
     | 
    
         
            +
                    for column in columns:
         
     | 
| 
      
 1423 
     | 
    
         
            +
                        extra = column.upper()
         
     | 
| 
      
 1424 
     | 
    
         
            +
                        uom, pk, discrete = self._get_uom_pk_discrete_for_df_properties(extra = extra, length_uom = length_uom)
         
     | 
| 
      
 1425 
     | 
    
         
            +
                        if discrete:
         
     | 
| 
      
 1426 
     | 
    
         
            +
                            null_value = -1
         
     | 
| 
      
 1427 
     | 
    
         
            +
                            na_value = -1
         
     | 
| 
      
 1428 
     | 
    
         
            +
                            dtype = np.int32
         
     | 
| 
      
 1429 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 1430 
     | 
    
         
            +
                            null_value = None
         
     | 
| 
      
 1431 
     | 
    
         
            +
                            na_value = np.nan
         
     | 
| 
      
 1432 
     | 
    
         
            +
                            dtype = float
         
     | 
| 
      
 1433 
     | 
    
         
            +
                        # 'SKIN': use defaults for now; todo: create local property kind for skin
         
     | 
| 
      
 1434 
     | 
    
         
            +
                        if column == 'STAT':
         
     | 
| 
      
 1435 
     | 
    
         
            +
                            col_as_list = list(df[column])
         
     | 
| 
      
 1436 
     | 
    
         
            +
                            expanded = np.array([(0 if (str(st).upper() in ['OFF', '0', 'FALSE']) else 1) for st in col_as_list],
         
     | 
| 
      
 1437 
     | 
    
         
            +
                                                dtype = np.int8)
         
     | 
| 
      
 1438 
     | 
    
         
            +
                            dtype = np.int8
         
     | 
| 
      
 1439 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 1440 
     | 
    
         
            +
                            expanded = df[column].to_numpy(dtype = dtype, copy = True, na_value = na_value)
         
     | 
| 
      
 1441 
     | 
    
         
            +
                        extra_pc.add_cached_array_to_imported_list(
         
     | 
| 
      
 1442 
     | 
    
         
            +
                            expanded,
         
     | 
| 
      
 1443 
     | 
    
         
            +
                            'blocked well dataframe',
         
     | 
| 
      
 1444 
     | 
    
         
            +
                            extra,
         
     | 
| 
      
 1445 
     | 
    
         
            +
                            discrete = discrete,
         
     | 
| 
      
 1446 
     | 
    
         
            +
                            uom = uom,
         
     | 
| 
      
 1447 
     | 
    
         
            +
                            property_kind = pk,
         
     | 
| 
      
 1448 
     | 
    
         
            +
                            local_property_kind_uuid = None,
         
     | 
| 
      
 1449 
     | 
    
         
            +
                            facet_type = None,
         
     | 
| 
      
 1450 
     | 
    
         
            +
                            facet = None,
         
     | 
| 
      
 1451 
     | 
    
         
            +
                            realization = realization,
         
     | 
| 
      
 1452 
     | 
    
         
            +
                            indexable_element = 'cells',
         
     | 
| 
      
 1453 
     | 
    
         
            +
                            count = 1,
         
     | 
| 
      
 1454 
     | 
    
         
            +
                            time_index = time_index,
         
     | 
| 
      
 1455 
     | 
    
         
            +
                            null_value = null_value,
         
     | 
| 
      
 1456 
     | 
    
         
            +
                        )
         
     | 
| 
      
 1457 
     | 
    
         
            +
                    extra_pc.write_hdf5_for_imported_list()
         
     | 
| 
      
 1458 
     | 
    
         
            +
                    extra_pc.create_xml_for_imported_list_and_add_parts_to_model(time_series_uuid = time_series_uuid,
         
     | 
| 
      
 1459 
     | 
    
         
            +
                                                                                 find_local_property_kinds = True)
         
     | 
| 
       1936 
1460 
     | 
    
         | 
| 
       1937 
     | 
    
         
            -
             
     | 
| 
      
 1461 
     | 
    
         
            +
                def static_kh(self,
         
     | 
| 
      
 1462 
     | 
    
         
            +
                              ntg_uuid = None,
         
     | 
| 
      
 1463 
     | 
    
         
            +
                              perm_i_uuid = None,
         
     | 
| 
      
 1464 
     | 
    
         
            +
                              perm_j_uuid = None,
         
     | 
| 
      
 1465 
     | 
    
         
            +
                              perm_k_uuid = None,
         
     | 
| 
      
 1466 
     | 
    
         
            +
                              satw_uuid = None,
         
     | 
| 
      
 1467 
     | 
    
         
            +
                              sato_uuid = None,
         
     | 
| 
      
 1468 
     | 
    
         
            +
                              satg_uuid = None,
         
     | 
| 
      
 1469 
     | 
    
         
            +
                              region_uuid = None,
         
     | 
| 
      
 1470 
     | 
    
         
            +
                              active_only = False,
         
     | 
| 
      
 1471 
     | 
    
         
            +
                              min_k0 = None,
         
     | 
| 
      
 1472 
     | 
    
         
            +
                              max_k0 = None,
         
     | 
| 
      
 1473 
     | 
    
         
            +
                              k0_list = None,
         
     | 
| 
      
 1474 
     | 
    
         
            +
                              min_length = None,
         
     | 
| 
      
 1475 
     | 
    
         
            +
                              min_kh = None,
         
     | 
| 
      
 1476 
     | 
    
         
            +
                              max_depth = None,
         
     | 
| 
      
 1477 
     | 
    
         
            +
                              max_satw = None,
         
     | 
| 
      
 1478 
     | 
    
         
            +
                              min_sato = None,
         
     | 
| 
      
 1479 
     | 
    
         
            +
                              max_satg = None,
         
     | 
| 
      
 1480 
     | 
    
         
            +
                              perforation_list = None,
         
     | 
| 
      
 1481 
     | 
    
         
            +
                              region_list = None,
         
     | 
| 
      
 1482 
     | 
    
         
            +
                              set_k_face_intervals_vertical = False,
         
     | 
| 
      
 1483 
     | 
    
         
            +
                              anglv_ref = 'gravity',
         
     | 
| 
      
 1484 
     | 
    
         
            +
                              angla_plane_ref = None,
         
     | 
| 
      
 1485 
     | 
    
         
            +
                              length_mode = 'MD',
         
     | 
| 
      
 1486 
     | 
    
         
            +
                              length_uom = None,
         
     | 
| 
      
 1487 
     | 
    
         
            +
                              use_face_centres = False,
         
     | 
| 
      
 1488 
     | 
    
         
            +
                              preferential_perforation = True):
         
     | 
| 
      
 1489 
     | 
    
         
            +
                    """Returns the total static K.H (permeability x height).
         
     | 
| 
       1938 
1490 
     | 
    
         | 
| 
       1939 
     | 
    
         
            -
             
     | 
| 
       1940 
     | 
    
         
            -
             
     | 
| 
      
 1491 
     | 
    
         
            +
                    notes:
         
     | 
| 
      
 1492 
     | 
    
         
            +
                       length units are those of trajectory md_uom unless length_upm is set;
         
     | 
| 
      
 1493 
     | 
    
         
            +
                       see doc string for dataframe() method for argument descriptions; perm_i_uuid required
         
     | 
| 
      
 1494 
     | 
    
         
            +
                    """
         
     | 
| 
       1941 
1495 
     | 
    
         | 
| 
       1942 
     | 
    
         
            -
                     
     | 
| 
       1943 
     | 
    
         
            -
             
     | 
| 
       1944 
     | 
    
         
            -
             
     | 
| 
       1945 
     | 
    
         
            -
             
     | 
| 
       1946 
     | 
    
         
            -
             
     | 
| 
       1947 
     | 
    
         
            -
             
     | 
| 
       1948 
     | 
    
         
            -
             
     | 
| 
       1949 
     | 
    
         
            -
             
     | 
| 
       1950 
     | 
    
         
            -
             
     | 
| 
       1951 
     | 
    
         
            -
             
     | 
| 
      
 1496 
     | 
    
         
            +
                    df = self.dataframe(i_col = 'I',
         
     | 
| 
      
 1497 
     | 
    
         
            +
                                        j_col = 'J',
         
     | 
| 
      
 1498 
     | 
    
         
            +
                                        k_col = 'K',
         
     | 
| 
      
 1499 
     | 
    
         
            +
                                        one_based = False,
         
     | 
| 
      
 1500 
     | 
    
         
            +
                                        extra_columns_list = ['KH'],
         
     | 
| 
      
 1501 
     | 
    
         
            +
                                        ntg_uuid = ntg_uuid,
         
     | 
| 
      
 1502 
     | 
    
         
            +
                                        perm_i_uuid = perm_i_uuid,
         
     | 
| 
      
 1503 
     | 
    
         
            +
                                        perm_j_uuid = perm_j_uuid,
         
     | 
| 
      
 1504 
     | 
    
         
            +
                                        perm_k_uuid = perm_k_uuid,
         
     | 
| 
      
 1505 
     | 
    
         
            +
                                        satw_uuid = satw_uuid,
         
     | 
| 
      
 1506 
     | 
    
         
            +
                                        sato_uuid = sato_uuid,
         
     | 
| 
      
 1507 
     | 
    
         
            +
                                        satg_uuid = satg_uuid,
         
     | 
| 
      
 1508 
     | 
    
         
            +
                                        region_uuid = region_uuid,
         
     | 
| 
      
 1509 
     | 
    
         
            +
                                        active_only = active_only,
         
     | 
| 
      
 1510 
     | 
    
         
            +
                                        min_k0 = min_k0,
         
     | 
| 
      
 1511 
     | 
    
         
            +
                                        max_k0 = max_k0,
         
     | 
| 
      
 1512 
     | 
    
         
            +
                                        k0_list = k0_list,
         
     | 
| 
      
 1513 
     | 
    
         
            +
                                        min_length = min_length,
         
     | 
| 
      
 1514 
     | 
    
         
            +
                                        min_kh = min_kh,
         
     | 
| 
      
 1515 
     | 
    
         
            +
                                        max_depth = max_depth,
         
     | 
| 
      
 1516 
     | 
    
         
            +
                                        max_satw = max_satw,
         
     | 
| 
      
 1517 
     | 
    
         
            +
                                        min_sato = min_sato,
         
     | 
| 
      
 1518 
     | 
    
         
            +
                                        max_satg = max_satg,
         
     | 
| 
      
 1519 
     | 
    
         
            +
                                        perforation_list = perforation_list,
         
     | 
| 
      
 1520 
     | 
    
         
            +
                                        region_list = region_list,
         
     | 
| 
      
 1521 
     | 
    
         
            +
                                        set_k_face_intervals_vertical = set_k_face_intervals_vertical,
         
     | 
| 
      
 1522 
     | 
    
         
            +
                                        anglv_ref = anglv_ref,
         
     | 
| 
      
 1523 
     | 
    
         
            +
                                        angla_plane_ref = angla_plane_ref,
         
     | 
| 
      
 1524 
     | 
    
         
            +
                                        length_mode = length_mode,
         
     | 
| 
      
 1525 
     | 
    
         
            +
                                        length_uom = length_uom,
         
     | 
| 
      
 1526 
     | 
    
         
            +
                                        use_face_centres = use_face_centres,
         
     | 
| 
      
 1527 
     | 
    
         
            +
                                        preferential_perforation = preferential_perforation)
         
     | 
| 
       1952 
1528 
     | 
    
         | 
| 
       1953 
     | 
    
         
            -
                     
     | 
| 
       1954 
     | 
    
         
            -
                        log.warning('empty perforation list specified for blocked well dataframe: no rows will be included')
         
     | 
| 
      
 1529 
     | 
    
         
            +
                    return sum(df['KH'])
         
     | 
| 
       1955 
1530 
     | 
    
         | 
| 
       1956 
     | 
    
         
            -
                 
     | 
| 
       1957 
     | 
    
         
            -
             
     | 
| 
       1958 
     | 
    
         
            -
             
     | 
| 
       1959 
     | 
    
         
            -
             
     | 
| 
       1960 
     | 
    
         
            -
             
     | 
| 
       1961 
     | 
    
         
            -
             
     | 
| 
       1962 
     | 
    
         
            -
             
     | 
| 
       1963 
     | 
    
         
            -
             
     | 
| 
       1964 
     | 
    
         
            -
             
     | 
| 
       1965 
     | 
    
         
            -
             
     | 
| 
       1966 
     | 
    
         
            -
             
     | 
| 
       1967 
     | 
    
         
            -
             
     | 
| 
       1968 
     | 
    
         
            -
             
     | 
| 
       1969 
     | 
    
         
            -
             
     | 
| 
       1970 
     | 
    
         
            -
             
     | 
| 
       1971 
     | 
    
         
            -
             
     | 
| 
       1972 
     | 
    
         
            -
             
     | 
| 
       1973 
     | 
    
         
            -
             
     | 
| 
       1974 
     | 
    
         
            -
             
     | 
| 
       1975 
     | 
    
         
            -
             
     | 
| 
       1976 
     | 
    
         
            -
             
     | 
| 
       1977 
     | 
    
         
            -
             
     | 
| 
       1978 
     | 
    
         
            -
             
     | 
| 
       1979 
     | 
    
         
            -
             
     | 
| 
       1980 
     | 
    
         
            -
             
     | 
| 
       1981 
     | 
    
         
            -
             
     | 
| 
       1982 
     | 
    
         
            -
             
     | 
| 
       1983 
     | 
    
         
            -
             
     | 
| 
       1984 
     | 
    
         
            -
             
     | 
| 
       1985 
     | 
    
         
            -
             
     | 
| 
      
 1531 
     | 
    
         
            +
                def write_wellspec(self,
         
     | 
| 
      
 1532 
     | 
    
         
            +
                                   wellspec_file,
         
     | 
| 
      
 1533 
     | 
    
         
            +
                                   well_name = None,
         
     | 
| 
      
 1534 
     | 
    
         
            +
                                   mode = 'a',
         
     | 
| 
      
 1535 
     | 
    
         
            +
                                   extra_columns_list = [],
         
     | 
| 
      
 1536 
     | 
    
         
            +
                                   ntg_uuid = None,
         
     | 
| 
      
 1537 
     | 
    
         
            +
                                   perm_i_uuid = None,
         
     | 
| 
      
 1538 
     | 
    
         
            +
                                   perm_j_uuid = None,
         
     | 
| 
      
 1539 
     | 
    
         
            +
                                   perm_k_uuid = None,
         
     | 
| 
      
 1540 
     | 
    
         
            +
                                   satw_uuid = None,
         
     | 
| 
      
 1541 
     | 
    
         
            +
                                   sato_uuid = None,
         
     | 
| 
      
 1542 
     | 
    
         
            +
                                   satg_uuid = None,
         
     | 
| 
      
 1543 
     | 
    
         
            +
                                   region_uuid = None,
         
     | 
| 
      
 1544 
     | 
    
         
            +
                                   radw = None,
         
     | 
| 
      
 1545 
     | 
    
         
            +
                                   skin = None,
         
     | 
| 
      
 1546 
     | 
    
         
            +
                                   stat = None,
         
     | 
| 
      
 1547 
     | 
    
         
            +
                                   active_only = False,
         
     | 
| 
      
 1548 
     | 
    
         
            +
                                   min_k0 = None,
         
     | 
| 
      
 1549 
     | 
    
         
            +
                                   max_k0 = None,
         
     | 
| 
      
 1550 
     | 
    
         
            +
                                   k0_list = None,
         
     | 
| 
      
 1551 
     | 
    
         
            +
                                   min_length = None,
         
     | 
| 
      
 1552 
     | 
    
         
            +
                                   min_kh = None,
         
     | 
| 
      
 1553 
     | 
    
         
            +
                                   max_depth = None,
         
     | 
| 
      
 1554 
     | 
    
         
            +
                                   max_satw = None,
         
     | 
| 
      
 1555 
     | 
    
         
            +
                                   min_sato = None,
         
     | 
| 
      
 1556 
     | 
    
         
            +
                                   max_satg = None,
         
     | 
| 
      
 1557 
     | 
    
         
            +
                                   perforation_list = None,
         
     | 
| 
      
 1558 
     | 
    
         
            +
                                   region_list = None,
         
     | 
| 
      
 1559 
     | 
    
         
            +
                                   set_k_face_intervals_vertical = False,
         
     | 
| 
      
 1560 
     | 
    
         
            +
                                   depth_inc_down = True,
         
     | 
| 
      
 1561 
     | 
    
         
            +
                                   anglv_ref = 'gravity',
         
     | 
| 
      
 1562 
     | 
    
         
            +
                                   angla_plane_ref = None,
         
     | 
| 
      
 1563 
     | 
    
         
            +
                                   length_mode = 'MD',
         
     | 
| 
      
 1564 
     | 
    
         
            +
                                   length_uom = None,
         
     | 
| 
      
 1565 
     | 
    
         
            +
                                   preferential_perforation = True,
         
     | 
| 
      
 1566 
     | 
    
         
            +
                                   space_instead_of_tab_separator = True,
         
     | 
| 
      
 1567 
     | 
    
         
            +
                                   align_columns = True,
         
     | 
| 
      
 1568 
     | 
    
         
            +
                                   preceeding_blank_lines = 0,
         
     | 
| 
      
 1569 
     | 
    
         
            +
                                   trailing_blank_lines = 0,
         
     | 
| 
      
 1570 
     | 
    
         
            +
                                   length_uom_comment = False,
         
     | 
| 
      
 1571 
     | 
    
         
            +
                                   write_nexus_units = True,
         
     | 
| 
      
 1572 
     | 
    
         
            +
                                   float_format = '5.3',
         
     | 
| 
      
 1573 
     | 
    
         
            +
                                   use_properties = False,
         
     | 
| 
      
 1574 
     | 
    
         
            +
                                   property_time_index = None):
         
     | 
| 
      
 1575 
     | 
    
         
            +
                    """Writes Nexus WELLSPEC keyword to an ascii file.
         
     | 
| 
       1986 
1576 
     | 
    
         | 
| 
       1987 
     | 
    
         
            -
                     
     | 
| 
      
 1577 
     | 
    
         
            +
                    returns:
         
     | 
| 
      
 1578 
     | 
    
         
            +
                       pandas DataFrame containing data that has been written to the wellspec file
         
     | 
| 
       1988 
1579 
     | 
    
         | 
| 
       1989 
     | 
    
         
            -
             
     | 
| 
       1990 
     | 
    
         
            -
             
     | 
| 
       1991 
     | 
    
         
            -
             
     | 
| 
       1992 
     | 
    
         
            -
                     
     | 
| 
      
 1580 
     | 
    
         
            +
                    note:
         
     | 
| 
      
 1581 
     | 
    
         
            +
                       see doc string for dataframe() method for most of the argument descriptions;
         
     | 
| 
      
 1582 
     | 
    
         
            +
                       align_columns and float_format arguments are deprecated and no longer used
         
     | 
| 
      
 1583 
     | 
    
         
            +
                    """
         
     | 
| 
       1993 
1584 
     | 
    
         | 
| 
       1994 
     | 
    
         
            -
                     
     | 
| 
       1995 
     | 
    
         
            -
                        min_kh = None
         
     | 
| 
       1996 
     | 
    
         
            -
                    doing_kh = False
         
     | 
| 
       1997 
     | 
    
         
            -
                    if ('KH' in column_list or min_kh is not None) and 'KH' not in pc_titles:
         
     | 
| 
       1998 
     | 
    
         
            -
                        assert perm_i_uuid is not None, 'KH requested (or minimum specified) without I direction permeabilty being specified'
         
     | 
| 
       1999 
     | 
    
         
            -
                        doing_kh = True
         
     | 
| 
       2000 
     | 
    
         
            -
                    if 'WBC' in column_list and 'WBC' not in pc_titles:
         
     | 
| 
       2001 
     | 
    
         
            -
                        assert perm_i_uuid is not None, 'WBC requested without I direction permeabilty being specified'
         
     | 
| 
       2002 
     | 
    
         
            -
                        doing_kh = True
         
     | 
| 
      
 1585 
     | 
    
         
            +
                    assert wellspec_file, 'no output file specified to write WELLSPEC to'
         
     | 
| 
       2003 
1586 
     | 
    
         | 
| 
       2004 
     | 
    
         
            -
                     
     | 
| 
      
 1587 
     | 
    
         
            +
                    col_width_dict = {
         
     | 
| 
      
 1588 
     | 
    
         
            +
                        'IW': 4,
         
     | 
| 
      
 1589 
     | 
    
         
            +
                        'JW': 4,
         
     | 
| 
      
 1590 
     | 
    
         
            +
                        'L': 4,
         
     | 
| 
      
 1591 
     | 
    
         
            +
                        'ANGLA': 8,
         
     | 
| 
      
 1592 
     | 
    
         
            +
                        'ANGLV': 8,
         
     | 
| 
      
 1593 
     | 
    
         
            +
                        'LENGTH': 8,
         
     | 
| 
      
 1594 
     | 
    
         
            +
                        'KH': 10,
         
     | 
| 
      
 1595 
     | 
    
         
            +
                        'DEPTH': 10,
         
     | 
| 
      
 1596 
     | 
    
         
            +
                        'MD': 10,
         
     | 
| 
      
 1597 
     | 
    
         
            +
                        'X': 8,
         
     | 
| 
      
 1598 
     | 
    
         
            +
                        'Y': 12,
         
     | 
| 
      
 1599 
     | 
    
         
            +
                        'SKIN': 7,
         
     | 
| 
      
 1600 
     | 
    
         
            +
                        'RADW': 5,
         
     | 
| 
      
 1601 
     | 
    
         
            +
                        'RADB': 8,
         
     | 
| 
      
 1602 
     | 
    
         
            +
                        'PPERF': 5
         
     | 
| 
      
 1603 
     | 
    
         
            +
                    }
         
     | 
| 
       2005 
1604 
     | 
    
         | 
| 
       2006 
     | 
    
         
            -
             
     | 
| 
       2007 
     | 
    
         
            -
                def __verify_perm_j_k_uuids_for_kh_and_well_inflow(doing_kh, do_well_inflow, perm_i_uuid, perm_j_uuid, perm_k_uuid):
         
     | 
| 
       2008 
     | 
    
         
            -
                    # verify that the J and K direction permeabilities have been specified if well inflow properties or
         
     | 
| 
       2009 
     | 
    
         
            -
                    # permeability thickness properties are to be added to the dataframe.
         
     | 
| 
      
 1605 
     | 
    
         
            +
                    well_name = self.__get_well_name(well_name = well_name)
         
     | 
| 
       2010 
1606 
     | 
    
         | 
| 
       2011 
     | 
    
         
            -
                     
     | 
| 
       2012 
     | 
    
         
            -
             
     | 
| 
       2013 
     | 
    
         
            -
             
     | 
| 
       2014 
     | 
    
         
            -
             
     | 
| 
       2015 
     | 
    
         
            -
             
     | 
| 
       2016 
     | 
    
         
            -
             
     | 
| 
       2017 
     | 
    
         
            -
             
     | 
| 
       2018 
     | 
    
         
            -
             
     | 
| 
       2019 
     | 
    
         
            -
             
     | 
| 
       2020 
     | 
    
         
            -
             
     | 
| 
       2021 
     | 
    
         
            -
             
     | 
| 
       2022 
     | 
    
         
            -
             
     | 
| 
      
 1607 
     | 
    
         
            +
                    df = self.dataframe(one_based = True,
         
     | 
| 
      
 1608 
     | 
    
         
            +
                                        extra_columns_list = extra_columns_list,
         
     | 
| 
      
 1609 
     | 
    
         
            +
                                        ntg_uuid = ntg_uuid,
         
     | 
| 
      
 1610 
     | 
    
         
            +
                                        perm_i_uuid = perm_i_uuid,
         
     | 
| 
      
 1611 
     | 
    
         
            +
                                        perm_j_uuid = perm_j_uuid,
         
     | 
| 
      
 1612 
     | 
    
         
            +
                                        perm_k_uuid = perm_k_uuid,
         
     | 
| 
      
 1613 
     | 
    
         
            +
                                        satw_uuid = satw_uuid,
         
     | 
| 
      
 1614 
     | 
    
         
            +
                                        sato_uuid = sato_uuid,
         
     | 
| 
      
 1615 
     | 
    
         
            +
                                        satg_uuid = satg_uuid,
         
     | 
| 
      
 1616 
     | 
    
         
            +
                                        region_uuid = region_uuid,
         
     | 
| 
      
 1617 
     | 
    
         
            +
                                        radw = radw,
         
     | 
| 
      
 1618 
     | 
    
         
            +
                                        skin = skin,
         
     | 
| 
      
 1619 
     | 
    
         
            +
                                        stat = stat,
         
     | 
| 
      
 1620 
     | 
    
         
            +
                                        active_only = active_only,
         
     | 
| 
      
 1621 
     | 
    
         
            +
                                        min_k0 = min_k0,
         
     | 
| 
      
 1622 
     | 
    
         
            +
                                        max_k0 = max_k0,
         
     | 
| 
      
 1623 
     | 
    
         
            +
                                        k0_list = k0_list,
         
     | 
| 
      
 1624 
     | 
    
         
            +
                                        min_length = min_length,
         
     | 
| 
      
 1625 
     | 
    
         
            +
                                        min_kh = min_kh,
         
     | 
| 
      
 1626 
     | 
    
         
            +
                                        max_depth = max_depth,
         
     | 
| 
      
 1627 
     | 
    
         
            +
                                        max_satw = max_satw,
         
     | 
| 
      
 1628 
     | 
    
         
            +
                                        min_sato = min_sato,
         
     | 
| 
      
 1629 
     | 
    
         
            +
                                        max_satg = max_satg,
         
     | 
| 
      
 1630 
     | 
    
         
            +
                                        perforation_list = perforation_list,
         
     | 
| 
      
 1631 
     | 
    
         
            +
                                        region_list = region_list,
         
     | 
| 
      
 1632 
     | 
    
         
            +
                                        depth_inc_down = depth_inc_down,
         
     | 
| 
      
 1633 
     | 
    
         
            +
                                        set_k_face_intervals_vertical = set_k_face_intervals_vertical,
         
     | 
| 
      
 1634 
     | 
    
         
            +
                                        anglv_ref = anglv_ref,
         
     | 
| 
      
 1635 
     | 
    
         
            +
                                        angla_plane_ref = angla_plane_ref,
         
     | 
| 
      
 1636 
     | 
    
         
            +
                                        length_mode = length_mode,
         
     | 
| 
      
 1637 
     | 
    
         
            +
                                        length_uom = length_uom,
         
     | 
| 
      
 1638 
     | 
    
         
            +
                                        preferential_perforation = preferential_perforation,
         
     | 
| 
      
 1639 
     | 
    
         
            +
                                        use_properties = use_properties,
         
     | 
| 
      
 1640 
     | 
    
         
            +
                                        property_time_index = property_time_index)
         
     | 
| 
       2023 
1641 
     | 
    
         | 
| 
       2024 
     | 
    
         
            -
                     
     | 
| 
      
 1642 
     | 
    
         
            +
                    sep = ' ' if space_instead_of_tab_separator else '\t'
         
     | 
| 
       2025 
1643 
     | 
    
         | 
| 
       2026 
     | 
    
         
            -
             
     | 
| 
       2027 
     | 
    
         
            -
             
     | 
| 
       2028 
     | 
    
         
            -
             
     | 
| 
      
 1644 
     | 
    
         
            +
                    with open(wellspec_file, mode = mode) as fp:
         
     | 
| 
      
 1645 
     | 
    
         
            +
                        for _ in range(preceeding_blank_lines):
         
     | 
| 
      
 1646 
     | 
    
         
            +
                            fp.write('\n')
         
     | 
| 
       2029 
1647 
     | 
    
         | 
| 
       2030 
     | 
    
         
            -
             
     | 
| 
       2031 
     | 
    
         
            -
             
     | 
| 
       2032 
     | 
    
         
            -
             
     | 
| 
       2033 
     | 
    
         
            -
             
     | 
| 
       2034 
     | 
    
         
            -
             
     | 
| 
       2035 
     | 
    
         
            -
             
     | 
| 
       2036 
     | 
    
         
            -
                    if k0_list is not None and len(k0_list) == 0:
         
     | 
| 
       2037 
     | 
    
         
            -
                        log.warning('no layers included for blocked well dataframe: no rows will be included')
         
     | 
| 
      
 1648 
     | 
    
         
            +
                        self.__write_wellspec_file_units_metadata(write_nexus_units = write_nexus_units,
         
     | 
| 
      
 1649 
     | 
    
         
            +
                                                                  fp = fp,
         
     | 
| 
      
 1650 
     | 
    
         
            +
                                                                  length_uom = length_uom,
         
     | 
| 
      
 1651 
     | 
    
         
            +
                                                                  length_uom_comment = length_uom_comment,
         
     | 
| 
      
 1652 
     | 
    
         
            +
                                                                  extra_columns_list = extra_columns_list,
         
     | 
| 
      
 1653 
     | 
    
         
            +
                                                                  well_name = well_name)
         
     | 
| 
       2038 
1654 
     | 
    
         | 
| 
       2039 
     | 
    
         
            -
             
     | 
| 
       2040 
     | 
    
         
            -
                def __verify_if_angles_xyz_and_length_to_be_added(column_list, pc_titles, doing_kh, do_well_inflow, length_mode):
         
     | 
| 
       2041 
     | 
    
         
            -
                    # determine if angla, anglv, x, y, z and length data are to be added as properties to the dataframe
         
     | 
| 
      
 1655 
     | 
    
         
            +
                        BlockedWell.__write_wellspec_file_columns(df = df, fp = fp, col_width_dict = col_width_dict, sep = sep)
         
     | 
| 
       2042 
1656 
     | 
    
         | 
| 
       2043 
     | 
    
         
            -
             
     | 
| 
       2044 
     | 
    
         
            -
                                        ('ANGLV' in column_list and 'ANGLV' not in pc_titles), (doing_kh), (do_well_inflow)])
         
     | 
| 
       2045 
     | 
    
         
            -
                    doing_xyz = any([('X' in column_list and 'X' not in pc_titles), ('Y' in column_list and 'Y' not in pc_titles),
         
     | 
| 
       2046 
     | 
    
         
            -
                                     ('DEPTH' in column_list and 'DEPTH' not in pc_titles)])
         
     | 
| 
       2047 
     | 
    
         
            -
                    doing_entry_exit = any([(doing_angles),
         
     | 
| 
       2048 
     | 
    
         
            -
                                            ('LENGTH' in column_list and 'LENGTH' not in pc_titles and length_mode == 'straight')])
         
     | 
| 
      
 1657 
     | 
    
         
            +
                        fp.write('\n')
         
     | 
| 
       2049 
1658 
     | 
    
         | 
| 
       2050 
     | 
    
         
            -
             
     | 
| 
       2051 
     | 
    
         
            -
             
     | 
| 
       2052 
     | 
    
         
            -
             
     | 
| 
       2053 
     | 
    
         
            -
             
     | 
| 
       2054 
     | 
    
         
            -
             
     | 
| 
       2055 
     | 
    
         
            -
             
     | 
| 
       2056 
     | 
    
         
            -
                    #                                     length_mode == 'straight')
         
     | 
| 
      
 1659 
     | 
    
         
            +
                        BlockedWell.__write_wellspec_file_rows_from_dataframe(df = df,
         
     | 
| 
      
 1660 
     | 
    
         
            +
                                                                              fp = fp,
         
     | 
| 
      
 1661 
     | 
    
         
            +
                                                                              col_width_dict = col_width_dict,
         
     | 
| 
      
 1662 
     | 
    
         
            +
                                                                              sep = sep)
         
     | 
| 
      
 1663 
     | 
    
         
            +
                        for _ in range(trailing_blank_lines):
         
     | 
| 
      
 1664 
     | 
    
         
            +
                            fp.write('\n')
         
     | 
| 
       2057 
1665 
     | 
    
         | 
| 
       2058 
     | 
    
         
            -
                    return  
     | 
| 
      
 1666 
     | 
    
         
            +
                    return df
         
     | 
| 
       2059 
1667 
     | 
    
         | 
| 
       2060 
     | 
    
         
            -
                def  
     | 
| 
       2061 
     | 
    
         
            -
                     
     | 
| 
       2062 
     | 
    
         
            -
                    # verify that each grid's crs units are consistent in all directions
         
     | 
| 
      
 1668 
     | 
    
         
            +
                def kji0_marker(self, active_only = True):
         
     | 
| 
      
 1669 
     | 
    
         
            +
                    """Convenience method returning (k0, j0, i0), grid_uuid of first blocked interval."""
         
     | 
| 
       2063 
1670 
     | 
    
         | 
| 
       2064 
     | 
    
         
            -
                     
     | 
| 
       2065 
     | 
    
         
            -
             
     | 
| 
       2066 
     | 
    
         
            -
             
     | 
| 
       2067 
     | 
    
         
            -
                     
     | 
| 
       2068 
     | 
    
         
            -
                        grid_crs = crs.Crs(self.model, uuid = grid.crs_uuid)
         
     | 
| 
       2069 
     | 
    
         
            -
                        grid_crs_list.append(grid_crs)
         
     | 
| 
       2070 
     | 
    
         
            -
                    return grid_crs_list
         
     | 
| 
      
 1671 
     | 
    
         
            +
                    cells, grids = self.cell_indices_and_grid_list()
         
     | 
| 
      
 1672 
     | 
    
         
            +
                    if cells is None or grids is None or len(grids) == 0:
         
     | 
| 
      
 1673 
     | 
    
         
            +
                        return None, None, None, None
         
     | 
| 
      
 1674 
     | 
    
         
            +
                    return cells[0], grids[0].uuid
         
     | 
| 
       2071 
1675 
     | 
    
         | 
| 
       2072 
     | 
    
         
            -
                def  
     | 
| 
      
 1676 
     | 
    
         
            +
                def xyz_marker(self, active_only = True):
         
     | 
| 
      
 1677 
     | 
    
         
            +
                    """Convenience method returning (x, y, z), crs_uuid of perforation in first blocked interval.
         
     | 
| 
       2073 
1678 
     | 
    
         | 
| 
       2074 
     | 
    
         
            -
                     
     | 
| 
       2075 
     | 
    
         
            -
             
     | 
| 
       2076 
     | 
    
         
            -
             
     | 
| 
       2077 
     | 
    
         
            -
                     
     | 
| 
       2078 
     | 
    
         
            -
                        traj_crs = crs.Crs(self.trajectory.model, uuid = self.trajectory.crs_uuid)
         
     | 
| 
       2079 
     | 
    
         
            -
                        traj_z_inc_down = traj_crs.z_inc_down
         
     | 
| 
      
 1679 
     | 
    
         
            +
                    notes:
         
     | 
| 
      
 1680 
     | 
    
         
            +
                       active_only argument not yet in use;
         
     | 
| 
      
 1681 
     | 
    
         
            +
                       returns None, None if no blocked interval found
         
     | 
| 
      
 1682 
     | 
    
         
            +
                    """
         
     | 
| 
       2080 
1683 
     | 
    
         | 
| 
       2081 
     | 
    
         
            -
                     
     | 
| 
      
 1684 
     | 
    
         
            +
                    cells, grids = self.cell_indices_and_grid_list()
         
     | 
| 
      
 1685 
     | 
    
         
            +
                    if cells is None or grids is None or len(grids) == 0:
         
     | 
| 
      
 1686 
     | 
    
         
            +
                        return None, None
         
     | 
| 
      
 1687 
     | 
    
         
            +
                    node_index = 0
         
     | 
| 
      
 1688 
     | 
    
         
            +
                    while node_index < self.node_count - 1 and self.grid_indices[node_index] == -1:
         
     | 
| 
      
 1689 
     | 
    
         
            +
                        node_index += 1
         
     | 
| 
      
 1690 
     | 
    
         
            +
                    if node_index >= self.node_count - 1:
         
     | 
| 
      
 1691 
     | 
    
         
            +
                        return None, None
         
     | 
| 
      
 1692 
     | 
    
         
            +
                    md = 0.5 * (self.node_mds[node_index] + self.node_mds[node_index + 1])
         
     | 
| 
      
 1693 
     | 
    
         
            +
                    xyz = self.trajectory.xyz_for_md(md)
         
     | 
| 
      
 1694 
     | 
    
         
            +
                    return xyz, self.trajectory.crs_uuid
         
     | 
| 
       2082 
1695 
     | 
    
         | 
| 
       2083 
     | 
    
         
            -
                 
     | 
| 
       2084 
     | 
    
         
            -
             
     | 
| 
       2085 
     | 
    
         
            -
                    """Check whether the maximum depth specified has been exceeded with the current interval."""
         
     | 
| 
      
 1696 
     | 
    
         
            +
                def create_feature_and_interpretation(self, shared_interpretation = True):
         
     | 
| 
      
 1697 
     | 
    
         
            +
                    """Instantiate new empty WellboreFeature and WellboreInterpretation objects.
         
     | 
| 
       2086 
1698 
     | 
    
         | 
| 
       2087 
     | 
    
         
            -
                     
     | 
| 
       2088 
     | 
    
         
            -
             
     | 
| 
       2089 
     | 
    
         
            -
             
     | 
| 
       2090 
     | 
    
         
            -
             
     | 
| 
       2091 
     | 
    
         
            -
             
     | 
| 
       2092 
     | 
    
         
            -
                         
     | 
| 
       2093 
     | 
    
         
            -
             
     | 
| 
       2094 
     | 
    
         
            -
             
     | 
| 
       2095 
     | 
    
         
            -
             
     | 
| 
       2096 
     | 
    
         
            -
             
     | 
| 
       2097 
     | 
    
         
            -
             
     | 
| 
       2098 
     | 
    
         
            -
             
     | 
| 
       2099 
     | 
    
         
            -
             
     | 
| 
      
 1699 
     | 
    
         
            +
                    note:
         
     | 
| 
      
 1700 
     | 
    
         
            +
                        uses the Blocked well citation title or other related object title as the well name
         
     | 
| 
      
 1701 
     | 
    
         
            +
                    """
         
     | 
| 
      
 1702 
     | 
    
         
            +
                    title = self.well_name
         
     | 
| 
      
 1703 
     | 
    
         
            +
                    if not title:
         
     | 
| 
      
 1704 
     | 
    
         
            +
                        title = self.title
         
     | 
| 
      
 1705 
     | 
    
         
            +
                        if not title and self.trajectory is not None:
         
     | 
| 
      
 1706 
     | 
    
         
            +
                            title = rqw.well_name(self.trajectory)
         
     | 
| 
      
 1707 
     | 
    
         
            +
                            if not title:
         
     | 
| 
      
 1708 
     | 
    
         
            +
                                title = 'WELL'
         
     | 
| 
      
 1709 
     | 
    
         
            +
                    if self.trajectory is not None:
         
     | 
| 
      
 1710 
     | 
    
         
            +
                        traj_interp_uuid = self.model.uuid(obj_type = 'WellboreInterpretation', related_uuid = self.trajectory.uuid)
         
     | 
| 
      
 1711 
     | 
    
         
            +
                        if traj_interp_uuid is not None:
         
     | 
| 
      
 1712 
     | 
    
         
            +
                            if shared_interpretation:
         
     | 
| 
      
 1713 
     | 
    
         
            +
                                self.wellbore_interpretation = rqo.WellboreInterpretation(parent_model = self.model,
         
     | 
| 
      
 1714 
     | 
    
         
            +
                                                                                          uuid = traj_interp_uuid)
         
     | 
| 
      
 1715 
     | 
    
         
            +
                            traj_feature_uuid = self.model.uuid(obj_type = 'WellboreFeature', related_uuid = traj_interp_uuid)
         
     | 
| 
      
 1716 
     | 
    
         
            +
                            if traj_feature_uuid is not None:
         
     | 
| 
      
 1717 
     | 
    
         
            +
                                self.wellbore_feature = rqo.WellboreFeature(parent_model = self.model, uuid = traj_feature_uuid)
         
     | 
| 
      
 1718 
     | 
    
         
            +
                    if self.wellbore_feature is None:
         
     | 
| 
      
 1719 
     | 
    
         
            +
                        self.wellbore_feature = rqo.WellboreFeature(parent_model = self.model, feature_name = title)
         
     | 
| 
      
 1720 
     | 
    
         
            +
                        self.feature_to_be_written = True
         
     | 
| 
      
 1721 
     | 
    
         
            +
                    if self.wellbore_interpretation is None:
         
     | 
| 
      
 1722 
     | 
    
         
            +
                        title = title if not self.wellbore_feature.title else self.wellbore_feature.title
         
     | 
| 
      
 1723 
     | 
    
         
            +
                        self.wellbore_interpretation = rqo.WellboreInterpretation(parent_model = self.model,
         
     | 
| 
      
 1724 
     | 
    
         
            +
                                                                                  title = title,
         
     | 
| 
      
 1725 
     | 
    
         
            +
                                                                                  wellbore_feature = self.wellbore_feature)
         
     | 
| 
      
 1726 
     | 
    
         
            +
                        if self.trajectory.wellbore_interpretation is None and shared_interpretation:
         
     | 
| 
      
 1727 
     | 
    
         
            +
                            self.trajectory.wellbore_interpretation = self.wellbore_interpretation
         
     | 
| 
      
 1728 
     | 
    
         
            +
                        self.interpretation_to_be_written = True
         
     | 
| 
       2100 
1729 
     | 
    
         | 
| 
       2101 
     | 
    
         
            -
             
     | 
| 
       2102 
     | 
    
         
            -
             
     | 
| 
       2103 
     | 
    
         
            -
             
     | 
| 
       2104 
     | 
    
         
            -
             
     | 
| 
       2105 
     | 
    
         
            -
             
     | 
| 
       2106 
     | 
    
         
            -
             
     | 
| 
       2107 
     | 
    
         
            -
             
     | 
| 
       2108 
     | 
    
         
            -
             
     | 
| 
       2109 
     | 
    
         
            -
             
     | 
| 
       2110 
     | 
    
         
            -
             
     | 
| 
       2111 
     | 
    
         
            -
                    saturation_limit_exceeded_1 = (max_satw is not None and
         
     | 
| 
       2112 
     | 
    
         
            -
                                                   BlockedWell.__prop_array(satw_uuid, grid)[tuple_kji0] > max_satw)
         
     | 
| 
       2113 
     | 
    
         
            -
                    saturation_limit_exceeded_2 = (min_sato is not None and
         
     | 
| 
       2114 
     | 
    
         
            -
                                                   BlockedWell.__prop_array(sato_uuid, grid)[tuple_kji0] < min_sato)
         
     | 
| 
       2115 
     | 
    
         
            -
                    saturation_limit_exceeded_3 = (max_satg is not None and
         
     | 
| 
       2116 
     | 
    
         
            -
                                                   BlockedWell.__prop_array(satg_uuid, grid)[tuple_kji0] > max_satg)
         
     | 
| 
       2117 
     | 
    
         
            -
                    skip_interval = any([
         
     | 
| 
       2118 
     | 
    
         
            -
                        max_depth_exceeded, inactive_grid, out_of_bounds_layer_1, out_of_bounds_layer_2, out_of_bounds_region,
         
     | 
| 
       2119 
     | 
    
         
            -
                        saturation_limit_exceeded_1, saturation_limit_exceeded_2, saturation_limit_exceeded_3
         
     | 
| 
       2120 
     | 
    
         
            -
                    ])
         
     | 
| 
      
 1730 
     | 
    
         
            +
                def create_md_datum_and_trajectory(self,
         
     | 
| 
      
 1731 
     | 
    
         
            +
                                                   grid,
         
     | 
| 
      
 1732 
     | 
    
         
            +
                                                   trajectory_mds,
         
     | 
| 
      
 1733 
     | 
    
         
            +
                                                   trajectory_points,
         
     | 
| 
      
 1734 
     | 
    
         
            +
                                                   length_uom,
         
     | 
| 
      
 1735 
     | 
    
         
            +
                                                   well_name,
         
     | 
| 
      
 1736 
     | 
    
         
            +
                                                   set_depth_zero = False,
         
     | 
| 
      
 1737 
     | 
    
         
            +
                                                   set_tangent_vectors = False,
         
     | 
| 
      
 1738 
     | 
    
         
            +
                                                   create_feature_and_interp = True):
         
     | 
| 
      
 1739 
     | 
    
         
            +
                    """Creates an Md Datum object and a (simulation) Trajectory object for this blocked well.
         
     | 
| 
       2121 
1740 
     | 
    
         | 
| 
       2122 
     | 
    
         
            -
                     
     | 
| 
      
 1741 
     | 
    
         
            +
                    note:
         
     | 
| 
      
 1742 
     | 
    
         
            +
                       not usually called directly; used by import methods
         
     | 
| 
      
 1743 
     | 
    
         
            +
                    """
         
     | 
| 
       2123 
1744 
     | 
    
         | 
| 
       2124 
     | 
    
         
            -
             
     | 
| 
       2125 
     | 
    
         
            -
             
     | 
| 
      
 1745 
     | 
    
         
            +
                    if not well_name:
         
     | 
| 
      
 1746 
     | 
    
         
            +
                        well_name = self.title
         
     | 
| 
       2126 
1747 
     | 
    
         | 
| 
       2127 
     | 
    
         
            -
                     
     | 
| 
       2128 
     | 
    
         
            -
                     
     | 
| 
       2129 
     | 
    
         
            -
             
     | 
| 
       2130 
     | 
    
         
            -
             
     | 
| 
       2131 
     | 
    
         
            -
             
     | 
| 
       2132 
     | 
    
         
            -
             
     | 
| 
       2133 
     | 
    
         
            -
             
     | 
| 
       2134 
     | 
    
         
            -
             
     | 
| 
       2135 
     | 
    
         
            -
                                if perf_end <= self.node_mds[interval] or perf_start >= self.node_mds[interval + 1]:
         
     | 
| 
       2136 
     | 
    
         
            -
                                    continue
         
     | 
| 
       2137 
     | 
    
         
            -
                                if perf_start <= self.node_mds[interval]:
         
     | 
| 
       2138 
     | 
    
         
            -
                                    if perf_end >= self.node_mds[interval + 1]:
         
     | 
| 
       2139 
     | 
    
         
            -
                                        perf_length += self.node_mds[interval + 1] - self.node_mds[interval]
         
     | 
| 
       2140 
     | 
    
         
            -
                                        break
         
     | 
| 
       2141 
     | 
    
         
            -
                                    else:
         
     | 
| 
       2142 
     | 
    
         
            -
                                        perf_length += perf_end - self.node_mds[interval]
         
     | 
| 
       2143 
     | 
    
         
            -
                                else:
         
     | 
| 
       2144 
     | 
    
         
            -
                                    if perf_end >= self.node_mds[interval + 1]:
         
     | 
| 
       2145 
     | 
    
         
            -
                                        perf_length += self.node_mds[interval + 1] - perf_start
         
     | 
| 
       2146 
     | 
    
         
            -
                                    else:
         
     | 
| 
       2147 
     | 
    
         
            -
                                        perf_length += perf_end - perf_start
         
     | 
| 
       2148 
     | 
    
         
            -
                            if perf_length < length_tol:
         
     | 
| 
       2149 
     | 
    
         
            -
                                skip_interval = True
         
     | 
| 
       2150 
     | 
    
         
            -
                                perf_length = 0.0
         
     | 
| 
       2151 
     | 
    
         
            -
                            part_perf_fraction = min(1.0, perf_length / (self.node_mds[interval + 1] - self.node_mds[interval]))
         
     | 
| 
      
 1748 
     | 
    
         
            +
                    # create md datum node for synthetic trajectory, using crs for grid
         
     | 
| 
      
 1749 
     | 
    
         
            +
                    datum_location = trajectory_points[0].copy()
         
     | 
| 
      
 1750 
     | 
    
         
            +
                    if set_depth_zero:
         
     | 
| 
      
 1751 
     | 
    
         
            +
                        datum_location[2] = 0.0
         
     | 
| 
      
 1752 
     | 
    
         
            +
                    datum = rqw.MdDatum(self.model,
         
     | 
| 
      
 1753 
     | 
    
         
            +
                                        crs_uuid = grid.crs_uuid,
         
     | 
| 
      
 1754 
     | 
    
         
            +
                                        location = datum_location,
         
     | 
| 
      
 1755 
     | 
    
         
            +
                                        md_reference = 'mean sea level')
         
     | 
| 
       2152 
1756 
     | 
    
         | 
| 
       2153 
     | 
    
         
            -
                     
     | 
| 
      
 1757 
     | 
    
         
            +
                    # create synthetic trajectory object, using crs for grid
         
     | 
| 
      
 1758 
     | 
    
         
            +
                    trajectory_mds_array = np.array(trajectory_mds)
         
     | 
| 
      
 1759 
     | 
    
         
            +
                    trajectory_xyz_array = np.array(trajectory_points)
         
     | 
| 
      
 1760 
     | 
    
         
            +
                    trajectory_df = pd.DataFrame({
         
     | 
| 
      
 1761 
     | 
    
         
            +
                        'MD': trajectory_mds_array,
         
     | 
| 
      
 1762 
     | 
    
         
            +
                        'X': trajectory_xyz_array[..., 0],
         
     | 
| 
      
 1763 
     | 
    
         
            +
                        'Y': trajectory_xyz_array[..., 1],
         
     | 
| 
      
 1764 
     | 
    
         
            +
                        'Z': trajectory_xyz_array[..., 2]
         
     | 
| 
      
 1765 
     | 
    
         
            +
                    })
         
     | 
| 
      
 1766 
     | 
    
         
            +
                    self.trajectory = rqw.Trajectory(self.model,
         
     | 
| 
      
 1767 
     | 
    
         
            +
                                                     md_datum = datum,
         
     | 
| 
      
 1768 
     | 
    
         
            +
                                                     data_frame = trajectory_df,
         
     | 
| 
      
 1769 
     | 
    
         
            +
                                                     length_uom = length_uom,
         
     | 
| 
      
 1770 
     | 
    
         
            +
                                                     well_name = well_name,
         
     | 
| 
      
 1771 
     | 
    
         
            +
                                                     set_tangent_vectors = set_tangent_vectors)
         
     | 
| 
      
 1772 
     | 
    
         
            +
                    self.trajectory_to_be_written = True
         
     | 
| 
       2154 
1773 
     | 
    
         | 
| 
       2155 
     | 
    
         
            -
             
     | 
| 
       2156 
     | 
    
         
            -
             
     | 
| 
       2157 
     | 
    
         
            -
                    # calculate the entry and exit points for the interval and set the entry and exit coordinate reference system
         
     | 
| 
      
 1774 
     | 
    
         
            +
                    if create_feature_and_interp:
         
     | 
| 
      
 1775 
     | 
    
         
            +
                        self.create_feature_and_interpretation()
         
     | 
| 
       2158 
1776 
     | 
    
         | 
| 
       2159 
     | 
    
         
            -
             
     | 
| 
       2160 
     | 
    
         
            -
             
     | 
| 
       2161 
     | 
    
         
            -
             
     | 
| 
       2162 
     | 
    
         
            -
             
     | 
| 
       2163 
     | 
    
         
            -
             
     | 
| 
       2164 
     | 
    
         
            -
             
     | 
| 
       2165 
     | 
    
         
            -
             
     | 
| 
       2166 
     | 
    
         
            -
             
     | 
| 
       2167 
     | 
    
         
            -
                            if self.face_pair_indices[ci, 1, 0] >= 0:
         
     | 
| 
       2168 
     | 
    
         
            -
                                exit_xyz = grid.face_centre(cell_kji0, self.face_pair_indices[ci, 1, 0],
         
     | 
| 
       2169 
     | 
    
         
            -
                                                            self.face_pair_indices[ci, 1, 1])
         
     | 
| 
       2170 
     | 
    
         
            -
                            else:
         
     | 
| 
       2171 
     | 
    
         
            -
                                exit_xyz = grid.face_centre(cell_kji0, self.face_pair_indices[ci, 0, 0],
         
     | 
| 
       2172 
     | 
    
         
            -
                                                            1 - self.face_pair_indices[ci, 0, 1])
         
     | 
| 
       2173 
     | 
    
         
            -
                            ee_crs = grid_crs
         
     | 
| 
       2174 
     | 
    
         
            -
                        else:
         
     | 
| 
       2175 
     | 
    
         
            -
                            entry_xyz = self.trajectory.xyz_for_md(self.node_mds[interval])
         
     | 
| 
       2176 
     | 
    
         
            -
                            exit_xyz = self.trajectory.xyz_for_md(self.node_mds[interval + 1])
         
     | 
| 
       2177 
     | 
    
         
            -
                            ee_crs = traj_crs
         
     | 
| 
      
 1777 
     | 
    
         
            +
                def create_xml(self,
         
     | 
| 
      
 1778 
     | 
    
         
            +
                               ext_uuid = None,
         
     | 
| 
      
 1779 
     | 
    
         
            +
                               create_for_trajectory_if_needed = True,
         
     | 
| 
      
 1780 
     | 
    
         
            +
                               add_as_part = True,
         
     | 
| 
      
 1781 
     | 
    
         
            +
                               add_relationships = True,
         
     | 
| 
      
 1782 
     | 
    
         
            +
                               title = None,
         
     | 
| 
      
 1783 
     | 
    
         
            +
                               originator = None):
         
     | 
| 
      
 1784 
     | 
    
         
            +
                    """Create a blocked wellbore representation node from this BlockedWell object, optionally add as part.
         
     | 
| 
       2178 
1785 
     | 
    
         | 
| 
       2179 
     | 
    
         
            -
                     
     | 
| 
      
 1786 
     | 
    
         
            +
                    note:
         
     | 
| 
      
 1787 
     | 
    
         
            +
                       trajectory xml node must be in place before calling this function;
         
     | 
| 
      
 1788 
     | 
    
         
            +
                       witsml log reference, interval stratigraphic units, and cell fluid phase units not yet supported
         
     | 
| 
       2180 
1789 
     | 
    
         | 
| 
       2181 
     | 
    
         
            -
             
     | 
| 
       2182 
     | 
    
         
            -
             
     | 
| 
       2183 
     | 
    
         
            -
                    """Calculate the length of the interval."""
         
     | 
| 
      
 1790 
     | 
    
         
            +
                    :meta common:
         
     | 
| 
      
 1791 
     | 
    
         
            +
                    """
         
     | 
| 
       2184 
1792 
     | 
    
         | 
| 
       2185 
     | 
    
         
            -
                     
     | 
| 
       2186 
     | 
    
         
            -
                    if length_mode == 'MD':
         
     | 
| 
       2187 
     | 
    
         
            -
                        length = self.node_mds[interval + 1] - self.node_mds[interval]
         
     | 
| 
       2188 
     | 
    
         
            -
                        if length_uom is not None and self.trajectory is not None and length_uom != self.trajectory.md_uom:
         
     | 
| 
       2189 
     | 
    
         
            -
                            length = wam.convert_lengths(length, self.trajectory.md_uom, length_uom)
         
     | 
| 
       2190 
     | 
    
         
            -
                    else:  # use straight line length between entry and exit
         
     | 
| 
       2191 
     | 
    
         
            -
                        entry_xyz, exit_xyz = BlockedWell._single_uom_entry_exit_xyz(entry_xyz, exit_xyz, ee_crs)
         
     | 
| 
       2192 
     | 
    
         
            -
                        length = vec.naive_length(exit_xyz - entry_xyz)
         
     | 
| 
       2193 
     | 
    
         
            -
                        if length_uom is not None:
         
     | 
| 
       2194 
     | 
    
         
            -
                            length = wam.convert_lengths(length, ee_crs.z_units, length_uom)
         
     | 
| 
       2195 
     | 
    
         
            -
                        elif self.trajectory is not None:
         
     | 
| 
       2196 
     | 
    
         
            -
                            length = wam.convert_lengths(length, ee_crs.z_units, self.trajectory.md_uom)
         
     | 
| 
       2197 
     | 
    
         
            -
                    if perforation_list is not None:
         
     | 
| 
       2198 
     | 
    
         
            -
                        length *= part_perf_fraction
         
     | 
| 
       2199 
     | 
    
         
            -
                    if min_length is not None and length < min_length:
         
     | 
| 
       2200 
     | 
    
         
            -
                        skip_interval = True
         
     | 
| 
      
 1793 
     | 
    
         
            +
                    assert self.trajectory is not None, 'trajectory object missing'
         
     | 
| 
       2201 
1794 
     | 
    
         | 
| 
       2202 
     | 
    
         
            -
                     
     | 
| 
      
 1795 
     | 
    
         
            +
                    if ext_uuid is None:
         
     | 
| 
      
 1796 
     | 
    
         
            +
                        ext_uuid = self.model.h5_uuid()
         
     | 
| 
       2203 
1797 
     | 
    
         | 
| 
       2204 
     | 
    
         
            -
             
     | 
| 
       2205 
     | 
    
         
            -
             
     | 
| 
       2206 
     | 
    
         
            -
                    if  
     | 
| 
       2207 
     | 
    
         
            -
                         
     | 
| 
       2208 
     | 
    
         
            -
                     
     | 
| 
       2209 
     | 
    
         
            -
                    if crs.xy_units != required_uom:
         
     | 
| 
       2210 
     | 
    
         
            -
                        xyz[0] = wam.convert_lengths(xyz[0], crs.xy_units, required_uom)
         
     | 
| 
       2211 
     | 
    
         
            -
                        xyz[1] = wam.convert_lengths(xyz[1], crs.xy_units, required_uom)
         
     | 
| 
       2212 
     | 
    
         
            -
                    if crs.z_units != required_uom:
         
     | 
| 
       2213 
     | 
    
         
            -
                        xyz[2] = wam.convert_lengths(xyz[2], crs.z_units, required_uom)
         
     | 
| 
       2214 
     | 
    
         
            -
                    return xyz
         
     | 
| 
      
 1798 
     | 
    
         
            +
                    if title:
         
     | 
| 
      
 1799 
     | 
    
         
            +
                        self.title = title
         
     | 
| 
      
 1800 
     | 
    
         
            +
                    if not self.title:
         
     | 
| 
      
 1801 
     | 
    
         
            +
                        self.title = self.well_name
         
     | 
| 
      
 1802 
     | 
    
         
            +
                    title = self.title
         
     | 
| 
       2215 
1803 
     | 
    
         | 
| 
       2216 
     | 
    
         
            -
             
     | 
| 
       2217 
     | 
    
         
            -
             
     | 
| 
       2218 
     | 
    
         
            -
             
     | 
| 
       2219 
     | 
    
         
            -
                            BlockedWell._single_uom_xyz(exit_xyz, ee_crs, ee_crs.z_units))
         
     | 
| 
      
 1804 
     | 
    
         
            +
                    self.__create_wellbore_feature_and_interpretation_xml_if_needed(add_as_part = add_as_part,
         
     | 
| 
      
 1805 
     | 
    
         
            +
                                                                                    add_relationships = add_relationships,
         
     | 
| 
      
 1806 
     | 
    
         
            +
                                                                                    originator = originator)
         
     | 
| 
       2220 
1807 
     | 
    
         | 
| 
       2221 
     | 
    
         
            -
             
     | 
| 
       2222 
     | 
    
         
            -
             
     | 
| 
       2223 
     | 
    
         
            -
             
     | 
| 
       2224 
     | 
    
         
            -
             
     | 
| 
      
 1808 
     | 
    
         
            +
                    self.__create_trajectory_xml_if_needed(create_for_trajectory_if_needed = create_for_trajectory_if_needed,
         
     | 
| 
      
 1809 
     | 
    
         
            +
                                                           add_as_part = add_as_part,
         
     | 
| 
      
 1810 
     | 
    
         
            +
                                                           add_relationships = add_relationships,
         
     | 
| 
      
 1811 
     | 
    
         
            +
                                                           originator = originator,
         
     | 
| 
      
 1812 
     | 
    
         
            +
                                                           ext_uuid = ext_uuid,
         
     | 
| 
      
 1813 
     | 
    
         
            +
                                                           title = title)
         
     | 
| 
       2225 
1814 
     | 
    
         | 
| 
       2226 
     | 
    
         
            -
                     
     | 
| 
       2227 
     | 
    
         
            -
                    cosine_anglv = cosine_angla = 1.0
         
     | 
| 
       2228 
     | 
    
         
            -
                    anglv = pc.single_array_ref(citation_title = 'ANGLV')[ci] if 'ANGLV' in pc_titles else None
         
     | 
| 
       2229 
     | 
    
         
            -
                    angla = pc.single_array_ref(citation_title = 'ANGLA')[ci] if 'ANGLA' in pc_titles else None
         
     | 
| 
      
 1815 
     | 
    
         
            +
                    assert self.trajectory.root is not None, 'trajectory xml not established'
         
     | 
| 
       2230 
1816 
     | 
    
         | 
| 
       2231 
     | 
    
         
            -
                     
     | 
| 
       2232 
     | 
    
         
            -
                                             (np.all(self.face_pair_indices[ci] == k_face_check) or
         
     | 
| 
       2233 
     | 
    
         
            -
                                              np.all(self.face_pair_indices[ci] == k_face_check_end))):
         
     | 
| 
       2234 
     | 
    
         
            -
                        anglv, sine_anglv, cosine_anglv, vector, a_ref_vector = BlockedWell.__get_anglv_for_interval(
         
     | 
| 
       2235 
     | 
    
         
            -
                            anglv = anglv,
         
     | 
| 
       2236 
     | 
    
         
            -
                            entry_xyz = entry_xyz,
         
     | 
| 
       2237 
     | 
    
         
            -
                            exit_xyz = exit_xyz,
         
     | 
| 
       2238 
     | 
    
         
            -
                            ee_crs = ee_crs,
         
     | 
| 
       2239 
     | 
    
         
            -
                            traj_z_inc_down = traj_z_inc_down,
         
     | 
| 
       2240 
     | 
    
         
            -
                            grid = grid,
         
     | 
| 
       2241 
     | 
    
         
            -
                            grid_crs = grid_crs,
         
     | 
| 
       2242 
     | 
    
         
            -
                            cell_kji0 = cell_kji0,
         
     | 
| 
       2243 
     | 
    
         
            -
                            anglv_ref = anglv_ref,
         
     | 
| 
       2244 
     | 
    
         
            -
                            angla_plane_ref = angla_plane_ref)
         
     | 
| 
       2245 
     | 
    
         
            -
                        if anglv != 0.0:
         
     | 
| 
       2246 
     | 
    
         
            -
                            angla, sine_angla, cosine_angla = BlockedWell.__get_angla_for_interval(angla = angla,
         
     | 
| 
       2247 
     | 
    
         
            -
                                                                                                   grid = grid,
         
     | 
| 
       2248 
     | 
    
         
            -
                                                                                                   cell_kji0 = cell_kji0,
         
     | 
| 
       2249 
     | 
    
         
            -
                                                                                                   vector = vector,
         
     | 
| 
       2250 
     | 
    
         
            -
                                                                                                   a_ref_vector = a_ref_vector)
         
     | 
| 
       2251 
     | 
    
         
            -
                    if angla is None:
         
     | 
| 
       2252 
     | 
    
         
            -
                        angla = 0.0
         
     | 
| 
       2253 
     | 
    
         
            -
                    if anglv is None:
         
     | 
| 
       2254 
     | 
    
         
            -
                        anglv = 0.0
         
     | 
| 
      
 1817 
     | 
    
         
            +
                    bw_node = super().create_xml(title = title, originator = originator, add_as_part = False)
         
     | 
| 
       2255 
1818 
     | 
    
         | 
| 
       2256 
     | 
    
         
            -
                     
     | 
| 
      
 1819 
     | 
    
         
            +
                    # wellbore frame elements
         
     | 
| 
       2257 
1820 
     | 
    
         | 
| 
       2258 
     | 
    
         
            -
             
     | 
| 
       2259 
     | 
    
         
            -
             
     | 
| 
       2260 
     | 
    
         
            -
             
     | 
| 
      
 1821 
     | 
    
         
            +
                    nc_node, mds_node, mds_values_node, cc_node, cis_node, cnull_node, cis_values_node, gis_node, gnull_node,  \
         
     | 
| 
      
 1822 
     | 
    
         
            +
                        gis_values_node, fis_node, fnull_node, fis_values_node =  \
         
     | 
| 
      
 1823 
     | 
    
         
            +
                        self.__create_bw_node_sub_elements(bw_node = bw_node)
         
     | 
| 
       2261 
1824 
     | 
    
         | 
| 
       2262 
     | 
    
         
            -
                     
     | 
| 
       2263 
     | 
    
         
            -
             
     | 
| 
      
 1825 
     | 
    
         
            +
                    self.__create_hdf5_dataset_references(ext_uuid = ext_uuid,
         
     | 
| 
      
 1826 
     | 
    
         
            +
                                                          mds_values_node = mds_values_node,
         
     | 
| 
      
 1827 
     | 
    
         
            +
                                                          cis_values_node = cis_values_node,
         
     | 
| 
      
 1828 
     | 
    
         
            +
                                                          gis_values_node = gis_values_node,
         
     | 
| 
      
 1829 
     | 
    
         
            +
                                                          fis_values_node = fis_values_node)
         
     | 
| 
       2264 
1830 
     | 
    
         | 
| 
       2265 
     | 
    
         
            -
                     
     | 
| 
       2266 
     | 
    
         
            -
             
     | 
| 
       2267 
     | 
    
         
            -
                    if grid.crs.xy_units != grid.crs.z_units:
         
     | 
| 
       2268 
     | 
    
         
            -
                        i_axis[2] = wam.convert_lengths(i_axis[2], grid.crs.z_units, grid.crs.xy_units)
         
     | 
| 
       2269 
     | 
    
         
            -
                    i_axis = vec.unit_vector(i_axis)
         
     | 
| 
       2270 
     | 
    
         
            -
                    if a_ref_vector is not None:  # project vector and i axis onto a plane
         
     | 
| 
       2271 
     | 
    
         
            -
                        vector -= vec.dot_product(vector, a_ref_vector) * a_ref_vector
         
     | 
| 
       2272 
     | 
    
         
            -
                        vector = vec.unit_vector(vector)
         
     | 
| 
       2273 
     | 
    
         
            -
                        # log.debug('i axis unit vector: ' + str(i_axis))
         
     | 
| 
       2274 
     | 
    
         
            -
                        i_axis -= vec.dot_product(i_axis, a_ref_vector) * a_ref_vector
         
     | 
| 
       2275 
     | 
    
         
            -
                        i_axis = vec.unit_vector(i_axis)
         
     | 
| 
       2276 
     | 
    
         
            -
                    # log.debug('i axis unit vector in reference plane: ' + str(i_axis))
         
     | 
| 
       2277 
     | 
    
         
            -
                    if angla is not None:
         
     | 
| 
       2278 
     | 
    
         
            -
                        angla_rad = vec.radians_from_degrees(angla)
         
     | 
| 
       2279 
     | 
    
         
            -
                        cosine_angla = maths.cos(angla_rad)
         
     | 
| 
       2280 
     | 
    
         
            -
                        sine_angla = maths.sin(angla_rad)
         
     | 
| 
       2281 
     | 
    
         
            -
                    else:
         
     | 
| 
       2282 
     | 
    
         
            -
                        cosine_angla = min(max(vec.dot_product(vector, i_axis), -1.0), 1.0)
         
     | 
| 
       2283 
     | 
    
         
            -
                        angla_rad = maths.acos(cosine_angla)
         
     | 
| 
       2284 
     | 
    
         
            -
                        # negate angla if vector is 'clockwise from' i_axis when viewed from above, projected in the xy plane
         
     | 
| 
       2285 
     | 
    
         
            -
                        # todo: have discussion around angla sign under different ijk handedness (and z inc direction?)
         
     | 
| 
       2286 
     | 
    
         
            -
                        sine_angla = maths.sin(angla_rad)
         
     | 
| 
       2287 
     | 
    
         
            -
                        angla = vec.degrees_from_radians(angla_rad)
         
     | 
| 
       2288 
     | 
    
         
            -
                        if vec.clockwise((0.0, 0.0), i_axis, vector) > 0.0:
         
     | 
| 
       2289 
     | 
    
         
            -
                            angla = -angla
         
     | 
| 
       2290 
     | 
    
         
            -
                            angla_rad = -angla_rad  ## as angle_rad before --> typo?
         
     | 
| 
       2291 
     | 
    
         
            -
                            sine_angla = -sine_angla
         
     | 
| 
      
 1831 
     | 
    
         
            +
                    traj_root, grid_root, interp_root = self.__create_trajectory_grid_wellbore_interpretation_reference_nodes(
         
     | 
| 
      
 1832 
     | 
    
         
            +
                        bw_node = bw_node)
         
     | 
| 
       2292 
1833 
     | 
    
         | 
| 
       2293 
     | 
    
         
            -
                     
     | 
| 
      
 1834 
     | 
    
         
            +
                    self.__add_as_part_and_add_relationships_if_required(add_as_part = add_as_part,
         
     | 
| 
      
 1835 
     | 
    
         
            +
                                                                         add_relationships = add_relationships,
         
     | 
| 
      
 1836 
     | 
    
         
            +
                                                                         bw_node = bw_node,
         
     | 
| 
      
 1837 
     | 
    
         
            +
                                                                         interp_root = interp_root,
         
     | 
| 
      
 1838 
     | 
    
         
            +
                                                                         ext_uuid = ext_uuid)
         
     | 
| 
       2294 
1839 
     | 
    
         | 
| 
       2295 
     | 
    
         
            -
                    return  
     | 
| 
      
 1840 
     | 
    
         
            +
                    return bw_node
         
     | 
| 
       2296 
1841 
     | 
    
         | 
| 
       2297 
     | 
    
         
            -
                 
     | 
| 
       2298 
     | 
    
         
            -
             
     | 
| 
       2299 
     | 
    
         
            -
                                             anglv_ref, angla_plane_ref):
         
     | 
| 
       2300 
     | 
    
         
            -
                    """Get anglv and related trigonometric transforms for the interval."""
         
     | 
| 
      
 1842 
     | 
    
         
            +
                def write_hdf5(self, file_name = None, mode = 'a', create_for_trajectory_if_needed = True):
         
     | 
| 
      
 1843 
     | 
    
         
            +
                    """Create or append to an hdf5 file, writing datasets for the measured depths, grid, cell & face indices.
         
     | 
| 
       2301 
1844 
     | 
    
         | 
| 
       2302 
     | 
    
         
            -
                     
     | 
| 
       2303 
     | 
    
         
            -
             
     | 
| 
      
 1845 
     | 
    
         
            +
                    :meta common:
         
     | 
| 
      
 1846 
     | 
    
         
            +
                    """
         
     | 
| 
       2304 
1847 
     | 
    
         | 
| 
       2305 
     | 
    
         
            -
                     
     | 
| 
       2306 
     | 
    
         
            -
                    vector = vec.unit_vector(np.array(exit_xyz) - np.array(entry_xyz))  # nominal wellbore vector for interval
         
     | 
| 
       2307 
     | 
    
         
            -
                    if traj_z_inc_down is not None and traj_z_inc_down != grid_crs.z_inc_down:
         
     | 
| 
       2308 
     | 
    
         
            -
                        vector[2] = -vector[2]
         
     | 
| 
       2309 
     | 
    
         
            -
                    if grid.crs.xy_units == grid.crs.z_units:
         
     | 
| 
       2310 
     | 
    
         
            -
                        unit_adjusted_vector = vector
         
     | 
| 
       2311 
     | 
    
         
            -
                    else:
         
     | 
| 
       2312 
     | 
    
         
            -
                        unit_adjusted_vector = vector.copy()
         
     | 
| 
       2313 
     | 
    
         
            -
                        unit_adjusted_vector[2] = wam.convert_lengths(unit_adjusted_vector[2], grid.crs.z_units, grid.crs.xy_units)
         
     | 
| 
       2314 
     | 
    
         
            -
                    v_ref_vector = BlockedWell.__get_ref_vector(grid, grid_crs, cell_kji0, anglv_ref)
         
     | 
| 
       2315 
     | 
    
         
            -
                    # log.debug('v ref vector: ' + str(v_ref_vector))
         
     | 
| 
       2316 
     | 
    
         
            -
                    if angla_plane_ref == anglv_ref:
         
     | 
| 
       2317 
     | 
    
         
            -
                        a_ref_vector = v_ref_vector
         
     | 
| 
       2318 
     | 
    
         
            -
                    else:
         
     | 
| 
       2319 
     | 
    
         
            -
                        a_ref_vector = BlockedWell.__get_ref_vector(grid, grid_crs, cell_kji0, angla_plane_ref)
         
     | 
| 
       2320 
     | 
    
         
            -
                    # log.debug('a ref vector: ' + str(a_ref_vector))
         
     | 
| 
       2321 
     | 
    
         
            -
                    if anglv is not None:
         
     | 
| 
       2322 
     | 
    
         
            -
                        anglv_rad = vec.radians_from_degrees(anglv)
         
     | 
| 
       2323 
     | 
    
         
            -
                        cosine_anglv = maths.cos(anglv_rad)
         
     | 
| 
       2324 
     | 
    
         
            -
                        sine_anglv = maths.sin(anglv_rad)
         
     | 
| 
       2325 
     | 
    
         
            -
                    else:
         
     | 
| 
       2326 
     | 
    
         
            -
                        cosine_anglv = min(max(vec.dot_product(unit_adjusted_vector, v_ref_vector), -1.0), 1.0)
         
     | 
| 
       2327 
     | 
    
         
            -
                        anglv_rad = maths.acos(cosine_anglv)
         
     | 
| 
       2328 
     | 
    
         
            -
                        sine_anglv = maths.sin(anglv_rad)
         
     | 
| 
       2329 
     | 
    
         
            -
                        anglv = vec.degrees_from_radians(anglv_rad)
         
     | 
| 
       2330 
     | 
    
         
            -
                    # log.debug('anglv: ' + str(anglv))
         
     | 
| 
      
 1848 
     | 
    
         
            +
                    # NB: array data must all have been set up prior to calling this function
         
     | 
| 
       2331 
1849 
     | 
    
         | 
| 
       2332 
     | 
    
         
            -
                     
     | 
| 
      
 1850 
     | 
    
         
            +
                    if self.uuid is None:
         
     | 
| 
      
 1851 
     | 
    
         
            +
                        self.uuid = bu.new_uuid()
         
     | 
| 
       2333 
1852 
     | 
    
         | 
| 
       2334 
     | 
    
         
            -
             
     | 
| 
       2335 
     | 
    
         
            -
                def __get_ntg_and_directional_perm_for_interval(doing_kh, do_well_inflow, ntg_uuid, grid, tuple_kji0,
         
     | 
| 
       2336 
     | 
    
         
            -
                                                                isotropic_perm, preferential_perforation, part_perf_fraction,
         
     | 
| 
       2337 
     | 
    
         
            -
                                                                perm_i_uuid, perm_j_uuid, perm_k_uuid):
         
     | 
| 
       2338 
     | 
    
         
            -
                    """Get the net-to-gross and directional permeability arrays for the interval."""
         
     | 
| 
      
 1853 
     | 
    
         
            +
                    h5_reg = rwh5.H5Register(self.model)
         
     | 
| 
       2339 
1854 
     | 
    
         | 
| 
       2340 
     | 
    
         
            -
                     
     | 
| 
       2341 
     | 
    
         
            -
             
     | 
| 
       2342 
     | 
    
         
            -
             
     | 
| 
       2343 
     | 
    
         
            -
                        if ntg_uuid is None:
         
     | 
| 
       2344 
     | 
    
         
            -
                            ntg = 1.0
         
     | 
| 
       2345 
     | 
    
         
            -
                            ntg_is_one = True
         
     | 
| 
       2346 
     | 
    
         
            -
                        else:
         
     | 
| 
       2347 
     | 
    
         
            -
                            ntg = BlockedWell.__prop_array(ntg_uuid, grid)[tuple_kji0]
         
     | 
| 
       2348 
     | 
    
         
            -
                            ntg_is_one = maths.isclose(ntg, 1.0, rel_tol = 0.001)
         
     | 
| 
       2349 
     | 
    
         
            -
                        if isotropic_perm and ntg_is_one:
         
     | 
| 
       2350 
     | 
    
         
            -
                            k_i = k_j = k_k = BlockedWell.__prop_array(perm_i_uuid, grid)[tuple_kji0]
         
     | 
| 
       2351 
     | 
    
         
            -
                        else:
         
     | 
| 
       2352 
     | 
    
         
            -
                            if preferential_perforation and not ntg_is_one:
         
     | 
| 
       2353 
     | 
    
         
            -
                                if part_perf_fraction <= ntg:
         
     | 
| 
       2354 
     | 
    
         
            -
                                    ntg = 1.0  # effective ntg when perforated intervals are in pay
         
     | 
| 
       2355 
     | 
    
         
            -
                                else:
         
     | 
| 
       2356 
     | 
    
         
            -
                                    ntg /= part_perf_fraction  # adjusted ntg when some perforations in non-pay
         
     | 
| 
       2357 
     | 
    
         
            -
                            # todo: check netgross facet type in property perm i & j parts: if set to gross then don't multiply by ntg below
         
     | 
| 
       2358 
     | 
    
         
            -
                            k_i = BlockedWell.__prop_array(perm_i_uuid, grid)[tuple_kji0] * ntg
         
     | 
| 
       2359 
     | 
    
         
            -
                            k_j = BlockedWell.__prop_array(perm_j_uuid, grid)[tuple_kji0] * ntg
         
     | 
| 
       2360 
     | 
    
         
            -
                            k_k = BlockedWell.__prop_array(perm_k_uuid, grid)[tuple_kji0]
         
     | 
| 
      
 1855 
     | 
    
         
            +
                    if create_for_trajectory_if_needed and self.trajectory_to_be_written:
         
     | 
| 
      
 1856 
     | 
    
         
            +
                        self.trajectory.write_hdf5(file_name, mode = mode)
         
     | 
| 
      
 1857 
     | 
    
         
            +
                        mode = 'a'
         
     | 
| 
       2361 
1858 
     | 
    
         | 
| 
       2362 
     | 
    
         
            -
                     
     | 
| 
      
 1859 
     | 
    
         
            +
                    h5_reg.register_dataset(self.uuid, 'NodeMd', self.node_mds)
         
     | 
| 
      
 1860 
     | 
    
         
            +
                    h5_reg.register_dataset(self.uuid, 'CellIndices', self.cell_indices)  # could use int32?
         
     | 
| 
      
 1861 
     | 
    
         
            +
                    h5_reg.register_dataset(self.uuid, 'GridIndices', self.grid_indices)  # could use int32?
         
     | 
| 
      
 1862 
     | 
    
         
            +
                    # convert face index pairs from [axis, polarity] back to strange local face numbering
         
     | 
| 
      
 1863 
     | 
    
         
            +
                    mask = (self.face_pair_indices.flatten() == -1).reshape((-1, 2))  # 2nd axis is (axis, polarity)
         
     | 
| 
      
 1864 
     | 
    
         
            +
                    masked_face_indices = np.where(mask, 0, self.face_pair_indices.reshape((-1, 2)))  # 2nd axis is (axis, polarity)
         
     | 
| 
      
 1865 
     | 
    
         
            +
                    # using flat array for raw_face_indices array
         
     | 
| 
      
 1866 
     | 
    
         
            +
                    # other resqml writing code might use an array with one int per entry point and one per exit point, with 2nd axis as (entry, exit)
         
     | 
| 
      
 1867 
     | 
    
         
            +
                    raw_face_indices = np.where(mask[:, 0], -1, self.face_index_map[masked_face_indices[:, 0],
         
     | 
| 
      
 1868 
     | 
    
         
            +
                                                                                    masked_face_indices[:,
         
     | 
| 
      
 1869 
     | 
    
         
            +
                                                                                                        1]].flatten()).reshape(-1)
         
     | 
| 
       2363 
1870 
     | 
    
         | 
| 
       2364 
     | 
    
         
            -
             
     | 
| 
       2365 
     | 
    
         
            -
                def __get_kh_for_interval(doing_kh, isotropic_perm, ntg_is_one, length, perm_i_uuid, grid, tuple_kji0, k_i, k_j,
         
     | 
| 
       2366 
     | 
    
         
            -
                                          k_k, anglv, sine_anglv, cosine_anglv, sine_angla, cosine_angla, min_kh, pc, pc_titles,
         
     | 
| 
       2367 
     | 
    
         
            -
                                          ci):
         
     | 
| 
       2368 
     | 
    
         
            -
                    """Get the permeability-thickness value for the interval."""
         
     | 
| 
      
 1871 
     | 
    
         
            +
                    h5_reg.register_dataset(self.uuid, 'LocalFacePairPerCellIndices', raw_face_indices)  # could use uint8?
         
     | 
| 
       2369 
1872 
     | 
    
         | 
| 
       2370 
     | 
    
         
            -
                     
     | 
| 
       2371 
     | 
    
         
            -
                    if doing_kh:
         
     | 
| 
       2372 
     | 
    
         
            -
                        kh = BlockedWell.__get_kh_if_doing_kh(isotropic_perm = isotropic_perm,
         
     | 
| 
       2373 
     | 
    
         
            -
                                                              ntg_is_one = ntg_is_one,
         
     | 
| 
       2374 
     | 
    
         
            -
                                                              length = length,
         
     | 
| 
       2375 
     | 
    
         
            -
                                                              perm_i_uuid = perm_i_uuid,
         
     | 
| 
       2376 
     | 
    
         
            -
                                                              grid = grid,
         
     | 
| 
       2377 
     | 
    
         
            -
                                                              tuple_kji0 = tuple_kji0,
         
     | 
| 
       2378 
     | 
    
         
            -
                                                              k_i = k_i,
         
     | 
| 
       2379 
     | 
    
         
            -
                                                              k_j = k_j,
         
     | 
| 
       2380 
     | 
    
         
            -
                                                              k_k = k_k,
         
     | 
| 
       2381 
     | 
    
         
            -
                                                              anglv = anglv,
         
     | 
| 
       2382 
     | 
    
         
            -
                                                              sine_anglv = sine_anglv,
         
     | 
| 
       2383 
     | 
    
         
            -
                                                              cosine_anglv = cosine_anglv,
         
     | 
| 
       2384 
     | 
    
         
            -
                                                              sine_angla = sine_angla,
         
     | 
| 
       2385 
     | 
    
         
            -
                                                              cosine_angla = cosine_angla)
         
     | 
| 
       2386 
     | 
    
         
            -
                        if min_kh is not None and kh < min_kh:
         
     | 
| 
       2387 
     | 
    
         
            -
                            skip_interval = True
         
     | 
| 
       2388 
     | 
    
         
            -
                    elif 'KH' in pc_titles:
         
     | 
| 
       2389 
     | 
    
         
            -
                        kh = pc.single_array_ref(citation_title = 'KH')[ci]
         
     | 
| 
       2390 
     | 
    
         
            -
                    else:
         
     | 
| 
       2391 
     | 
    
         
            -
                        kh = None
         
     | 
| 
       2392 
     | 
    
         
            -
                    return skip_interval, kh
         
     | 
| 
      
 1873 
     | 
    
         
            +
                    h5_reg.write(file = file_name, mode = mode)
         
     | 
| 
       2393 
1874 
     | 
    
         | 
| 
       2394 
     | 
    
         
            -
                 
     | 
| 
       2395 
     | 
    
         
            -
             
     | 
| 
       2396 
     | 
    
         
            -
                                         sine_anglv, cosine_anglv, sine_angla, cosine_angla):
         
     | 
| 
       2397 
     | 
    
         
            -
                    # note: this is believed to return required value even when grid crs has mixed xy & z units;
         
     | 
| 
       2398 
     | 
    
         
            -
                    # angles are true angles accounting for any mixed units
         
     | 
| 
       2399 
     | 
    
         
            -
                    if isotropic_perm and ntg_is_one:
         
     | 
| 
       2400 
     | 
    
         
            -
                        kh = length * BlockedWell.__prop_array(perm_i_uuid, grid)[tuple_kji0]
         
     | 
| 
       2401 
     | 
    
         
            -
                    else:
         
     | 
| 
       2402 
     | 
    
         
            -
                        if np.isnan(k_i) or np.isnan(k_j):
         
     | 
| 
       2403 
     | 
    
         
            -
                            kh = 0.0
         
     | 
| 
       2404 
     | 
    
         
            -
                        elif anglv == 0.0:
         
     | 
| 
       2405 
     | 
    
         
            -
                            kh = length * maths.sqrt(k_i * k_j)
         
     | 
| 
       2406 
     | 
    
         
            -
                        elif np.isnan(k_k):
         
     | 
| 
       2407 
     | 
    
         
            -
                            kh = 0.0
         
     | 
| 
       2408 
     | 
    
         
            -
                        else:
         
     | 
| 
       2409 
     | 
    
         
            -
                            k_e = maths.pow(k_i * k_j * k_k, 1.0 / 3.0)
         
     | 
| 
       2410 
     | 
    
         
            -
                            if k_e == 0.0:
         
     | 
| 
       2411 
     | 
    
         
            -
                                kh = 0.0
         
     | 
| 
       2412 
     | 
    
         
            -
                            else:
         
     | 
| 
       2413 
     | 
    
         
            -
                                l_i = length * maths.sqrt(k_e / k_i) * sine_anglv * cosine_angla
         
     | 
| 
       2414 
     | 
    
         
            -
                                l_j = length * maths.sqrt(k_e / k_j) * sine_anglv * sine_angla
         
     | 
| 
       2415 
     | 
    
         
            -
                                l_k = length * maths.sqrt(k_e / k_k) * cosine_anglv
         
     | 
| 
       2416 
     | 
    
         
            -
                                l_p = maths.sqrt(l_i * l_i + l_j * l_j + l_k * l_k)
         
     | 
| 
       2417 
     | 
    
         
            -
                                kh = k_e * l_p
         
     | 
| 
       2418 
     | 
    
         
            -
                    return kh
         
     | 
| 
      
 1875 
     | 
    
         
            +
                def add_grid_property_to_blocked_well(self, uuid_list):
         
     | 
| 
      
 1876 
     | 
    
         
            +
                    """Add properties to blocked wells from a list of uuids for properties on the supporting grid."""
         
     | 
| 
       2419 
1877 
     | 
    
         | 
| 
       2420 
     | 
    
         
            -
             
     | 
| 
       2421 
     | 
    
         
            -
                def __get_pc_arrays_for_interval(pc, pc_timeless, pc_titles, ci, length, radw, skin, length_uom, grid, traj_crs):
         
     | 
| 
       2422 
     | 
    
         
            -
                    """Get the property collection arrays for the interval."""
         
     | 
| 
      
 1878 
     | 
    
         
            +
                    part_list = [self.model.part_for_uuid(uuid) for uuid in uuid_list]
         
     | 
| 
       2423 
1879 
     | 
    
         | 
| 
       2424 
     | 
    
         
            -
                     
     | 
| 
      
 1880 
     | 
    
         
            +
                    assert len(self.grid_list) == 1, "only blocked wells with a single grid can be handled currently"
         
     | 
| 
      
 1881 
     | 
    
         
            +
                    grid = self.grid_list[0]
         
     | 
| 
      
 1882 
     | 
    
         
            +
                    # filter to only those properties on the grid
         
     | 
| 
      
 1883 
     | 
    
         
            +
                    parts = self.model.parts_list_filtered_by_supporting_uuid(part_list, grid.uuid)
         
     | 
| 
      
 1884 
     | 
    
         
            +
                    if len(parts) < len(uuid_list):
         
     | 
| 
      
 1885 
     | 
    
         
            +
                        log.warning(
         
     | 
| 
      
 1886 
     | 
    
         
            +
                            f"{len(uuid_list)-len(parts)} uuids ignored as they do not belong to the same grid as the blocked well")
         
     | 
| 
       2425 
1887 
     | 
    
         | 
| 
       2426 
     | 
    
         
            -
             
     | 
| 
       2427 
     | 
    
         
            -
             
     | 
| 
       2428 
     | 
    
         
            -
             
     | 
| 
      
 1888 
     | 
    
         
            +
                    gridpc = grid.extract_property_collection()
         
     | 
| 
      
 1889 
     | 
    
         
            +
                    # only 'cell' properties are handled
         
     | 
| 
      
 1890 
     | 
    
         
            +
                    cell_parts = [part for part in parts if gridpc.indexable_for_part(part) == 'cells']
         
     | 
| 
      
 1891 
     | 
    
         
            +
                    if len(cell_parts) < len(parts):
         
     | 
| 
      
 1892 
     | 
    
         
            +
                        log.warning(f"{len(parts)-len(cell_parts)} uuids ignored as they do not have indexable element of cells")
         
     | 
| 
       2429 
1893 
     | 
    
         | 
| 
       2430 
     | 
    
         
            -
             
     | 
| 
       2431 
     | 
    
         
            -
                         
     | 
| 
       2432 
     | 
    
         
            -
             
     | 
| 
       2433 
     | 
    
         
            -
                             
     | 
| 
       2434 
     | 
    
         
            -
                             
     | 
| 
       2435 
     | 
    
         
            -
             
     | 
| 
       2436 
     | 
    
         
            -
             
     | 
| 
       2437 
     | 
    
         
            -
             
     | 
| 
       2438 
     | 
    
         
            -
                                 
     | 
| 
       2439 
     | 
    
         
            -
             
     | 
| 
       2440 
     | 
    
         
            -
             
     | 
| 
       2441 
     | 
    
         
            -
                             
     | 
| 
       2442 
     | 
    
         
            -
                                v = pc_timeless.cached_part_array_ref(p)[ci]
         
     | 
| 
       2443 
     | 
    
         
            -
                                pc_uom = pc.uom_for_part(p)
         
     | 
| 
       2444 
     | 
    
         
            -
                        if pc_uom is not None and uom is not None and pc_uom != uom:
         
     | 
| 
       2445 
     | 
    
         
            -
                            v = wam.convert_lengths(v, pc_uom, uom)
         
     | 
| 
       2446 
     | 
    
         
            -
                        return v
         
     | 
| 
      
 1894 
     | 
    
         
            +
                    if len(cell_parts) > 0:
         
     | 
| 
      
 1895 
     | 
    
         
            +
                        bwpc = rqp.PropertyCollection(support = self)
         
     | 
| 
      
 1896 
     | 
    
         
            +
                        if len(gridpc.string_lookup_uuid_list()) > 0:
         
     | 
| 
      
 1897 
     | 
    
         
            +
                            sl_dict = {}
         
     | 
| 
      
 1898 
     | 
    
         
            +
                            for part in cell_parts:
         
     | 
| 
      
 1899 
     | 
    
         
            +
                                if gridpc.string_lookup_uuid_for_part(part) in sl_dict.keys():
         
     | 
| 
      
 1900 
     | 
    
         
            +
                                    sl_dict[gridpc.string_lookup_uuid_for_part(part)] =  \
         
     | 
| 
      
 1901 
     | 
    
         
            +
                                        sl_dict[gridpc.string_lookup_uuid_for_part(part)] + [part]
         
     | 
| 
      
 1902 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 1903 
     | 
    
         
            +
                                    sl_dict[gridpc.string_lookup_uuid_for_part(part)] = [part]
         
     | 
| 
      
 1904 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 1905 
     | 
    
         
            +
                            sl_dict = {None: cell_parts}
         
     | 
| 
       2447 
1906 
     | 
    
         | 
| 
       2448 
     | 
    
         
            -
             
     | 
| 
       2449 
     | 
    
         
            -
                         
     | 
| 
       2450 
     | 
    
         
            -
             
     | 
| 
       2451 
     | 
    
         
            -
             
     | 
| 
       2452 
     | 
    
         
            -
             
     | 
| 
       2453 
     | 
    
         
            -
             
     | 
| 
       2454 
     | 
    
         
            -
             
     | 
| 
       2455 
     | 
    
         
            -
             
     | 
| 
       2456 
     | 
    
         
            -
             
     | 
| 
       2457 
     | 
    
         
            -
             
     | 
| 
       2458 
     | 
    
         
            -
             
     | 
| 
       2459 
     | 
    
         
            -
             
     | 
| 
       2460 
     | 
    
         
            -
             
     | 
| 
       2461 
     | 
    
         
            -
             
     | 
| 
       2462 
     | 
    
         
            -
             
     | 
| 
       2463 
     | 
    
         
            -
                    wi = get_item(None, 'WI', pc_titles, pc, pc_timeless, ci, None)
         
     | 
| 
       2464 
     | 
    
         
            -
                    wbc = get_item(None, 'WBC', pc_titles, pc, pc_timeless, ci, None)
         
     | 
| 
      
 1907 
     | 
    
         
            +
                        sl_ts_dict = {}
         
     | 
| 
      
 1908 
     | 
    
         
            +
                        for sl_uuid in sl_dict.keys():
         
     | 
| 
      
 1909 
     | 
    
         
            +
                            if len(gridpc.time_series_uuid_list()) > 0:
         
     | 
| 
      
 1910 
     | 
    
         
            +
                                # dictionary with keys for string_lookup uuids and None where missing
         
     | 
| 
      
 1911 
     | 
    
         
            +
                                # values for each key are a list of property parts associated with that lookup uuid, or None
         
     | 
| 
      
 1912 
     | 
    
         
            +
                                time_dict = {}
         
     | 
| 
      
 1913 
     | 
    
         
            +
                                for part in sl_dict[sl_uuid]:
         
     | 
| 
      
 1914 
     | 
    
         
            +
                                    if gridpc.time_series_uuid_for_part(part) in time_dict.keys():
         
     | 
| 
      
 1915 
     | 
    
         
            +
                                        time_dict[gridpc.time_series_uuid_for_part(part)] =  \
         
     | 
| 
      
 1916 
     | 
    
         
            +
                                            time_dict[gridpc.time_series_uuid_for_part(part)] + [part]
         
     | 
| 
      
 1917 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 1918 
     | 
    
         
            +
                                        time_dict[gridpc.time_series_uuid_for_part(part)] = [part]
         
     | 
| 
      
 1919 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 1920 
     | 
    
         
            +
                                time_dict = {None: sl_dict[sl_uuid]}
         
     | 
| 
      
 1921 
     | 
    
         
            +
                            sl_ts_dict[sl_uuid] = time_dict
         
     | 
| 
       2465 
1922 
     | 
    
         | 
| 
       2466 
     | 
    
         
            -
             
     | 
| 
       2467 
     | 
    
         
            -
             
     | 
| 
       2468 
     | 
    
         
            -
             
     | 
| 
       2469 
     | 
    
         
            -
             
     | 
| 
       2470 
     | 
    
         
            -
             
     | 
| 
       2471 
     | 
    
         
            -
             
     | 
| 
       2472 
     | 
    
         
            -
             
     | 
| 
       2473 
     | 
    
         
            -
             
     | 
| 
       2474 
     | 
    
         
            -
             
     | 
| 
       2475 
     | 
    
         
            -
             
     | 
| 
       2476 
     | 
    
         
            -
             
     | 
| 
       2477 
     | 
    
         
            -
             
     | 
| 
       2478 
     | 
    
         
            -
             
     | 
| 
       2479 
     | 
    
         
            -
             
     | 
| 
       2480 
     | 
    
         
            -
             
     | 
| 
       2481 
     | 
    
         
            -
             
     | 
| 
       2482 
     | 
    
         
            -
             
     | 
| 
       2483 
     | 
    
         
            -
             
     | 
| 
       2484 
     | 
    
         
            -
             
     | 
| 
       2485 
     | 
    
         
            -
             
     | 
| 
      
 1923 
     | 
    
         
            +
                        for sl_uuid in sl_ts_dict.keys():
         
     | 
| 
      
 1924 
     | 
    
         
            +
                            time_dict = sl_ts_dict[sl_uuid]
         
     | 
| 
      
 1925 
     | 
    
         
            +
                            for time_uuid in time_dict.keys():
         
     | 
| 
      
 1926 
     | 
    
         
            +
                                parts = time_dict[time_uuid]
         
     | 
| 
      
 1927 
     | 
    
         
            +
                                for part in parts:
         
     | 
| 
      
 1928 
     | 
    
         
            +
                                    array = gridpc.cached_part_array_ref(part)
         
     | 
| 
      
 1929 
     | 
    
         
            +
                                    indices = self.cell_indices_for_grid_uuid(grid.uuid)
         
     | 
| 
      
 1930 
     | 
    
         
            +
                                    bwarray = np.empty(shape = (indices.shape[0],), dtype = array.dtype)
         
     | 
| 
      
 1931 
     | 
    
         
            +
                                    for i, ind in enumerate(indices):
         
     | 
| 
      
 1932 
     | 
    
         
            +
                                        bwarray[i] = array[tuple(ind)]
         
     | 
| 
      
 1933 
     | 
    
         
            +
                                    bwpc.add_cached_array_to_imported_list(
         
     | 
| 
      
 1934 
     | 
    
         
            +
                                        bwarray,
         
     | 
| 
      
 1935 
     | 
    
         
            +
                                        source_info = f'property from grid {grid.title}',
         
     | 
| 
      
 1936 
     | 
    
         
            +
                                        keyword = gridpc.citation_title_for_part(part),
         
     | 
| 
      
 1937 
     | 
    
         
            +
                                        discrete = (not gridpc.continuous_for_part(part)),
         
     | 
| 
      
 1938 
     | 
    
         
            +
                                        uom = gridpc.uom_for_part(part),
         
     | 
| 
      
 1939 
     | 
    
         
            +
                                        time_index = gridpc.time_index_for_part(part),
         
     | 
| 
      
 1940 
     | 
    
         
            +
                                        null_value = gridpc.null_value_for_part(part),
         
     | 
| 
      
 1941 
     | 
    
         
            +
                                        property_kind = gridpc.property_kind_for_part(part),
         
     | 
| 
      
 1942 
     | 
    
         
            +
                                        local_property_kind_uuid = gridpc.local_property_kind_uuid(part),
         
     | 
| 
      
 1943 
     | 
    
         
            +
                                        facet_type = gridpc.facet_type_for_part(part),
         
     | 
| 
      
 1944 
     | 
    
         
            +
                                        facet = gridpc.facet_for_part(part),
         
     | 
| 
      
 1945 
     | 
    
         
            +
                                        realization = gridpc.realization_for_part(part),
         
     | 
| 
      
 1946 
     | 
    
         
            +
                                        indexable_element = 'cells')
         
     | 
| 
      
 1947 
     | 
    
         
            +
                                bwpc.write_hdf5_for_imported_list(use_int32 = False)
         
     | 
| 
      
 1948 
     | 
    
         
            +
                                bwpc.create_xml_for_imported_list_and_add_parts_to_model(time_series_uuid = time_uuid,
         
     | 
| 
      
 1949 
     | 
    
         
            +
                                                                                         string_lookup_uuid = sl_uuid)
         
     | 
| 
      
 1950 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 1951 
     | 
    
         
            +
                        log.debug(
         
     | 
| 
      
 1952 
     | 
    
         
            +
                            "no properties added - uuids either not 'cell' properties or blocked well is associated with multiple grids"
         
     | 
| 
      
 1953 
     | 
    
         
            +
                        )
         
     | 
| 
       2486 
1954 
     | 
    
         | 
| 
       2487 
     | 
    
         
            -
             
     | 
| 
       2488 
     | 
    
         
            -
             
     | 
| 
       2489 
     | 
    
         
            -
                        wam.convert_lengths(cell_axial_vectors[..., 2], grid.crs.z_units, length_uom)
         
     | 
| 
       2490 
     | 
    
         
            -
                        d2 = np.empty(3)
         
     | 
| 
       2491 
     | 
    
         
            -
                        for axis in range(3):
         
     | 
| 
       2492 
     | 
    
         
            -
                            d2[axis] = np.sum(cell_axial_vectors[axis] * cell_axial_vectors[axis])
         
     | 
| 
       2493 
     | 
    
         
            -
                        if radb is None:
         
     | 
| 
       2494 
     | 
    
         
            -
                            radb_e = BlockedWell.__calculate_radb_e(k_ei = k_ei,
         
     | 
| 
       2495 
     | 
    
         
            -
                                                                    k_ej = k_ej,
         
     | 
| 
       2496 
     | 
    
         
            -
                                                                    k_ek = k_ek,
         
     | 
| 
       2497 
     | 
    
         
            -
                                                                    k_i = k_i,
         
     | 
| 
       2498 
     | 
    
         
            -
                                                                    k_j = k_j,
         
     | 
| 
       2499 
     | 
    
         
            -
                                                                    k_k = k_k,
         
     | 
| 
       2500 
     | 
    
         
            -
                                                                    d2 = d2,
         
     | 
| 
       2501 
     | 
    
         
            -
                                                                    sine_anglv = sine_anglv,
         
     | 
| 
       2502 
     | 
    
         
            -
                                                                    cosine_anglv = cosine_anglv,
         
     | 
| 
       2503 
     | 
    
         
            -
                                                                    sine_angla = sine_angla,
         
     | 
| 
       2504 
     | 
    
         
            -
                                                                    cosine_angla = cosine_angla)
         
     | 
| 
       2505 
     | 
    
         
            -
                            radb = radw * radb_e / radw_e
         
     | 
| 
       2506 
     | 
    
         
            -
                            log.debug(f'RADB value calculated in BlockedWell dataframe method as: {radb}')
         
     | 
| 
       2507 
     | 
    
         
            -
                        if wi is None:
         
     | 
| 
       2508 
     | 
    
         
            -
                            wi = 0.0 if radb <= 0.0 else 2.0 * maths.pi / (maths.log(radb / radw) + skin)
         
     | 
| 
       2509 
     | 
    
         
            -
                        if 'WBC' in column_list and wbc is None:
         
     | 
| 
       2510 
     | 
    
         
            -
                            assert length_uom == 'm' or length_uom.startswith('ft'),  \
         
     | 
| 
       2511 
     | 
    
         
            -
                                'WBC only calculable for length uom of m or ft*'
         
     | 
| 
       2512 
     | 
    
         
            -
                            conversion_constant = 8.5270171e-5 if length_uom == 'm' else 0.006328286
         
     | 
| 
       2513 
     | 
    
         
            -
                            wbc = conversion_constant * kh * wi  # note: pperf aleady accounted for in kh
         
     | 
| 
      
 1955 
     | 
    
         
            +
                def _set_cell_interval_map(self):
         
     | 
| 
      
 1956 
     | 
    
         
            +
                    """Sets up an index mapping from blocked cell index to interval index, accounting for unblocked intervals."""
         
     | 
| 
       2514 
1957 
     | 
    
         | 
| 
       2515 
     | 
    
         
            -
                     
     | 
| 
      
 1958 
     | 
    
         
            +
                    self.cell_interval_map = np.zeros(self.cell_count, dtype = np.int32)
         
     | 
| 
      
 1959 
     | 
    
         
            +
                    ci = 0
         
     | 
| 
      
 1960 
     | 
    
         
            +
                    for ii in range(self.node_count - 1):
         
     | 
| 
      
 1961 
     | 
    
         
            +
                        if self.grid_indices[ii] < 0:
         
     | 
| 
      
 1962 
     | 
    
         
            +
                            continue
         
     | 
| 
      
 1963 
     | 
    
         
            +
                        self.cell_interval_map[ci] = ii
         
     | 
| 
      
 1964 
     | 
    
         
            +
                        ci += 1
         
     | 
| 
      
 1965 
     | 
    
         
            +
                    assert ci == self.cell_count
         
     | 
| 
       2516 
1966 
     | 
    
         | 
| 
       2517 
     | 
    
         
            -
                 
     | 
| 
       2518 
     | 
    
         
            -
             
     | 
| 
       2519 
     | 
    
         
            -
                                              cosine_angla):
         
     | 
| 
      
 1967 
     | 
    
         
            +
                def __derive_from_wellspec_check_well_name(self, well_name):
         
     | 
| 
      
 1968 
     | 
    
         
            +
                    """Set the well name to be used in the wellspec file."""
         
     | 
| 
       2520 
1969 
     | 
    
         | 
| 
       2521 
     | 
    
         
            -
                    if  
     | 
| 
       2522 
     | 
    
         
            -
                         
     | 
| 
       2523 
     | 
    
         
            -
                        radw_e = radw
         
     | 
| 
      
 1970 
     | 
    
         
            +
                    if well_name:
         
     | 
| 
      
 1971 
     | 
    
         
            +
                        self.well_name = well_name
         
     | 
| 
       2524 
1972 
     | 
    
         
             
                    else:
         
     | 
| 
       2525 
     | 
    
         
            -
                         
     | 
| 
       2526 
     | 
    
         
            -
             
     | 
| 
       2527 
     | 
    
         
            -
                         
     | 
| 
       2528 
     | 
    
         
            -
             
     | 
| 
       2529 
     | 
    
         
            -
                        r_wj = 0.0 if k_ej == 0.0 else 0.5 * radw * (maths.sqrt(k_ej / k_i) + maths.sqrt(k_ej / k_k))
         
     | 
| 
       2530 
     | 
    
         
            -
                        r_wk = 0.0 if k_ek == 0.0 else 0.5 * radw * (maths.sqrt(k_ek / k_i) + maths.sqrt(k_ek / k_j))
         
     | 
| 
       2531 
     | 
    
         
            -
                        rwi = r_wi * sine_anglv * cosine_angla
         
     | 
| 
       2532 
     | 
    
         
            -
                        rwj = r_wj * sine_anglv * sine_angla
         
     | 
| 
       2533 
     | 
    
         
            -
                        rwk = r_wk * cosine_anglv
         
     | 
| 
       2534 
     | 
    
         
            -
                        radw_e = maths.sqrt(rwi * rwi + rwj * rwj + rwk * rwk)
         
     | 
| 
       2535 
     | 
    
         
            -
                        if radw_e == 0.0:
         
     | 
| 
       2536 
     | 
    
         
            -
                            radw_e = radw  # no permeability in this situation anyway
         
     | 
| 
       2537 
     | 
    
         
            -
             
     | 
| 
       2538 
     | 
    
         
            -
                    return k_ei, k_ej, k_ek, radw_e
         
     | 
| 
      
 1973 
     | 
    
         
            +
                        well_name = self.well_name
         
     | 
| 
      
 1974 
     | 
    
         
            +
                    if not self.title:
         
     | 
| 
      
 1975 
     | 
    
         
            +
                        self.title = well_name
         
     | 
| 
      
 1976 
     | 
    
         
            +
                    return well_name
         
     | 
| 
       2539 
1977 
     | 
    
         | 
| 
       2540 
1978 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       2541 
     | 
    
         
            -
                def  
     | 
| 
       2542 
     | 
    
         
            -
             
     | 
| 
       2543 
     | 
    
         
            -
                     
     | 
| 
       2544 
     | 
    
         
            -
             
     | 
| 
       2545 
     | 
    
         
            -
                     
     | 
| 
       2546 
     | 
    
         
            -
                     
     | 
| 
       2547 
     | 
    
         
            -
                     
     | 
| 
       2548 
     | 
    
         
            -
                     
     | 
| 
       2549 
     | 
    
         
            -
                    radb_e = maths.sqrt(rbi * rbi + rbj * rbj + rbk * rbk)
         
     | 
| 
      
 1979 
     | 
    
         
            +
                def __cell_kji0_from_df(df, df_row):
         
     | 
| 
      
 1980 
     | 
    
         
            +
                    row = df.iloc[df_row]
         
     | 
| 
      
 1981 
     | 
    
         
            +
                    if pd.isna(row.iloc[0]) or pd.isna(row.iloc[1]) or pd.isna(row.iloc[2]):
         
     | 
| 
      
 1982 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 1983 
     | 
    
         
            +
                    cell_kji0 = np.empty((3,), dtype = np.int32)
         
     | 
| 
      
 1984 
     | 
    
         
            +
                    cell_kji0[:] = row.iloc[2], row.iloc[1], row.iloc[0]
         
     | 
| 
      
 1985 
     | 
    
         
            +
                    cell_kji0[:] -= 1
         
     | 
| 
      
 1986 
     | 
    
         
            +
                    return cell_kji0
         
     | 
| 
       2550 
1987 
     | 
    
         | 
| 
       2551 
     | 
    
         
            -
             
     | 
| 
      
 1988 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 1989 
     | 
    
         
            +
                def __verify_grid_name(grid_name_to_check, row, skipped_warning_grid, well_name):
         
     | 
| 
      
 1990 
     | 
    
         
            +
                    """Check whether the grid associated with a row of the dataframe matches the expected grid name."""
         
     | 
| 
      
 1991 
     | 
    
         
            +
                    skip_row = False
         
     | 
| 
      
 1992 
     | 
    
         
            +
                    if grid_name_to_check and pd.notna(row['GRID']) and grid_name_to_check != str(row['GRID']).upper():
         
     | 
| 
      
 1993 
     | 
    
         
            +
                        other_grid = str(row['GRID'])
         
     | 
| 
      
 1994 
     | 
    
         
            +
                        if skipped_warning_grid != other_grid:
         
     | 
| 
      
 1995 
     | 
    
         
            +
                            log.warning('skipping perforation(s) in grid ' + other_grid + ' for well ' + str(well_name))
         
     | 
| 
      
 1996 
     | 
    
         
            +
                            skipped_warning_grid = other_grid
         
     | 
| 
      
 1997 
     | 
    
         
            +
                            skip_row = True
         
     | 
| 
      
 1998 
     | 
    
         
            +
                    return skipped_warning_grid, skip_row
         
     | 
| 
       2552 
1999 
     | 
    
         | 
| 
       2553 
     | 
    
         
            -
                 
     | 
| 
       2554 
     | 
    
         
            -
             
     | 
| 
       2555 
     | 
    
         
            -
             
     | 
| 
      
 2000 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2001 
     | 
    
         
            +
                def __calculate_entry_and_exit_axes_polarities_and_points(angles_present, row, cp, well_name, df, i, cell_kji0,
         
     | 
| 
      
 2002 
     | 
    
         
            +
                                                                          blocked_cells_kji0, use_face_centres, xy_units, z_units):
         
     | 
| 
      
 2003 
     | 
    
         
            +
                    if angles_present:
         
     | 
| 
      
 2004 
     | 
    
         
            +
                        entry_axis, entry_polarity, entry_xyz, exit_axis, exit_polarity, exit_xyz =  \
         
     | 
| 
      
 2005 
     | 
    
         
            +
                        BlockedWell.__calculate_entry_and_exit_axes_polarities_and_points_using_angles(
         
     | 
| 
      
 2006 
     | 
    
         
            +
                            row = row, cp = cp, well_name = well_name, xy_units = xy_units, z_units = z_units)
         
     | 
| 
      
 2007 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2008 
     | 
    
         
            +
                        # fabricate entry and exit axes and polarities based on indices alone
         
     | 
| 
      
 2009 
     | 
    
         
            +
                        # note: could use geometry but here a cheap rough-and-ready approach is used
         
     | 
| 
      
 2010 
     | 
    
         
            +
                        log.debug('row ' + str(i) + ': using cell moves')
         
     | 
| 
      
 2011 
     | 
    
         
            +
                        entry_axis, entry_polarity, exit_axis, exit_polarity = BlockedWell.__calculate_entry_and_exit_axes_polarities_and_points_using_indices(
         
     | 
| 
      
 2012 
     | 
    
         
            +
                            df = df, i = i, cell_kji0 = cell_kji0, blocked_cells_kji0 = blocked_cells_kji0)
         
     | 
| 
       2556 
2013 
     | 
    
         | 
| 
       2557 
     | 
    
         
            -
                     
     | 
| 
       2558 
     | 
    
         
            -
             
     | 
| 
       2559 
     | 
    
         
            -
                         
     | 
| 
       2560 
     | 
    
         
            -
             
     | 
| 
       2561 
     | 
    
         
            -
             
     | 
| 
       2562 
     | 
    
         
            -
             
     | 
| 
       2563 
     | 
    
         
            -
             
     | 
| 
       2564 
     | 
    
         
            -
                                                          traj_z_inc_down = traj_z_inc_down,
         
     | 
| 
       2565 
     | 
    
         
            -
                                                          entry_xyz = entry_xyz,
         
     | 
| 
       2566 
     | 
    
         
            -
                                                          exit_xyz = exit_xyz,
         
     | 
| 
       2567 
     | 
    
         
            -
                                                          ee_crs = ee_crs)
         
     | 
| 
       2568 
     | 
    
         
            -
                    xyz = np.array(xyz)
         
     | 
| 
       2569 
     | 
    
         
            -
                    for i, col_header in enumerate(['X', 'Y', 'DEPTH']):
         
     | 
| 
       2570 
     | 
    
         
            -
                        if col_header in pc_titles:
         
     | 
| 
       2571 
     | 
    
         
            -
                            xyz[i] = pc.single_array_ref(citation_title = col_header)[ci]
         
     | 
| 
      
 2014 
     | 
    
         
            +
                    entry_xyz, exit_xyz = BlockedWell.__override_vector_based_xyz_entry_and_exit_points_if_necessary(
         
     | 
| 
      
 2015 
     | 
    
         
            +
                        use_face_centres = use_face_centres,
         
     | 
| 
      
 2016 
     | 
    
         
            +
                        entry_axis = entry_axis,
         
     | 
| 
      
 2017 
     | 
    
         
            +
                        exit_axis = exit_axis,
         
     | 
| 
      
 2018 
     | 
    
         
            +
                        entry_polarity = entry_polarity,
         
     | 
| 
      
 2019 
     | 
    
         
            +
                        exit_polarity = exit_polarity,
         
     | 
| 
      
 2020 
     | 
    
         
            +
                        cp = cp)
         
     | 
| 
       2572 
2021 
     | 
    
         | 
| 
       2573 
     | 
    
         
            -
                    return  
     | 
| 
      
 2022 
     | 
    
         
            +
                    return entry_axis, entry_polarity, entry_xyz, exit_axis, exit_polarity, exit_xyz
         
     | 
| 
       2574 
2023 
     | 
    
         | 
| 
       2575 
     | 
    
         
            -
                 
     | 
| 
       2576 
     | 
    
         
            -
             
     | 
| 
      
 2024 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2025 
     | 
    
         
            +
                def __calculate_entry_and_exit_axes_polarities_and_points_using_angles(row, cp, well_name, xy_units, z_units):
         
     | 
| 
      
 2026 
     | 
    
         
            +
                    """Calculate entry and exit axes, polarities and points using azimuth and inclination angles."""
         
     | 
| 
       2577 
2027 
     | 
    
         | 
| 
       2578 
     | 
    
         
            -
                     
     | 
| 
       2579 
     | 
    
         
            -
             
     | 
| 
       2580 
     | 
    
         
            -
             
     | 
| 
       2581 
     | 
    
         
            -
             
     | 
| 
       2582 
     | 
    
         
            -
                        if depth_inc_down and traj_z_inc_down is False:
         
     | 
| 
       2583 
     | 
    
         
            -
                            xyz[2] = -xyz[2]
         
     | 
| 
      
 2028 
     | 
    
         
            +
                    angla = row['ANGLA']
         
     | 
| 
      
 2029 
     | 
    
         
            +
                    inclination = row['ANGLV']
         
     | 
| 
      
 2030 
     | 
    
         
            +
                    if inclination < 0.001:
         
     | 
| 
      
 2031 
     | 
    
         
            +
                        azimuth = 0.0
         
     | 
| 
       2584 
2032 
     | 
    
         
             
                    else:
         
     | 
| 
       2585 
     | 
    
         
            -
                         
     | 
| 
       2586 
     | 
    
         
            -
                         
     | 
| 
       2587 
     | 
    
         
            -
             
     | 
| 
       2588 
     | 
    
         
            -
             
     | 
| 
       2589 
     | 
    
         
            -
             
     | 
| 
       2590 
     | 
    
         
            -
             
     | 
| 
       2591 
     | 
    
         
            -
                     
     | 
| 
      
 2033 
     | 
    
         
            +
                        i_vector = np.sum(cp[:, :, 1] - cp[:, :, 0], axis = (0, 1))
         
     | 
| 
      
 2034 
     | 
    
         
            +
                        azimuth = vec.azimuth(i_vector) - angla  # see Nexus keyword reference doc
         
     | 
| 
      
 2035 
     | 
    
         
            +
                    well_vector = vec.unit_vector_from_azimuth_and_inclination(azimuth, inclination) * 10000.0
         
     | 
| 
      
 2036 
     | 
    
         
            +
                    if xy_units != z_units:
         
     | 
| 
      
 2037 
     | 
    
         
            +
                        well_vector[2] = wam.convert_lengths(well_vector[2], xy_units, z_units)
         
     | 
| 
      
 2038 
     | 
    
         
            +
                        well_vector = vec.unit_vector(well_vector) * 10000.0
         
     | 
| 
      
 2039 
     | 
    
         
            +
                    # todo: the following might be producing NaN's when vector passes precisely through an edge
         
     | 
| 
      
 2040 
     | 
    
         
            +
                    (entry_axis, entry_polarity, entry_xyz, exit_axis, exit_polarity, exit_xyz) =  \
         
     | 
| 
      
 2041 
     | 
    
         
            +
                        rqwu.find_entry_and_exit(cp, -well_vector, well_vector, well_name)
         
     | 
| 
      
 2042 
     | 
    
         
            +
                    return entry_axis, entry_polarity, entry_xyz, exit_axis, exit_polarity, exit_xyz
         
     | 
| 
       2592 
2043 
     | 
    
         | 
| 
       2593 
     | 
    
         
            -
                def  
     | 
| 
       2594 
     | 
    
         
            -
                    """Convert the measured depth to the correct units or get the measured depth from the property collection."""
         
     | 
| 
      
 2044 
     | 
    
         
            +
                def __calculate_entry_and_exit_axes_polarities_and_points_using_indices(df, i, cell_kji0, blocked_cells_kji0):
         
     | 
| 
       2595 
2045 
     | 
    
         | 
| 
       2596 
     | 
    
         
            -
                     
     | 
| 
       2597 
     | 
    
         
            -
                         
     | 
| 
       2598 
     | 
    
         
            -
                     
     | 
| 
       2599 
     | 
    
         
            -
                         
     | 
| 
      
 2046 
     | 
    
         
            +
                    entry_axis, entry_polarity = BlockedWell.__fabricate_entry_axis_and_polarity_using_indices(
         
     | 
| 
      
 2047 
     | 
    
         
            +
                        i, cell_kji0, blocked_cells_kji0)
         
     | 
| 
      
 2048 
     | 
    
         
            +
                    exit_axis, exit_polarity = BlockedWell.__fabricate_exit_axis_and_polarity_using_indices(
         
     | 
| 
      
 2049 
     | 
    
         
            +
                        i, cell_kji0, entry_axis, entry_polarity, df)
         
     | 
| 
       2600 
2050 
     | 
    
         | 
| 
       2601 
     | 
    
         
            -
                    return  
     | 
| 
      
 2051 
     | 
    
         
            +
                    return entry_axis, entry_polarity, exit_axis, exit_polarity
         
     | 
| 
       2602 
2052 
     | 
    
         | 
| 
       2603 
2053 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       2604 
     | 
    
         
            -
                def  
     | 
| 
       2605 
     | 
    
         
            -
             
     | 
| 
       2606 
     | 
    
         
            -
                                                        cell_kji0, row_ci_list, ci):
         
     | 
| 
       2607 
     | 
    
         
            -
                    """Append the row of data corresponding to the interval to the dataframe."""
         
     | 
| 
       2608 
     | 
    
         
            -
             
     | 
| 
       2609 
     | 
    
         
            -
                    column_names = [
         
     | 
| 
       2610 
     | 
    
         
            -
                        'GRID', 'RADW', 'SKIN', 'ANGLA', 'ANGLV', 'LENGTH', 'KH', 'DEPTH', 'MD', 'X', 'Y', 'STAT', 'PPERF', 'RADB',
         
     | 
| 
       2611 
     | 
    
         
            -
                        'WI', 'WBC'
         
     | 
| 
       2612 
     | 
    
         
            -
                    ]
         
     | 
| 
       2613 
     | 
    
         
            -
                    column_values = [
         
     | 
| 
       2614 
     | 
    
         
            -
                        grid_name, radw, skin, angla, anglv, length, kh, xyz[2], md, xyz[0], xyz[1], stat, part_perf_fraction, radb,
         
     | 
| 
       2615 
     | 
    
         
            -
                        wi, wbc
         
     | 
| 
       2616 
     | 
    
         
            -
                    ]
         
     | 
| 
       2617 
     | 
    
         
            -
                    column_values_dict = dict(zip(column_names, column_values))
         
     | 
| 
      
 2054 
     | 
    
         
            +
                def __fabricate_entry_axis_and_polarity_using_indices(i, cell_kji0, blocked_cells_kji0):
         
     | 
| 
      
 2055 
     | 
    
         
            +
                    """Fabricate entry and exit axes and polarities based on indices alone.
         
     | 
| 
       2618 
2056 
     | 
    
         | 
| 
       2619 
     | 
    
         
            -
                     
     | 
| 
       2620 
     | 
    
         
            -
             
     | 
| 
       2621 
     | 
    
         
            -
                     
     | 
| 
       2622 
     | 
    
         
            -
                        if col_index < 3:
         
     | 
| 
       2623 
     | 
    
         
            -
                            if one_based:
         
     | 
| 
       2624 
     | 
    
         
            -
                                row_dict[col] = [cell_kji0[2 - col_index] + 1]
         
     | 
| 
       2625 
     | 
    
         
            -
                            else:
         
     | 
| 
       2626 
     | 
    
         
            -
                                row_dict[col] = [cell_kji0[2 - col_index]]
         
     | 
| 
       2627 
     | 
    
         
            -
                        else:
         
     | 
| 
       2628 
     | 
    
         
            -
                            row_dict[col] = [column_values_dict[col]]
         
     | 
| 
      
 2057 
     | 
    
         
            +
                    note:
         
     | 
| 
      
 2058 
     | 
    
         
            +
                        could use geometry but here a cheap rough-and-ready approach is used
         
     | 
| 
      
 2059 
     | 
    
         
            +
                    """
         
     | 
| 
       2629 
2060 
     | 
    
         | 
| 
       2630 
     | 
    
         
            -
                     
     | 
| 
       2631 
     | 
    
         
            -
                         
     | 
| 
       2632 
     | 
    
         
            -
             
     | 
| 
      
 2061 
     | 
    
         
            +
                    if i == 0:
         
     | 
| 
      
 2062 
     | 
    
         
            +
                        entry_axis, entry_polarity = 0, 0  # K-
         
     | 
| 
      
 2063 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2064 
     | 
    
         
            +
                        entry_move = cell_kji0 - blocked_cells_kji0[-1]
         
     | 
| 
      
 2065 
     | 
    
         
            +
                        log.debug(f'entry move: {entry_move}')
         
     | 
| 
      
 2066 
     | 
    
         
            +
                        if entry_move[1] == 0 and entry_move[2] == 0:  # K move
         
     | 
| 
      
 2067 
     | 
    
         
            +
                            entry_axis = 0
         
     | 
| 
      
 2068 
     | 
    
         
            +
                            entry_polarity = 0 if entry_move[0] >= 0 else 1
         
     | 
| 
      
 2069 
     | 
    
         
            +
                        elif abs(entry_move[1]) > abs(entry_move[2]):  # J dominant move
         
     | 
| 
      
 2070 
     | 
    
         
            +
                            entry_axis = 1
         
     | 
| 
      
 2071 
     | 
    
         
            +
                            entry_polarity = 0 if entry_move[1] >= 0 else 1
         
     | 
| 
      
 2072 
     | 
    
         
            +
                        else:  # I dominant move
         
     | 
| 
      
 2073 
     | 
    
         
            +
                            entry_axis = 2
         
     | 
| 
      
 2074 
     | 
    
         
            +
                            entry_polarity = 0 if entry_move[2] >= 0 else 1
         
     | 
| 
      
 2075 
     | 
    
         
            +
                    return entry_axis, entry_polarity
         
     | 
| 
      
 2076 
     | 
    
         
            +
             
     | 
| 
      
 2077 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2078 
     | 
    
         
            +
                def __fabricate_exit_axis_and_polarity_using_indices(i, cell_kji0, entry_axis, entry_polarity, df):
         
     | 
| 
      
 2079 
     | 
    
         
            +
                    if i == len(df) - 1:
         
     | 
| 
      
 2080 
     | 
    
         
            +
                        exit_axis, exit_polarity = entry_axis, 1 - entry_polarity
         
     | 
| 
      
 2081 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2082 
     | 
    
         
            +
                        next_cell_kji0 = BlockedWell.__cell_kji0_from_df(df, i + 1)
         
     | 
| 
      
 2083 
     | 
    
         
            +
                        if next_cell_kji0 is None:
         
     | 
| 
      
 2084 
     | 
    
         
            +
                            exit_axis, exit_polarity = entry_axis, 1 - entry_polarity
         
     | 
| 
       2633 
2085 
     | 
    
         
             
                        else:
         
     | 
| 
       2634 
     | 
    
         
            -
                             
     | 
| 
       2635 
     | 
    
         
            -
             
     | 
| 
      
 2086 
     | 
    
         
            +
                            exit_move = next_cell_kji0 - cell_kji0
         
     | 
| 
      
 2087 
     | 
    
         
            +
                            log.debug(f'exit move: {exit_move}')
         
     | 
| 
      
 2088 
     | 
    
         
            +
                            if exit_move[1] == 0 and exit_move[2] == 0:  # K move
         
     | 
| 
      
 2089 
     | 
    
         
            +
                                exit_axis = 0
         
     | 
| 
      
 2090 
     | 
    
         
            +
                                exit_polarity = 1 if exit_move[0] >= 0 else 0
         
     | 
| 
      
 2091 
     | 
    
         
            +
                            elif abs(exit_move[1]) > abs(exit_move[2]):  # J dominant move
         
     | 
| 
      
 2092 
     | 
    
         
            +
                                exit_axis = 1
         
     | 
| 
      
 2093 
     | 
    
         
            +
                                exit_polarity = 1 if exit_move[1] >= 0 else 0
         
     | 
| 
      
 2094 
     | 
    
         
            +
                            else:  # I dominant move
         
     | 
| 
      
 2095 
     | 
    
         
            +
                                exit_axis = 2
         
     | 
| 
      
 2096 
     | 
    
         
            +
                                exit_polarity = 1 if exit_move[2] >= 0 else 0
         
     | 
| 
      
 2097 
     | 
    
         
            +
                    return exit_axis, exit_polarity
         
     | 
| 
       2636 
2098 
     | 
    
         | 
| 
       2637 
     | 
    
         
            -
             
     | 
| 
      
 2099 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2100 
     | 
    
         
            +
                def __override_vector_based_xyz_entry_and_exit_points_if_necessary(use_face_centres, entry_axis, exit_axis,
         
     | 
| 
      
 2101 
     | 
    
         
            +
                                                                                   entry_polarity, exit_polarity, cp):
         
     | 
| 
      
 2102 
     | 
    
         
            +
                    """Override the vector based xyz entry and exit with face centres."""
         
     | 
| 
       2638 
2103 
     | 
    
         | 
| 
       2639 
     | 
    
         
            -
                     
     | 
| 
      
 2104 
     | 
    
         
            +
                    if use_face_centres:  # override the vector based xyz entry and exit points with face centres
         
     | 
| 
      
 2105 
     | 
    
         
            +
                        if entry_axis == 0:
         
     | 
| 
      
 2106 
     | 
    
         
            +
                            entry_xyz = np.mean(cp[entry_polarity, :, :], axis = (0, 1))
         
     | 
| 
      
 2107 
     | 
    
         
            +
                        elif entry_axis == 1:
         
     | 
| 
      
 2108 
     | 
    
         
            +
                            entry_xyz = np.mean(cp[:, entry_polarity, :], axis = (0, 1))
         
     | 
| 
      
 2109 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 2110 
     | 
    
         
            +
                            entry_xyz = np.mean(cp[:, :, entry_polarity], axis = (0, 1))  # entry_axis == 2, ie. I
         
     | 
| 
      
 2111 
     | 
    
         
            +
                        if exit_axis == 0:
         
     | 
| 
      
 2112 
     | 
    
         
            +
                            exit_xyz = np.mean(cp[exit_polarity, :, :], axis = (0, 1))
         
     | 
| 
      
 2113 
     | 
    
         
            +
                        elif exit_axis == 1:
         
     | 
| 
      
 2114 
     | 
    
         
            +
                            exit_xyz = np.mean(cp[:, exit_polarity, :], axis = (0, 1))
         
     | 
| 
      
 2115 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 2116 
     | 
    
         
            +
                            exit_xyz = np.mean(cp[:, :, exit_polarity], axis = (0, 1))  # exit_axis == 2, ie. I
         
     | 
| 
      
 2117 
     | 
    
         
            +
                        return entry_xyz, exit_xyz
         
     | 
| 
       2640 
2118 
     | 
    
         | 
| 
       2641 
     | 
    
         
            -
                 
     | 
| 
       2642 
     | 
    
         
            -
             
     | 
| 
       2643 
     | 
    
         
            -
             
     | 
| 
       2644 
     | 
    
         
            -
             
     | 
| 
       2645 
     | 
    
         
            -
             
     | 
| 
       2646 
     | 
    
         
            -
             
     | 
| 
       2647 
     | 
    
         
            -
             
     | 
| 
       2648 
     | 
    
         
            -
             
     | 
| 
      
 2119 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2120 
     | 
    
         
            +
                def __add_interval(previous_xyz, entry_axis, entry_polarity, entry_xyz, exit_axis, exit_polarity, exit_xyz,
         
     | 
| 
      
 2121 
     | 
    
         
            +
                                   cell_kji0, trajectory_mds, trajectory_points, blocked_intervals, blocked_cells_kji0,
         
     | 
| 
      
 2122 
     | 
    
         
            +
                                   blocked_face_pairs, xy_units, z_units, length_uom):
         
     | 
| 
      
 2123 
     | 
    
         
            +
                    if previous_xyz is None:  # first entry
         
     | 
| 
      
 2124 
     | 
    
         
            +
                        log.debug('adding mean sea level trajectory start')
         
     | 
| 
      
 2125 
     | 
    
         
            +
                        previous_xyz = entry_xyz.copy()
         
     | 
| 
      
 2126 
     | 
    
         
            +
                        previous_xyz[2] = 0.0  # use depth zero as md datum
         
     | 
| 
      
 2127 
     | 
    
         
            +
                        trajectory_mds.append(0.0)
         
     | 
| 
      
 2128 
     | 
    
         
            +
                        trajectory_points.append(previous_xyz)
         
     | 
| 
      
 2129 
     | 
    
         
            +
                    if not vec.isclose(previous_xyz, entry_xyz, tolerance = 0.05):  # add an unblocked interval
         
     | 
| 
      
 2130 
     | 
    
         
            +
                        log.debug('adding unblocked interval')
         
     | 
| 
      
 2131 
     | 
    
         
            +
                        trajectory_points.append(entry_xyz)
         
     | 
| 
      
 2132 
     | 
    
         
            +
                        new_md = trajectory_mds[-1] + BlockedWell._md_length(entry_xyz - previous_xyz, xy_units, z_units,
         
     | 
| 
      
 2133 
     | 
    
         
            +
                                                                             length_uom)
         
     | 
| 
      
 2134 
     | 
    
         
            +
                        trajectory_mds.append(new_md)
         
     | 
| 
      
 2135 
     | 
    
         
            +
                        blocked_intervals.append(-1)  # unblocked interval
         
     | 
| 
      
 2136 
     | 
    
         
            +
                        previous_xyz = entry_xyz
         
     | 
| 
      
 2137 
     | 
    
         
            +
                    log.debug('adding blocked interval for cell kji0: ' + str(cell_kji0))
         
     | 
| 
      
 2138 
     | 
    
         
            +
                    trajectory_points.append(exit_xyz)
         
     | 
| 
      
 2139 
     | 
    
         
            +
                    new_md = trajectory_mds[-1] + BlockedWell._md_length(exit_xyz - previous_xyz, xy_units, z_units, length_uom)
         
     | 
| 
      
 2140 
     | 
    
         
            +
                    trajectory_mds.append(new_md)
         
     | 
| 
      
 2141 
     | 
    
         
            +
                    blocked_intervals.append(0)  # blocked interval
         
     | 
| 
      
 2142 
     | 
    
         
            +
                    previous_xyz = exit_xyz
         
     | 
| 
      
 2143 
     | 
    
         
            +
                    blocked_cells_kji0.append(cell_kji0)
         
     | 
| 
      
 2144 
     | 
    
         
            +
                    blocked_face_pairs.append(((entry_axis, entry_polarity), (exit_axis, exit_polarity)))
         
     | 
| 
       2649 
2145 
     | 
    
         | 
| 
       2650 
     | 
    
         
            -
                     
     | 
| 
      
 2146 
     | 
    
         
            +
                    return previous_xyz, trajectory_mds, trajectory_points, blocked_intervals, blocked_cells_kji0, blocked_face_pairs
         
     | 
| 
      
 2147 
     | 
    
         
            +
             
     | 
| 
      
 2148 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2149 
     | 
    
         
            +
                def _md_length(xyz_vector, xy_units, z_units, length_uom):
         
     | 
| 
      
 2150 
     | 
    
         
            +
                    if length_uom == xy_units and length_uom == z_units:
         
     | 
| 
      
 2151 
     | 
    
         
            +
                        return vec.naive_length(xyz_vector)
         
     | 
| 
      
 2152 
     | 
    
         
            +
                    x = wam.convert_lengths(xyz_vector[0], xy_units, length_uom)
         
     | 
| 
      
 2153 
     | 
    
         
            +
                    y = wam.convert_lengths(xyz_vector[1], xy_units, length_uom)
         
     | 
| 
      
 2154 
     | 
    
         
            +
                    z = wam.convert_lengths(xyz_vector[2], z_units, length_uom)
         
     | 
| 
      
 2155 
     | 
    
         
            +
                    return vec.naive_length((x, y, z))
         
     | 
| 
      
 2156 
     | 
    
         
            +
             
     | 
| 
      
 2157 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2158 
     | 
    
         
            +
                def __add_tail_to_trajectory_if_necessary(blocked_count, exit_axis, exit_polarity, cell_kji0, grid,
         
     | 
| 
      
 2159 
     | 
    
         
            +
                                                          trajectory_points, trajectory_mds):
         
     | 
| 
      
 2160 
     | 
    
         
            +
                    """Add tail to trajcetory if last segment terminates at bottom face in bottom layer."""
         
     | 
| 
      
 2161 
     | 
    
         
            +
             
     | 
| 
      
 2162 
     | 
    
         
            +
                    if blocked_count > 0 and exit_axis == 0 and exit_polarity == 1 and cell_kji0[
         
     | 
| 
      
 2163 
     | 
    
         
            +
                            0] == grid.nk - 1 and grid.k_direction_is_down:
         
     | 
| 
      
 2164 
     | 
    
         
            +
                        tail_length = 10.0  # metres or feet
         
     | 
| 
      
 2165 
     | 
    
         
            +
                        tail_xyz = trajectory_points[-1].copy()
         
     | 
| 
      
 2166 
     | 
    
         
            +
                        tail_xyz[2] += tail_length * (1.0 if grid.z_inc_down() else -1.0)
         
     | 
| 
      
 2167 
     | 
    
         
            +
                        trajectory_points.append(tail_xyz)
         
     | 
| 
      
 2168 
     | 
    
         
            +
                        new_md = trajectory_mds[-1] + tail_length
         
     | 
| 
      
 2169 
     | 
    
         
            +
                        trajectory_mds.append(new_md)
         
     | 
| 
      
 2170 
     | 
    
         
            +
             
     | 
| 
      
 2171 
     | 
    
         
            +
                    return trajectory_points, trajectory_mds
         
     | 
| 
      
 2172 
     | 
    
         
            +
             
     | 
| 
      
 2173 
     | 
    
         
            +
                def __add_as_properties_if_specified(self,
         
     | 
| 
      
 2174 
     | 
    
         
            +
                                                     add_as_properties,
         
     | 
| 
      
 2175 
     | 
    
         
            +
                                                     df,
         
     | 
| 
      
 2176 
     | 
    
         
            +
                                                     length_uom,
         
     | 
| 
      
 2177 
     | 
    
         
            +
                                                     time_index = None,
         
     | 
| 
      
 2178 
     | 
    
         
            +
                                                     time_series_uuid = None):
         
     | 
| 
      
 2179 
     | 
    
         
            +
                    # if add_as_properties is True and present as a list of wellspec column names, both the blocked well and
         
     | 
| 
      
 2180 
     | 
    
         
            +
                    # the properties will have their hdf5 data written, xml created and be added as parts to the model
         
     | 
| 
      
 2181 
     | 
    
         
            +
             
     | 
| 
      
 2182 
     | 
    
         
            +
                    if add_as_properties and len(df.columns) > 3:
         
     | 
| 
      
 2183 
     | 
    
         
            +
                        # NB: atypical writing of hdf5 data and xml creation in order to support related properties
         
     | 
| 
      
 2184 
     | 
    
         
            +
                        self.write_hdf5()
         
     | 
| 
      
 2185 
     | 
    
         
            +
                        self.create_xml()
         
     | 
| 
       2651 
2186 
     | 
    
         
             
                        if isinstance(add_as_properties, list):
         
     | 
| 
       2652 
2187 
     | 
    
         
             
                            for col in add_as_properties:
         
     | 
| 
       2653 
     | 
    
         
            -
                                assert col in  
     | 
| 
      
 2188 
     | 
    
         
            +
                                assert col in df.columns[3:]  # could just skip missing columns
         
     | 
| 
       2654 
2189 
     | 
    
         
             
                            property_columns = add_as_properties
         
     | 
| 
       2655 
2190 
     | 
    
         
             
                        else:
         
     | 
| 
       2656 
     | 
    
         
            -
                            property_columns =  
     | 
| 
      
 2191 
     | 
    
         
            +
                            property_columns = df.columns[3:]
         
     | 
| 
       2657 
2192 
     | 
    
         
             
                        self.add_df_properties(df,
         
     | 
| 
       2658 
2193 
     | 
    
         
             
                                               property_columns,
         
     | 
| 
       2659 
2194 
     | 
    
         
             
                                               length_uom = length_uom,
         
     | 
| 
       2660 
2195 
     | 
    
         
             
                                               time_index = time_index,
         
     | 
| 
       2661 
2196 
     | 
    
         
             
                                               time_series_uuid = time_series_uuid)
         
     | 
| 
       2662 
2197 
     | 
    
         | 
| 
       2663 
     | 
    
         
            -
                def  
     | 
| 
       2664 
     | 
    
         
            -
             
     | 
| 
       2665 
     | 
    
         
            -
                                      columns,
         
     | 
| 
       2666 
     | 
    
         
            -
                                      length_uom = None,
         
     | 
| 
       2667 
     | 
    
         
            -
                                      time_index = None,
         
     | 
| 
       2668 
     | 
    
         
            -
                                      time_series_uuid = None,
         
     | 
| 
       2669 
     | 
    
         
            -
                                      realization = None):
         
     | 
| 
       2670 
     | 
    
         
            -
                    """Creates a property part for each column in the dataframe, based on the dataframe values.
         
     | 
| 
      
 2198 
     | 
    
         
            +
                def __set_grid(self, grid, wellspec_file, cellio_file, column_ji0):
         
     | 
| 
      
 2199 
     | 
    
         
            +
                    """Set the grid to which the blocked well belongs."""
         
     | 
| 
       2671 
2200 
     | 
    
         | 
| 
       2672 
     | 
    
         
            -
                     
     | 
| 
       2673 
     | 
    
         
            -
             
     | 
| 
       2674 
     | 
    
         
            -
                         
     | 
| 
       2675 
     | 
    
         
            -
             
     | 
| 
       2676 
     | 
    
         
            -
                         
     | 
| 
       2677 
     | 
    
         
            -
             
     | 
| 
       2678 
     | 
    
         
            -
                        time_series_uuid (uuid.UUID, optional): if adding a timestamp to the property, this is
         
     | 
| 
       2679 
     | 
    
         
            -
                            the uuid of the TimeSeries object
         
     | 
| 
       2680 
     | 
    
         
            -
                        realization (int, optional): if present, is used as the realization number for all the
         
     | 
| 
       2681 
     | 
    
         
            -
                            properties
         
     | 
| 
      
 2201 
     | 
    
         
            +
                    if grid is None and (self.trajectory is not None or wellspec_file is not None or cellio_file is not None or
         
     | 
| 
      
 2202 
     | 
    
         
            +
                                         column_ji0 is not None):
         
     | 
| 
      
 2203 
     | 
    
         
            +
                        grid_final = self.model.grid()
         
     | 
| 
      
 2204 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2205 
     | 
    
         
            +
                        grid_final = grid
         
     | 
| 
      
 2206 
     | 
    
         
            +
                    return grid_final
         
     | 
| 
       2682 
2207 
     | 
    
         | 
| 
       2683 
     | 
    
         
            -
             
     | 
| 
       2684 
     | 
    
         
            -
             
     | 
| 
      
 2208 
     | 
    
         
            +
                def __check_cellio_init_okay(self, cellio_file, well_name, grid):
         
     | 
| 
      
 2209 
     | 
    
         
            +
                    """Checks if BlockedWell object initialization from a cellio file is okay."""
         
     | 
| 
       2685 
2210 
     | 
    
         | 
| 
       2686 
     | 
    
         
            -
                     
     | 
| 
       2687 
     | 
    
         
            -
             
     | 
| 
       2688 
     | 
    
         
            -
                         
     | 
| 
       2689 
     | 
    
         
            -
                        this method currently only handles single grid situations;
         
     | 
| 
       2690 
     | 
    
         
            -
                        dataframe rows must be in the same order as the cells in the blocked well
         
     | 
| 
       2691 
     | 
    
         
            -
                    """
         
     | 
| 
       2692 
     | 
    
         
            -
                    # todo: enhance to handle multiple grids
         
     | 
| 
       2693 
     | 
    
         
            -
                    assert len(self.grid_list) == 1
         
     | 
| 
       2694 
     | 
    
         
            -
                    if columns is None or len(columns) == 0 or len(df) == 0:
         
     | 
| 
       2695 
     | 
    
         
            -
                        return
         
     | 
| 
       2696 
     | 
    
         
            -
                    if length_uom is None:
         
     | 
| 
       2697 
     | 
    
         
            -
                        length_uom = self.trajectory.md_uom
         
     | 
| 
       2698 
     | 
    
         
            -
                    extra_pc = rqp.PropertyCollection()
         
     | 
| 
       2699 
     | 
    
         
            -
                    extra_pc.set_support(support = self)
         
     | 
| 
       2700 
     | 
    
         
            -
                    assert len(df) == self.cell_count
         
     | 
| 
      
 2211 
     | 
    
         
            +
                    okay = self.import_from_rms_cellio(cellio_file, well_name, grid)
         
     | 
| 
      
 2212 
     | 
    
         
            +
                    if not okay:
         
     | 
| 
      
 2213 
     | 
    
         
            +
                        self.node_count = 0
         
     | 
| 
       2701 
2214 
     | 
    
         | 
| 
       2702 
     | 
    
         
            -
             
     | 
| 
       2703 
     | 
    
         
            -
             
     | 
| 
       2704 
     | 
    
         
            -
                        uom, pk, discrete = self._get_uom_pk_discrete_for_df_properties(extra = extra, length_uom = length_uom)
         
     | 
| 
       2705 
     | 
    
         
            -
                        if discrete:
         
     | 
| 
       2706 
     | 
    
         
            -
                            null_value = -1
         
     | 
| 
       2707 
     | 
    
         
            -
                            na_value = -1
         
     | 
| 
       2708 
     | 
    
         
            -
                            dtype = np.int32
         
     | 
| 
       2709 
     | 
    
         
            -
                        else:
         
     | 
| 
       2710 
     | 
    
         
            -
                            null_value = None
         
     | 
| 
       2711 
     | 
    
         
            -
                            na_value = np.NaN
         
     | 
| 
       2712 
     | 
    
         
            -
                            dtype = float
         
     | 
| 
       2713 
     | 
    
         
            -
                        # 'SKIN': use defaults for now; todo: create local property kind for skin
         
     | 
| 
       2714 
     | 
    
         
            -
                        if column == 'STAT':
         
     | 
| 
       2715 
     | 
    
         
            -
                            col_as_list = list(df[column])
         
     | 
| 
       2716 
     | 
    
         
            -
                            expanded = np.array([(0 if (str(st).upper() in ['OFF', '0']) else 1) for st in col_as_list],
         
     | 
| 
       2717 
     | 
    
         
            -
                                                dtype = int)
         
     | 
| 
       2718 
     | 
    
         
            -
                        else:
         
     | 
| 
       2719 
     | 
    
         
            -
                            expanded = df[column].to_numpy(dtype = dtype, copy = True, na_value = na_value)
         
     | 
| 
       2720 
     | 
    
         
            -
                        extra_pc.add_cached_array_to_imported_list(
         
     | 
| 
       2721 
     | 
    
         
            -
                            expanded,
         
     | 
| 
       2722 
     | 
    
         
            -
                            'blocked well dataframe',
         
     | 
| 
       2723 
     | 
    
         
            -
                            extra,
         
     | 
| 
       2724 
     | 
    
         
            -
                            discrete = discrete,
         
     | 
| 
       2725 
     | 
    
         
            -
                            uom = uom,
         
     | 
| 
       2726 
     | 
    
         
            -
                            property_kind = pk,
         
     | 
| 
       2727 
     | 
    
         
            -
                            local_property_kind_uuid = None,
         
     | 
| 
       2728 
     | 
    
         
            -
                            facet_type = None,
         
     | 
| 
       2729 
     | 
    
         
            -
                            facet = None,
         
     | 
| 
       2730 
     | 
    
         
            -
                            realization = realization,
         
     | 
| 
       2731 
     | 
    
         
            -
                            indexable_element = 'cells',
         
     | 
| 
       2732 
     | 
    
         
            -
                            count = 1,
         
     | 
| 
       2733 
     | 
    
         
            -
                            time_index = time_index,
         
     | 
| 
       2734 
     | 
    
         
            -
                            null_value = null_value,
         
     | 
| 
       2735 
     | 
    
         
            -
                        )
         
     | 
| 
       2736 
     | 
    
         
            -
                    extra_pc.write_hdf5_for_imported_list()
         
     | 
| 
       2737 
     | 
    
         
            -
                    extra_pc.create_xml_for_imported_list_and_add_parts_to_model(time_series_uuid = time_series_uuid,
         
     | 
| 
       2738 
     | 
    
         
            -
                                                                                 find_local_property_kinds = True)
         
     | 
| 
      
 2215 
     | 
    
         
            +
                def _load_from_xml(self):
         
     | 
| 
      
 2216 
     | 
    
         
            +
                    """Loads the blocked wellbore object from an xml node (and associated hdf5 data)."""
         
     | 
| 
       2739 
2217 
     | 
    
         | 
| 
       2740 
     | 
    
         
            -
             
     | 
| 
       2741 
     | 
    
         
            -
                     
     | 
| 
       2742 
     | 
    
         
            -
                    # todo: this is horribly inefficient, building a whole dictionary for every call but only using one entry
         
     | 
| 
       2743 
     | 
    
         
            -
                    if length_uom not in ['m', 'ft']:
         
     | 
| 
       2744 
     | 
    
         
            -
                        raise ValueError(f"The length_uom {length_uom} must be either 'm' or 'ft'.")
         
     | 
| 
       2745 
     | 
    
         
            -
                    if extra == 'TEMP' and (temperature_uom is None or
         
     | 
| 
       2746 
     | 
    
         
            -
                                            temperature_uom not in wam.valid_uoms('thermodynamic temperature')):
         
     | 
| 
       2747 
     | 
    
         
            -
                        raise ValueError(f"The temperature_uom must be in {wam.valid_uoms('thermodynamic temperature')}.")
         
     | 
| 
      
 2218 
     | 
    
         
            +
                    node = self.root
         
     | 
| 
      
 2219 
     | 
    
         
            +
                    assert node is not None
         
     | 
| 
       2748 
2220 
     | 
    
         | 
| 
       2749 
     | 
    
         
            -
                     
     | 
| 
       2750 
     | 
    
         
            -
                                                                                                   extra = extra)
         
     | 
| 
       2751 
     | 
    
         
            -
                    uom_pk_discrete_dict = {
         
     | 
| 
       2752 
     | 
    
         
            -
                        'ANGLA': ('dega', 'azimuth', False),
         
     | 
| 
       2753 
     | 
    
         
            -
                        'ANGLV': ('dega', 'inclination', False),
         
     | 
| 
       2754 
     | 
    
         
            -
                        'KH': (f'mD.{length_uom}', 'permeability length', False),
         
     | 
| 
       2755 
     | 
    
         
            -
                        'PPERF': (f'{length_uom}/{length_uom}', 'perforation fraction', False),
         
     | 
| 
       2756 
     | 
    
         
            -
                        'STAT': (None, 'well connection open', True),
         
     | 
| 
       2757 
     | 
    
         
            -
                        'LENGTH': length_uom_pk_discrete,
         
     | 
| 
       2758 
     | 
    
         
            -
                        'MD': (length_uom, 'measured depth', False),
         
     | 
| 
       2759 
     | 
    
         
            -
                        'X': length_uom_pk_discrete,
         
     | 
| 
       2760 
     | 
    
         
            -
                        'Y': length_uom_pk_discrete,
         
     | 
| 
       2761 
     | 
    
         
            -
                        'DEPTH': (length_uom, 'depth', False),
         
     | 
| 
       2762 
     | 
    
         
            -
                        'RADW': (length_uom, 'wellbore radius', False),
         
     | 
| 
       2763 
     | 
    
         
            -
                        'RADB': (length_uom, 'block equivalent radius', False),
         
     | 
| 
       2764 
     | 
    
         
            -
                        'RADBP': length_uom_pk_discrete,
         
     | 
| 
       2765 
     | 
    
         
            -
                        'RADWP': length_uom_pk_discrete,
         
     | 
| 
       2766 
     | 
    
         
            -
                        'FM': (f'{length_uom}/{length_uom}', 'matrix fraction', False),
         
     | 
| 
       2767 
     | 
    
         
            -
                        'IRELPM': (None, 'relative permeability index', True),  # TODO: change to 'region initialization' with facet
         
     | 
| 
       2768 
     | 
    
         
            -
                        'SECT': (None, 'wellbore section index', True),
         
     | 
| 
       2769 
     | 
    
         
            -
                        'LAYER': (None, 'layer index', True),
         
     | 
| 
       2770 
     | 
    
         
            -
                        'ANGLE': ('dega', 'plane angle', False),
         
     | 
| 
       2771 
     | 
    
         
            -
                        'TEMP': (temperature_uom, 'thermodynamic temperature', False),
         
     | 
| 
       2772 
     | 
    
         
            -
                        'MDCON': length_uom_pk_discrete,
         
     | 
| 
       2773 
     | 
    
         
            -
                        'K': ('mD', 'rock permeability', False),
         
     | 
| 
       2774 
     | 
    
         
            -
                        'DZ': (length_uom, 'cell length', False),  # TODO: add direction facet
         
     | 
| 
       2775 
     | 
    
         
            -
                        'DTOP': (length_uom, 'depth', False),
         
     | 
| 
       2776 
     | 
    
         
            -
                        'DBOT': (length_uom, 'depth', False),
         
     | 
| 
       2777 
     | 
    
         
            -
                        'SKIN': ('Euc', 'skin', False),
         
     | 
| 
       2778 
     | 
    
         
            -
                        'WI': ('Euc', 'well connection index', False),
         
     | 
| 
       2779 
     | 
    
         
            -
                    }
         
     | 
| 
       2780 
     | 
    
         
            -
                    return uom_pk_discrete_dict.get(extra, ('Euc', 'generic continuous', False))
         
     | 
| 
      
 2221 
     | 
    
         
            +
                    self.__find_trajectory_uuid(node = node)
         
     | 
| 
       2781 
2222 
     | 
    
         | 
| 
       2782 
     | 
    
         
            -
             
     | 
| 
       2783 
     | 
    
         
            -
                     
     | 
| 
       2784 
     | 
    
         
            -
             
     | 
| 
       2785 
     | 
    
         
            -
             
     | 
| 
       2786 
     | 
    
         
            -
             
     | 
| 
       2787 
     | 
    
         
            -
             
     | 
| 
       2788 
     | 
    
         
            -
             
     | 
| 
       2789 
     | 
    
         
            -
             
     | 
| 
      
 2223 
     | 
    
         
            +
                    self.node_count = rqet.find_tag_int(node, 'NodeCount')
         
     | 
| 
      
 2224 
     | 
    
         
            +
                    assert self.node_count is not None and self.node_count >= 2, 'problem with blocked well node count'
         
     | 
| 
      
 2225 
     | 
    
         
            +
             
     | 
| 
      
 2226 
     | 
    
         
            +
                    mds_node = rqet.find_tag(node, 'NodeMd')
         
     | 
| 
      
 2227 
     | 
    
         
            +
                    assert mds_node is not None, 'blocked well node measured depths hdf5 reference not found in xml'
         
     | 
| 
      
 2228 
     | 
    
         
            +
                    rqwu.load_hdf5_array(self, mds_node, 'node_mds')
         
     | 
| 
      
 2229 
     | 
    
         
            +
             
     | 
| 
      
 2230 
     | 
    
         
            +
                    # Statement below has no effect, is this a bug?
         
     | 
| 
      
 2231 
     | 
    
         
            +
                    self.node_mds is not None and self.node_mds.ndim == 1 and self.node_mds.size == self.node_count
         
     | 
| 
      
 2232 
     | 
    
         
            +
             
     | 
| 
      
 2233 
     | 
    
         
            +
                    self.cell_count = rqet.find_tag_int(node, 'CellCount')
         
     | 
| 
      
 2234 
     | 
    
         
            +
                    assert self.cell_count is not None and self.cell_count > 0
         
     | 
| 
      
 2235 
     | 
    
         
            +
             
     | 
| 
      
 2236 
     | 
    
         
            +
                    # todo: remove this if block once RMS export issue resolved
         
     | 
| 
      
 2237 
     | 
    
         
            +
                    if self.cell_count == self.node_count:
         
     | 
| 
      
 2238 
     | 
    
         
            +
                        extended_mds = np.empty((self.node_mds.size + 1,))
         
     | 
| 
      
 2239 
     | 
    
         
            +
                        extended_mds[:-1] = self.node_mds
         
     | 
| 
      
 2240 
     | 
    
         
            +
                        extended_mds[-1] = self.node_mds[-1] + 1.0
         
     | 
| 
      
 2241 
     | 
    
         
            +
                        self.node_mds = extended_mds
         
     | 
| 
      
 2242 
     | 
    
         
            +
                        self.node_count += 1
         
     | 
| 
      
 2243 
     | 
    
         
            +
             
     | 
| 
      
 2244 
     | 
    
         
            +
                    assert self.cell_count < self.node_count
         
     | 
| 
      
 2245 
     | 
    
         
            +
             
     | 
| 
      
 2246 
     | 
    
         
            +
                    unique_grid_indices = self.__find_gi_node_and_load_hdf5_array(node = node)
         
     | 
| 
      
 2247 
     | 
    
         
            +
             
     | 
| 
      
 2248 
     | 
    
         
            +
                    self.__find_grid_node(node = node, unique_grid_indices = unique_grid_indices)
         
     | 
| 
      
 2249 
     | 
    
         
            +
             
     | 
| 
      
 2250 
     | 
    
         
            +
                    self.__find_ci_node_and_load_hdf5_array(node = node)
         
     | 
| 
      
 2251 
     | 
    
         
            +
             
     | 
| 
      
 2252 
     | 
    
         
            +
                    self.__find_fi_node_and_load_hdf5_array(node)
         
     | 
| 
      
 2253 
     | 
    
         
            +
             
     | 
| 
      
 2254 
     | 
    
         
            +
                    interp_uuid = rqet.find_nested_tags_text(node, ['RepresentedInterpretation', 'UUID'])
         
     | 
| 
      
 2255 
     | 
    
         
            +
                    if interp_uuid is None:
         
     | 
| 
      
 2256 
     | 
    
         
            +
                        self.wellbore_interpretation = None
         
     | 
| 
       2790 
2257 
     | 
    
         
             
                    else:
         
     | 
| 
       2791 
     | 
    
         
            -
                         
     | 
| 
       2792 
     | 
    
         
            -
             
     | 
| 
       2793 
     | 
    
         
            -
             
     | 
| 
      
 2258 
     | 
    
         
            +
                        self.wellbore_interpretation = rqo.WellboreInterpretation(self.model, uuid = interp_uuid)
         
     | 
| 
      
 2259 
     | 
    
         
            +
             
     | 
| 
      
 2260 
     | 
    
         
            +
                    # Set up matches between cell_indices and grid_indices
         
     | 
| 
      
 2261 
     | 
    
         
            +
                    self.cell_grid_link = self.map_cell_and_grid_indices()
         
     | 
| 
      
 2262 
     | 
    
         
            +
             
     | 
| 
      
 2263 
     | 
    
         
            +
                def __find_trajectory_uuid(self, node):
         
     | 
| 
      
 2264 
     | 
    
         
            +
                    """Find and verify the uuid of the trajectory associated with the BlockedWell object."""
         
     | 
| 
      
 2265 
     | 
    
         
            +
             
     | 
| 
      
 2266 
     | 
    
         
            +
                    trajectory_uuid = bu.uuid_from_string(rqet.find_nested_tags_text(node, ['Trajectory', 'UUID']))
         
     | 
| 
      
 2267 
     | 
    
         
            +
                    assert trajectory_uuid is not None, 'blocked well trajectory reference not found in xml'
         
     | 
| 
      
 2268 
     | 
    
         
            +
                    if self.trajectory is None:
         
     | 
| 
      
 2269 
     | 
    
         
            +
                        self.trajectory = rqw.Trajectory(self.model, uuid = trajectory_uuid)
         
     | 
| 
       2794 
2270 
     | 
    
         
             
                    else:
         
     | 
| 
       2795 
     | 
    
         
            -
                         
     | 
| 
       2796 
     | 
    
         
            -
                    return uom, pk, False
         
     | 
| 
      
 2271 
     | 
    
         
            +
                        assert bu.matching_uuids(self.trajectory.uuid, trajectory_uuid), 'blocked well trajectory uuid mismatch'
         
     | 
| 
       2797 
2272 
     | 
    
         | 
| 
       2798 
     | 
    
         
            -
                def  
     | 
| 
       2799 
     | 
    
         
            -
             
     | 
| 
       2800 
     | 
    
         
            -
                              perm_i_uuid = None,
         
     | 
| 
       2801 
     | 
    
         
            -
                              perm_j_uuid = None,
         
     | 
| 
       2802 
     | 
    
         
            -
                              perm_k_uuid = None,
         
     | 
| 
       2803 
     | 
    
         
            -
                              satw_uuid = None,
         
     | 
| 
       2804 
     | 
    
         
            -
                              sato_uuid = None,
         
     | 
| 
       2805 
     | 
    
         
            -
                              satg_uuid = None,
         
     | 
| 
       2806 
     | 
    
         
            -
                              region_uuid = None,
         
     | 
| 
       2807 
     | 
    
         
            -
                              active_only = False,
         
     | 
| 
       2808 
     | 
    
         
            -
                              min_k0 = None,
         
     | 
| 
       2809 
     | 
    
         
            -
                              max_k0 = None,
         
     | 
| 
       2810 
     | 
    
         
            -
                              k0_list = None,
         
     | 
| 
       2811 
     | 
    
         
            -
                              min_length = None,
         
     | 
| 
       2812 
     | 
    
         
            -
                              min_kh = None,
         
     | 
| 
       2813 
     | 
    
         
            -
                              max_depth = None,
         
     | 
| 
       2814 
     | 
    
         
            -
                              max_satw = None,
         
     | 
| 
       2815 
     | 
    
         
            -
                              min_sato = None,
         
     | 
| 
       2816 
     | 
    
         
            -
                              max_satg = None,
         
     | 
| 
       2817 
     | 
    
         
            -
                              perforation_list = None,
         
     | 
| 
       2818 
     | 
    
         
            -
                              region_list = None,
         
     | 
| 
       2819 
     | 
    
         
            -
                              set_k_face_intervals_vertical = False,
         
     | 
| 
       2820 
     | 
    
         
            -
                              anglv_ref = 'gravity',
         
     | 
| 
       2821 
     | 
    
         
            -
                              angla_plane_ref = None,
         
     | 
| 
       2822 
     | 
    
         
            -
                              length_mode = 'MD',
         
     | 
| 
       2823 
     | 
    
         
            -
                              length_uom = None,
         
     | 
| 
       2824 
     | 
    
         
            -
                              use_face_centres = False,
         
     | 
| 
       2825 
     | 
    
         
            -
                              preferential_perforation = True):
         
     | 
| 
       2826 
     | 
    
         
            -
                    """Returns the total static K.H (permeability x height).
         
     | 
| 
      
 2273 
     | 
    
         
            +
                def __find_ci_node_and_load_hdf5_array(self, node):
         
     | 
| 
      
 2274 
     | 
    
         
            +
                    """Find the BlockedWell object's cell indices hdf5 reference node and load the array."""
         
     | 
| 
       2827 
2275 
     | 
    
         | 
| 
       2828 
     | 
    
         
            -
                     
     | 
| 
       2829 
     | 
    
         
            -
             
     | 
| 
       2830 
     | 
    
         
            -
             
     | 
| 
       2831 
     | 
    
         
            -
                     
     | 
| 
      
 2276 
     | 
    
         
            +
                    ci_node = rqet.find_tag(node, 'CellIndices')
         
     | 
| 
      
 2277 
     | 
    
         
            +
                    assert ci_node is not None, 'blocked well cell indices hdf5 reference not found in xml'
         
     | 
| 
      
 2278 
     | 
    
         
            +
                    rqwu.load_hdf5_array(self, ci_node, 'cell_indices', dtype = self.cell_index_dtype)
         
     | 
| 
      
 2279 
     | 
    
         
            +
                    assert (self.cell_indices is not None and self.cell_indices.ndim == 1 and
         
     | 
| 
      
 2280 
     | 
    
         
            +
                            self.cell_indices.size == self.cell_count), 'mismatch in number of cell indices for blocked well'
         
     | 
| 
      
 2281 
     | 
    
         
            +
                    self.cellind_null = rqet.find_tag_int(ci_node, 'NullValue')
         
     | 
| 
      
 2282 
     | 
    
         
            +
                    if self.cellind_null is None:
         
     | 
| 
      
 2283 
     | 
    
         
            +
                        self.cellind_null = -1  # if no Null found assume -1 default
         
     | 
| 
       2832 
2284 
     | 
    
         | 
| 
       2833 
     | 
    
         
            -
             
     | 
| 
       2834 
     | 
    
         
            -
             
     | 
| 
       2835 
     | 
    
         
            -
                                        k_col = 'K',
         
     | 
| 
       2836 
     | 
    
         
            -
                                        one_based = False,
         
     | 
| 
       2837 
     | 
    
         
            -
                                        extra_columns_list = ['KH'],
         
     | 
| 
       2838 
     | 
    
         
            -
                                        ntg_uuid = ntg_uuid,
         
     | 
| 
       2839 
     | 
    
         
            -
                                        perm_i_uuid = perm_i_uuid,
         
     | 
| 
       2840 
     | 
    
         
            -
                                        perm_j_uuid = perm_j_uuid,
         
     | 
| 
       2841 
     | 
    
         
            -
                                        perm_k_uuid = perm_k_uuid,
         
     | 
| 
       2842 
     | 
    
         
            -
                                        satw_uuid = satw_uuid,
         
     | 
| 
       2843 
     | 
    
         
            -
                                        sato_uuid = sato_uuid,
         
     | 
| 
       2844 
     | 
    
         
            -
                                        satg_uuid = satg_uuid,
         
     | 
| 
       2845 
     | 
    
         
            -
                                        region_uuid = region_uuid,
         
     | 
| 
       2846 
     | 
    
         
            -
                                        active_only = active_only,
         
     | 
| 
       2847 
     | 
    
         
            -
                                        min_k0 = min_k0,
         
     | 
| 
       2848 
     | 
    
         
            -
                                        max_k0 = max_k0,
         
     | 
| 
       2849 
     | 
    
         
            -
                                        k0_list = k0_list,
         
     | 
| 
       2850 
     | 
    
         
            -
                                        min_length = min_length,
         
     | 
| 
       2851 
     | 
    
         
            -
                                        min_kh = min_kh,
         
     | 
| 
       2852 
     | 
    
         
            -
                                        max_depth = max_depth,
         
     | 
| 
       2853 
     | 
    
         
            -
                                        max_satw = max_satw,
         
     | 
| 
       2854 
     | 
    
         
            -
                                        min_sato = min_sato,
         
     | 
| 
       2855 
     | 
    
         
            -
                                        max_satg = max_satg,
         
     | 
| 
       2856 
     | 
    
         
            -
                                        perforation_list = perforation_list,
         
     | 
| 
       2857 
     | 
    
         
            -
                                        region_list = region_list,
         
     | 
| 
       2858 
     | 
    
         
            -
                                        set_k_face_intervals_vertical = set_k_face_intervals_vertical,
         
     | 
| 
       2859 
     | 
    
         
            -
                                        anglv_ref = anglv_ref,
         
     | 
| 
       2860 
     | 
    
         
            -
                                        angla_plane_ref = angla_plane_ref,
         
     | 
| 
       2861 
     | 
    
         
            -
                                        length_mode = length_mode,
         
     | 
| 
       2862 
     | 
    
         
            -
                                        length_uom = length_uom,
         
     | 
| 
       2863 
     | 
    
         
            -
                                        use_face_centres = use_face_centres,
         
     | 
| 
       2864 
     | 
    
         
            -
                                        preferential_perforation = preferential_perforation)
         
     | 
| 
      
 2285 
     | 
    
         
            +
                def __find_fi_node_and_load_hdf5_array(self, node):
         
     | 
| 
      
 2286 
     | 
    
         
            +
                    """Find the BlockedWell object's face indices hdf5 reference node and load the array."""
         
     | 
| 
       2865 
2287 
     | 
    
         | 
| 
       2866 
     | 
    
         
            -
                     
     | 
| 
      
 2288 
     | 
    
         
            +
                    fi_node = rqet.find_tag(node, 'LocalFacePairPerCellIndices')
         
     | 
| 
      
 2289 
     | 
    
         
            +
                    assert fi_node is not None, 'blocked well face indices hdf5 reference not found in xml'
         
     | 
| 
      
 2290 
     | 
    
         
            +
                    rqwu.load_hdf5_array(self, fi_node, 'raw_face_indices', dtype = np.int8)
         
     | 
| 
      
 2291 
     | 
    
         
            +
                    assert self.raw_face_indices is not None, 'failed to load face indices for blocked well'
         
     | 
| 
      
 2292 
     | 
    
         
            +
                    assert self.raw_face_indices.size == 2 * self.cell_count, 'mismatch in number of cell faces for blocked well'
         
     | 
| 
      
 2293 
     | 
    
         
            +
                    if self.raw_face_indices.ndim > 1:
         
     | 
| 
      
 2294 
     | 
    
         
            +
                        self.raw_face_indices = self.raw_face_indices.reshape((self.raw_face_indices.size,))
         
     | 
| 
      
 2295 
     | 
    
         
            +
                    mask = np.where(self.raw_face_indices == -1)
         
     | 
| 
      
 2296 
     | 
    
         
            +
                    self.raw_face_indices[mask] = 0
         
     | 
| 
      
 2297 
     | 
    
         
            +
                    self.face_pair_indices = self.face_index_inverse_map[self.raw_face_indices]
         
     | 
| 
      
 2298 
     | 
    
         
            +
                    self.face_pair_indices[mask] = (-1, -1)
         
     | 
| 
      
 2299 
     | 
    
         
            +
                    self.face_pair_indices = self.face_pair_indices.reshape((-1, 2, 2))
         
     | 
| 
      
 2300 
     | 
    
         
            +
                    del self.raw_face_indices
         
     | 
| 
      
 2301 
     | 
    
         
            +
                    self.facepair_null = rqet.find_tag_int(fi_node, 'NullValue')
         
     | 
| 
      
 2302 
     | 
    
         
            +
                    if self.facepair_null is None:
         
     | 
| 
      
 2303 
     | 
    
         
            +
                        self.facepair_null = -1
         
     | 
| 
       2867 
2304 
     | 
    
         | 
| 
       2868 
     | 
    
         
            -
                def  
     | 
| 
       2869 
     | 
    
         
            -
             
     | 
| 
       2870 
     | 
    
         
            -
                                   well_name = None,
         
     | 
| 
       2871 
     | 
    
         
            -
                                   mode = 'a',
         
     | 
| 
       2872 
     | 
    
         
            -
                                   extra_columns_list = [],
         
     | 
| 
       2873 
     | 
    
         
            -
                                   ntg_uuid = None,
         
     | 
| 
       2874 
     | 
    
         
            -
                                   perm_i_uuid = None,
         
     | 
| 
       2875 
     | 
    
         
            -
                                   perm_j_uuid = None,
         
     | 
| 
       2876 
     | 
    
         
            -
                                   perm_k_uuid = None,
         
     | 
| 
       2877 
     | 
    
         
            -
                                   satw_uuid = None,
         
     | 
| 
       2878 
     | 
    
         
            -
                                   sato_uuid = None,
         
     | 
| 
       2879 
     | 
    
         
            -
                                   satg_uuid = None,
         
     | 
| 
       2880 
     | 
    
         
            -
                                   region_uuid = None,
         
     | 
| 
       2881 
     | 
    
         
            -
                                   radw = None,
         
     | 
| 
       2882 
     | 
    
         
            -
                                   skin = None,
         
     | 
| 
       2883 
     | 
    
         
            -
                                   stat = None,
         
     | 
| 
       2884 
     | 
    
         
            -
                                   active_only = False,
         
     | 
| 
       2885 
     | 
    
         
            -
                                   min_k0 = None,
         
     | 
| 
       2886 
     | 
    
         
            -
                                   max_k0 = None,
         
     | 
| 
       2887 
     | 
    
         
            -
                                   k0_list = None,
         
     | 
| 
       2888 
     | 
    
         
            -
                                   min_length = None,
         
     | 
| 
       2889 
     | 
    
         
            -
                                   min_kh = None,
         
     | 
| 
       2890 
     | 
    
         
            -
                                   max_depth = None,
         
     | 
| 
       2891 
     | 
    
         
            -
                                   max_satw = None,
         
     | 
| 
       2892 
     | 
    
         
            -
                                   min_sato = None,
         
     | 
| 
       2893 
     | 
    
         
            -
                                   max_satg = None,
         
     | 
| 
       2894 
     | 
    
         
            -
                                   perforation_list = None,
         
     | 
| 
       2895 
     | 
    
         
            -
                                   region_list = None,
         
     | 
| 
       2896 
     | 
    
         
            -
                                   set_k_face_intervals_vertical = False,
         
     | 
| 
       2897 
     | 
    
         
            -
                                   depth_inc_down = True,
         
     | 
| 
       2898 
     | 
    
         
            -
                                   anglv_ref = 'gravity',
         
     | 
| 
       2899 
     | 
    
         
            -
                                   angla_plane_ref = None,
         
     | 
| 
       2900 
     | 
    
         
            -
                                   length_mode = 'MD',
         
     | 
| 
       2901 
     | 
    
         
            -
                                   length_uom = None,
         
     | 
| 
       2902 
     | 
    
         
            -
                                   preferential_perforation = True,
         
     | 
| 
       2903 
     | 
    
         
            -
                                   space_instead_of_tab_separator = True,
         
     | 
| 
       2904 
     | 
    
         
            -
                                   align_columns = True,
         
     | 
| 
       2905 
     | 
    
         
            -
                                   preceeding_blank_lines = 0,
         
     | 
| 
       2906 
     | 
    
         
            -
                                   trailing_blank_lines = 0,
         
     | 
| 
       2907 
     | 
    
         
            -
                                   length_uom_comment = False,
         
     | 
| 
       2908 
     | 
    
         
            -
                                   write_nexus_units = True,
         
     | 
| 
       2909 
     | 
    
         
            -
                                   float_format = '5.3',
         
     | 
| 
       2910 
     | 
    
         
            -
                                   use_properties = False,
         
     | 
| 
       2911 
     | 
    
         
            -
                                   property_time_index = None):
         
     | 
| 
       2912 
     | 
    
         
            -
                    """Writes Nexus WELLSPEC keyword to an ascii file.
         
     | 
| 
      
 2305 
     | 
    
         
            +
                def __find_gi_node_and_load_hdf5_array(self, node):
         
     | 
| 
      
 2306 
     | 
    
         
            +
                    """Find the BlockedWell object's grid indices hdf5 reference node and load the array."""
         
     | 
| 
       2913 
2307 
     | 
    
         | 
| 
       2914 
     | 
    
         
            -
                     
     | 
| 
       2915 
     | 
    
         
            -
             
     | 
| 
      
 2308 
     | 
    
         
            +
                    gi_node = rqet.find_tag(node, 'GridIndices')
         
     | 
| 
      
 2309 
     | 
    
         
            +
                    assert gi_node is not None, 'blocked well grid indices hdf5 reference not found in xml'
         
     | 
| 
      
 2310 
     | 
    
         
            +
                    rqwu.load_hdf5_array(self, gi_node, 'grid_indices', dtype = np.int32)
         
     | 
| 
      
 2311 
     | 
    
         
            +
                    # assert self.grid_indices is not None and self.grid_indices.ndim == 1 and self.grid_indices.size == self.node_count - 1
         
     | 
| 
      
 2312 
     | 
    
         
            +
                    # temporary code to handle blocked wells with incorrectly shaped grid indices wrt. nodes
         
     | 
| 
      
 2313 
     | 
    
         
            +
                    assert self.grid_indices is not None and self.grid_indices.ndim == 1
         
     | 
| 
      
 2314 
     | 
    
         
            +
                    if self.grid_indices.size != self.node_count - 1:
         
     | 
| 
      
 2315 
     | 
    
         
            +
                        if self.grid_indices.size == self.cell_count and self.node_count == 2 * self.cell_count:
         
     | 
| 
      
 2316 
     | 
    
         
            +
                            log.warning(f'handling node duplication or missing unblocked intervals in blocked well: {self.title}')
         
     | 
| 
      
 2317 
     | 
    
         
            +
                            expanded_grid_indices = np.full(self.node_count - 1, -1, dtype = np.int32)
         
     | 
| 
      
 2318 
     | 
    
         
            +
                            expanded_grid_indices[::2] = self.grid_indices
         
     | 
| 
      
 2319 
     | 
    
         
            +
                            self.grid_indices = expanded_grid_indices
         
     | 
| 
      
 2320 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 2321 
     | 
    
         
            +
                            raise ValueError(
         
     | 
| 
      
 2322 
     | 
    
         
            +
                                f'incorrect grid indices size with respect to node count in blocked well: {self.title}')
         
     | 
| 
      
 2323 
     | 
    
         
            +
                    # end of temporary code
         
     | 
| 
      
 2324 
     | 
    
         
            +
                    unique_grid_indices = np.unique(self.grid_indices)  # sorted list of unique values
         
     | 
| 
      
 2325 
     | 
    
         
            +
                    self.gridind_null = rqet.find_tag_int(gi_node, 'NullValue')
         
     | 
| 
      
 2326 
     | 
    
         
            +
                    if self.gridind_null is None:
         
     | 
| 
      
 2327 
     | 
    
         
            +
                        self.gridind_null = -1  # if no Null found assume -1 default
         
     | 
| 
      
 2328 
     | 
    
         
            +
                    return unique_grid_indices
         
     | 
| 
       2916 
2329 
     | 
    
         | 
| 
       2917 
     | 
    
         
            -
             
     | 
| 
       2918 
     | 
    
         
            -
             
     | 
| 
       2919 
     | 
    
         
            -
                       align_columns and float_format arguments are deprecated and no longer used
         
     | 
| 
       2920 
     | 
    
         
            -
                    """
         
     | 
| 
      
 2330 
     | 
    
         
            +
                def __find_grid_node(self, node, unique_grid_indices):
         
     | 
| 
      
 2331 
     | 
    
         
            +
                    """Find the BlockedWell object's grid reference node(s)."""
         
     | 
| 
       2921 
2332 
     | 
    
         | 
| 
       2922 
     | 
    
         
            -
                     
     | 
| 
      
 2333 
     | 
    
         
            +
                    grid_node_list = rqet.list_of_tag(node, 'Grid')
         
     | 
| 
      
 2334 
     | 
    
         
            +
                    assert len(grid_node_list) > 0, 'blocked well grid reference(s) not found in xml'
         
     | 
| 
      
 2335 
     | 
    
         
            +
                    assert unique_grid_indices[0] >= -1 and unique_grid_indices[-1] < len(
         
     | 
| 
      
 2336 
     | 
    
         
            +
                        grid_node_list), 'blocked well grid index out of range'
         
     | 
| 
      
 2337 
     | 
    
         
            +
                    assert np.count_nonzero(
         
     | 
| 
      
 2338 
     | 
    
         
            +
                        self.grid_indices >= 0) == self.cell_count, 'mismatch in number of blocked well intervals'
         
     | 
| 
      
 2339 
     | 
    
         
            +
                    self.grid_list = []
         
     | 
| 
      
 2340 
     | 
    
         
            +
                    for grid_ref_node in grid_node_list:
         
     | 
| 
      
 2341 
     | 
    
         
            +
                        grid_node = self.model.referenced_node(grid_ref_node)
         
     | 
| 
      
 2342 
     | 
    
         
            +
                        assert grid_node is not None, 'grid referenced in blocked well xml is not present in model'
         
     | 
| 
      
 2343 
     | 
    
         
            +
                        grid_uuid = rqet.uuid_for_part_root(grid_node)
         
     | 
| 
      
 2344 
     | 
    
         
            +
                        grid_obj = self.model.grid(uuid = grid_uuid, find_properties = False)
         
     | 
| 
      
 2345 
     | 
    
         
            +
                        self.grid_list.append(grid_obj)
         
     | 
| 
      
 2346 
     | 
    
         
            +
                        if grid_obj.is_big():
         
     | 
| 
      
 2347 
     | 
    
         
            +
                            self.cell_index_dtype = np.int64
         
     | 
| 
       2923 
2348 
     | 
    
         | 
| 
       2924 
     | 
    
         
            -
             
     | 
| 
       2925 
     | 
    
         
            -
             
     | 
| 
       2926 
     | 
    
         
            -
             
     | 
| 
       2927 
     | 
    
         
            -
             
     | 
| 
       2928 
     | 
    
         
            -
             
     | 
| 
       2929 
     | 
    
         
            -
                         
     | 
| 
       2930 
     | 
    
         
            -
                         
     | 
| 
       2931 
     | 
    
         
            -
                        ' 
     | 
| 
       2932 
     | 
    
         
            -
                        ' 
     | 
| 
       2933 
     | 
    
         
            -
                         
     | 
| 
       2934 
     | 
    
         
            -
                        ' 
     | 
| 
       2935 
     | 
    
         
            -
                         
     | 
| 
       2936 
     | 
    
         
            -
             
     | 
| 
       2937 
     | 
    
         
            -
                         
     | 
| 
       2938 
     | 
    
         
            -
             
     | 
| 
       2939 
     | 
    
         
            -
             
     | 
| 
       2940 
     | 
    
         
            -
                     
     | 
| 
      
 2349 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2350 
     | 
    
         
            +
                def __verify_header_lines_in_cellio_file(fp, well_name, cellio_file):
         
     | 
| 
      
 2351 
     | 
    
         
            +
                    """Find and verify the information in the header lines for the specified well in the RMS cellio file."""
         
     | 
| 
      
 2352 
     | 
    
         
            +
             
     | 
| 
      
 2353 
     | 
    
         
            +
                    while True:
         
     | 
| 
      
 2354 
     | 
    
         
            +
                        kf.skip_blank_lines_and_comments(fp)
         
     | 
| 
      
 2355 
     | 
    
         
            +
                        line = fp.readline()  # file format version number?
         
     | 
| 
      
 2356 
     | 
    
         
            +
                        assert line, 'well ' + str(well_name) + ' not found in file ' + str(cellio_file)
         
     | 
| 
      
 2357 
     | 
    
         
            +
                        fp.readline()  # 'Undefined'
         
     | 
| 
      
 2358 
     | 
    
         
            +
                        words = fp.readline().split()
         
     | 
| 
      
 2359 
     | 
    
         
            +
                        assert len(words), 'missing header info in cell I/O file'
         
     | 
| 
      
 2360 
     | 
    
         
            +
                        if words[0].upper() == well_name.upper():
         
     | 
| 
      
 2361 
     | 
    
         
            +
                            break
         
     | 
| 
      
 2362 
     | 
    
         
            +
                        while not kf.blank_line(fp):
         
     | 
| 
      
 2363 
     | 
    
         
            +
                            fp.readline()  # skip to block of data for next well
         
     | 
| 
      
 2364 
     | 
    
         
            +
                    header_lines = int(fp.readline().strip())
         
     | 
| 
      
 2365 
     | 
    
         
            +
                    for _ in range(header_lines):
         
     | 
| 
      
 2366 
     | 
    
         
            +
                        fp.readline()
         
     | 
| 
      
 2367 
     | 
    
         
            +
             
     | 
| 
      
 2368 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2369 
     | 
    
         
            +
                def __parse_non_blank_line_in_cellio_file(line, grid, cellio_z_inc_down, grid_z_inc_down):
         
     | 
| 
      
 2370 
     | 
    
         
            +
                    """Parse each non-blank line in the RMS cellio file for the relevant parameters."""
         
     | 
| 
      
 2371 
     | 
    
         
            +
             
     | 
| 
      
 2372 
     | 
    
         
            +
                    words = line.split()
         
     | 
| 
      
 2373 
     | 
    
         
            +
                    assert len(words) >= 9, 'not enough items on data line in cell I/O file, minimum 9 expected'
         
     | 
| 
      
 2374 
     | 
    
         
            +
                    i1, j1, k1 = int(words[0]), int(words[1]), int(words[2])
         
     | 
| 
      
 2375 
     | 
    
         
            +
                    cell_kji0 = np.array((k1 - 1, j1 - 1, i1 - 1), dtype = np.int32)
         
     | 
| 
      
 2376 
     | 
    
         
            +
                    assert np.all(0 <= cell_kji0) and np.all(
         
     | 
| 
      
 2377 
     | 
    
         
            +
                        cell_kji0 < grid.extent_kji), 'cell I/O cell index not within grid extent'
         
     | 
| 
      
 2378 
     | 
    
         
            +
                    entry_xyz = np.array((float(words[3]), float(words[4]), float(words[5])))
         
     | 
| 
      
 2379 
     | 
    
         
            +
                    exit_xyz = np.array((float(words[6]), float(words[7]), float(words[8])))
         
     | 
| 
      
 2380 
     | 
    
         
            +
                    if cellio_z_inc_down is None:
         
     | 
| 
      
 2381 
     | 
    
         
            +
                        cellio_z_inc_down = bool(entry_xyz[2] + exit_xyz[2] > 0.0)
         
     | 
| 
      
 2382 
     | 
    
         
            +
                    if cellio_z_inc_down != grid_z_inc_down:
         
     | 
| 
      
 2383 
     | 
    
         
            +
                        entry_xyz[2] = -entry_xyz[2]
         
     | 
| 
      
 2384 
     | 
    
         
            +
                        exit_xyz[2] = -exit_xyz[2]
         
     | 
| 
      
 2385 
     | 
    
         
            +
                    return cell_kji0, entry_xyz, exit_xyz
         
     | 
| 
      
 2386 
     | 
    
         
            +
             
     | 
| 
      
 2387 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2388 
     | 
    
         
            +
                def __calculate_cell_cp_center_and_vectors(grid, cell_kji0, entry_xyz, exit_xyz, well_name):
         
     | 
| 
      
 2389 
     | 
    
         
            +
                    # calculate the i,j,k coordinates that represent the corner points and center of a perforation cell
         
     | 
| 
      
 2390 
     | 
    
         
            +
                    # calculate the entry and exit vectors for the perforation cell
         
     | 
| 
      
 2391 
     | 
    
         
            +
             
     | 
| 
      
 2392 
     | 
    
         
            +
                    cp = grid.corner_points(cell_kji0 = cell_kji0, cache_resqml_array = False)
         
     | 
| 
      
 2393 
     | 
    
         
            +
                    assert not np.any(np.isnan(
         
     | 
| 
      
 2394 
     | 
    
         
            +
                        cp)), 'missing geometry for perforation cell(kji0) ' + str(cell_kji0) + ' for well ' + str(well_name)
         
     | 
| 
      
 2395 
     | 
    
         
            +
                    cell_centre = np.mean(cp, axis = (0, 1, 2))
         
     | 
| 
      
 2396 
     | 
    
         
            +
                    # let's hope everything is in the same coordinate reference system!
         
     | 
| 
      
 2397 
     | 
    
         
            +
                    entry_vector = 100.0 * (entry_xyz - cell_centre)
         
     | 
| 
      
 2398 
     | 
    
         
            +
                    exit_vector = 100.0 * (exit_xyz - cell_centre)
         
     | 
| 
      
 2399 
     | 
    
         
            +
                    return cp, cell_centre, entry_vector, exit_vector
         
     | 
| 
      
 2400 
     | 
    
         
            +
             
     | 
| 
      
 2401 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2402 
     | 
    
         
            +
                def __check_number_of_blocked_well_intervals(blocked_cells_kji0, well_name, grid_name):
         
     | 
| 
      
 2403 
     | 
    
         
            +
                    """Check that at least one interval is blocked for the specified well."""
         
     | 
| 
      
 2404 
     | 
    
         
            +
             
     | 
| 
      
 2405 
     | 
    
         
            +
                    blocked_count = len(blocked_cells_kji0)
         
     | 
| 
      
 2406 
     | 
    
         
            +
                    if blocked_count == 0:
         
     | 
| 
      
 2407 
     | 
    
         
            +
                        log.warning(f"No intervals blocked for well {well_name} in grid"
         
     | 
| 
      
 2408 
     | 
    
         
            +
                                    f"{f' {grid_name}' if grid_name is not None else ''}.")
         
     | 
| 
      
 2409 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 2410 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2411 
     | 
    
         
            +
                        log.info(f"{blocked_count} interval{rqwu._pl(blocked_count)} blocked for well {well_name} in"
         
     | 
| 
      
 2412 
     | 
    
         
            +
                                 f" grid{f' {grid_name}' if grid_name is not None else ''}.")
         
     | 
| 
      
 2413 
     | 
    
         
            +
             
     | 
| 
      
 2414 
     | 
    
         
            +
                def __get_interval_count(self):
         
     | 
| 
      
 2415 
     | 
    
         
            +
                    """Get the number of intervals to be added to the dataframe."""
         
     | 
| 
      
 2416 
     | 
    
         
            +
             
     | 
| 
      
 2417 
     | 
    
         
            +
                    if self.node_count is None or self.node_count < 2:
         
     | 
| 
      
 2418 
     | 
    
         
            +
                        interval_count = 0
         
     | 
| 
      
 2419 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2420 
     | 
    
         
            +
                        interval_count = self.node_count - 1
         
     | 
| 
      
 2421 
     | 
    
         
            +
             
     | 
| 
      
 2422 
     | 
    
         
            +
                    return interval_count
         
     | 
| 
      
 2423 
     | 
    
         
            +
             
     | 
| 
      
 2424 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2425 
     | 
    
         
            +
                def __prop_array(uuid_or_dict, grid):
         
     | 
| 
      
 2426 
     | 
    
         
            +
                    assert uuid_or_dict is not None and grid is not None
         
     | 
| 
      
 2427 
     | 
    
         
            +
                    if isinstance(uuid_or_dict, dict):
         
     | 
| 
      
 2428 
     | 
    
         
            +
                        prop_uuid = uuid_or_dict[grid.uuid]
         
     | 
| 
      
 2429 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2430 
     | 
    
         
            +
                        prop_uuid = uuid_or_dict  # uuid either in form of string or uuid.UUID
         
     | 
| 
      
 2431 
     | 
    
         
            +
                    return grid.property_collection.single_array_ref(uuid = prop_uuid)
         
     | 
| 
      
 2432 
     | 
    
         
            +
             
     | 
| 
      
 2433 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2434 
     | 
    
         
            +
                def __get_ref_vector(grid, grid_crs, cell_kji0, mode):
         
     | 
| 
      
 2435 
     | 
    
         
            +
                    # returns unit vector with true direction, ie. accounts for differing xy & z units in grid's crs
         
     | 
| 
      
 2436 
     | 
    
         
            +
                    # gravity = np.array((0.0, 0.0, 1.0))
         
     | 
| 
      
 2437 
     | 
    
         
            +
                    if mode == 'normal well i+':
         
     | 
| 
      
 2438 
     | 
    
         
            +
                        return None  # ANGLA only: option for no projection onto a plane
         
     | 
| 
      
 2439 
     | 
    
         
            +
                    ref_vector = None
         
     | 
| 
      
 2440 
     | 
    
         
            +
                    # options for anglv or angla reference: 'z down', 'z+', 'k down', 'k+', 'normal ij', 'normal ij down'
         
     | 
| 
      
 2441 
     | 
    
         
            +
                    if mode == 'z+':
         
     | 
| 
      
 2442 
     | 
    
         
            +
                        ref_vector = np.array((0.0, 0.0, 1.0))
         
     | 
| 
      
 2443 
     | 
    
         
            +
                    elif mode == 'z down':
         
     | 
| 
      
 2444 
     | 
    
         
            +
                        if grid_crs.z_inc_down:
         
     | 
| 
      
 2445 
     | 
    
         
            +
                            ref_vector = np.array((0.0, 0.0, 1.0))
         
     | 
| 
      
 2446 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 2447 
     | 
    
         
            +
                            ref_vector = np.array((0.0, 0.0, -1.0))
         
     | 
| 
      
 2448 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2449 
     | 
    
         
            +
                        cell_axial_vectors = grid.interface_vectors_kji(cell_kji0)
         
     | 
| 
      
 2450 
     | 
    
         
            +
                        if grid_crs.xy_units != grid_crs.z_units:
         
     | 
| 
      
 2451 
     | 
    
         
            +
                            wam.convert_lengths(cell_axial_vectors[..., 2], grid_crs.z_units, grid_crs.xy_units)
         
     | 
| 
      
 2452 
     | 
    
         
            +
                        if mode in ['k+', 'k down']:
         
     | 
| 
      
 2453 
     | 
    
         
            +
                            ref_vector = vec.unit_vector(cell_axial_vectors[0])
         
     | 
| 
      
 2454 
     | 
    
         
            +
                            if mode == 'k down' and not grid.k_direction_is_down:
         
     | 
| 
      
 2455 
     | 
    
         
            +
                                ref_vector = -ref_vector
         
     | 
| 
      
 2456 
     | 
    
         
            +
                        else:  # normal to plane of ij axes
         
     | 
| 
      
 2457 
     | 
    
         
            +
                            ref_vector = vec.unit_vector(vec.cross_product(cell_axial_vectors[1], cell_axial_vectors[2]))
         
     | 
| 
      
 2458 
     | 
    
         
            +
                            if mode == 'normal ij down':
         
     | 
| 
      
 2459 
     | 
    
         
            +
                                if grid_crs.z_inc_down:
         
     | 
| 
      
 2460 
     | 
    
         
            +
                                    if ref_vector[2] < 0.0:
         
     | 
| 
      
 2461 
     | 
    
         
            +
                                        ref_vector = -ref_vector
         
     | 
| 
      
 2462 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 2463 
     | 
    
         
            +
                                    if ref_vector[2] > 0.0:
         
     | 
| 
      
 2464 
     | 
    
         
            +
                                        ref_vector = -ref_vector
         
     | 
| 
      
 2465 
     | 
    
         
            +
                        if ref_vector is None or ref_vector[2] == 0.0:
         
     | 
| 
      
 2466 
     | 
    
         
            +
                            if grid_crs.z_inc_down:
         
     | 
| 
      
 2467 
     | 
    
         
            +
                                ref_vector = np.array((0.0, 0.0, 1.0))
         
     | 
| 
      
 2468 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 2469 
     | 
    
         
            +
                                ref_vector = np.array((0.0, 0.0, -1.0))
         
     | 
| 
      
 2470 
     | 
    
         
            +
                    return ref_vector
         
     | 
| 
      
 2471 
     | 
    
         
            +
             
     | 
| 
      
 2472 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2473 
     | 
    
         
            +
                def __verify_angle_references(anglv_ref, angla_plane_ref):
         
     | 
| 
      
 2474 
     | 
    
         
            +
                    """Verify that the references for anglv and angla are one of the acceptable options."""
         
     | 
| 
      
 2475 
     | 
    
         
            +
             
     | 
| 
      
 2476 
     | 
    
         
            +
                    assert anglv_ref in ['gravity', 'z down', 'z+', 'k down', 'k+', 'normal ij', 'normal ij down']
         
     | 
| 
      
 2477 
     | 
    
         
            +
                    if anglv_ref == 'gravity':
         
     | 
| 
      
 2478 
     | 
    
         
            +
                        anglv_ref = 'z down'
         
     | 
| 
      
 2479 
     | 
    
         
            +
                    if angla_plane_ref is None:
         
     | 
| 
      
 2480 
     | 
    
         
            +
                        angla_plane_ref = anglv_ref
         
     | 
| 
      
 2481 
     | 
    
         
            +
                    assert angla_plane_ref in [
         
     | 
| 
      
 2482 
     | 
    
         
            +
                        'gravity', 'z down', 'z+', 'k down', 'k+', 'normal ij', 'normal ij down', 'normal well i+'
         
     | 
| 
      
 2483 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 2484 
     | 
    
         
            +
                    if angla_plane_ref == 'gravity':
         
     | 
| 
      
 2485 
     | 
    
         
            +
                        angla_plane_ref = 'z down'
         
     | 
| 
      
 2486 
     | 
    
         
            +
                    return anglv_ref, angla_plane_ref
         
     | 
| 
      
 2487 
     | 
    
         
            +
             
     | 
| 
      
 2488 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2489 
     | 
    
         
            +
                def __verify_saturation_ranges_and_property_uuids(max_satw, min_sato, max_satg, satw_uuid, sato_uuid, satg_uuid):
         
     | 
| 
      
 2490 
     | 
    
         
            +
                    # verify that the fluid saturation limits fall within 0.0 to 1.0 and that the uuid of the required
         
     | 
| 
      
 2491 
     | 
    
         
            +
                    # saturation property array has been specified.
         
     | 
| 
      
 2492 
     | 
    
         
            +
             
     | 
| 
      
 2493 
     | 
    
         
            +
                    if max_satw is not None and max_satw >= 1.0:
         
     | 
| 
      
 2494 
     | 
    
         
            +
                        max_satw = None
         
     | 
| 
      
 2495 
     | 
    
         
            +
                    if min_sato is not None and min_sato <= 0.0:
         
     | 
| 
      
 2496 
     | 
    
         
            +
                        min_sato = None
         
     | 
| 
      
 2497 
     | 
    
         
            +
                    if max_satg is not None and max_satg >= 1.0:
         
     | 
| 
      
 2498 
     | 
    
         
            +
                        max_satg = None
         
     | 
| 
      
 2499 
     | 
    
         
            +
             
     | 
| 
      
 2500 
     | 
    
         
            +
                    phase_list = ['water', 'oil', 'gas']
         
     | 
| 
      
 2501 
     | 
    
         
            +
                    phase_saturation_limits_list = [max_satw, min_sato, max_satg]
         
     | 
| 
      
 2502 
     | 
    
         
            +
                    uuids_list = [satw_uuid, sato_uuid, satg_uuid]
         
     | 
| 
      
 2503 
     | 
    
         
            +
             
     | 
| 
      
 2504 
     | 
    
         
            +
                    for phase, phase_limit, uuid in zip(phase_list, phase_saturation_limits_list, uuids_list):
         
     | 
| 
      
 2505 
     | 
    
         
            +
                        if phase_limit is not None:
         
     | 
| 
      
 2506 
     | 
    
         
            +
                            assert uuid is not None, f'{phase} saturation limit specified without saturation property array'
         
     | 
| 
      
 2507 
     | 
    
         
            +
             
     | 
| 
      
 2508 
     | 
    
         
            +
                    return max_satw, min_sato, max_satg
         
     | 
| 
      
 2509 
     | 
    
         
            +
             
     | 
| 
      
 2510 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2511 
     | 
    
         
            +
                def __verify_extra_properties_to_be_added_to_dataframe(extra_columns_list, column_list, add_as_properties,
         
     | 
| 
      
 2512 
     | 
    
         
            +
                                                                       use_properties, skin, stat, radw):
         
     | 
| 
      
 2513 
     | 
    
         
            +
                    """Determine which extra columns, if any, should be added as properties to the dataframe.
         
     | 
| 
      
 2514 
     | 
    
         
            +
             
     | 
| 
      
 2515 
     | 
    
         
            +
                    note:
         
     | 
| 
      
 2516 
     | 
    
         
            +
                        if skin, stat or radw are None, default values are specified
         
     | 
| 
      
 2517 
     | 
    
         
            +
                    """
         
     | 
| 
      
 2518 
     | 
    
         
            +
             
     | 
| 
      
 2519 
     | 
    
         
            +
                    if extra_columns_list:
         
     | 
| 
      
 2520 
     | 
    
         
            +
                        for extra in extra_columns_list:
         
     | 
| 
      
 2521 
     | 
    
         
            +
                            assert extra.upper() in [
         
     | 
| 
      
 2522 
     | 
    
         
            +
                                'GRID', 'ANGLA', 'ANGLV', 'LENGTH', 'KH', 'DEPTH', 'MD', 'X', 'Y', 'SKIN', 'RADW', 'PPERF', 'RADB',
         
     | 
| 
      
 2523 
     | 
    
         
            +
                                'WI', 'WBC', 'STAT'
         
     | 
| 
      
 2524 
     | 
    
         
            +
                            ]
         
     | 
| 
      
 2525 
     | 
    
         
            +
                            column_list.append(extra.upper())
         
     | 
| 
      
 2526 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2527 
     | 
    
         
            +
                        add_as_properties = use_properties = False
         
     | 
| 
      
 2528 
     | 
    
         
            +
                    assert not (add_as_properties and use_properties)
         
     | 
| 
      
 2529 
     | 
    
         
            +
             
     | 
| 
      
 2530 
     | 
    
         
            +
                    column_list, skin, stat, radw = BlockedWell.__check_skin_stat_radw_to_be_added_as_properties(
         
     | 
| 
      
 2531 
     | 
    
         
            +
                        skin = skin, stat = stat, radw = radw, column_list = column_list)
         
     | 
| 
      
 2532 
     | 
    
         
            +
             
     | 
| 
      
 2533 
     | 
    
         
            +
                    return column_list, add_as_properties, use_properties, skin, stat, radw
         
     | 
| 
      
 2534 
     | 
    
         
            +
             
     | 
| 
      
 2535 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2536 
     | 
    
         
            +
                def __check_perforation_properties_to_be_added(column_list, perforation_list):
         
     | 
| 
      
 2537 
     | 
    
         
            +
             
     | 
| 
      
 2538 
     | 
    
         
            +
                    if all(['LENGTH' in column_list, 'PPERF' in column_list, 'KH' not in column_list, perforation_list
         
     | 
| 
      
 2539 
     | 
    
         
            +
                            is not None]):
         
     | 
| 
      
 2540 
     | 
    
         
            +
                        log.warning(
         
     | 
| 
      
 2541 
     | 
    
         
            +
                            'both LENGTH and PPERF will include effects of partial perforation; only one should be used in WELLSPEC'
         
     | 
| 
      
 2542 
     | 
    
         
            +
                        )
         
     | 
| 
      
 2543 
     | 
    
         
            +
                    elif all([
         
     | 
| 
      
 2544 
     | 
    
         
            +
                            perforation_list is not None, 'LENGTH' not in column_list, 'PPERF' not in column_list, 'KH'
         
     | 
| 
      
 2545 
     | 
    
         
            +
                            not in column_list, 'WBC' not in column_list
         
     | 
| 
      
 2546 
     | 
    
         
            +
                    ]):
         
     | 
| 
      
 2547 
     | 
    
         
            +
                        log.warning('perforation list supplied but no use of LENGTH, KH, PPERF nor WBC')
         
     | 
| 
      
 2548 
     | 
    
         
            +
             
     | 
| 
      
 2549 
     | 
    
         
            +
                    if perforation_list is not None and len(perforation_list) == 0:
         
     | 
| 
      
 2550 
     | 
    
         
            +
                        log.warning('empty perforation list specified for blocked well dataframe: no rows will be included')
         
     | 
| 
      
 2551 
     | 
    
         
            +
             
     | 
| 
      
 2552 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2553 
     | 
    
         
            +
                def __check_skin_stat_radw_to_be_added_as_properties(skin, stat, radw, column_list):
         
     | 
| 
      
 2554 
     | 
    
         
            +
                    """Verify whether skin should be added as a property in the dataframe."""
         
     | 
| 
      
 2555 
     | 
    
         
            +
             
     | 
| 
      
 2556 
     | 
    
         
            +
                    if skin is not None and 'SKIN' not in column_list:
         
     | 
| 
      
 2557 
     | 
    
         
            +
                        column_list.append('SKIN')
         
     | 
| 
      
 2558 
     | 
    
         
            +
             
     | 
| 
      
 2559 
     | 
    
         
            +
                    if stat is not None:
         
     | 
| 
      
 2560 
     | 
    
         
            +
                        assert str(stat).upper() in ['ON', 'OFF']
         
     | 
| 
      
 2561 
     | 
    
         
            +
                        stat = str(stat).upper()
         
     | 
| 
      
 2562 
     | 
    
         
            +
                        if 'STAT' not in column_list:
         
     | 
| 
      
 2563 
     | 
    
         
            +
                            column_list.append('STAT')
         
     | 
| 
      
 2564 
     | 
    
         
            +
             
     | 
| 
      
 2565 
     | 
    
         
            +
             
     | 
| 
      
 2566 
     | 
    
         
            +
            #         else:
         
     | 
| 
      
 2567 
     | 
    
         
            +
            #             stat = 'ON'
         
     | 
| 
      
 2568 
     | 
    
         
            +
             
     | 
| 
      
 2569 
     | 
    
         
            +
                    if radw is not None and 'RADW' not in column_list:
         
     | 
| 
      
 2570 
     | 
    
         
            +
                        column_list.append('RADW')
         
     | 
| 
      
 2571 
     | 
    
         
            +
             
     | 
| 
      
 2572 
     | 
    
         
            +
                    return column_list, skin, stat, radw
         
     | 
| 
      
 2573 
     | 
    
         
            +
             
     | 
| 
      
 2574 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2575 
     | 
    
         
            +
                def __verify_perm_i_uuid_for_well_inflow(column_list, perm_i_uuid, pc_titles):
         
     | 
| 
      
 2576 
     | 
    
         
            +
                    # Verify that the I direction permeability has been specified if well inflow properties are to be added
         
     | 
| 
      
 2577 
     | 
    
         
            +
                    # to the dataframe.
         
     | 
| 
      
 2578 
     | 
    
         
            +
             
     | 
| 
      
 2579 
     | 
    
         
            +
                    do_well_inflow = (('WI' in column_list and 'WI' not in pc_titles) or
         
     | 
| 
      
 2580 
     | 
    
         
            +
                                      ('WBC' in column_list and 'WBC' not in pc_titles) or
         
     | 
| 
      
 2581 
     | 
    
         
            +
                                      ('RADB' in column_list and 'RADB' not in pc_titles))
         
     | 
| 
      
 2582 
     | 
    
         
            +
                    if do_well_inflow:
         
     | 
| 
      
 2583 
     | 
    
         
            +
                        assert perm_i_uuid is not None, 'WI, RADB or WBC requested without I direction permeabilty being specified'
         
     | 
| 
      
 2584 
     | 
    
         
            +
             
     | 
| 
      
 2585 
     | 
    
         
            +
                    return do_well_inflow
         
     | 
| 
      
 2586 
     | 
    
         
            +
             
     | 
| 
      
 2587 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2588 
     | 
    
         
            +
                def __verify_perm_i_uuid_for_kh(min_kh, column_list, perm_i_uuid, pc_titles):
         
     | 
| 
      
 2589 
     | 
    
         
            +
                    # verify that the I direction permeability has been specified if permeability thickness and
         
     | 
| 
      
 2590 
     | 
    
         
            +
                    # wellbore constant properties are to be added to the dataframe.
         
     | 
| 
      
 2591 
     | 
    
         
            +
             
     | 
| 
      
 2592 
     | 
    
         
            +
                    if min_kh is not None and min_kh <= 0.0:
         
     | 
| 
      
 2593 
     | 
    
         
            +
                        min_kh = None
         
     | 
| 
      
 2594 
     | 
    
         
            +
                    doing_kh = False
         
     | 
| 
      
 2595 
     | 
    
         
            +
                    if ('KH' in column_list or min_kh is not None) and 'KH' not in pc_titles:
         
     | 
| 
      
 2596 
     | 
    
         
            +
                        assert perm_i_uuid is not None, 'KH requested (or minimum specified) without I direction permeabilty being specified'
         
     | 
| 
      
 2597 
     | 
    
         
            +
                        doing_kh = True
         
     | 
| 
      
 2598 
     | 
    
         
            +
                    if 'WBC' in column_list and 'WBC' not in pc_titles:
         
     | 
| 
      
 2599 
     | 
    
         
            +
                        assert perm_i_uuid is not None, 'WBC requested without I direction permeabilty being specified'
         
     | 
| 
      
 2600 
     | 
    
         
            +
                        doing_kh = True
         
     | 
| 
      
 2601 
     | 
    
         
            +
             
     | 
| 
      
 2602 
     | 
    
         
            +
                    return min_kh, doing_kh
         
     | 
| 
      
 2603 
     | 
    
         
            +
             
     | 
| 
      
 2604 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2605 
     | 
    
         
            +
                def __verify_perm_j_k_uuids_for_kh_and_well_inflow(doing_kh, do_well_inflow, perm_i_uuid, perm_j_uuid, perm_k_uuid):
         
     | 
| 
      
 2606 
     | 
    
         
            +
                    # verify that the J and K direction permeabilities have been specified if well inflow properties or
         
     | 
| 
      
 2607 
     | 
    
         
            +
                    # permeability thickness properties are to be added to the dataframe.
         
     | 
| 
      
 2608 
     | 
    
         
            +
             
     | 
| 
      
 2609 
     | 
    
         
            +
                    isotropic_perm = None
         
     | 
| 
      
 2610 
     | 
    
         
            +
                    if doing_kh or do_well_inflow:
         
     | 
| 
      
 2611 
     | 
    
         
            +
                        if perm_j_uuid is None and perm_k_uuid is None:
         
     | 
| 
      
 2612 
     | 
    
         
            +
                            isotropic_perm = True
         
     | 
| 
      
 2613 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 2614 
     | 
    
         
            +
                            if perm_j_uuid is None:
         
     | 
| 
      
 2615 
     | 
    
         
            +
                                perm_j_uuid = perm_i_uuid
         
     | 
| 
      
 2616 
     | 
    
         
            +
                            if perm_k_uuid is None:
         
     | 
| 
      
 2617 
     | 
    
         
            +
                                perm_k_uuid = perm_i_uuid
         
     | 
| 
      
 2618 
     | 
    
         
            +
                            # following line assumes arguments are passed in same form; if not, some unnecessary maths might be done
         
     | 
| 
      
 2619 
     | 
    
         
            +
                            isotropic_perm = (bu.matching_uuids(perm_i_uuid, perm_j_uuid) and
         
     | 
| 
      
 2620 
     | 
    
         
            +
                                              bu.matching_uuids(perm_i_uuid, perm_k_uuid))
         
     | 
| 
      
 2621 
     | 
    
         
            +
             
     | 
| 
      
 2622 
     | 
    
         
            +
                    return perm_j_uuid, perm_k_uuid, isotropic_perm
         
     | 
| 
      
 2623 
     | 
    
         
            +
             
     | 
| 
      
 2624 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2625 
     | 
    
         
            +
                def __verify_k_layers_to_be_included(min_k0, max_k0, k0_list):
         
     | 
| 
      
 2626 
     | 
    
         
            +
                    # verify that the k layers to be included in the dataframe exist within the appropriate range
         
     | 
| 
      
 2627 
     | 
    
         
            +
             
     | 
| 
      
 2628 
     | 
    
         
            +
                    if min_k0 is None:
         
     | 
| 
      
 2629 
     | 
    
         
            +
                        min_k0 = 0
         
     | 
| 
      
 2630 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2631 
     | 
    
         
            +
                        assert min_k0 >= 0
         
     | 
| 
      
 2632 
     | 
    
         
            +
                    if max_k0 is not None:
         
     | 
| 
      
 2633 
     | 
    
         
            +
                        assert min_k0 <= max_k0
         
     | 
| 
      
 2634 
     | 
    
         
            +
                    if k0_list is not None and len(k0_list) == 0:
         
     | 
| 
      
 2635 
     | 
    
         
            +
                        log.warning('no layers included for blocked well dataframe: no rows will be included')
         
     | 
| 
      
 2636 
     | 
    
         
            +
             
     | 
| 
      
 2637 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2638 
     | 
    
         
            +
                def __verify_if_angles_xyz_and_length_to_be_added(column_list, pc_titles, doing_kh, do_well_inflow, length_mode):
         
     | 
| 
      
 2639 
     | 
    
         
            +
                    # determine if angla, anglv, x, y, z and length data are to be added as properties to the dataframe
         
     | 
| 
      
 2640 
     | 
    
         
            +
             
     | 
| 
      
 2641 
     | 
    
         
            +
                    doing_angles = any([('ANGLA' in column_list and 'ANGLA' not in pc_titles),
         
     | 
| 
      
 2642 
     | 
    
         
            +
                                        ('ANGLV' in column_list and 'ANGLV' not in pc_titles), (doing_kh), (do_well_inflow)])
         
     | 
| 
      
 2643 
     | 
    
         
            +
                    doing_xyz = any([('X' in column_list and 'X' not in pc_titles), ('Y' in column_list and 'Y' not in pc_titles),
         
     | 
| 
      
 2644 
     | 
    
         
            +
                                     ('DEPTH' in column_list and 'DEPTH' not in pc_titles)])
         
     | 
| 
      
 2645 
     | 
    
         
            +
                    doing_entry_exit = any([(doing_angles),
         
     | 
| 
      
 2646 
     | 
    
         
            +
                                            ('LENGTH' in column_list and 'LENGTH' not in pc_titles and length_mode == 'straight')])
         
     | 
| 
      
 2647 
     | 
    
         
            +
             
     | 
| 
      
 2648 
     | 
    
         
            +
                    # doing_angles = (('ANGLA' in column_list and 'ANGLA' not in pc_titles) or
         
     | 
| 
      
 2649 
     | 
    
         
            +
                    #                 ('ANGLV' in column_list and 'ANGLV' not in pc_titles) or doing_kh or do_well_inflow)
         
     | 
| 
      
 2650 
     | 
    
         
            +
                    # doing_xyz = (('X' in column_list and 'X' not in pc_titles) or (
         
     | 
| 
      
 2651 
     | 
    
         
            +
                    #             'Y' in column_list and 'Y' not in pc_titles) or
         
     | 
| 
      
 2652 
     | 
    
         
            +
                    #              ('DEPTH' in column_list and 'DEPTH' not in pc_titles))
         
     | 
| 
      
 2653 
     | 
    
         
            +
                    # doing_entry_exit = doing_angles or ('LENGTH' in column_list and 'LENGTH' not in pc_titles and
         
     | 
| 
      
 2654 
     | 
    
         
            +
                    #                                     length_mode == 'straight')
         
     | 
| 
      
 2655 
     | 
    
         
            +
             
     | 
| 
      
 2656 
     | 
    
         
            +
                    return doing_angles, doing_xyz, doing_entry_exit
         
     | 
| 
      
 2657 
     | 
    
         
            +
             
     | 
| 
      
 2658 
     | 
    
         
            +
                def __verify_number_of_grids_and_crs_units(self, column_list):
         
     | 
| 
      
 2659 
     | 
    
         
            +
                    # verify that a GRID column is included in the dataframe if the well intersects more than one grid
         
     | 
| 
      
 2660 
     | 
    
         
            +
                    # verify that each grid's crs units are consistent in all directions
         
     | 
| 
      
 2661 
     | 
    
         
            +
             
     | 
| 
      
 2662 
     | 
    
         
            +
                    if 'GRID' not in column_list and self.number_of_grids() > 1:
         
     | 
| 
      
 2663 
     | 
    
         
            +
                        log.error('creating blocked well dataframe without GRID column for well that intersects more than one grid')
         
     | 
| 
      
 2664 
     | 
    
         
            +
                    grid_crs_list = []
         
     | 
| 
      
 2665 
     | 
    
         
            +
                    for grid in self.grid_list:
         
     | 
| 
      
 2666 
     | 
    
         
            +
                        grid_crs = crs.Crs(self.model, uuid = grid.crs_uuid)
         
     | 
| 
      
 2667 
     | 
    
         
            +
                        grid_crs_list.append(grid_crs)
         
     | 
| 
      
 2668 
     | 
    
         
            +
                    return grid_crs_list
         
     | 
| 
      
 2669 
     | 
    
         
            +
             
     | 
| 
      
 2670 
     | 
    
         
            +
                def __get_trajectory_crs_and_z_inc_down(self):
         
     | 
| 
      
 2671 
     | 
    
         
            +
             
     | 
| 
      
 2672 
     | 
    
         
            +
                    if self.trajectory is None or self.trajectory.crs_uuid is None:
         
     | 
| 
      
 2673 
     | 
    
         
            +
                        traj_crs = None
         
     | 
| 
      
 2674 
     | 
    
         
            +
                        traj_z_inc_down = None
         
     | 
| 
      
 2675 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2676 
     | 
    
         
            +
                        traj_crs = crs.Crs(self.trajectory.model, uuid = self.trajectory.crs_uuid)
         
     | 
| 
      
 2677 
     | 
    
         
            +
                        traj_z_inc_down = traj_crs.z_inc_down
         
     | 
| 
      
 2678 
     | 
    
         
            +
             
     | 
| 
      
 2679 
     | 
    
         
            +
                    return traj_crs, traj_z_inc_down
         
     | 
| 
      
 2680 
     | 
    
         
            +
             
     | 
| 
      
 2681 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2682 
     | 
    
         
            +
                def __check_cell_depth(max_depth, grid, cell_kji0, grid_crs):
         
     | 
| 
      
 2683 
     | 
    
         
            +
                    """Check whether the maximum depth specified has been exceeded with the current interval."""
         
     | 
| 
      
 2684 
     | 
    
         
            +
             
     | 
| 
      
 2685 
     | 
    
         
            +
                    max_depth_exceeded = False
         
     | 
| 
      
 2686 
     | 
    
         
            +
                    if max_depth is not None:
         
     | 
| 
      
 2687 
     | 
    
         
            +
                        cell_depth = grid.centre_point(cell_kji0)[2]
         
     | 
| 
      
 2688 
     | 
    
         
            +
                        if not grid_crs.z_inc_down:
         
     | 
| 
      
 2689 
     | 
    
         
            +
                            cell_depth = -cell_depth
         
     | 
| 
      
 2690 
     | 
    
         
            +
                        if cell_depth > max_depth:
         
     | 
| 
      
 2691 
     | 
    
         
            +
                            max_depth_exceeded = True
         
     | 
| 
      
 2692 
     | 
    
         
            +
                    return max_depth_exceeded
         
     | 
| 
      
 2693 
     | 
    
         
            +
             
     | 
| 
      
 2694 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2695 
     | 
    
         
            +
                def __skip_interval_check(max_depth, grid, cell_kji0, grid_crs, active_only, tuple_kji0, min_k0, max_k0, k0_list,
         
     | 
| 
      
 2696 
     | 
    
         
            +
                                          region_list, region_uuid, max_satw, satw_uuid, min_sato, sato_uuid, max_satg, satg_uuid):
         
     | 
| 
      
 2697 
     | 
    
         
            +
                    """Check whether any conditions are met that mean the interval should be skipped."""
         
     | 
| 
      
 2698 
     | 
    
         
            +
             
     | 
| 
      
 2699 
     | 
    
         
            +
                    max_depth_exceeded = BlockedWell.__check_cell_depth(max_depth = max_depth,
         
     | 
| 
      
 2700 
     | 
    
         
            +
                                                                        grid = grid,
         
     | 
| 
      
 2701 
     | 
    
         
            +
                                                                        cell_kji0 = cell_kji0,
         
     | 
| 
      
 2702 
     | 
    
         
            +
                                                                        grid_crs = grid_crs)
         
     | 
| 
      
 2703 
     | 
    
         
            +
                    inactive_grid = active_only and grid.inactive is not None and grid.inactive[tuple_kji0]
         
     | 
| 
      
 2704 
     | 
    
         
            +
                    out_of_bounds_layer_1 = (min_k0 is not None and cell_kji0[0] < min_k0) or (max_k0 is not None and
         
     | 
| 
      
 2705 
     | 
    
         
            +
                                                                                               cell_kji0[0] > max_k0)
         
     | 
| 
      
 2706 
     | 
    
         
            +
                    out_of_bounds_layer_2 = k0_list is not None and cell_kji0[0] not in k0_list
         
     | 
| 
      
 2707 
     | 
    
         
            +
                    out_of_bounds_region = (region_list is not None and
         
     | 
| 
      
 2708 
     | 
    
         
            +
                                            BlockedWell.__prop_array(region_uuid, grid)[tuple_kji0] not in region_list)
         
     | 
| 
      
 2709 
     | 
    
         
            +
                    saturation_limit_exceeded_1 = (max_satw is not None and
         
     | 
| 
      
 2710 
     | 
    
         
            +
                                                   BlockedWell.__prop_array(satw_uuid, grid)[tuple_kji0] > max_satw)
         
     | 
| 
      
 2711 
     | 
    
         
            +
                    saturation_limit_exceeded_2 = (min_sato is not None and
         
     | 
| 
      
 2712 
     | 
    
         
            +
                                                   BlockedWell.__prop_array(sato_uuid, grid)[tuple_kji0] < min_sato)
         
     | 
| 
      
 2713 
     | 
    
         
            +
                    saturation_limit_exceeded_3 = (max_satg is not None and
         
     | 
| 
      
 2714 
     | 
    
         
            +
                                                   BlockedWell.__prop_array(satg_uuid, grid)[tuple_kji0] > max_satg)
         
     | 
| 
      
 2715 
     | 
    
         
            +
                    skip_interval = any([
         
     | 
| 
      
 2716 
     | 
    
         
            +
                        max_depth_exceeded, inactive_grid, out_of_bounds_layer_1, out_of_bounds_layer_2, out_of_bounds_region,
         
     | 
| 
      
 2717 
     | 
    
         
            +
                        saturation_limit_exceeded_1, saturation_limit_exceeded_2, saturation_limit_exceeded_3
         
     | 
| 
      
 2718 
     | 
    
         
            +
                    ])
         
     | 
| 
      
 2719 
     | 
    
         
            +
             
     | 
| 
      
 2720 
     | 
    
         
            +
                    return skip_interval
         
     | 
| 
      
 2721 
     | 
    
         
            +
             
     | 
| 
      
 2722 
     | 
    
         
            +
                def __get_part_perf_fraction_for_interval(self, pc, pc_titles, ci, perforation_list, interval, length_tol = 0.01):
         
     | 
| 
      
 2723 
     | 
    
         
            +
                    """Get the partial perforation fraction for the interval."""
         
     | 
| 
      
 2724 
     | 
    
         
            +
             
     | 
| 
      
 2725 
     | 
    
         
            +
                    skip_interval = False
         
     | 
| 
      
 2726 
     | 
    
         
            +
                    if 'PPERF' in pc_titles:
         
     | 
| 
      
 2727 
     | 
    
         
            +
                        part_perf_fraction = pc.single_array_ref(citation_title = 'PPERF')[ci]
         
     | 
| 
      
 2728 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2729 
     | 
    
         
            +
                        part_perf_fraction = 1.0
         
     | 
| 
      
 2730 
     | 
    
         
            +
                        if perforation_list is not None:
         
     | 
| 
      
 2731 
     | 
    
         
            +
                            perf_length = 0.0
         
     | 
| 
      
 2732 
     | 
    
         
            +
                            for perf_start, perf_end in perforation_list:
         
     | 
| 
      
 2733 
     | 
    
         
            +
                                if perf_end <= self.node_mds[interval] or perf_start >= self.node_mds[interval + 1]:
         
     | 
| 
      
 2734 
     | 
    
         
            +
                                    continue
         
     | 
| 
      
 2735 
     | 
    
         
            +
                                if perf_start <= self.node_mds[interval]:
         
     | 
| 
      
 2736 
     | 
    
         
            +
                                    if perf_end >= self.node_mds[interval + 1]:
         
     | 
| 
      
 2737 
     | 
    
         
            +
                                        perf_length += self.node_mds[interval + 1] - self.node_mds[interval]
         
     | 
| 
      
 2738 
     | 
    
         
            +
                                        break
         
     | 
| 
      
 2739 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 2740 
     | 
    
         
            +
                                        perf_length += perf_end - self.node_mds[interval]
         
     | 
| 
      
 2741 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 2742 
     | 
    
         
            +
                                    if perf_end >= self.node_mds[interval + 1]:
         
     | 
| 
      
 2743 
     | 
    
         
            +
                                        perf_length += self.node_mds[interval + 1] - perf_start
         
     | 
| 
      
 2744 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 2745 
     | 
    
         
            +
                                        perf_length += perf_end - perf_start
         
     | 
| 
      
 2746 
     | 
    
         
            +
                            if perf_length < length_tol:
         
     | 
| 
      
 2747 
     | 
    
         
            +
                                skip_interval = True
         
     | 
| 
      
 2748 
     | 
    
         
            +
                                perf_length = 0.0
         
     | 
| 
      
 2749 
     | 
    
         
            +
                            part_perf_fraction = min(1.0, perf_length / (self.node_mds[interval + 1] - self.node_mds[interval]))
         
     | 
| 
      
 2750 
     | 
    
         
            +
             
     | 
| 
      
 2751 
     | 
    
         
            +
                    return skip_interval, part_perf_fraction
         
     | 
| 
      
 2752 
     | 
    
         
            +
             
     | 
| 
      
 2753 
     | 
    
         
            +
                def __get_entry_exit_xyz_and_crs_for_interval(self, doing_entry_exit, use_face_centres, grid, cell_kji0, interval,
         
     | 
| 
      
 2754 
     | 
    
         
            +
                                                              ci, grid_crs, traj_crs):
         
     | 
| 
      
 2755 
     | 
    
         
            +
                    # calculate the entry and exit points for the interval and set the entry and exit coordinate reference system
         
     | 
| 
      
 2756 
     | 
    
         
            +
             
     | 
| 
      
 2757 
     | 
    
         
            +
                    entry_xyz = None
         
     | 
| 
      
 2758 
     | 
    
         
            +
                    exit_xyz = None
         
     | 
| 
      
 2759 
     | 
    
         
            +
                    ee_crs = None
         
     | 
| 
      
 2760 
     | 
    
         
            +
                    if doing_entry_exit:
         
     | 
| 
      
 2761 
     | 
    
         
            +
                        assert self.trajectory is not None
         
     | 
| 
      
 2762 
     | 
    
         
            +
                        if use_face_centres:
         
     | 
| 
      
 2763 
     | 
    
         
            +
                            entry_xyz = grid.face_centre(cell_kji0, self.face_pair_indices[ci, 0, 0], self.face_pair_indices[ci, 0,
         
     | 
| 
      
 2764 
     | 
    
         
            +
                                                                                                                             1])
         
     | 
| 
      
 2765 
     | 
    
         
            +
                            if self.face_pair_indices[ci, 1, 0] >= 0:
         
     | 
| 
      
 2766 
     | 
    
         
            +
                                exit_xyz = grid.face_centre(cell_kji0, self.face_pair_indices[ci, 1, 0],
         
     | 
| 
      
 2767 
     | 
    
         
            +
                                                            self.face_pair_indices[ci, 1, 1])
         
     | 
| 
      
 2768 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 2769 
     | 
    
         
            +
                                exit_xyz = grid.face_centre(cell_kji0, self.face_pair_indices[ci, 0, 0],
         
     | 
| 
      
 2770 
     | 
    
         
            +
                                                            1 - self.face_pair_indices[ci, 0, 1])
         
     | 
| 
      
 2771 
     | 
    
         
            +
                            ee_crs = grid_crs
         
     | 
| 
      
 2772 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 2773 
     | 
    
         
            +
                            entry_xyz = self.trajectory.xyz_for_md(self.node_mds[interval])
         
     | 
| 
      
 2774 
     | 
    
         
            +
                            exit_xyz = self.trajectory.xyz_for_md(self.node_mds[interval + 1])
         
     | 
| 
      
 2775 
     | 
    
         
            +
                            ee_crs = traj_crs
         
     | 
| 
      
 2776 
     | 
    
         
            +
             
     | 
| 
      
 2777 
     | 
    
         
            +
                    return entry_xyz, exit_xyz, ee_crs
         
     | 
| 
      
 2778 
     | 
    
         
            +
             
     | 
| 
      
 2779 
     | 
    
         
            +
                def __get_length_of_interval(self, length_mode, interval, length_uom, entry_xyz, exit_xyz, ee_crs, perforation_list,
         
     | 
| 
      
 2780 
     | 
    
         
            +
                                             part_perf_fraction, min_length):
         
     | 
| 
      
 2781 
     | 
    
         
            +
                    """Calculate the length of the interval."""
         
     | 
| 
      
 2782 
     | 
    
         
            +
             
     | 
| 
      
 2783 
     | 
    
         
            +
                    skip_interval = False
         
     | 
| 
      
 2784 
     | 
    
         
            +
                    if length_mode == 'MD':
         
     | 
| 
      
 2785 
     | 
    
         
            +
                        length = self.node_mds[interval + 1] - self.node_mds[interval]
         
     | 
| 
      
 2786 
     | 
    
         
            +
                        if length_uom is not None and self.trajectory is not None and length_uom != self.trajectory.md_uom:
         
     | 
| 
      
 2787 
     | 
    
         
            +
                            length = wam.convert_lengths(length, self.trajectory.md_uom, length_uom)
         
     | 
| 
      
 2788 
     | 
    
         
            +
                    else:  # use straight line length between entry and exit
         
     | 
| 
      
 2789 
     | 
    
         
            +
                        entry_xyz, exit_xyz = BlockedWell._single_uom_entry_exit_xyz(entry_xyz, exit_xyz, ee_crs)
         
     | 
| 
      
 2790 
     | 
    
         
            +
                        length = vec.naive_length(exit_xyz - entry_xyz)
         
     | 
| 
      
 2791 
     | 
    
         
            +
                        if length_uom is not None:
         
     | 
| 
      
 2792 
     | 
    
         
            +
                            length = wam.convert_lengths(length, ee_crs.z_units, length_uom)
         
     | 
| 
      
 2793 
     | 
    
         
            +
                        elif self.trajectory is not None:
         
     | 
| 
      
 2794 
     | 
    
         
            +
                            length = wam.convert_lengths(length, ee_crs.z_units, self.trajectory.md_uom)
         
     | 
| 
      
 2795 
     | 
    
         
            +
                    if perforation_list is not None:
         
     | 
| 
      
 2796 
     | 
    
         
            +
                        length *= part_perf_fraction
         
     | 
| 
      
 2797 
     | 
    
         
            +
                    if min_length is not None and length < min_length:
         
     | 
| 
      
 2798 
     | 
    
         
            +
                        skip_interval = True
         
     | 
| 
      
 2799 
     | 
    
         
            +
             
     | 
| 
      
 2800 
     | 
    
         
            +
                    return skip_interval, length
         
     | 
| 
      
 2801 
     | 
    
         
            +
             
     | 
| 
      
 2802 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2803 
     | 
    
         
            +
                def _single_uom_xyz(xyz, crs, required_uom):
         
     | 
| 
      
 2804 
     | 
    
         
            +
                    if xyz is None:
         
     | 
| 
      
 2805 
     | 
    
         
            +
                        return None
         
     | 
| 
      
 2806 
     | 
    
         
            +
                    xyz = np.array(xyz, dtype = float)
         
     | 
| 
      
 2807 
     | 
    
         
            +
                    if crs.xy_units != required_uom:
         
     | 
| 
      
 2808 
     | 
    
         
            +
                        xyz[0] = wam.convert_lengths(xyz[0], crs.xy_units, required_uom)
         
     | 
| 
      
 2809 
     | 
    
         
            +
                        xyz[1] = wam.convert_lengths(xyz[1], crs.xy_units, required_uom)
         
     | 
| 
      
 2810 
     | 
    
         
            +
                    if crs.z_units != required_uom:
         
     | 
| 
      
 2811 
     | 
    
         
            +
                        xyz[2] = wam.convert_lengths(xyz[2], crs.z_units, required_uom)
         
     | 
| 
      
 2812 
     | 
    
         
            +
                    return xyz
         
     | 
| 
      
 2813 
     | 
    
         
            +
             
     | 
| 
      
 2814 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2815 
     | 
    
         
            +
                def _single_uom_entry_exit_xyz(entry_xyz, exit_xyz, ee_crs):
         
     | 
| 
      
 2816 
     | 
    
         
            +
                    return (BlockedWell._single_uom_xyz(entry_xyz, ee_crs, ee_crs.z_units),
         
     | 
| 
      
 2817 
     | 
    
         
            +
                            BlockedWell._single_uom_xyz(exit_xyz, ee_crs, ee_crs.z_units))
         
     | 
| 
      
 2818 
     | 
    
         
            +
             
     | 
| 
      
 2819 
     | 
    
         
            +
                def __get_angles_for_interval(self, pc, pc_titles, doing_angles, set_k_face_intervals_vertical, ci, k_face_check,
         
     | 
| 
      
 2820 
     | 
    
         
            +
                                              k_face_check_end, entry_xyz, exit_xyz, ee_crs, traj_z_inc_down, grid, grid_crs,
         
     | 
| 
      
 2821 
     | 
    
         
            +
                                              cell_kji0, anglv_ref, angla_plane_ref):
         
     | 
| 
      
 2822 
     | 
    
         
            +
                    """Calculate angla, anglv and related trigonometirc transforms for the interval."""
         
     | 
| 
      
 2823 
     | 
    
         
            +
             
     | 
| 
      
 2824 
     | 
    
         
            +
                    sine_anglv = sine_angla = 0.0
         
     | 
| 
      
 2825 
     | 
    
         
            +
                    cosine_anglv = cosine_angla = 1.0
         
     | 
| 
      
 2826 
     | 
    
         
            +
                    anglv = pc.single_array_ref(citation_title = 'ANGLV')[ci] if 'ANGLV' in pc_titles else None
         
     | 
| 
      
 2827 
     | 
    
         
            +
                    angla = pc.single_array_ref(citation_title = 'ANGLA')[ci] if 'ANGLA' in pc_titles else None
         
     | 
| 
      
 2828 
     | 
    
         
            +
             
     | 
| 
      
 2829 
     | 
    
         
            +
                    if doing_angles and not (set_k_face_intervals_vertical and
         
     | 
| 
      
 2830 
     | 
    
         
            +
                                             (np.all(self.face_pair_indices[ci] == k_face_check) or
         
     | 
| 
      
 2831 
     | 
    
         
            +
                                              np.all(self.face_pair_indices[ci] == k_face_check_end))):
         
     | 
| 
      
 2832 
     | 
    
         
            +
                        anglv, sine_anglv, cosine_anglv, vector, a_ref_vector = BlockedWell.__get_anglv_for_interval(
         
     | 
| 
      
 2833 
     | 
    
         
            +
                            anglv = anglv,
         
     | 
| 
      
 2834 
     | 
    
         
            +
                            entry_xyz = entry_xyz,
         
     | 
| 
      
 2835 
     | 
    
         
            +
                            exit_xyz = exit_xyz,
         
     | 
| 
      
 2836 
     | 
    
         
            +
                            ee_crs = ee_crs,
         
     | 
| 
      
 2837 
     | 
    
         
            +
                            traj_z_inc_down = traj_z_inc_down,
         
     | 
| 
      
 2838 
     | 
    
         
            +
                            grid = grid,
         
     | 
| 
      
 2839 
     | 
    
         
            +
                            grid_crs = grid_crs,
         
     | 
| 
      
 2840 
     | 
    
         
            +
                            cell_kji0 = cell_kji0,
         
     | 
| 
      
 2841 
     | 
    
         
            +
                            anglv_ref = anglv_ref,
         
     | 
| 
      
 2842 
     | 
    
         
            +
                            angla_plane_ref = angla_plane_ref)
         
     | 
| 
      
 2843 
     | 
    
         
            +
                        if anglv != 0.0:
         
     | 
| 
      
 2844 
     | 
    
         
            +
                            angla, sine_angla, cosine_angla = BlockedWell.__get_angla_for_interval(angla = angla,
         
     | 
| 
      
 2845 
     | 
    
         
            +
                                                                                                   grid = grid,
         
     | 
| 
      
 2846 
     | 
    
         
            +
                                                                                                   cell_kji0 = cell_kji0,
         
     | 
| 
      
 2847 
     | 
    
         
            +
                                                                                                   vector = vector,
         
     | 
| 
      
 2848 
     | 
    
         
            +
                                                                                                   a_ref_vector = a_ref_vector)
         
     | 
| 
      
 2849 
     | 
    
         
            +
                    if angla is None:
         
     | 
| 
      
 2850 
     | 
    
         
            +
                        angla = 0.0
         
     | 
| 
      
 2851 
     | 
    
         
            +
                    if anglv is None:
         
     | 
| 
      
 2852 
     | 
    
         
            +
                        anglv = 0.0
         
     | 
| 
      
 2853 
     | 
    
         
            +
             
     | 
| 
      
 2854 
     | 
    
         
            +
                    return anglv, sine_anglv, cosine_anglv, angla, sine_angla, cosine_angla
         
     | 
| 
      
 2855 
     | 
    
         
            +
             
     | 
| 
      
 2856 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2857 
     | 
    
         
            +
                def __get_angla_for_interval(angla, grid, cell_kji0, vector, a_ref_vector):
         
     | 
| 
      
 2858 
     | 
    
         
            +
                    """Calculate angla and related trigonometric transforms for the interval."""
         
     | 
| 
      
 2859 
     | 
    
         
            +
             
     | 
| 
      
 2860 
     | 
    
         
            +
                    if vector is None:
         
     | 
| 
      
 2861 
     | 
    
         
            +
                        return None, None, None
         
     | 
| 
      
 2862 
     | 
    
         
            +
             
     | 
| 
      
 2863 
     | 
    
         
            +
                    # project well vector and i-axis vector onto plane defined by normal vector a_ref_vector
         
     | 
| 
      
 2864 
     | 
    
         
            +
                    i_axis = grid.interface_vector(cell_kji0, 2)
         
     | 
| 
      
 2865 
     | 
    
         
            +
                    if grid.crs.xy_units != grid.crs.z_units:
         
     | 
| 
      
 2866 
     | 
    
         
            +
                        i_axis[2] = wam.convert_lengths(i_axis[2], grid.crs.z_units, grid.crs.xy_units)
         
     | 
| 
      
 2867 
     | 
    
         
            +
                    i_axis = vec.unit_vector(i_axis)
         
     | 
| 
      
 2868 
     | 
    
         
            +
                    if a_ref_vector is not None:  # project vector and i axis onto a plane
         
     | 
| 
      
 2869 
     | 
    
         
            +
                        vector -= vec.dot_product(vector, a_ref_vector) * a_ref_vector
         
     | 
| 
      
 2870 
     | 
    
         
            +
                        vector = vec.unit_vector(vector)
         
     | 
| 
      
 2871 
     | 
    
         
            +
                        # log.debug('i axis unit vector: ' + str(i_axis))
         
     | 
| 
      
 2872 
     | 
    
         
            +
                        i_axis -= vec.dot_product(i_axis, a_ref_vector) * a_ref_vector
         
     | 
| 
      
 2873 
     | 
    
         
            +
                        i_axis = vec.unit_vector(i_axis)
         
     | 
| 
      
 2874 
     | 
    
         
            +
                    # log.debug('i axis unit vector in reference plane: ' + str(i_axis))
         
     | 
| 
      
 2875 
     | 
    
         
            +
                    if angla is not None:
         
     | 
| 
      
 2876 
     | 
    
         
            +
                        angla_rad = vec.radians_from_degrees(angla)
         
     | 
| 
      
 2877 
     | 
    
         
            +
                        cosine_angla = maths.cos(angla_rad)
         
     | 
| 
      
 2878 
     | 
    
         
            +
                        sine_angla = maths.sin(angla_rad)
         
     | 
| 
      
 2879 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2880 
     | 
    
         
            +
                        cosine_angla = min(max(vec.dot_product(vector, i_axis), -1.0), 1.0)
         
     | 
| 
      
 2881 
     | 
    
         
            +
                        angla_rad = maths.acos(cosine_angla)
         
     | 
| 
      
 2882 
     | 
    
         
            +
                        # negate angla if vector is 'clockwise from' i_axis when viewed from above, projected in the xy plane
         
     | 
| 
      
 2883 
     | 
    
         
            +
                        # todo: have discussion around angla sign under different ijk handedness (and z inc direction?)
         
     | 
| 
      
 2884 
     | 
    
         
            +
                        sine_angla = maths.sin(angla_rad)
         
     | 
| 
      
 2885 
     | 
    
         
            +
                        angla = vec.degrees_from_radians(angla_rad)
         
     | 
| 
      
 2886 
     | 
    
         
            +
                        if vec.clockwise((0.0, 0.0), i_axis, vector) > 0.0:
         
     | 
| 
      
 2887 
     | 
    
         
            +
                            angla = -angla
         
     | 
| 
      
 2888 
     | 
    
         
            +
                            angla_rad = -angla_rad  ## as angle_rad before --> typo?
         
     | 
| 
      
 2889 
     | 
    
         
            +
                            sine_angla = -sine_angla
         
     | 
| 
      
 2890 
     | 
    
         
            +
             
     | 
| 
      
 2891 
     | 
    
         
            +
                    # log.debug('angla: ' + str(angla))
         
     | 
| 
      
 2892 
     | 
    
         
            +
             
     | 
| 
      
 2893 
     | 
    
         
            +
                    return angla, sine_angla, cosine_angla
         
     | 
| 
      
 2894 
     | 
    
         
            +
             
     | 
| 
      
 2895 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2896 
     | 
    
         
            +
                def __get_anglv_for_interval(anglv, entry_xyz, exit_xyz, ee_crs, traj_z_inc_down, grid, grid_crs, cell_kji0,
         
     | 
| 
      
 2897 
     | 
    
         
            +
                                             anglv_ref, angla_plane_ref):
         
     | 
| 
      
 2898 
     | 
    
         
            +
                    """Get anglv and related trigonometric transforms for the interval."""
         
     | 
| 
      
 2899 
     | 
    
         
            +
             
     | 
| 
      
 2900 
     | 
    
         
            +
                    if entry_xyz is None or exit_xyz is None:
         
     | 
| 
      
 2901 
     | 
    
         
            +
                        return None, None, None, None, None
         
     | 
| 
      
 2902 
     | 
    
         
            +
             
     | 
| 
      
 2903 
     | 
    
         
            +
                    entry_xyz, exit_xyz = BlockedWell._single_uom_entry_exit_xyz(entry_xyz, exit_xyz, ee_crs)
         
     | 
| 
      
 2904 
     | 
    
         
            +
                    vector = vec.unit_vector(np.array(exit_xyz) - np.array(entry_xyz))  # nominal wellbore vector for interval
         
     | 
| 
      
 2905 
     | 
    
         
            +
                    if traj_z_inc_down is not None and traj_z_inc_down != grid_crs.z_inc_down:
         
     | 
| 
      
 2906 
     | 
    
         
            +
                        vector[2] = -vector[2]
         
     | 
| 
      
 2907 
     | 
    
         
            +
                    if grid.crs.xy_units == grid.crs.z_units:
         
     | 
| 
      
 2908 
     | 
    
         
            +
                        unit_adjusted_vector = vector
         
     | 
| 
      
 2909 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2910 
     | 
    
         
            +
                        unit_adjusted_vector = vector.copy()
         
     | 
| 
      
 2911 
     | 
    
         
            +
                        unit_adjusted_vector[2] = wam.convert_lengths(unit_adjusted_vector[2], grid.crs.z_units, grid.crs.xy_units)
         
     | 
| 
      
 2912 
     | 
    
         
            +
                    v_ref_vector = BlockedWell.__get_ref_vector(grid, grid_crs, cell_kji0, anglv_ref)
         
     | 
| 
      
 2913 
     | 
    
         
            +
                    # log.debug('v ref vector: ' + str(v_ref_vector))
         
     | 
| 
      
 2914 
     | 
    
         
            +
                    if angla_plane_ref == anglv_ref:
         
     | 
| 
      
 2915 
     | 
    
         
            +
                        a_ref_vector = v_ref_vector
         
     | 
| 
      
 2916 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2917 
     | 
    
         
            +
                        a_ref_vector = BlockedWell.__get_ref_vector(grid, grid_crs, cell_kji0, angla_plane_ref)
         
     | 
| 
      
 2918 
     | 
    
         
            +
                    # log.debug('a ref vector: ' + str(a_ref_vector))
         
     | 
| 
      
 2919 
     | 
    
         
            +
                    if anglv is not None:
         
     | 
| 
      
 2920 
     | 
    
         
            +
                        anglv_rad = vec.radians_from_degrees(anglv)
         
     | 
| 
      
 2921 
     | 
    
         
            +
                        cosine_anglv = maths.cos(anglv_rad)
         
     | 
| 
      
 2922 
     | 
    
         
            +
                        sine_anglv = maths.sin(anglv_rad)
         
     | 
| 
      
 2923 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2924 
     | 
    
         
            +
                        cosine_anglv = min(max(vec.dot_product(unit_adjusted_vector, v_ref_vector), -1.0), 1.0)
         
     | 
| 
      
 2925 
     | 
    
         
            +
                        anglv_rad = maths.acos(cosine_anglv)
         
     | 
| 
      
 2926 
     | 
    
         
            +
                        sine_anglv = maths.sin(anglv_rad)
         
     | 
| 
      
 2927 
     | 
    
         
            +
                        anglv = vec.degrees_from_radians(anglv_rad)
         
     | 
| 
      
 2928 
     | 
    
         
            +
                    # log.debug('anglv: ' + str(anglv))
         
     | 
| 
      
 2929 
     | 
    
         
            +
             
     | 
| 
      
 2930 
     | 
    
         
            +
                    return anglv, sine_anglv, cosine_anglv, vector, a_ref_vector
         
     | 
| 
      
 2931 
     | 
    
         
            +
             
     | 
| 
      
 2932 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2933 
     | 
    
         
            +
                def __get_ntg_and_directional_perm_for_interval(doing_kh, do_well_inflow, ntg_uuid, grid, tuple_kji0,
         
     | 
| 
      
 2934 
     | 
    
         
            +
                                                                isotropic_perm, preferential_perforation, part_perf_fraction,
         
     | 
| 
      
 2935 
     | 
    
         
            +
                                                                perm_i_uuid, perm_j_uuid, perm_k_uuid):
         
     | 
| 
      
 2936 
     | 
    
         
            +
                    """Get the net-to-gross and directional permeability arrays for the interval."""
         
     | 
| 
      
 2937 
     | 
    
         
            +
             
     | 
| 
      
 2938 
     | 
    
         
            +
                    ntg_is_one = False
         
     | 
| 
      
 2939 
     | 
    
         
            +
                    k_i = k_j = k_k = None
         
     | 
| 
      
 2940 
     | 
    
         
            +
                    if doing_kh or do_well_inflow:
         
     | 
| 
      
 2941 
     | 
    
         
            +
                        if ntg_uuid is None:
         
     | 
| 
      
 2942 
     | 
    
         
            +
                            ntg = 1.0
         
     | 
| 
      
 2943 
     | 
    
         
            +
                            ntg_is_one = True
         
     | 
| 
      
 2944 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 2945 
     | 
    
         
            +
                            ntg = BlockedWell.__prop_array(ntg_uuid, grid)[tuple_kji0]
         
     | 
| 
      
 2946 
     | 
    
         
            +
                            ntg_is_one = maths.isclose(ntg, 1.0, rel_tol = 0.001)
         
     | 
| 
      
 2947 
     | 
    
         
            +
                        if isotropic_perm and ntg_is_one:
         
     | 
| 
      
 2948 
     | 
    
         
            +
                            k_i = k_j = k_k = BlockedWell.__prop_array(perm_i_uuid, grid)[tuple_kji0]
         
     | 
| 
      
 2949 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 2950 
     | 
    
         
            +
                            if preferential_perforation and not ntg_is_one:
         
     | 
| 
      
 2951 
     | 
    
         
            +
                                if part_perf_fraction <= ntg:
         
     | 
| 
      
 2952 
     | 
    
         
            +
                                    ntg = 1.0  # effective ntg when perforated intervals are in pay
         
     | 
| 
      
 2953 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 2954 
     | 
    
         
            +
                                    ntg /= part_perf_fraction  # adjusted ntg when some perforations in non-pay
         
     | 
| 
      
 2955 
     | 
    
         
            +
                            # todo: check netgross facet type in property perm i & j parts: if set to gross then don't multiply by ntg below
         
     | 
| 
      
 2956 
     | 
    
         
            +
                            k_i = BlockedWell.__prop_array(perm_i_uuid, grid)[tuple_kji0] * ntg
         
     | 
| 
      
 2957 
     | 
    
         
            +
                            k_j = BlockedWell.__prop_array(perm_j_uuid, grid)[tuple_kji0] * ntg
         
     | 
| 
      
 2958 
     | 
    
         
            +
                            k_k = BlockedWell.__prop_array(perm_k_uuid, grid)[tuple_kji0]
         
     | 
| 
      
 2959 
     | 
    
         
            +
             
     | 
| 
      
 2960 
     | 
    
         
            +
                    return ntg_is_one, k_i, k_j, k_k
         
     | 
| 
      
 2961 
     | 
    
         
            +
             
     | 
| 
      
 2962 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2963 
     | 
    
         
            +
                def __get_kh_for_interval(doing_kh, isotropic_perm, ntg_is_one, length, perm_i_uuid, grid, tuple_kji0, k_i, k_j,
         
     | 
| 
      
 2964 
     | 
    
         
            +
                                          k_k, anglv, sine_anglv, cosine_anglv, sine_angla, cosine_angla, min_kh, pc, pc_titles,
         
     | 
| 
      
 2965 
     | 
    
         
            +
                                          ci):
         
     | 
| 
      
 2966 
     | 
    
         
            +
                    """Get the permeability-thickness value for the interval."""
         
     | 
| 
      
 2967 
     | 
    
         
            +
             
     | 
| 
      
 2968 
     | 
    
         
            +
                    skip_interval = False
         
     | 
| 
      
 2969 
     | 
    
         
            +
                    if doing_kh:
         
     | 
| 
      
 2970 
     | 
    
         
            +
                        kh = BlockedWell.__get_kh_if_doing_kh(isotropic_perm = isotropic_perm,
         
     | 
| 
      
 2971 
     | 
    
         
            +
                                                              ntg_is_one = ntg_is_one,
         
     | 
| 
      
 2972 
     | 
    
         
            +
                                                              length = length,
         
     | 
| 
      
 2973 
     | 
    
         
            +
                                                              perm_i_uuid = perm_i_uuid,
         
     | 
| 
      
 2974 
     | 
    
         
            +
                                                              grid = grid,
         
     | 
| 
      
 2975 
     | 
    
         
            +
                                                              tuple_kji0 = tuple_kji0,
         
     | 
| 
      
 2976 
     | 
    
         
            +
                                                              k_i = k_i,
         
     | 
| 
      
 2977 
     | 
    
         
            +
                                                              k_j = k_j,
         
     | 
| 
      
 2978 
     | 
    
         
            +
                                                              k_k = k_k,
         
     | 
| 
      
 2979 
     | 
    
         
            +
                                                              anglv = anglv,
         
     | 
| 
      
 2980 
     | 
    
         
            +
                                                              sine_anglv = sine_anglv,
         
     | 
| 
      
 2981 
     | 
    
         
            +
                                                              cosine_anglv = cosine_anglv,
         
     | 
| 
      
 2982 
     | 
    
         
            +
                                                              sine_angla = sine_angla,
         
     | 
| 
      
 2983 
     | 
    
         
            +
                                                              cosine_angla = cosine_angla)
         
     | 
| 
      
 2984 
     | 
    
         
            +
                        if min_kh is not None and kh < min_kh:
         
     | 
| 
      
 2985 
     | 
    
         
            +
                            skip_interval = True
         
     | 
| 
      
 2986 
     | 
    
         
            +
                    elif 'KH' in pc_titles:
         
     | 
| 
      
 2987 
     | 
    
         
            +
                        kh = pc.single_array_ref(citation_title = 'KH')[ci]
         
     | 
| 
      
 2988 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 2989 
     | 
    
         
            +
                        kh = None
         
     | 
| 
      
 2990 
     | 
    
         
            +
                    return skip_interval, kh
         
     | 
| 
       2941 
2991 
     | 
    
         | 
| 
       2942 
     | 
    
         
            -
             
     | 
| 
      
 2992 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 2993 
     | 
    
         
            +
                def __get_kh_if_doing_kh(isotropic_perm, ntg_is_one, length, perm_i_uuid, grid, tuple_kji0, k_i, k_j, k_k, anglv,
         
     | 
| 
      
 2994 
     | 
    
         
            +
                                         sine_anglv, cosine_anglv, sine_angla, cosine_angla):
         
     | 
| 
      
 2995 
     | 
    
         
            +
                    # note: this is believed to return required value even when grid crs has mixed xy & z units;
         
     | 
| 
      
 2996 
     | 
    
         
            +
                    # angles are true angles accounting for any mixed units
         
     | 
| 
      
 2997 
     | 
    
         
            +
                    if isotropic_perm and ntg_is_one:
         
     | 
| 
      
 2998 
     | 
    
         
            +
                        kh = length * BlockedWell.__prop_array(perm_i_uuid, grid)[tuple_kji0]
         
     | 
| 
      
 2999 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 3000 
     | 
    
         
            +
                        if np.isnan(k_i) or np.isnan(k_j):
         
     | 
| 
      
 3001 
     | 
    
         
            +
                            kh = 0.0
         
     | 
| 
      
 3002 
     | 
    
         
            +
                        elif anglv == 0.0:
         
     | 
| 
      
 3003 
     | 
    
         
            +
                            kh = length * maths.sqrt(k_i * k_j)
         
     | 
| 
      
 3004 
     | 
    
         
            +
                        elif np.isnan(k_k):
         
     | 
| 
      
 3005 
     | 
    
         
            +
                            kh = 0.0
         
     | 
| 
      
 3006 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 3007 
     | 
    
         
            +
                            k_e = maths.pow(k_i * k_j * k_k, 1.0 / 3.0)
         
     | 
| 
      
 3008 
     | 
    
         
            +
                            if k_e == 0.0:
         
     | 
| 
      
 3009 
     | 
    
         
            +
                                kh = 0.0
         
     | 
| 
      
 3010 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 3011 
     | 
    
         
            +
                                l_i = length * maths.sqrt(k_e / k_i) * sine_anglv * cosine_angla
         
     | 
| 
      
 3012 
     | 
    
         
            +
                                l_j = length * maths.sqrt(k_e / k_j) * sine_anglv * sine_angla
         
     | 
| 
      
 3013 
     | 
    
         
            +
                                l_k = length * maths.sqrt(k_e / k_k) * cosine_anglv
         
     | 
| 
      
 3014 
     | 
    
         
            +
                                l_p = maths.sqrt(l_i * l_i + l_j * l_j + l_k * l_k)
         
     | 
| 
      
 3015 
     | 
    
         
            +
                                kh = k_e * l_p
         
     | 
| 
      
 3016 
     | 
    
         
            +
                    return kh
         
     | 
| 
       2943 
3017 
     | 
    
         | 
| 
       2944 
     | 
    
         
            -
             
     | 
| 
       2945 
     | 
    
         
            -
             
     | 
| 
       2946 
     | 
    
         
            -
             
     | 
| 
       2947 
     | 
    
         
            -
             
     | 
| 
       2948 
     | 
    
         
            -
                                        perm_j_uuid = perm_j_uuid,
         
     | 
| 
       2949 
     | 
    
         
            -
                                        perm_k_uuid = perm_k_uuid,
         
     | 
| 
       2950 
     | 
    
         
            -
                                        satw_uuid = satw_uuid,
         
     | 
| 
       2951 
     | 
    
         
            -
                                        sato_uuid = sato_uuid,
         
     | 
| 
       2952 
     | 
    
         
            -
                                        satg_uuid = satg_uuid,
         
     | 
| 
       2953 
     | 
    
         
            -
                                        region_uuid = region_uuid,
         
     | 
| 
       2954 
     | 
    
         
            -
                                        radw = radw,
         
     | 
| 
       2955 
     | 
    
         
            -
                                        skin = skin,
         
     | 
| 
       2956 
     | 
    
         
            -
                                        stat = stat,
         
     | 
| 
       2957 
     | 
    
         
            -
                                        active_only = active_only,
         
     | 
| 
       2958 
     | 
    
         
            -
                                        min_k0 = min_k0,
         
     | 
| 
       2959 
     | 
    
         
            -
                                        max_k0 = max_k0,
         
     | 
| 
       2960 
     | 
    
         
            -
                                        k0_list = k0_list,
         
     | 
| 
       2961 
     | 
    
         
            -
                                        min_length = min_length,
         
     | 
| 
       2962 
     | 
    
         
            -
                                        min_kh = min_kh,
         
     | 
| 
       2963 
     | 
    
         
            -
                                        max_depth = max_depth,
         
     | 
| 
       2964 
     | 
    
         
            -
                                        max_satw = max_satw,
         
     | 
| 
       2965 
     | 
    
         
            -
                                        min_sato = min_sato,
         
     | 
| 
       2966 
     | 
    
         
            -
                                        max_satg = max_satg,
         
     | 
| 
       2967 
     | 
    
         
            -
                                        perforation_list = perforation_list,
         
     | 
| 
       2968 
     | 
    
         
            -
                                        region_list = region_list,
         
     | 
| 
       2969 
     | 
    
         
            -
                                        depth_inc_down = depth_inc_down,
         
     | 
| 
       2970 
     | 
    
         
            -
                                        set_k_face_intervals_vertical = set_k_face_intervals_vertical,
         
     | 
| 
       2971 
     | 
    
         
            -
                                        anglv_ref = anglv_ref,
         
     | 
| 
       2972 
     | 
    
         
            -
                                        angla_plane_ref = angla_plane_ref,
         
     | 
| 
       2973 
     | 
    
         
            -
                                        length_mode = length_mode,
         
     | 
| 
       2974 
     | 
    
         
            -
                                        length_uom = length_uom,
         
     | 
| 
       2975 
     | 
    
         
            -
                                        preferential_perforation = preferential_perforation,
         
     | 
| 
       2976 
     | 
    
         
            -
                                        use_properties = use_properties,
         
     | 
| 
       2977 
     | 
    
         
            -
                                        property_time_index = property_time_index)
         
     | 
| 
      
 3018 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 3019 
     | 
    
         
            +
                def __get_pc_arrays_for_interval(pc, pc_timeless, pc_titles, ci, length, radw, skin, stat, length_uom, grid,
         
     | 
| 
      
 3020 
     | 
    
         
            +
                                                 traj_crs):
         
     | 
| 
      
 3021 
     | 
    
         
            +
                    """Get the property collection arrays for the interval."""
         
     | 
| 
       2978 
3022 
     | 
    
         | 
| 
       2979 
     | 
    
         
            -
                     
     | 
| 
      
 3023 
     | 
    
         
            +
                    def get_item(v, title, pc_titles, pc, pc_timeless, ci, uom):
         
     | 
| 
       2980 
3024 
     | 
    
         | 
| 
       2981 
     | 
    
         
            -
             
     | 
| 
       2982 
     | 
    
         
            -
             
     | 
| 
       2983 
     | 
    
         
            -
             
     | 
| 
      
 3025 
     | 
    
         
            +
                        def pk_for_title(title):
         
     | 
| 
      
 3026 
     | 
    
         
            +
                            d = {
         
     | 
| 
      
 3027 
     | 
    
         
            +
                                'RADW': 'wellbore radius',
         
     | 
| 
      
 3028 
     | 
    
         
            +
                                'RADB': 'block equivalent radius',
         
     | 
| 
      
 3029 
     | 
    
         
            +
                                'SKIN': 'skin',
         
     | 
| 
      
 3030 
     | 
    
         
            +
                                'STAT': 'well connection open'
         
     | 
| 
      
 3031 
     | 
    
         
            +
                            }
         
     | 
| 
      
 3032 
     | 
    
         
            +
                            return d.get(title)
         
     | 
| 
       2984 
3033 
     | 
    
         | 
| 
       2985 
     | 
    
         
            -
                         
     | 
| 
       2986 
     | 
    
         
            -
             
     | 
| 
       2987 
     | 
    
         
            -
             
     | 
| 
       2988 
     | 
    
         
            -
             
     | 
| 
       2989 
     | 
    
         
            -
             
     | 
| 
       2990 
     | 
    
         
            -
             
     | 
| 
      
 3034 
     | 
    
         
            +
                        p = None
         
     | 
| 
      
 3035 
     | 
    
         
            +
                        pk = pk_for_title(title)
         
     | 
| 
      
 3036 
     | 
    
         
            +
                        pc_uom = None
         
     | 
| 
      
 3037 
     | 
    
         
            +
                        for try_pc in [pc, pc_timeless]:
         
     | 
| 
      
 3038 
     | 
    
         
            +
                            if try_pc is None:
         
     | 
| 
      
 3039 
     | 
    
         
            +
                                continue
         
     | 
| 
      
 3040 
     | 
    
         
            +
                            if title in pc_titles:
         
     | 
| 
      
 3041 
     | 
    
         
            +
                                p = try_pc.singleton(citation_title = title)
         
     | 
| 
      
 3042 
     | 
    
         
            +
                            if p is None and pk is not None:
         
     | 
| 
      
 3043 
     | 
    
         
            +
                                p = try_pc.singleton(property_kind = pk)
         
     | 
| 
      
 3044 
     | 
    
         
            +
                            if p is not None:
         
     | 
| 
      
 3045 
     | 
    
         
            +
                                v = try_pc.cached_part_array_ref(p)[ci]
         
     | 
| 
      
 3046 
     | 
    
         
            +
                                pc_uom = try_pc.uom_for_part(p)
         
     | 
| 
      
 3047 
     | 
    
         
            +
                                break
         
     | 
| 
      
 3048 
     | 
    
         
            +
                        if (title == 'STAT' or pk == 'well connection open') and v is not None and not isinstance(v, str):
         
     | 
| 
      
 3049 
     | 
    
         
            +
                            v = 'ON' if v else 'OFF'
         
     | 
| 
      
 3050 
     | 
    
         
            +
                        if pc_uom is not None and uom is not None and pc_uom != uom:
         
     | 
| 
      
 3051 
     | 
    
         
            +
                            v = wam.convert_lengths(v, pc_uom, uom)
         
     | 
| 
      
 3052 
     | 
    
         
            +
                        return v
         
     | 
| 
       2991 
3053 
     | 
    
         | 
| 
       2992 
     | 
    
         
            -
             
     | 
| 
      
 3054 
     | 
    
         
            +
                    if length_uom is None:
         
     | 
| 
      
 3055 
     | 
    
         
            +
                        l_uom = traj_crs.z_units
         
     | 
| 
      
 3056 
     | 
    
         
            +
                        r_uom = grid.crs.xy_units
         
     | 
| 
      
 3057 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 3058 
     | 
    
         
            +
                        l_uom = length_uom
         
     | 
| 
      
 3059 
     | 
    
         
            +
                        r_uom = length_uom
         
     | 
| 
      
 3060 
     | 
    
         
            +
                    length = get_item(length, 'LENGTH', pc_titles, pc, pc_timeless, ci, l_uom)
         
     | 
| 
      
 3061 
     | 
    
         
            +
                    radw = get_item(radw, 'RADW', pc_titles, pc, pc_timeless, ci, r_uom)
         
     | 
| 
      
 3062 
     | 
    
         
            +
                    stat = get_item(stat, 'STAT', pc_titles, pc, pc_timeless, ci, None)
         
     | 
| 
      
 3063 
     | 
    
         
            +
                    assert radw is None or radw > 0.0  # todo: allow zero for inactive intervals?
         
     | 
| 
      
 3064 
     | 
    
         
            +
                    skin = get_item(skin, 'SKIN', pc_titles, pc, pc_timeless, ci, None)
         
     | 
| 
      
 3065 
     | 
    
         
            +
                    if skin is None:
         
     | 
| 
      
 3066 
     | 
    
         
            +
                        skin = get_item(None, 'skin', pc_titles, pc, pc_timeless, ci, None)
         
     | 
| 
      
 3067 
     | 
    
         
            +
                    radb = get_item(None, 'RADB', pc_titles, pc, pc_timeless, ci, r_uom)
         
     | 
| 
      
 3068 
     | 
    
         
            +
                    if radb is None:
         
     | 
| 
      
 3069 
     | 
    
         
            +
                        radb = get_item(None, 'block equivalent radius', pc_titles, pc, pc_timeless, ci, r_uom)
         
     | 
| 
      
 3070 
     | 
    
         
            +
                    wi = get_item(None, 'WI', pc_titles, pc, pc_timeless, ci, None)
         
     | 
| 
      
 3071 
     | 
    
         
            +
                    wbc = get_item(None, 'WBC', pc_titles, pc, pc_timeless, ci, None)
         
     | 
| 
       2993 
3072 
     | 
    
         | 
| 
       2994 
     | 
    
         
            -
             
     | 
| 
      
 3073 
     | 
    
         
            +
                    return length, radw, skin, radb, wi, wbc, stat
         
     | 
| 
       2995 
3074 
     | 
    
         | 
| 
       2996 
     | 
    
         
            -
             
     | 
| 
       2997 
     | 
    
         
            -
             
     | 
| 
       2998 
     | 
    
         
            -
             
     | 
| 
       2999 
     | 
    
         
            -
             
     | 
| 
       3000 
     | 
    
         
            -
                        for _ in range(trailing_blank_lines):
         
     | 
| 
       3001 
     | 
    
         
            -
                            fp.write('\n')
         
     | 
| 
      
 3075 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 3076 
     | 
    
         
            +
                def __get_well_inflow_parameters_for_interval(do_well_inflow, isotropic_perm, ntg_is_one, k_i, k_j, k_k, sine_anglv,
         
     | 
| 
      
 3077 
     | 
    
         
            +
                                                              cosine_anglv, sine_angla, cosine_angla, grid, cell_kji0, radw, radb,
         
     | 
| 
      
 3078 
     | 
    
         
            +
                                                              wi, wbc, skin, kh, length_uom, column_list):
         
     | 
| 
       3002 
3079 
     | 
    
         | 
| 
       3003 
     | 
    
         
            -
                     
     | 
| 
      
 3080 
     | 
    
         
            +
                    if do_well_inflow:
         
     | 
| 
      
 3081 
     | 
    
         
            +
                        if not length_uom:
         
     | 
| 
      
 3082 
     | 
    
         
            +
                            length_uom = grid.crs.z_units
         
     | 
| 
      
 3083 
     | 
    
         
            +
                        k_ei, k_ej, k_ek, radw_e = BlockedWell.__calculate_ke_and_radw_e(isotropic_perm = isotropic_perm,
         
     | 
| 
      
 3084 
     | 
    
         
            +
                                                                                         ntg_is_one = ntg_is_one,
         
     | 
| 
      
 3085 
     | 
    
         
            +
                                                                                         radw = radw,
         
     | 
| 
      
 3086 
     | 
    
         
            +
                                                                                         k_i = k_i,
         
     | 
| 
      
 3087 
     | 
    
         
            +
                                                                                         k_j = k_j,
         
     | 
| 
      
 3088 
     | 
    
         
            +
                                                                                         k_k = k_k,
         
     | 
| 
      
 3089 
     | 
    
         
            +
                                                                                         sine_anglv = sine_anglv,
         
     | 
| 
      
 3090 
     | 
    
         
            +
                                                                                         cosine_anglv = cosine_anglv,
         
     | 
| 
      
 3091 
     | 
    
         
            +
                                                                                         sine_angla = sine_angla,
         
     | 
| 
      
 3092 
     | 
    
         
            +
                                                                                         cosine_angla = cosine_angla)
         
     | 
| 
       3004 
3093 
     | 
    
         | 
| 
       3005 
     | 
    
         
            -
             
     | 
| 
       3006 
     | 
    
         
            -
             
     | 
| 
       3007 
     | 
    
         
            -
             
     | 
| 
       3008 
     | 
    
         
            -
             
     | 
| 
       3009 
     | 
    
         
            -
             
     | 
| 
       3010 
     | 
    
         
            -
             
     | 
| 
       3011 
     | 
    
         
            -
             
     | 
| 
       3012 
     | 
    
         
            -
             
     | 
| 
       3013 
     | 
    
         
            -
             
     | 
| 
       3014 
     | 
    
         
            -
             
     | 
| 
       3015 
     | 
    
         
            -
             
     | 
| 
       3016 
     | 
    
         
            -
             
     | 
| 
       3017 
     | 
    
         
            -
             
     | 
| 
      
 3094 
     | 
    
         
            +
                        cell_axial_vectors = grid.interface_vectors_kji(cell_kji0)
         
     | 
| 
      
 3095 
     | 
    
         
            +
                        wam.convert_lengths(cell_axial_vectors[..., :2], grid.crs.xy_units, length_uom)
         
     | 
| 
      
 3096 
     | 
    
         
            +
                        wam.convert_lengths(cell_axial_vectors[..., 2], grid.crs.z_units, length_uom)
         
     | 
| 
      
 3097 
     | 
    
         
            +
                        d2 = np.empty(3)
         
     | 
| 
      
 3098 
     | 
    
         
            +
                        for axis in range(3):
         
     | 
| 
      
 3099 
     | 
    
         
            +
                            d2[axis] = np.sum(cell_axial_vectors[axis] * cell_axial_vectors[axis])
         
     | 
| 
      
 3100 
     | 
    
         
            +
                        if radb is None:
         
     | 
| 
      
 3101 
     | 
    
         
            +
                            radb_e = BlockedWell.__calculate_radb_e(k_ei = k_ei,
         
     | 
| 
      
 3102 
     | 
    
         
            +
                                                                    k_ej = k_ej,
         
     | 
| 
      
 3103 
     | 
    
         
            +
                                                                    k_ek = k_ek,
         
     | 
| 
      
 3104 
     | 
    
         
            +
                                                                    k_i = k_i,
         
     | 
| 
      
 3105 
     | 
    
         
            +
                                                                    k_j = k_j,
         
     | 
| 
      
 3106 
     | 
    
         
            +
                                                                    k_k = k_k,
         
     | 
| 
      
 3107 
     | 
    
         
            +
                                                                    d2 = d2,
         
     | 
| 
      
 3108 
     | 
    
         
            +
                                                                    sine_anglv = sine_anglv,
         
     | 
| 
      
 3109 
     | 
    
         
            +
                                                                    cosine_anglv = cosine_anglv,
         
     | 
| 
      
 3110 
     | 
    
         
            +
                                                                    sine_angla = sine_angla,
         
     | 
| 
      
 3111 
     | 
    
         
            +
                                                                    cosine_angla = cosine_angla)
         
     | 
| 
      
 3112 
     | 
    
         
            +
                            radb = radw * radb_e / radw_e
         
     | 
| 
      
 3113 
     | 
    
         
            +
                            log.debug(f'RADB value calculated in BlockedWell dataframe method as: {radb}')
         
     | 
| 
      
 3114 
     | 
    
         
            +
                        if wi is None:
         
     | 
| 
      
 3115 
     | 
    
         
            +
                            wi = 0.0 if radb <= 0.0 else 2.0 * maths.pi / (maths.log(radb / radw) + skin)
         
     | 
| 
      
 3116 
     | 
    
         
            +
                        if 'WBC' in column_list and wbc is None:
         
     | 
| 
      
 3117 
     | 
    
         
            +
                            assert length_uom == 'm' or length_uom.startswith('ft'),  \
         
     | 
| 
      
 3118 
     | 
    
         
            +
                                'WBC only calculable for length uom of m or ft*'
         
     | 
| 
      
 3119 
     | 
    
         
            +
                            conversion_constant = 8.5270171e-5 if length_uom == 'm' else 0.006328286
         
     | 
| 
      
 3120 
     | 
    
         
            +
                            wbc = conversion_constant * kh * wi  # note: pperf aleady accounted for in kh
         
     | 
| 
       3018 
3121 
     | 
    
         | 
| 
       3019 
     | 
    
         
            -
             
     | 
| 
       3020 
     | 
    
         
            -
                def __is_float_column(col_name):
         
     | 
| 
       3021 
     | 
    
         
            -
                    if col_name.upper() in [
         
     | 
| 
       3022 
     | 
    
         
            -
                            'ANGLA', 'ANGLV', 'LENGTH', 'KH', 'DEPTH', 'MD', 'X', 'Y', 'SKIN', 'RADW', 'RADB', 'PPERF'
         
     | 
| 
       3023 
     | 
    
         
            -
                    ]:
         
     | 
| 
       3024 
     | 
    
         
            -
                        return True
         
     | 
| 
       3025 
     | 
    
         
            -
                    return False
         
     | 
| 
      
 3122 
     | 
    
         
            +
                    return radb, wi, wbc
         
     | 
| 
       3026 
3123 
     | 
    
         | 
| 
       3027 
3124 
     | 
    
         
             
                @staticmethod
         
     | 
| 
       3028 
     | 
    
         
            -
                def  
     | 
| 
       3029 
     | 
    
         
            -
             
     | 
| 
       3030 
     | 
    
         
            -
                        return True
         
     | 
| 
       3031 
     | 
    
         
            -
                    return False
         
     | 
| 
      
 3125 
     | 
    
         
            +
                def __calculate_ke_and_radw_e(isotropic_perm, ntg_is_one, radw, k_i, k_j, k_k, sine_anglv, cosine_anglv, sine_angla,
         
     | 
| 
      
 3126 
     | 
    
         
            +
                                              cosine_angla):
         
     | 
| 
       3032 
3127 
     | 
    
         | 
| 
       3033 
     | 
    
         
            -
             
     | 
| 
       3034 
     | 
    
         
            -
             
     | 
| 
      
 3128 
     | 
    
         
            +
                    if isotropic_perm and ntg_is_one:
         
     | 
| 
      
 3129 
     | 
    
         
            +
                        k_ei = k_ej = k_ek = k_i
         
     | 
| 
      
 3130 
     | 
    
         
            +
                        radw_e = radw
         
     | 
| 
      
 3131 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 3132 
     | 
    
         
            +
                        k_ei = maths.sqrt(k_j * k_k)
         
     | 
| 
      
 3133 
     | 
    
         
            +
                        k_ej = maths.sqrt(k_i * k_k)
         
     | 
| 
      
 3134 
     | 
    
         
            +
                        k_ek = maths.sqrt(k_i * k_j)
         
     | 
| 
      
 3135 
     | 
    
         
            +
                        r_wi = 0.0 if k_ei == 0.0 else 0.5 * radw * (maths.sqrt(k_ei / k_j) + maths.sqrt(k_ei / k_k))
         
     | 
| 
      
 3136 
     | 
    
         
            +
                        r_wj = 0.0 if k_ej == 0.0 else 0.5 * radw * (maths.sqrt(k_ej / k_i) + maths.sqrt(k_ej / k_k))
         
     | 
| 
      
 3137 
     | 
    
         
            +
                        r_wk = 0.0 if k_ek == 0.0 else 0.5 * radw * (maths.sqrt(k_ek / k_i) + maths.sqrt(k_ek / k_j))
         
     | 
| 
      
 3138 
     | 
    
         
            +
                        rwi = r_wi * sine_anglv * cosine_angla
         
     | 
| 
      
 3139 
     | 
    
         
            +
                        rwj = r_wj * sine_anglv * sine_angla
         
     | 
| 
      
 3140 
     | 
    
         
            +
                        rwk = r_wk * cosine_anglv
         
     | 
| 
      
 3141 
     | 
    
         
            +
                        radw_e = maths.sqrt(rwi * rwi + rwj * rwj + rwk * rwk)
         
     | 
| 
      
 3142 
     | 
    
         
            +
                        if radw_e == 0.0:
         
     | 
| 
      
 3143 
     | 
    
         
            +
                            radw_e = radw  # no permeability in this situation anyway
         
     | 
| 
       3035 
3144 
     | 
    
         | 
| 
       3036 
     | 
    
         
            -
                     
     | 
| 
       3037 
     | 
    
         
            -
                        if self.well_name:
         
     | 
| 
       3038 
     | 
    
         
            -
                            well_name = self.well_name
         
     | 
| 
       3039 
     | 
    
         
            -
                        elif self.root is not None:
         
     | 
| 
       3040 
     | 
    
         
            -
                            well_name = rqet.citation_title_for_node(self.root)
         
     | 
| 
       3041 
     | 
    
         
            -
                        elif self.wellbore_interpretation is not None:
         
     | 
| 
       3042 
     | 
    
         
            -
                            well_name = self.wellbore_interpretation.title
         
     | 
| 
       3043 
     | 
    
         
            -
                        elif self.trajectory is not None:
         
     | 
| 
       3044 
     | 
    
         
            -
                            well_name = self.trajectory.title
         
     | 
| 
       3045 
     | 
    
         
            -
                        if not well_name:
         
     | 
| 
       3046 
     | 
    
         
            -
                            log.warning('no well name identified for use in WELLSPEC')
         
     | 
| 
       3047 
     | 
    
         
            -
                            well_name = 'WELLNAME'
         
     | 
| 
       3048 
     | 
    
         
            -
                    well_name = BlockedWell.__tidy_well_name(well_name)
         
     | 
| 
      
 3145 
     | 
    
         
            +
                    return k_ei, k_ej, k_ek, radw_e
         
     | 
| 
       3049 
3146 
     | 
    
         | 
| 
       3050 
     | 
    
         
            -
             
     | 
| 
      
 3147 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 3148 
     | 
    
         
            +
                def __calculate_radb_e(k_ei, k_ej, k_ek, k_i, k_j, k_k, d2, sine_anglv, cosine_anglv, sine_angla, cosine_angla):
         
     | 
| 
       3051 
3149 
     | 
    
         | 
| 
       3052 
     | 
    
         
            -
             
     | 
| 
       3053 
     | 
    
         
            -
             
     | 
| 
       3054 
     | 
    
         
            -
                     
     | 
| 
       3055 
     | 
    
         
            -
                     
     | 
| 
      
 3150 
     | 
    
         
            +
                    r_bi = 0.0 if k_ei == 0.0 else 0.14 * maths.sqrt(k_ei * (d2[1] / k_j + d2[0] / k_k))
         
     | 
| 
      
 3151 
     | 
    
         
            +
                    r_bj = 0.0 if k_ej == 0.0 else 0.14 * maths.sqrt(k_ej * (d2[2] / k_i + d2[0] / k_k))
         
     | 
| 
      
 3152 
     | 
    
         
            +
                    r_bk = 0.0 if k_ek == 0.0 else 0.14 * maths.sqrt(k_ek * (d2[2] / k_i + d2[1] / k_j))
         
     | 
| 
      
 3153 
     | 
    
         
            +
                    rbi = r_bi * sine_anglv * cosine_angla
         
     | 
| 
      
 3154 
     | 
    
         
            +
                    rbj = r_bj * sine_anglv * sine_angla
         
     | 
| 
      
 3155 
     | 
    
         
            +
                    rbk = r_bk * cosine_anglv
         
     | 
| 
      
 3156 
     | 
    
         
            +
                    radb_e = maths.sqrt(rbi * rbi + rbj * rbj + rbk * rbk)
         
     | 
| 
       3056 
3157 
     | 
    
         | 
| 
       3057 
     | 
    
         
            -
                     
     | 
| 
       3058 
     | 
    
         
            -
                        length_uom_system_list = ['METRIC', 'ENGLISH']
         
     | 
| 
       3059 
     | 
    
         
            -
                        length_uom_index = ['m', 'ft'].index(length_uom)
         
     | 
| 
       3060 
     | 
    
         
            -
                        fp.write(f'{length_uom_system_list[length_uom_index]}\n\n')
         
     | 
| 
      
 3158 
     | 
    
         
            +
                    return radb_e
         
     | 
| 
       3061 
3159 
     | 
    
         | 
| 
       3062 
     | 
    
         
            -
             
     | 
| 
       3063 
     | 
    
         
            -
             
     | 
| 
       3064 
     | 
    
         
            -
             
     | 
| 
       3065 
     | 
    
         
            -
                    fp.write('WELLSPEC ' + str(well_name) + '\n')
         
     | 
| 
      
 3160 
     | 
    
         
            +
                def __get_xyz_for_interval(self, doing_xyz, length_mode, length_uom, md, traj_crs, depth_inc_down, traj_z_inc_down,
         
     | 
| 
      
 3161 
     | 
    
         
            +
                                           entry_xyz, exit_xyz, ee_crs, pc, pc_titles, ci):
         
     | 
| 
      
 3162 
     | 
    
         
            +
                    """Get the x, y and z location of the midpoint of the interval."""
         
     | 
| 
       3066 
3163 
     | 
    
         | 
| 
       3067 
     | 
    
         
            -
             
     | 
| 
       3068 
     | 
    
         
            -
             
     | 
| 
       3069 
     | 
    
         
            -
             
     | 
| 
       3070 
     | 
    
         
            -
             
     | 
| 
       3071 
     | 
    
         
            -
             
     | 
| 
       3072 
     | 
    
         
            -
             
     | 
| 
       3073 
     | 
    
         
            -
             
     | 
| 
       3074 
     | 
    
         
            -
             
     | 
| 
       3075 
     | 
    
         
            -
             
     | 
| 
       3076 
     | 
    
         
            -
             
     | 
| 
      
 3164 
     | 
    
         
            +
                    xyz = (np.nan, np.nan, np.nan)
         
     | 
| 
      
 3165 
     | 
    
         
            +
                    if doing_xyz:
         
     | 
| 
      
 3166 
     | 
    
         
            +
                        xyz = self.__get_xyz_if_doing_xyz(length_mode = length_mode,
         
     | 
| 
      
 3167 
     | 
    
         
            +
                                                          md = md,
         
     | 
| 
      
 3168 
     | 
    
         
            +
                                                          length_uom = length_uom,
         
     | 
| 
      
 3169 
     | 
    
         
            +
                                                          traj_crs = traj_crs,
         
     | 
| 
      
 3170 
     | 
    
         
            +
                                                          depth_inc_down = depth_inc_down,
         
     | 
| 
      
 3171 
     | 
    
         
            +
                                                          traj_z_inc_down = traj_z_inc_down,
         
     | 
| 
      
 3172 
     | 
    
         
            +
                                                          entry_xyz = entry_xyz,
         
     | 
| 
      
 3173 
     | 
    
         
            +
                                                          exit_xyz = exit_xyz,
         
     | 
| 
      
 3174 
     | 
    
         
            +
                                                          ee_crs = ee_crs)
         
     | 
| 
      
 3175 
     | 
    
         
            +
                    xyz = np.array(xyz)
         
     | 
| 
      
 3176 
     | 
    
         
            +
                    for i, col_header in enumerate(['X', 'Y', 'DEPTH']):
         
     | 
| 
      
 3177 
     | 
    
         
            +
                        if col_header in pc_titles:
         
     | 
| 
      
 3178 
     | 
    
         
            +
                            xyz[i] = pc.single_array_ref(citation_title = col_header)[ci]
         
     | 
| 
       3077 
3179 
     | 
    
         | 
| 
       3078 
     | 
    
         
            -
             
     | 
| 
       3079 
     | 
    
         
            -
                def __write_wellspec_file_rows_from_dataframe(df, fp, col_width_dict, sep):
         
     | 
| 
       3080 
     | 
    
         
            -
                    """Writes the non-blank lines of a Nexus WELLSPEC file from a BlockedWell dataframe."""
         
     | 
| 
      
 3180 
     | 
    
         
            +
                    return xyz
         
     | 
| 
       3081 
3181 
     | 
    
         | 
| 
       3082 
     | 
    
         
            -
             
     | 
| 
       3083 
     | 
    
         
            -
             
     | 
| 
       3084 
     | 
    
         
            -
                        for col_name in df.columns:
         
     | 
| 
       3085 
     | 
    
         
            -
                            try:
         
     | 
| 
       3086 
     | 
    
         
            -
                                if col_name in col_width_dict:
         
     | 
| 
       3087 
     | 
    
         
            -
                                    width = col_width_dict[col_name]
         
     | 
| 
       3088 
     | 
    
         
            -
                                else:
         
     | 
| 
       3089 
     | 
    
         
            -
                                    width = 10
         
     | 
| 
       3090 
     | 
    
         
            -
                                if BlockedWell.__is_float_column(col_name):
         
     | 
| 
       3091 
     | 
    
         
            -
                                    form = '{0:>' + str(width) + '.3f}'
         
     | 
| 
       3092 
     | 
    
         
            -
                                    value = row[col_name]
         
     | 
| 
       3093 
     | 
    
         
            -
                                    if col_name == 'ANGLA' and (pd.isna(row[col_name]) or value is None or np.isnan(value)):
         
     | 
| 
       3094 
     | 
    
         
            -
                                        value = 0.0
         
     | 
| 
       3095 
     | 
    
         
            -
                                    fp.write(sep + form.format(float(value)))
         
     | 
| 
       3096 
     | 
    
         
            -
                                else:
         
     | 
| 
       3097 
     | 
    
         
            -
                                    form = '{0:>' + str(width) + '}'
         
     | 
| 
       3098 
     | 
    
         
            -
                                    if BlockedWell.__is_int_column(col_name):
         
     | 
| 
       3099 
     | 
    
         
            -
                                        fp.write(sep + form.format(int(row[col_name])))
         
     | 
| 
       3100 
     | 
    
         
            -
                                    elif col_name == 'STAT':
         
     | 
| 
       3101 
     | 
    
         
            -
                                        fp.write(sep + form.format('OFF' if str(row['STAT']).upper() in ['0', 'OFF'] else 'ON'))
         
     | 
| 
       3102 
     | 
    
         
            -
                                    else:
         
     | 
| 
       3103 
     | 
    
         
            -
                                        fp.write(sep + form.format(str(row[col_name])))
         
     | 
| 
       3104 
     | 
    
         
            -
                            except Exception:
         
     | 
| 
       3105 
     | 
    
         
            -
                                fp.write(sep + str(row[col_name]))
         
     | 
| 
       3106 
     | 
    
         
            -
                        fp.write('\n')
         
     | 
| 
      
 3182 
     | 
    
         
            +
                def __get_xyz_if_doing_xyz(self, length_mode, md, length_uom, traj_crs, depth_inc_down, traj_z_inc_down, exit_xyz,
         
     | 
| 
      
 3183 
     | 
    
         
            +
                                           entry_xyz, ee_crs):
         
     | 
| 
       3107 
3184 
     | 
    
         | 
| 
       3108 
     | 
    
         
            -
             
     | 
| 
       3109 
     | 
    
         
            -
             
     | 
| 
      
 3185 
     | 
    
         
            +
                    if length_mode == 'MD' and self.trajectory is not None:
         
     | 
| 
      
 3186 
     | 
    
         
            +
                        xyz = self.trajectory.xyz_for_md(md)
         
     | 
| 
      
 3187 
     | 
    
         
            +
                        if length_uom is not None and length_uom != self.trajectory.md_uom:
         
     | 
| 
      
 3188 
     | 
    
         
            +
                            wam.convert_lengths(xyz, traj_crs.z_units, length_uom)
         
     | 
| 
      
 3189 
     | 
    
         
            +
                        if depth_inc_down and traj_z_inc_down is False:
         
     | 
| 
      
 3190 
     | 
    
         
            +
                            xyz[2] = -xyz[2]
         
     | 
| 
      
 3191 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 3192 
     | 
    
         
            +
                        xyz = 0.5 * (np.array(exit_xyz) + np.array(entry_xyz))
         
     | 
| 
      
 3193 
     | 
    
         
            +
                        if length_uom is not None and length_uom != ee_crs.z_units:
         
     | 
| 
      
 3194 
     | 
    
         
            +
                            xyz[2] = wam.convert_lengths(xyz[2], ee_crs.z_units, length_uom)
         
     | 
| 
      
 3195 
     | 
    
         
            +
                        if depth_inc_down != ee_crs.z_inc_down:
         
     | 
| 
      
 3196 
     | 
    
         
            +
                            xyz[2] = -xyz[2]
         
     | 
| 
       3110 
3197 
     | 
    
         | 
| 
       3111 
     | 
    
         
            -
                     
     | 
| 
       3112 
     | 
    
         
            -
                    if cells is None or grids is None or len(grids) == 0:
         
     | 
| 
       3113 
     | 
    
         
            -
                        return None, None, None, None
         
     | 
| 
       3114 
     | 
    
         
            -
                    return cells[0], grids[0].uuid
         
     | 
| 
      
 3198 
     | 
    
         
            +
                    return xyz
         
     | 
| 
       3115 
3199 
     | 
    
         | 
| 
       3116 
     | 
    
         
            -
                def  
     | 
| 
       3117 
     | 
    
         
            -
                    """ 
     | 
| 
      
 3200 
     | 
    
         
            +
                def __get_md_array_in_correct_units_for_interval(self, md, length_uom, pc, pc_titles, ci):
         
     | 
| 
      
 3201 
     | 
    
         
            +
                    """Convert the measured depth to the correct units or get the measured depth from the property collection."""
         
     | 
| 
       3118 
3202 
     | 
    
         | 
| 
       3119 
     | 
    
         
            -
                     
     | 
| 
       3120 
     | 
    
         
            -
             
     | 
| 
       3121 
     | 
    
         
            -
             
     | 
| 
       3122 
     | 
    
         
            -
             
     | 
| 
      
 3203 
     | 
    
         
            +
                    if 'MD' in pc_titles:
         
     | 
| 
      
 3204 
     | 
    
         
            +
                        md = pc.single_array_ref(citation_title = 'MD')[ci]
         
     | 
| 
      
 3205 
     | 
    
         
            +
                    elif length_uom is not None and self.trajectory is not None and length_uom != self.trajectory.md_uom:
         
     | 
| 
      
 3206 
     | 
    
         
            +
                        md = wam.convert_lengths(md, self.trajectory.md_uom, length_uom)
         
     | 
| 
       3123 
3207 
     | 
    
         | 
| 
       3124 
     | 
    
         
            -
                     
     | 
| 
       3125 
     | 
    
         
            -
                    if cells is None or grids is None or len(grids) == 0:
         
     | 
| 
       3126 
     | 
    
         
            -
                        return None, None
         
     | 
| 
       3127 
     | 
    
         
            -
                    node_index = 0
         
     | 
| 
       3128 
     | 
    
         
            -
                    while node_index < self.node_count - 1 and self.grid_indices[node_index] == -1:
         
     | 
| 
       3129 
     | 
    
         
            -
                        node_index += 1
         
     | 
| 
       3130 
     | 
    
         
            -
                    if node_index >= self.node_count - 1:
         
     | 
| 
       3131 
     | 
    
         
            -
                        return None, None
         
     | 
| 
       3132 
     | 
    
         
            -
                    md = 0.5 * (self.node_mds[node_index] + self.node_mds[node_index + 1])
         
     | 
| 
       3133 
     | 
    
         
            -
                    xyz = self.trajectory.xyz_for_md(md)
         
     | 
| 
       3134 
     | 
    
         
            -
                    return xyz, self.trajectory.crs_uuid
         
     | 
| 
      
 3208 
     | 
    
         
            +
                    return md
         
     | 
| 
       3135 
3209 
     | 
    
         | 
| 
       3136 
     | 
    
         
            -
                 
     | 
| 
       3137 
     | 
    
         
            -
             
     | 
| 
      
 3210 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 3211 
     | 
    
         
            +
                def __append_interval_data_to_dataframe(df, grid_name, radw, skin, angla, anglv, length, kh, xyz, md, stat,
         
     | 
| 
      
 3212 
     | 
    
         
            +
                                                        part_perf_fraction, radb, wi, wbc, column_list, one_based, row_dict,
         
     | 
| 
      
 3213 
     | 
    
         
            +
                                                        cell_kji0, row_ci_list, ci):
         
     | 
| 
      
 3214 
     | 
    
         
            +
                    """Append the row of data corresponding to the interval to the dataframe."""
         
     | 
| 
       3138 
3215 
     | 
    
         | 
| 
       3139 
     | 
    
         
            -
                     
     | 
| 
       3140 
     | 
    
         
            -
                         
     | 
| 
       3141 
     | 
    
         
            -
             
     | 
| 
       3142 
     | 
    
         
            -
                     
     | 
| 
       3143 
     | 
    
         
            -
                     
     | 
| 
       3144 
     | 
    
         
            -
                         
     | 
| 
       3145 
     | 
    
         
            -
                         
     | 
| 
       3146 
     | 
    
         
            -
             
     | 
| 
       3147 
     | 
    
         
            -
             
     | 
| 
       3148 
     | 
    
         
            -
                                title = 'WELL'
         
     | 
| 
       3149 
     | 
    
         
            -
                    if self.trajectory is not None:
         
     | 
| 
       3150 
     | 
    
         
            -
                        traj_interp_uuid = self.model.uuid(obj_type = 'WellboreInterpretation', related_uuid = self.trajectory.uuid)
         
     | 
| 
       3151 
     | 
    
         
            -
                        if traj_interp_uuid is not None:
         
     | 
| 
       3152 
     | 
    
         
            -
                            if shared_interpretation:
         
     | 
| 
       3153 
     | 
    
         
            -
                                self.wellbore_interpretation = rqo.WellboreInterpretation(parent_model = self.model,
         
     | 
| 
       3154 
     | 
    
         
            -
                                                                                          uuid = traj_interp_uuid)
         
     | 
| 
       3155 
     | 
    
         
            -
                            traj_feature_uuid = self.model.uuid(obj_type = 'WellboreFeature', related_uuid = traj_interp_uuid)
         
     | 
| 
       3156 
     | 
    
         
            -
                            if traj_feature_uuid is not None:
         
     | 
| 
       3157 
     | 
    
         
            -
                                self.wellbore_feature = rqo.WellboreFeature(parent_model = self.model, uuid = traj_feature_uuid)
         
     | 
| 
       3158 
     | 
    
         
            -
                    if self.wellbore_feature is None:
         
     | 
| 
       3159 
     | 
    
         
            -
                        self.wellbore_feature = rqo.WellboreFeature(parent_model = self.model, feature_name = title)
         
     | 
| 
       3160 
     | 
    
         
            -
                        self.feature_to_be_written = True
         
     | 
| 
       3161 
     | 
    
         
            -
                    if self.wellbore_interpretation is None:
         
     | 
| 
       3162 
     | 
    
         
            -
                        title = title if not self.wellbore_feature.title else self.wellbore_feature.title
         
     | 
| 
       3163 
     | 
    
         
            -
                        self.wellbore_interpretation = rqo.WellboreInterpretation(parent_model = self.model,
         
     | 
| 
       3164 
     | 
    
         
            -
                                                                                  title = title,
         
     | 
| 
       3165 
     | 
    
         
            -
                                                                                  wellbore_feature = self.wellbore_feature)
         
     | 
| 
       3166 
     | 
    
         
            -
                        if self.trajectory.wellbore_interpretation is None and shared_interpretation:
         
     | 
| 
       3167 
     | 
    
         
            -
                            self.trajectory.wellbore_interpretation = self.wellbore_interpretation
         
     | 
| 
       3168 
     | 
    
         
            -
                        self.interpretation_to_be_written = True
         
     | 
| 
      
 3216 
     | 
    
         
            +
                    column_names = [
         
     | 
| 
      
 3217 
     | 
    
         
            +
                        'GRID', 'RADW', 'SKIN', 'ANGLA', 'ANGLV', 'LENGTH', 'KH', 'DEPTH', 'MD', 'X', 'Y', 'STAT', 'PPERF', 'RADB',
         
     | 
| 
      
 3218 
     | 
    
         
            +
                        'WI', 'WBC'
         
     | 
| 
      
 3219 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 3220 
     | 
    
         
            +
                    column_values = [
         
     | 
| 
      
 3221 
     | 
    
         
            +
                        grid_name, radw, skin, angla, anglv, length, kh, xyz[2], md, xyz[0], xyz[1], stat, part_perf_fraction, radb,
         
     | 
| 
      
 3222 
     | 
    
         
            +
                        wi, wbc
         
     | 
| 
      
 3223 
     | 
    
         
            +
                    ]
         
     | 
| 
      
 3224 
     | 
    
         
            +
                    column_values_dict = dict(zip(column_names, column_values))
         
     | 
| 
       3169 
3225 
     | 
    
         | 
| 
       3170 
     | 
    
         
            -
             
     | 
| 
       3171 
     | 
    
         
            -
             
     | 
| 
       3172 
     | 
    
         
            -
             
     | 
| 
       3173 
     | 
    
         
            -
             
     | 
| 
       3174 
     | 
    
         
            -
             
     | 
| 
       3175 
     | 
    
         
            -
             
     | 
| 
       3176 
     | 
    
         
            -
             
     | 
| 
       3177 
     | 
    
         
            -
             
     | 
| 
       3178 
     | 
    
         
            -
             
     | 
| 
       3179 
     | 
    
         
            -
             
     | 
| 
      
 3226 
     | 
    
         
            +
                    data = df.to_dict()
         
     | 
| 
      
 3227 
     | 
    
         
            +
                    data = {k: list(v.values()) for k, v in data.items()}
         
     | 
| 
      
 3228 
     | 
    
         
            +
                    for col_index, col in enumerate(column_list):
         
     | 
| 
      
 3229 
     | 
    
         
            +
                        if col_index < 3:
         
     | 
| 
      
 3230 
     | 
    
         
            +
                            if one_based:
         
     | 
| 
      
 3231 
     | 
    
         
            +
                                row_dict[col] = [cell_kji0[2 - col_index] + 1]
         
     | 
| 
      
 3232 
     | 
    
         
            +
                            else:
         
     | 
| 
      
 3233 
     | 
    
         
            +
                                row_dict[col] = [cell_kji0[2 - col_index]]
         
     | 
| 
      
 3234 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 3235 
     | 
    
         
            +
                            row_dict[col] = [column_values_dict[col]]
         
     | 
| 
       3180 
3236 
     | 
    
         | 
| 
       3181 
     | 
    
         
            -
                     
     | 
| 
       3182 
     | 
    
         
            -
             
     | 
| 
       3183 
     | 
    
         
            -
             
     | 
| 
      
 3237 
     | 
    
         
            +
                    for col, vals in row_dict.items():
         
     | 
| 
      
 3238 
     | 
    
         
            +
                        if col in data:
         
     | 
| 
      
 3239 
     | 
    
         
            +
                            data[col].extend(vals)
         
     | 
| 
      
 3240 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 3241 
     | 
    
         
            +
                            data[col] = vals
         
     | 
| 
      
 3242 
     | 
    
         
            +
                    df = pd.DataFrame(data)
         
     | 
| 
       3184 
3243 
     | 
    
         | 
| 
       3185 
     | 
    
         
            -
                     
     | 
| 
       3186 
     | 
    
         
            -
                        well_name = self.title
         
     | 
| 
      
 3244 
     | 
    
         
            +
                    row_ci_list.append(ci)
         
     | 
| 
       3187 
3245 
     | 
    
         | 
| 
       3188 
     | 
    
         
            -
                     
     | 
| 
       3189 
     | 
    
         
            -
                    datum_location = trajectory_points[0].copy()
         
     | 
| 
       3190 
     | 
    
         
            -
                    if set_depth_zero:
         
     | 
| 
       3191 
     | 
    
         
            -
                        datum_location[2] = 0.0
         
     | 
| 
       3192 
     | 
    
         
            -
                    datum = rqw.MdDatum(self.model,
         
     | 
| 
       3193 
     | 
    
         
            -
                                        crs_uuid = grid.crs_uuid,
         
     | 
| 
       3194 
     | 
    
         
            -
                                        location = datum_location,
         
     | 
| 
       3195 
     | 
    
         
            -
                                        md_reference = 'mean sea level')
         
     | 
| 
      
 3246 
     | 
    
         
            +
                    return df
         
     | 
| 
       3196 
3247 
     | 
    
         | 
| 
       3197 
     | 
    
         
            -
             
     | 
| 
       3198 
     | 
    
         
            -
             
     | 
| 
       3199 
     | 
    
         
            -
             
     | 
| 
       3200 
     | 
    
         
            -
             
     | 
| 
       3201 
     | 
    
         
            -
             
     | 
| 
       3202 
     | 
    
         
            -
             
     | 
| 
       3203 
     | 
    
         
            -
             
     | 
| 
       3204 
     | 
    
         
            -
             
     | 
| 
       3205 
     | 
    
         
            -
                    })
         
     | 
| 
       3206 
     | 
    
         
            -
                    self.trajectory = rqw.Trajectory(self.model,
         
     | 
| 
       3207 
     | 
    
         
            -
                                                     md_datum = datum,
         
     | 
| 
       3208 
     | 
    
         
            -
                                                     data_frame = trajectory_df,
         
     | 
| 
       3209 
     | 
    
         
            -
                                                     length_uom = length_uom,
         
     | 
| 
       3210 
     | 
    
         
            -
                                                     well_name = well_name,
         
     | 
| 
       3211 
     | 
    
         
            -
                                                     set_tangent_vectors = set_tangent_vectors)
         
     | 
| 
       3212 
     | 
    
         
            -
                    self.trajectory_to_be_written = True
         
     | 
| 
      
 3248 
     | 
    
         
            +
                def __add_as_properties(self,
         
     | 
| 
      
 3249 
     | 
    
         
            +
                                        df,
         
     | 
| 
      
 3250 
     | 
    
         
            +
                                        add_as_properties,
         
     | 
| 
      
 3251 
     | 
    
         
            +
                                        extra_columns_list,
         
     | 
| 
      
 3252 
     | 
    
         
            +
                                        length_uom,
         
     | 
| 
      
 3253 
     | 
    
         
            +
                                        time_index = None,
         
     | 
| 
      
 3254 
     | 
    
         
            +
                                        time_series_uuid = None):
         
     | 
| 
      
 3255 
     | 
    
         
            +
                    """Adds property parts from df with columns listed in add_as_properties or extra_columns_list."""
         
     | 
| 
       3213 
3256 
     | 
    
         | 
| 
       3214 
     | 
    
         
            -
                    if  
     | 
| 
       3215 
     | 
    
         
            -
                         
     | 
| 
      
 3257 
     | 
    
         
            +
                    if add_as_properties:
         
     | 
| 
      
 3258 
     | 
    
         
            +
                        if isinstance(add_as_properties, list):
         
     | 
| 
      
 3259 
     | 
    
         
            +
                            for col in add_as_properties:
         
     | 
| 
      
 3260 
     | 
    
         
            +
                                assert col in extra_columns_list
         
     | 
| 
      
 3261 
     | 
    
         
            +
                            property_columns = add_as_properties
         
     | 
| 
      
 3262 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 3263 
     | 
    
         
            +
                            property_columns = extra_columns_list
         
     | 
| 
      
 3264 
     | 
    
         
            +
                        self.add_df_properties(df,
         
     | 
| 
      
 3265 
     | 
    
         
            +
                                               property_columns,
         
     | 
| 
      
 3266 
     | 
    
         
            +
                                               length_uom = length_uom,
         
     | 
| 
      
 3267 
     | 
    
         
            +
                                               time_index = time_index,
         
     | 
| 
      
 3268 
     | 
    
         
            +
                                               time_series_uuid = time_series_uuid)
         
     | 
| 
       3216 
3269 
     | 
    
         | 
| 
       3217 
     | 
    
         
            -
                def  
     | 
| 
       3218 
     | 
    
         
            -
             
     | 
| 
       3219 
     | 
    
         
            -
                               create_for_trajectory_if_needed = True,
         
     | 
| 
       3220 
     | 
    
         
            -
                               add_as_part = True,
         
     | 
| 
       3221 
     | 
    
         
            -
                               add_relationships = True,
         
     | 
| 
       3222 
     | 
    
         
            -
                               title = None,
         
     | 
| 
       3223 
     | 
    
         
            -
                               originator = None):
         
     | 
| 
       3224 
     | 
    
         
            -
                    """Create a blocked wellbore representation node from this BlockedWell object, optionally add as part.
         
     | 
| 
      
 3270 
     | 
    
         
            +
                def _get_uom_pk_discrete_for_df_properties(self, extra, length_uom, temperature_uom = None):
         
     | 
| 
      
 3271 
     | 
    
         
            +
                    """Set the property kind and unit of measure for all properties in the dataframe."""
         
     | 
| 
       3225 
3272 
     | 
    
         | 
| 
       3226 
     | 
    
         
            -
                     
     | 
| 
       3227 
     | 
    
         
            -
             
     | 
| 
       3228 
     | 
    
         
            -
             
     | 
| 
      
 3273 
     | 
    
         
            +
                    # todo: this is horribly inefficient, building a whole dictionary for every call but only using one entry
         
     | 
| 
      
 3274 
     | 
    
         
            +
                    if length_uom not in ['m', 'ft']:
         
     | 
| 
      
 3275 
     | 
    
         
            +
                        raise ValueError(f"The length_uom {length_uom} must be either 'm' or 'ft'.")
         
     | 
| 
      
 3276 
     | 
    
         
            +
                    if extra == 'TEMP' and (temperature_uom is None or
         
     | 
| 
      
 3277 
     | 
    
         
            +
                                            temperature_uom not in wam.valid_uoms('thermodynamic temperature')):
         
     | 
| 
      
 3278 
     | 
    
         
            +
                        raise ValueError(f"The temperature_uom must be in {wam.valid_uoms('thermodynamic temperature')}.")
         
     | 
| 
       3229 
3279 
     | 
    
         | 
| 
       3230 
     | 
    
         
            -
                     
     | 
| 
       3231 
     | 
    
         
            -
             
     | 
| 
      
 3280 
     | 
    
         
            +
                    length_uom_pk_discrete = self._get_uom_pk_discrete_for_length_based_properties(length_uom = length_uom,
         
     | 
| 
      
 3281 
     | 
    
         
            +
                                                                                                   extra = extra)
         
     | 
| 
      
 3282 
     | 
    
         
            +
                    uom_pk_discrete_dict = {
         
     | 
| 
      
 3283 
     | 
    
         
            +
                        'ANGLA': ('dega', 'azimuth', False),
         
     | 
| 
      
 3284 
     | 
    
         
            +
                        'ANGLV': ('dega', 'inclination', False),
         
     | 
| 
      
 3285 
     | 
    
         
            +
                        'KH': (f'mD.{length_uom}', 'permeability length', False),
         
     | 
| 
      
 3286 
     | 
    
         
            +
                        'PPERF': (f'{length_uom}/{length_uom}', 'perforation fraction', False),
         
     | 
| 
      
 3287 
     | 
    
         
            +
                        'STAT': (None, 'well connection open', True),
         
     | 
| 
      
 3288 
     | 
    
         
            +
                        'LENGTH': length_uom_pk_discrete,
         
     | 
| 
      
 3289 
     | 
    
         
            +
                        'MD': (length_uom, 'measured depth', False),
         
     | 
| 
      
 3290 
     | 
    
         
            +
                        'X': length_uom_pk_discrete,
         
     | 
| 
      
 3291 
     | 
    
         
            +
                        'Y': length_uom_pk_discrete,
         
     | 
| 
      
 3292 
     | 
    
         
            +
                        'DEPTH': (length_uom, 'depth', False),
         
     | 
| 
      
 3293 
     | 
    
         
            +
                        'RADW': (length_uom, 'wellbore radius', False),
         
     | 
| 
      
 3294 
     | 
    
         
            +
                        'RADB': (length_uom, 'block equivalent radius', False),
         
     | 
| 
      
 3295 
     | 
    
         
            +
                        'RADBP': length_uom_pk_discrete,
         
     | 
| 
      
 3296 
     | 
    
         
            +
                        'RADWP': length_uom_pk_discrete,
         
     | 
| 
      
 3297 
     | 
    
         
            +
                        'FM': (f'{length_uom}/{length_uom}', 'matrix fraction', False),
         
     | 
| 
      
 3298 
     | 
    
         
            +
                        'IRELPM': (None, 'relative permeability index', True),  # TODO: change to 'region initialization' with facet
         
     | 
| 
      
 3299 
     | 
    
         
            +
                        'SECT': (None, 'wellbore section index', True),
         
     | 
| 
      
 3300 
     | 
    
         
            +
                        'LAYER': (None, 'layer index', True),
         
     | 
| 
      
 3301 
     | 
    
         
            +
                        'ANGLE': ('dega', 'plane angle', False),
         
     | 
| 
      
 3302 
     | 
    
         
            +
                        'TEMP': (temperature_uom, 'thermodynamic temperature', False),
         
     | 
| 
      
 3303 
     | 
    
         
            +
                        'MDCON': length_uom_pk_discrete,
         
     | 
| 
      
 3304 
     | 
    
         
            +
                        'K': ('mD', 'rock permeability', False),
         
     | 
| 
      
 3305 
     | 
    
         
            +
                        'DZ': (length_uom, 'cell length', False),  # TODO: add direction facet
         
     | 
| 
      
 3306 
     | 
    
         
            +
                        'DTOP': (length_uom, 'depth', False),
         
     | 
| 
      
 3307 
     | 
    
         
            +
                        'DBOT': (length_uom, 'depth', False),
         
     | 
| 
      
 3308 
     | 
    
         
            +
                        'SKIN': ('Euc', 'skin', False),
         
     | 
| 
      
 3309 
     | 
    
         
            +
                        'WI': ('Euc', 'well connection index', False),
         
     | 
| 
      
 3310 
     | 
    
         
            +
                    }
         
     | 
| 
      
 3311 
     | 
    
         
            +
                    return uom_pk_discrete_dict.get(extra, ('Euc', 'generic continuous', False))
         
     | 
| 
       3232 
3312 
     | 
    
         | 
| 
       3233 
     | 
    
         
            -
             
     | 
| 
      
 3313 
     | 
    
         
            +
                def _get_uom_pk_discrete_for_length_based_properties(self, length_uom, extra):
         
     | 
| 
      
 3314 
     | 
    
         
            +
                    if length_uom is None or length_uom == 'Euc':
         
     | 
| 
      
 3315 
     | 
    
         
            +
                        if extra in ['LENGTH', 'MD', 'MDCON']:
         
     | 
| 
      
 3316 
     | 
    
         
            +
                            uom = self.trajectory.md_uom
         
     | 
| 
      
 3317 
     | 
    
         
            +
                        elif extra in ['X', 'Y', 'RADW', 'RADB', 'RADBP', 'RADWP']:
         
     | 
| 
      
 3318 
     | 
    
         
            +
                            uom = self.grid_list[0].xy_units()
         
     | 
| 
      
 3319 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 3320 
     | 
    
         
            +
                            uom = self.grid_list[0].z_units()
         
     | 
| 
      
 3321 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 3322 
     | 
    
         
            +
                        uom = length_uom
         
     | 
| 
      
 3323 
     | 
    
         
            +
                    if extra == 'DEPTH':
         
     | 
| 
      
 3324 
     | 
    
         
            +
                        pk = 'depth'
         
     | 
| 
      
 3325 
     | 
    
         
            +
                    else:
         
     | 
| 
      
 3326 
     | 
    
         
            +
                        pk = 'length'
         
     | 
| 
      
 3327 
     | 
    
         
            +
                    return uom, pk, False
         
     | 
| 
       3234 
3328 
     | 
    
         | 
| 
       3235 
     | 
    
         
            -
             
     | 
| 
       3236 
     | 
    
         
            -
             
     | 
| 
      
 3329 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 3330 
     | 
    
         
            +
                def __tidy_well_name(well_name):
         
     | 
| 
      
 3331 
     | 
    
         
            +
                    nexus_friendly = ''
         
     | 
| 
      
 3332 
     | 
    
         
            +
                    previous_underscore = False
         
     | 
| 
      
 3333 
     | 
    
         
            +
                    for ch in well_name:
         
     | 
| 
      
 3334 
     | 
    
         
            +
                        if not 32 <= ord(ch) < 128 or ch in ' ,!*#':
         
     | 
| 
      
 3335 
     | 
    
         
            +
                            ch = '_'
         
     | 
| 
      
 3336 
     | 
    
         
            +
                        if not (previous_underscore and ch == '_'):
         
     | 
| 
      
 3337 
     | 
    
         
            +
                            nexus_friendly += ch
         
     | 
| 
      
 3338 
     | 
    
         
            +
                        previous_underscore = (ch == '_')
         
     | 
| 
      
 3339 
     | 
    
         
            +
                    if not nexus_friendly:
         
     | 
| 
      
 3340 
     | 
    
         
            +
                        well_name = 'WELL_X'
         
     | 
| 
      
 3341 
     | 
    
         
            +
                    return nexus_friendly
         
     | 
| 
       3237 
3342 
     | 
    
         | 
| 
       3238 
     | 
    
         
            -
             
     | 
| 
       3239 
     | 
    
         
            -
             
     | 
| 
       3240 
     | 
    
         
            -
                    if  
     | 
| 
       3241 
     | 
    
         
            -
             
     | 
| 
       3242 
     | 
    
         
            -
                     
     | 
| 
      
 3343 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 3344 
     | 
    
         
            +
                def __is_float_column(col_name):
         
     | 
| 
      
 3345 
     | 
    
         
            +
                    if col_name.upper() in [
         
     | 
| 
      
 3346 
     | 
    
         
            +
                            'ANGLA', 'ANGLV', 'LENGTH', 'KH', 'DEPTH', 'MD', 'X', 'Y', 'SKIN', 'RADW', 'RADB', 'PPERF'
         
     | 
| 
      
 3347 
     | 
    
         
            +
                    ]:
         
     | 
| 
      
 3348 
     | 
    
         
            +
                        return True
         
     | 
| 
      
 3349 
     | 
    
         
            +
                    return False
         
     | 
| 
       3243 
3350 
     | 
    
         | 
| 
       3244 
     | 
    
         
            -
             
     | 
| 
       3245 
     | 
    
         
            -
             
     | 
| 
       3246 
     | 
    
         
            -
             
     | 
| 
      
 3351 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 3352 
     | 
    
         
            +
                def __is_int_column(col_name):
         
     | 
| 
      
 3353 
     | 
    
         
            +
                    if col_name.upper() in ['IW', 'JW', 'L']:
         
     | 
| 
      
 3354 
     | 
    
         
            +
                        return True
         
     | 
| 
      
 3355 
     | 
    
         
            +
                    return False
         
     | 
| 
       3247 
3356 
     | 
    
         | 
| 
       3248 
     | 
    
         
            -
             
     | 
| 
       3249 
     | 
    
         
            -
             
     | 
| 
       3250 
     | 
    
         
            -
                                                           add_relationships = add_relationships,
         
     | 
| 
       3251 
     | 
    
         
            -
                                                           originator = originator,
         
     | 
| 
       3252 
     | 
    
         
            -
                                                           ext_uuid = ext_uuid,
         
     | 
| 
       3253 
     | 
    
         
            -
                                                           title = title)
         
     | 
| 
      
 3357 
     | 
    
         
            +
                def __get_well_name(self, well_name):
         
     | 
| 
      
 3358 
     | 
    
         
            +
                    """Get the name of the well whose data is to be written to the Nexus WELLSPEC file."""
         
     | 
| 
       3254 
3359 
     | 
    
         | 
| 
       3255 
     | 
    
         
            -
                     
     | 
| 
      
 3360 
     | 
    
         
            +
                    if not well_name:
         
     | 
| 
      
 3361 
     | 
    
         
            +
                        if self.well_name:
         
     | 
| 
      
 3362 
     | 
    
         
            +
                            well_name = self.well_name
         
     | 
| 
      
 3363 
     | 
    
         
            +
                        elif self.root is not None:
         
     | 
| 
      
 3364 
     | 
    
         
            +
                            well_name = rqet.citation_title_for_node(self.root)
         
     | 
| 
      
 3365 
     | 
    
         
            +
                        elif self.wellbore_interpretation is not None:
         
     | 
| 
      
 3366 
     | 
    
         
            +
                            well_name = self.wellbore_interpretation.title
         
     | 
| 
      
 3367 
     | 
    
         
            +
                        elif self.trajectory is not None:
         
     | 
| 
      
 3368 
     | 
    
         
            +
                            well_name = self.trajectory.title
         
     | 
| 
      
 3369 
     | 
    
         
            +
                        if not well_name:
         
     | 
| 
      
 3370 
     | 
    
         
            +
                            log.warning('no well name identified for use in WELLSPEC')
         
     | 
| 
      
 3371 
     | 
    
         
            +
                            well_name = 'WELLNAME'
         
     | 
| 
      
 3372 
     | 
    
         
            +
                    well_name = BlockedWell.__tidy_well_name(well_name)
         
     | 
| 
       3256 
3373 
     | 
    
         | 
| 
       3257 
     | 
    
         
            -
                     
     | 
| 
      
 3374 
     | 
    
         
            +
                    return well_name
         
     | 
| 
       3258 
3375 
     | 
    
         | 
| 
       3259 
     | 
    
         
            -
             
     | 
| 
      
 3376 
     | 
    
         
            +
                def __write_wellspec_file_units_metadata(self, write_nexus_units, fp, length_uom, length_uom_comment,
         
     | 
| 
      
 3377 
     | 
    
         
            +
                                                         extra_columns_list, well_name):
         
     | 
| 
      
 3378 
     | 
    
         
            +
                    # write the units of measure (uom) and system of measure for length in the WELLSPEC file
         
     | 
| 
      
 3379 
     | 
    
         
            +
                    # also write a comment on the length uom if necessary
         
     | 
| 
       3260 
3380 
     | 
    
         | 
| 
       3261 
     | 
    
         
            -
                     
     | 
| 
       3262 
     | 
    
         
            -
                         
     | 
| 
       3263 
     | 
    
         
            -
                         
     | 
| 
      
 3381 
     | 
    
         
            +
                    if write_nexus_units:
         
     | 
| 
      
 3382 
     | 
    
         
            +
                        length_uom_system_list = ['METRIC', 'ENGLISH']
         
     | 
| 
      
 3383 
     | 
    
         
            +
                        length_uom_index = ['m', 'ft'].index(length_uom)
         
     | 
| 
      
 3384 
     | 
    
         
            +
                        fp.write(f'{length_uom_system_list[length_uom_index]}\n\n')
         
     | 
| 
       3264 
3385 
     | 
    
         | 
| 
       3265 
     | 
    
         
            -
                    self. 
     | 
| 
       3266 
     | 
    
         
            -
             
     | 
| 
       3267 
     | 
    
         
            -
             
     | 
| 
       3268 
     | 
    
         
            -
             
     | 
| 
       3269 
     | 
    
         
            -
                                                          fis_values_node = fis_values_node)
         
     | 
| 
      
 3386 
     | 
    
         
            +
                    if length_uom_comment and self.trajectory is not None and ('LENGTH' in extra_columns_list or 'MD'
         
     | 
| 
      
 3387 
     | 
    
         
            +
                                                                               in extra_columns_list or 'KH' in extra_columns_list):
         
     | 
| 
      
 3388 
     | 
    
         
            +
                        fp.write(f'! Length units along wellbore: {self.trajectory.md_uom if length_uom is None else length_uom}\n')
         
     | 
| 
      
 3389 
     | 
    
         
            +
                    fp.write('WELLSPEC ' + str(well_name) + '\n')
         
     | 
| 
       3270 
3390 
     | 
    
         | 
| 
       3271 
     | 
    
         
            -
             
     | 
| 
       3272 
     | 
    
         
            -
             
     | 
| 
      
 3391 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 3392 
     | 
    
         
            +
                def __write_wellspec_file_columns(df, fp, col_width_dict, sep):
         
     | 
| 
      
 3393 
     | 
    
         
            +
                    """Write the column names to the WELLSPEC file."""
         
     | 
| 
      
 3394 
     | 
    
         
            +
                    for col_name in df.columns:
         
     | 
| 
      
 3395 
     | 
    
         
            +
                        if col_name in col_width_dict:
         
     | 
| 
      
 3396 
     | 
    
         
            +
                            width = col_width_dict[col_name]
         
     | 
| 
      
 3397 
     | 
    
         
            +
                        else:
         
     | 
| 
      
 3398 
     | 
    
         
            +
                            width = 10
         
     | 
| 
      
 3399 
     | 
    
         
            +
                        form = '{0:>' + str(width) + '}'
         
     | 
| 
      
 3400 
     | 
    
         
            +
                        fp.write(sep + form.format(col_name))
         
     | 
| 
       3273 
3401 
     | 
    
         | 
| 
       3274 
     | 
    
         
            -
             
     | 
| 
       3275 
     | 
    
         
            -
             
     | 
| 
       3276 
     | 
    
         
            -
             
     | 
| 
       3277 
     | 
    
         
            -
                                                                         interp_root = interp_root,
         
     | 
| 
       3278 
     | 
    
         
            -
                                                                         ext_uuid = ext_uuid)
         
     | 
| 
      
 3402 
     | 
    
         
            +
                @staticmethod
         
     | 
| 
      
 3403 
     | 
    
         
            +
                def __write_wellspec_file_rows_from_dataframe(df, fp, col_width_dict, sep):
         
     | 
| 
      
 3404 
     | 
    
         
            +
                    """Writes the non-blank lines of a Nexus WELLSPEC file from a BlockedWell dataframe."""
         
     | 
| 
       3279 
3405 
     | 
    
         | 
| 
       3280 
     | 
    
         
            -
                     
     | 
| 
      
 3406 
     | 
    
         
            +
                    for row_info in df.iterrows():
         
     | 
| 
      
 3407 
     | 
    
         
            +
                        row = row_info[1]
         
     | 
| 
      
 3408 
     | 
    
         
            +
                        for col_name in df.columns:
         
     | 
| 
      
 3409 
     | 
    
         
            +
                            try:
         
     | 
| 
      
 3410 
     | 
    
         
            +
                                if col_name in col_width_dict:
         
     | 
| 
      
 3411 
     | 
    
         
            +
                                    width = col_width_dict[col_name]
         
     | 
| 
      
 3412 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 3413 
     | 
    
         
            +
                                    width = 10
         
     | 
| 
      
 3414 
     | 
    
         
            +
                                if BlockedWell.__is_float_column(col_name):
         
     | 
| 
      
 3415 
     | 
    
         
            +
                                    form = '{0:>' + str(width) + '.3f}'
         
     | 
| 
      
 3416 
     | 
    
         
            +
                                    value = row[col_name]
         
     | 
| 
      
 3417 
     | 
    
         
            +
                                    if col_name == 'ANGLA' and (pd.isna(row[col_name]) or value is None or np.isnan(value)):
         
     | 
| 
      
 3418 
     | 
    
         
            +
                                        value = 0.0
         
     | 
| 
      
 3419 
     | 
    
         
            +
                                    fp.write(sep + form.format(float(value)))
         
     | 
| 
      
 3420 
     | 
    
         
            +
                                else:
         
     | 
| 
      
 3421 
     | 
    
         
            +
                                    form = '{0:>' + str(width) + '}'
         
     | 
| 
      
 3422 
     | 
    
         
            +
                                    if BlockedWell.__is_int_column(col_name):
         
     | 
| 
      
 3423 
     | 
    
         
            +
                                        fp.write(sep + form.format(int(row[col_name])))
         
     | 
| 
      
 3424 
     | 
    
         
            +
                                    elif col_name == 'STAT':
         
     | 
| 
      
 3425 
     | 
    
         
            +
                                        fp.write(sep + form.format('OFF' if str(row['STAT']).upper() in ['0', 'OFF'] else 'ON'))
         
     | 
| 
      
 3426 
     | 
    
         
            +
                                    else:
         
     | 
| 
      
 3427 
     | 
    
         
            +
                                        fp.write(sep + form.format(str(row[col_name])))
         
     | 
| 
      
 3428 
     | 
    
         
            +
                            except Exception:
         
     | 
| 
      
 3429 
     | 
    
         
            +
                                fp.write(sep + str(row[col_name]))
         
     | 
| 
      
 3430 
     | 
    
         
            +
                        fp.write('\n')
         
     | 
| 
       3281 
3431 
     | 
    
         | 
| 
       3282 
3432 
     | 
    
         
             
                def __create_wellbore_feature_and_interpretation_xml_if_needed(self, add_as_part, add_relationships, originator):
         
     | 
| 
       3283 
3433 
     | 
    
         
             
                    """Create root node for WellboreFeature and WellboreInterpretation objects if necessary."""
         
     | 
| 
         @@ -3297,6 +3447,7 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       3297 
3447 
     | 
    
         
             
                def __create_trajectory_xml_if_needed(self, create_for_trajectory_if_needed, add_as_part, add_relationships,
         
     | 
| 
       3298 
3448 
     | 
    
         
             
                                                      originator, ext_uuid, title):
         
     | 
| 
       3299 
3449 
     | 
    
         
             
                    """Create root node for associated Trajectory object if necessary."""
         
     | 
| 
      
 3450 
     | 
    
         
            +
             
     | 
| 
       3300 
3451 
     | 
    
         
             
                    if create_for_trajectory_if_needed and self.trajectory_to_be_written and self.trajectory.root is None:
         
     | 
| 
       3301 
3452 
     | 
    
         
             
                        md_datum_root = self.trajectory.md_datum.create_xml(add_as_part = add_as_part,
         
     | 
| 
       3302 
3453 
     | 
    
         
             
                                                                            add_relationships = add_relationships,
         
     | 
| 
         @@ -3311,6 +3462,7 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       3311 
3462 
     | 
    
         | 
| 
       3312 
3463 
     | 
    
         
             
                def __create_bw_node_sub_elements(self, bw_node):
         
     | 
| 
       3313 
3464 
     | 
    
         
             
                    """Append sub-elements to the BlockedWell object's root node."""
         
     | 
| 
      
 3465 
     | 
    
         
            +
             
     | 
| 
       3314 
3466 
     | 
    
         
             
                    nc_node = rqet.SubElement(bw_node, ns['resqml2'] + 'NodeCount')
         
     | 
| 
       3315 
3467 
     | 
    
         
             
                    nc_node.set(ns['xsi'] + 'type', ns['xsd'] + 'positiveInteger')
         
     | 
| 
       3316 
3468 
     | 
    
         
             
                    nc_node.text = str(self.node_count)
         
     | 
| 
         @@ -3369,7 +3521,8 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       3369 
3521 
     | 
    
         
             
                    fis_values_node.set(ns['xsi'] + 'type', ns['eml'] + 'Hdf5Dataset')
         
     | 
| 
       3370 
3522 
     | 
    
         
             
                    fis_values_node.text = rqet.null_xml_text
         
     | 
| 
       3371 
3523 
     | 
    
         | 
| 
       3372 
     | 
    
         
            -
                    return nc_node, mds_node, mds_values_node, cc_node, cis_node, cnull_node, cis_values_node, gis_node, 
     | 
| 
      
 3524 
     | 
    
         
            +
                    return (nc_node, mds_node, mds_values_node, cc_node, cis_node, cnull_node, cis_values_node, gis_node,
         
     | 
| 
      
 3525 
     | 
    
         
            +
                            gnull_node, gis_values_node, fis_node, fnull_node, fis_values_node)
         
     | 
| 
       3373 
3526 
     | 
    
         | 
| 
       3374 
3527 
     | 
    
         
             
                def __create_trajectory_grid_wellbore_interpretation_reference_nodes(self, bw_node):
         
     | 
| 
       3375 
3528 
     | 
    
         
             
                    """Create nodes and add to BlockedWell object root node."""
         
     | 
| 
         @@ -3430,116 +3583,3 @@ class BlockedWell(BaseResqpy): 
     | 
|
| 
       3430 
3583 
     | 
    
         
             
                            ext_node = self.model.root_for_part(ext_part)
         
     | 
| 
       3431 
3584 
     | 
    
         
             
                            self.model.create_reciprocal_relationship(bw_node, 'mlToExternalPartProxy', ext_node,
         
     | 
| 
       3432 
3585 
     | 
    
         
             
                                                                      'externalPartProxyToMl')
         
     | 
| 
       3433 
     | 
    
         
            -
             
     | 
| 
       3434 
     | 
    
         
            -
                def write_hdf5(self, file_name = None, mode = 'a', create_for_trajectory_if_needed = True):
         
     | 
| 
       3435 
     | 
    
         
            -
                    """Create or append to an hdf5 file, writing datasets for the measured depths, grid, cell & face indices.
         
     | 
| 
       3436 
     | 
    
         
            -
             
     | 
| 
       3437 
     | 
    
         
            -
                    :meta common:
         
     | 
| 
       3438 
     | 
    
         
            -
                    """
         
     | 
| 
       3439 
     | 
    
         
            -
             
     | 
| 
       3440 
     | 
    
         
            -
                    # NB: array data must all have been set up prior to calling this function
         
     | 
| 
       3441 
     | 
    
         
            -
             
     | 
| 
       3442 
     | 
    
         
            -
                    if self.uuid is None:
         
     | 
| 
       3443 
     | 
    
         
            -
                        self.uuid = bu.new_uuid()
         
     | 
| 
       3444 
     | 
    
         
            -
             
     | 
| 
       3445 
     | 
    
         
            -
                    h5_reg = rwh5.H5Register(self.model)
         
     | 
| 
       3446 
     | 
    
         
            -
             
     | 
| 
       3447 
     | 
    
         
            -
                    if create_for_trajectory_if_needed and self.trajectory_to_be_written:
         
     | 
| 
       3448 
     | 
    
         
            -
                        self.trajectory.write_hdf5(file_name, mode = mode)
         
     | 
| 
       3449 
     | 
    
         
            -
                        mode = 'a'
         
     | 
| 
       3450 
     | 
    
         
            -
             
     | 
| 
       3451 
     | 
    
         
            -
                    h5_reg.register_dataset(self.uuid, 'NodeMd', self.node_mds)
         
     | 
| 
       3452 
     | 
    
         
            -
                    h5_reg.register_dataset(self.uuid, 'CellIndices', self.cell_indices)  # could use int32?
         
     | 
| 
       3453 
     | 
    
         
            -
                    h5_reg.register_dataset(self.uuid, 'GridIndices', self.grid_indices)  # could use int32?
         
     | 
| 
       3454 
     | 
    
         
            -
                    # convert face index pairs from [axis, polarity] back to strange local face numbering
         
     | 
| 
       3455 
     | 
    
         
            -
                    mask = (self.face_pair_indices.flatten() == -1).reshape((-1, 2))  # 2nd axis is (axis, polarity)
         
     | 
| 
       3456 
     | 
    
         
            -
                    masked_face_indices = np.where(mask, 0, self.face_pair_indices.reshape((-1, 2)))  # 2nd axis is (axis, polarity)
         
     | 
| 
       3457 
     | 
    
         
            -
                    # using flat array for raw_face_indices array
         
     | 
| 
       3458 
     | 
    
         
            -
                    # other resqml writing code might use an array with one int per entry point and one per exit point, with 2nd axis as (entry, exit)
         
     | 
| 
       3459 
     | 
    
         
            -
                    raw_face_indices = np.where(mask[:, 0], -1, self.face_index_map[masked_face_indices[:, 0],
         
     | 
| 
       3460 
     | 
    
         
            -
                                                                                    masked_face_indices[:,
         
     | 
| 
       3461 
     | 
    
         
            -
                                                                                                        1]].flatten()).reshape(-1)
         
     | 
| 
       3462 
     | 
    
         
            -
             
     | 
| 
       3463 
     | 
    
         
            -
                    h5_reg.register_dataset(self.uuid, 'LocalFacePairPerCellIndices', raw_face_indices)  # could use uint8?
         
     | 
| 
       3464 
     | 
    
         
            -
             
     | 
| 
       3465 
     | 
    
         
            -
                    h5_reg.write(file = file_name, mode = mode)
         
     | 
| 
       3466 
     | 
    
         
            -
             
     | 
| 
       3467 
     | 
    
         
            -
                def add_grid_property_to_blocked_well(self, uuid_list):
         
     | 
| 
       3468 
     | 
    
         
            -
                    """Add properties to blocked wells from a list of uuids for properties on the supporting grid."""
         
     | 
| 
       3469 
     | 
    
         
            -
             
     | 
| 
       3470 
     | 
    
         
            -
                    part_list = [self.model.part_for_uuid(uuid) for uuid in uuid_list]
         
     | 
| 
       3471 
     | 
    
         
            -
             
     | 
| 
       3472 
     | 
    
         
            -
                    assert len(self.grid_list) == 1, "only blocked wells with a single grid can be handled currently"
         
     | 
| 
       3473 
     | 
    
         
            -
                    grid = self.grid_list[0]
         
     | 
| 
       3474 
     | 
    
         
            -
                    # filter to only those properties on the grid
         
     | 
| 
       3475 
     | 
    
         
            -
                    parts = self.model.parts_list_filtered_by_supporting_uuid(part_list, grid.uuid)
         
     | 
| 
       3476 
     | 
    
         
            -
                    if len(parts) < len(uuid_list):
         
     | 
| 
       3477 
     | 
    
         
            -
                        log.warning(
         
     | 
| 
       3478 
     | 
    
         
            -
                            f"{len(uuid_list)-len(parts)} uuids ignored as they do not belong to the same grid as the blocked well")
         
     | 
| 
       3479 
     | 
    
         
            -
             
     | 
| 
       3480 
     | 
    
         
            -
                    gridpc = grid.extract_property_collection()
         
     | 
| 
       3481 
     | 
    
         
            -
                    # only 'cell' properties are handled
         
     | 
| 
       3482 
     | 
    
         
            -
                    cell_parts = [part for part in parts if gridpc.indexable_for_part(part) == 'cells']
         
     | 
| 
       3483 
     | 
    
         
            -
                    if len(cell_parts) < len(parts):
         
     | 
| 
       3484 
     | 
    
         
            -
                        log.warning(f"{len(parts)-len(cell_parts)} uuids ignored as they do not have indexable element of cells")
         
     | 
| 
       3485 
     | 
    
         
            -
             
     | 
| 
       3486 
     | 
    
         
            -
                    if len(cell_parts) > 0:
         
     | 
| 
       3487 
     | 
    
         
            -
                        bwpc = rqp.PropertyCollection(support = self)
         
     | 
| 
       3488 
     | 
    
         
            -
                        if len(gridpc.string_lookup_uuid_list()) > 0:
         
     | 
| 
       3489 
     | 
    
         
            -
                            sl_dict = {}
         
     | 
| 
       3490 
     | 
    
         
            -
                            for part in cell_parts:
         
     | 
| 
       3491 
     | 
    
         
            -
                                if gridpc.string_lookup_uuid_for_part(part) in sl_dict.keys():
         
     | 
| 
       3492 
     | 
    
         
            -
                                    sl_dict[gridpc.string_lookup_uuid_for_part(part)] =  \
         
     | 
| 
       3493 
     | 
    
         
            -
                                        sl_dict[gridpc.string_lookup_uuid_for_part(part)] + [part]
         
     | 
| 
       3494 
     | 
    
         
            -
                                else:
         
     | 
| 
       3495 
     | 
    
         
            -
                                    sl_dict[gridpc.string_lookup_uuid_for_part(part)] = [part]
         
     | 
| 
       3496 
     | 
    
         
            -
                        else:
         
     | 
| 
       3497 
     | 
    
         
            -
                            sl_dict = {None: cell_parts}
         
     | 
| 
       3498 
     | 
    
         
            -
             
     | 
| 
       3499 
     | 
    
         
            -
                        sl_ts_dict = {}
         
     | 
| 
       3500 
     | 
    
         
            -
                        for sl_uuid in sl_dict.keys():
         
     | 
| 
       3501 
     | 
    
         
            -
                            if len(gridpc.time_series_uuid_list()) > 0:
         
     | 
| 
       3502 
     | 
    
         
            -
                                # dictionary with keys for string_lookup uuids and None where missing
         
     | 
| 
       3503 
     | 
    
         
            -
                                # values for each key are a list of property parts associated with that lookup uuid, or None
         
     | 
| 
       3504 
     | 
    
         
            -
                                time_dict = {}
         
     | 
| 
       3505 
     | 
    
         
            -
                                for part in sl_dict[sl_uuid]:
         
     | 
| 
       3506 
     | 
    
         
            -
                                    if gridpc.time_series_uuid_for_part(part) in time_dict.keys():
         
     | 
| 
       3507 
     | 
    
         
            -
                                        time_dict[gridpc.time_series_uuid_for_part(part)] =  \
         
     | 
| 
       3508 
     | 
    
         
            -
                                            time_dict[gridpc.time_series_uuid_for_part(part)] + [part]
         
     | 
| 
       3509 
     | 
    
         
            -
                                    else:
         
     | 
| 
       3510 
     | 
    
         
            -
                                        time_dict[gridpc.time_series_uuid_for_part(part)] = [part]
         
     | 
| 
       3511 
     | 
    
         
            -
                            else:
         
     | 
| 
       3512 
     | 
    
         
            -
                                time_dict = {None: sl_dict[sl_uuid]}
         
     | 
| 
       3513 
     | 
    
         
            -
                            sl_ts_dict[sl_uuid] = time_dict
         
     | 
| 
       3514 
     | 
    
         
            -
             
     | 
| 
       3515 
     | 
    
         
            -
                        for sl_uuid in sl_ts_dict.keys():
         
     | 
| 
       3516 
     | 
    
         
            -
                            time_dict = sl_ts_dict[sl_uuid]
         
     | 
| 
       3517 
     | 
    
         
            -
                            for time_uuid in time_dict.keys():
         
     | 
| 
       3518 
     | 
    
         
            -
                                parts = time_dict[time_uuid]
         
     | 
| 
       3519 
     | 
    
         
            -
                                for part in parts:
         
     | 
| 
       3520 
     | 
    
         
            -
                                    array = gridpc.cached_part_array_ref(part)
         
     | 
| 
       3521 
     | 
    
         
            -
                                    indices = self.cell_indices_for_grid_uuid(grid.uuid)
         
     | 
| 
       3522 
     | 
    
         
            -
                                    bwarray = np.empty(shape = (indices.shape[0],), dtype = array.dtype)
         
     | 
| 
       3523 
     | 
    
         
            -
                                    for i, ind in enumerate(indices):
         
     | 
| 
       3524 
     | 
    
         
            -
                                        bwarray[i] = array[tuple(ind)]
         
     | 
| 
       3525 
     | 
    
         
            -
                                    bwpc.add_cached_array_to_imported_list(
         
     | 
| 
       3526 
     | 
    
         
            -
                                        bwarray,
         
     | 
| 
       3527 
     | 
    
         
            -
                                        source_info = f'property from grid {grid.title}',
         
     | 
| 
       3528 
     | 
    
         
            -
                                        keyword = gridpc.citation_title_for_part(part),
         
     | 
| 
       3529 
     | 
    
         
            -
                                        discrete = (not gridpc.continuous_for_part(part)),
         
     | 
| 
       3530 
     | 
    
         
            -
                                        uom = gridpc.uom_for_part(part),
         
     | 
| 
       3531 
     | 
    
         
            -
                                        time_index = gridpc.time_index_for_part(part),
         
     | 
| 
       3532 
     | 
    
         
            -
                                        null_value = gridpc.null_value_for_part(part),
         
     | 
| 
       3533 
     | 
    
         
            -
                                        property_kind = gridpc.property_kind_for_part(part),
         
     | 
| 
       3534 
     | 
    
         
            -
                                        local_property_kind_uuid = gridpc.local_property_kind_uuid(part),
         
     | 
| 
       3535 
     | 
    
         
            -
                                        facet_type = gridpc.facet_type_for_part(part),
         
     | 
| 
       3536 
     | 
    
         
            -
                                        facet = gridpc.facet_for_part(part),
         
     | 
| 
       3537 
     | 
    
         
            -
                                        realization = gridpc.realization_for_part(part),
         
     | 
| 
       3538 
     | 
    
         
            -
                                        indexable_element = 'cells')
         
     | 
| 
       3539 
     | 
    
         
            -
                                bwpc.write_hdf5_for_imported_list(use_int32 = False)
         
     | 
| 
       3540 
     | 
    
         
            -
                                bwpc.create_xml_for_imported_list_and_add_parts_to_model(time_series_uuid = time_uuid,
         
     | 
| 
       3541 
     | 
    
         
            -
                                                                                         string_lookup_uuid = sl_uuid)
         
     | 
| 
       3542 
     | 
    
         
            -
                    else:
         
     | 
| 
       3543 
     | 
    
         
            -
                        log.debug(
         
     | 
| 
       3544 
     | 
    
         
            -
                            "no properties added - uuids either not 'cell' properties or blocked well is associated with multiple grids"
         
     | 
| 
       3545 
     | 
    
         
            -
                        )
         
     |