resqpy 4.14.2__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 +13 -10
 - 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.2.dist-info → resqpy-5.1.5.dist-info}/METADATA +8 -9
 - {resqpy-4.14.2.dist-info → resqpy-5.1.5.dist-info}/RECORD +66 -66
 - {resqpy-4.14.2.dist-info → resqpy-5.1.5.dist-info}/WHEEL +1 -1
 - resqpy/grid/_moved_functions.py +0 -15
 - {resqpy-4.14.2.dist-info → resqpy-5.1.5.dist-info}/LICENSE +0 -0
 
| 
         @@ -4,8 +4,10 @@ import logging 
     | 
|
| 
       4 
4 
     | 
    
         | 
| 
       5 
5 
     | 
    
         
             
            log = logging.getLogger(__name__)
         
     | 
| 
       6 
6 
     | 
    
         | 
| 
      
 7 
     | 
    
         
            +
            import os
         
     | 
| 
       7 
8 
     | 
    
         
             
            import numpy as np
         
     | 
| 
       8 
9 
     | 
    
         
             
            import uuid
         
     | 
| 
      
 10 
     | 
    
         
            +
            import ast
         
     | 
| 
       9 
11 
     | 
    
         
             
            from typing import Tuple, Union, List, Optional, Callable
         
     | 
| 
       10 
12 
     | 
    
         
             
            from pathlib import Path
         
     | 
| 
       11 
13 
     | 
    
         
             
            from uuid import UUID
         
     | 
| 
         @@ -34,16 +36,22 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       34 
36 
     | 
    
         
             
                    trimmed: bool = False,
         
     | 
| 
       35 
37 
     | 
    
         
             
                    is_curtain = False,
         
     | 
| 
       36 
38 
     | 
    
         
             
                    extend_fault_representation: bool = False,
         
     | 
| 
       37 
     | 
    
         
            -
                    flange_inner_ring = False,
         
     | 
| 
       38 
     | 
    
         
            -
                    saucer_parameter = None,
         
     | 
| 
      
 39 
     | 
    
         
            +
                    flange_inner_ring: bool = False,
         
     | 
| 
      
 40 
     | 
    
         
            +
                    saucer_parameter: Optional[float] = None,
         
     | 
| 
       39 
41 
     | 
    
         
             
                    retriangulate: bool = False,
         
     | 
| 
       40 
     | 
    
         
            -
                    related_uuid = None,
         
     | 
| 
      
 42 
     | 
    
         
            +
                    related_uuid: Optional[Union[UUID, str]] = None,
         
     | 
| 
       41 
43 
     | 
    
         
             
                    progress_fn: Optional[Callable] = None,
         
     | 
| 
       42 
44 
     | 
    
         
             
                    extra_metadata = None,
         
     | 
| 
       43 
45 
     | 
    
         
             
                    return_properties: Optional[List[str]] = None,
         
     | 
| 
       44 
46 
     | 
    
         
             
                    raw_bisector: bool = False,
         
     | 
| 
       45 
47 
     | 
    
         
             
                    use_pack: bool = False,
         
     | 
| 
       46 
     | 
    
         
            -
                    flange_radius = None 
     | 
| 
      
 48 
     | 
    
         
            +
                    flange_radius: Optional[float] = None,
         
     | 
| 
      
 49 
     | 
    
         
            +
                    reorient: bool = True,
         
     | 
| 
      
 50 
     | 
    
         
            +
                    n_threads: int = 20,
         
     | 
| 
      
 51 
     | 
    
         
            +
                    patchwork: bool = False,
         
     | 
| 
      
 52 
     | 
    
         
            +
                    grid_patching_property_uuid: Optional[Union[UUID, str]] = None,
         
     | 
| 
      
 53 
     | 
    
         
            +
                    surface_patching_property_uuid: Optional[Union[UUID, str]] = None) ->  \
         
     | 
| 
      
 54 
     | 
    
         
            +
                        Tuple[int, bool, str, List[Union[UUID, str]]]:
         
     | 
| 
       47 
55 
     | 
    
         
             
                """Multiprocessing wrapper function of find_faces_to_represent_surface_regular_optimised.
         
     | 
| 
       48 
56 
     | 
    
         | 
| 
       49 
57 
     | 
    
         
             
                arguments:
         
     | 
| 
         @@ -92,10 +100,22 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       92 
100 
     | 
    
         
             
                       the returned dictionary has the passed strings as keys and numpy arrays as values
         
     | 
| 
       93 
101 
     | 
    
         
             
                    raw_bisector (bool, default False): if True and grid bisector is requested then it is left in a raw
         
     | 
| 
       94 
102 
     | 
    
         
             
                       form without assessing which side is shallower (True values indicate same side as origin cell)
         
     | 
| 
       95 
     | 
    
         
            -
                    use_pack (bool, default False): if True, boolean properties will be stored in numpy 
     | 
| 
       96 
     | 
    
         
            -
                       which will only be readable by resqpy based applications
         
     | 
| 
      
 103 
     | 
    
         
            +
                    use_pack (bool, default False): if True, boolean properties will be generated and stored in numpy
         
     | 
| 
      
 104 
     | 
    
         
            +
                       packed format, which will only be readable by resqpy based applications
         
     | 
| 
       97 
105 
     | 
    
         
             
                    flange_radius (float, optional): the radial distance to use for outer flange extension points; if None,
         
     | 
| 
       98 
106 
     | 
    
         
             
                       a large value will be calculated from the grid size; units are xy units of grid crs
         
     | 
| 
      
 107 
     | 
    
         
            +
                    reorient (bool, default True):  if True, the points are reoriented to minimise the
         
     | 
| 
      
 108 
     | 
    
         
            +
                       z range prior to retriangulation (ie. z axis is approximate normal to plane of points), to enhace the triangulation
         
     | 
| 
      
 109 
     | 
    
         
            +
                    n_threads (int, default 20): the number of parallel threads to use in numba points in triangles function
         
     | 
| 
      
 110 
     | 
    
         
            +
                    patchwork (bool, default False): if True and grid bisector is included in return properties, a compostite
         
     | 
| 
      
 111 
     | 
    
         
            +
                       bisector is generated, based on individual ones for each patch of the surface; the following two
         
     | 
| 
      
 112 
     | 
    
         
            +
                       arguments must be set if patchwork is True
         
     | 
| 
      
 113 
     | 
    
         
            +
                    grid_patching_property_uuid (uuid, optional): required if patchwork is True, the uuid of a discrete or
         
     | 
| 
      
 114 
     | 
    
         
            +
                       categorical cells property on the grid which will be used to determine which patch of the surface is
         
     | 
| 
      
 115 
     | 
    
         
            +
                       relevant to a cell
         
     | 
| 
      
 116 
     | 
    
         
            +
                    surface_patching_property_uuid (uuid, optional): required if patchwork is True, the uuid of a discrete or
         
     | 
| 
      
 117 
     | 
    
         
            +
                       categorical property on the patches of the surface, identifying the value of the grid patching property
         
     | 
| 
      
 118 
     | 
    
         
            +
                       that each patch relates to
         
     | 
| 
       99 
119 
     | 
    
         | 
| 
       100 
120 
     | 
    
         
             
                returns:
         
     | 
| 
       101 
121 
     | 
    
         
             
                    Tuple containing:
         
     | 
| 
         @@ -105,18 +125,15 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       105 
125 
     | 
    
         
             
                        - uuid_list (List[str]): list of UUIDs of relevant objects
         
     | 
| 
       106 
126 
     | 
    
         | 
| 
       107 
127 
     | 
    
         
             
                notes:
         
     | 
| 
       108 
     | 
    
         
            -
                     
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
             
     | 
| 
       111 
     | 
    
         
            -
                    the saucer_parameter is  
     | 
| 
       112 
     | 
    
         
            -
             
     | 
| 
       113 
     | 
    
         
            -
             
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
     | 
    
         
            -
             
     | 
| 
       116 
     | 
    
         
            -
                     
     | 
| 
       117 
     | 
    
         
            -
                    +ve angles result in the shift being in the direction of the -ve z hemisphere; -ve angles result in
         
     | 
| 
       118 
     | 
    
         
            -
                    the shift being in the +ve z hemisphere; in either case the direction of the shift is perpendicular
         
     | 
| 
       119 
     | 
    
         
            -
                    to the average plane of the original points
         
     | 
| 
      
 128 
     | 
    
         
            +
                    - use this function as argument to the multiprocessing function; it will create a new model that is saved
         
     | 
| 
      
 129 
     | 
    
         
            +
                      in a temporary epc file and returns the required values, which are used in the multiprocessing function to
         
     | 
| 
      
 130 
     | 
    
         
            +
                      recombine all the objects into a single epc file
         
     | 
| 
      
 131 
     | 
    
         
            +
                    - the saucer_parameter is between -90.0 and 90.0 and is interpreted as an angle to apply out of
         
     | 
| 
      
 132 
     | 
    
         
            +
                      the plane of the original points, to give a simple saucer shape;
         
     | 
| 
      
 133 
     | 
    
         
            +
                      +ve angles result in the shift being in the direction of the -ve z hemisphere; -ve angles result in
         
     | 
| 
      
 134 
     | 
    
         
            +
                      the shift being in the +ve z hemisphere; in either case the direction of the shift is perpendicular
         
     | 
| 
      
 135 
     | 
    
         
            +
                      to the average plane of the original points
         
     | 
| 
      
 136 
     | 
    
         
            +
                    - patchwork is not compatible with re-triangulation
         
     | 
| 
       120 
137 
     | 
    
         
             
                """
         
     | 
| 
       121 
138 
     | 
    
         
             
                tmp_dir = Path(parent_tmp_dir) / f"{uuid.uuid4()}"
         
     | 
| 
       122 
139 
     | 
    
         
             
                tmp_dir.mkdir(parents = True, exist_ok = True)
         
     | 
| 
         @@ -144,12 +161,20 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       144 
161 
     | 
    
         
             
                if flange_radius is None:
         
     | 
| 
       145 
162 
     | 
    
         
             
                    flange_radius = 5.0 * np.sum(np.array(grid.extent_kji, dtype = float) * np.array(grid.aligned_dxyz()))
         
     | 
| 
       146 
163 
     | 
    
         
             
                s_model = rq.Model(surface_epc, quiet = True)
         
     | 
| 
       147 
     | 
    
         
            -
                 
     | 
| 
      
 164 
     | 
    
         
            +
                surface_uuid = str(surface_uuid)
         
     | 
| 
      
 165 
     | 
    
         
            +
                model.copy_uuid_from_other_model(s_model, uuid = surface_uuid)
         
     | 
| 
      
 166 
     | 
    
         
            +
                if surface_patching_property_uuid is not None:
         
     | 
| 
      
 167 
     | 
    
         
            +
                    model.copy_uuid_from_other_model(s_model, uuid = surface_patching_property_uuid)
         
     | 
| 
      
 168 
     | 
    
         
            +
                    uuid_list.append(surface_patching_property_uuid)
         
     | 
| 
       148 
169 
     | 
    
         
             
                repr_type = model.type_of_part(model.part(uuid = surface_uuid), strip_obj = True)
         
     | 
| 
       149 
170 
     | 
    
         
             
                assert repr_type in ['TriangulatedSetRepresentation', 'PointSetRepresentation']
         
     | 
| 
      
 171 
     | 
    
         
            +
                assert repr_type == 'TriangulatedSetRepresentation' or not patchwork,  \
         
     | 
| 
      
 172 
     | 
    
         
            +
                    'patchwork only implemented for triangulated set surfaces'
         
     | 
| 
      
 173 
     | 
    
         
            +
             
     | 
| 
       150 
174 
     | 
    
         
             
                extended = False
         
     | 
| 
       151 
175 
     | 
    
         
             
                retriangulated = False
         
     | 
| 
       152 
176 
     | 
    
         
             
                flange_bool = None
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
       153 
178 
     | 
    
         
             
                if repr_type == 'PointSetRepresentation':
         
     | 
| 
       154 
179 
     | 
    
         
             
                    # trim pointset to grid xyz box
         
     | 
| 
       155 
180 
     | 
    
         
             
                    pset = rqs.PointSet(model, uuid = surface_uuid)
         
     | 
| 
         @@ -175,7 +200,7 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       175 
200 
     | 
    
         
             
                    surf = rqs.Surface(model, crs_uuid = grid.crs.uuid, title = surf_title)
         
     | 
| 
       176 
201 
     | 
    
         
             
                    flange_bool = surf.set_from_point_set(pset,
         
     | 
| 
       177 
202 
     | 
    
         
             
                                                          convexity_parameter = 2.0,
         
     | 
| 
       178 
     | 
    
         
            -
                                                          reorient =  
     | 
| 
      
 203 
     | 
    
         
            +
                                                          reorient = reorient,
         
     | 
| 
       179 
204 
     | 
    
         
             
                                                          extend_with_flange = extend_fault_representation,
         
     | 
| 
       180 
205 
     | 
    
         
             
                                                          flange_inner_ring = flange_inner_ring,
         
     | 
| 
       181 
206 
     | 
    
         
             
                                                          saucer_parameter = saucer_parameter,
         
     | 
| 
         @@ -189,19 +214,26 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       189 
214 
     | 
    
         
             
                    inherit_interpretation_relationship(model, surface_uuid, surf.uuid)
         
     | 
| 
       190 
215 
     | 
    
         
             
                    surface_uuid = surf.uuid
         
     | 
| 
       191 
216 
     | 
    
         | 
| 
       192 
     | 
    
         
            -
                surface = rqs.Surface(parent_model = model, uuid =  
     | 
| 
      
 217 
     | 
    
         
            +
                surface = rqs.Surface(parent_model = model, uuid = surface_uuid)
         
     | 
| 
       193 
218 
     | 
    
         
             
                surf_title = surface.title
         
     | 
| 
       194 
219 
     | 
    
         
             
                assert surf_title
         
     | 
| 
       195 
220 
     | 
    
         
             
                surface.change_crs(grid.crs)
         
     | 
| 
      
 221 
     | 
    
         
            +
                normal_vector = None
         
     | 
| 
      
 222 
     | 
    
         
            +
                if reorient:
         
     | 
| 
      
 223 
     | 
    
         
            +
                    normal_vector = surface.normal()
         
     | 
| 
      
 224 
     | 
    
         
            +
                if patchwork:  # disable trimming as whole patches could be trimmed out, changing the patch indexing from that expected
         
     | 
| 
      
 225 
     | 
    
         
            +
                    trimmed = True
         
     | 
| 
       196 
226 
     | 
    
         
             
                if not trimmed and surface.triangle_count() > 100:
         
     | 
| 
       197 
227 
     | 
    
         
             
                    if not surf_title.endswith('trimmed'):
         
     | 
| 
       198 
228 
     | 
    
         
             
                        surf_title += ' trimmed'
         
     | 
| 
       199 
229 
     | 
    
         
             
                    trimmed_surf = rqs.Surface(model, crs_uuid = grid.crs.uuid, title = surf_title)
         
     | 
| 
       200 
230 
     | 
    
         
             
                    # trimmed_surf.set_to_trimmed_surface(surf, xyz_box = xyz_box, xy_polygon = parent_seg.polygon)
         
     | 
| 
       201 
231 
     | 
    
         
             
                    trimmed_surf.set_to_trimmed_surface(surface, xyz_box = grid.xyz_box(local = True))
         
     | 
| 
      
 232 
     | 
    
         
            +
                    trimmed_surf.extra_metadata = surface.extra_metadata
         
     | 
| 
       202 
233 
     | 
    
         
             
                    surface = trimmed_surf
         
     | 
| 
       203 
234 
     | 
    
         
             
                    trimmed = True
         
     | 
| 
       204 
235 
     | 
    
         
             
                if (extend_fault_representation and not extended) or (retriangulate and not retriangulated):
         
     | 
| 
      
 236 
     | 
    
         
            +
                    assert not patchwork, 'extension or re-triangulation are not compatible with patchwork'
         
     | 
| 
       205 
237 
     | 
    
         
             
                    _, p = surface.triangles_and_points()
         
     | 
| 
       206 
238 
     | 
    
         
             
                    pset = rqs.PointSet(model, points_array = p, crs_uuid = grid.crs.uuid, title = surf_title)
         
     | 
| 
       207 
239 
     | 
    
         
             
                    if extend_fault_representation and not surf_title.endswith('extended'):
         
     | 
| 
         @@ -209,12 +241,13 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       209 
241 
     | 
    
         
             
                    surface = rqs.Surface(model, crs_uuid = grid.crs.uuid, title = surf_title)
         
     | 
| 
       210 
242 
     | 
    
         
             
                    flange_bool = surface.set_from_point_set(pset,
         
     | 
| 
       211 
243 
     | 
    
         
             
                                                             convexity_parameter = 2.0,
         
     | 
| 
       212 
     | 
    
         
            -
                                                             reorient =  
     | 
| 
      
 244 
     | 
    
         
            +
                                                             reorient = reorient,
         
     | 
| 
       213 
245 
     | 
    
         
             
                                                             extend_with_flange = extend_fault_representation,
         
     | 
| 
       214 
246 
     | 
    
         
             
                                                             flange_inner_ring = flange_inner_ring,
         
     | 
| 
       215 
247 
     | 
    
         
             
                                                             saucer_parameter = saucer_parameter,
         
     | 
| 
       216 
248 
     | 
    
         
             
                                                             flange_radial_distance = flange_radius,
         
     | 
| 
       217 
     | 
    
         
            -
                                                             make_clockwise = False 
     | 
| 
      
 249 
     | 
    
         
            +
                                                             make_clockwise = False,
         
     | 
| 
      
 250 
     | 
    
         
            +
                                                             normal_vector = normal_vector)
         
     | 
| 
       218 
251 
     | 
    
         
             
                    del pset
         
     | 
| 
       219 
252 
     | 
    
         
             
                    extended = extend_fault_representation
         
     | 
| 
       220 
253 
     | 
    
         
             
                    retriangulated = True
         
     | 
| 
         @@ -235,9 +268,26 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       235 
268 
     | 
    
         
             
                                                       property_kind = 'flange bool',
         
     | 
| 
       236 
269 
     | 
    
         
             
                                                       find_local_property_kind = True,
         
     | 
| 
       237 
270 
     | 
    
         
             
                                                       indexable_element = 'faces',
         
     | 
| 
       238 
     | 
    
         
            -
                                                       discrete = True 
     | 
| 
      
 271 
     | 
    
         
            +
                                                       discrete = True,
         
     | 
| 
      
 272 
     | 
    
         
            +
                                                       dtype = np.uint8)
         
     | 
| 
       239 
273 
     | 
    
         
             
                    uuid_list.append(flange_p.uuid)
         
     | 
| 
       240 
     | 
    
         
            -
             
     | 
| 
      
 274 
     | 
    
         
            +
             
     | 
| 
      
 275 
     | 
    
         
            +
                if not patchwork:
         
     | 
| 
      
 276 
     | 
    
         
            +
                    uuid_list.append(surface_uuid)
         
     | 
| 
      
 277 
     | 
    
         
            +
             
     | 
| 
      
 278 
     | 
    
         
            +
                patch_indices = None
         
     | 
| 
      
 279 
     | 
    
         
            +
                if patchwork:  # generate a patch indices array over grid cells based on supplied patching properties
         
     | 
| 
      
 280 
     | 
    
         
            +
                    assert grid_patching_property_uuid is not None and surface_patching_property_uuid is not None
         
     | 
| 
      
 281 
     | 
    
         
            +
                    g_patching_array = rqp.Property(g_model, uuid = grid_patching_property_uuid).array_ref()
         
     | 
| 
      
 282 
     | 
    
         
            +
                    assert g_patching_array.shape == tuple(grid.extent_kji)
         
     | 
| 
      
 283 
     | 
    
         
            +
                    s_patches_array = rqp.Property(model, uuid = surface_patching_property_uuid).array_ref()
         
     | 
| 
      
 284 
     | 
    
         
            +
                    patch_count = surface.number_of_patches()
         
     | 
| 
      
 285 
     | 
    
         
            +
                    assert s_patches_array.shape == (patch_count,)
         
     | 
| 
      
 286 
     | 
    
         
            +
                    p_dtype = (np.int8 if s_patches_array.shape[0] < 127 else np.int32)
         
     | 
| 
      
 287 
     | 
    
         
            +
                    patch_indices = np.full(g_patching_array.shape, -1, dtype = p_dtype)
         
     | 
| 
      
 288 
     | 
    
         
            +
                    for patch in range(patch_count):
         
     | 
| 
      
 289 
     | 
    
         
            +
                        gp = s_patches_array[patch]
         
     | 
| 
      
 290 
     | 
    
         
            +
                        patch_indices[(g_patching_array == gp).astype(bool)] = patch
         
     | 
| 
       241 
291 
     | 
    
         | 
| 
       242 
292 
     | 
    
         
             
                returns = rqgs.find_faces_to_represent_surface_regular_optimised(grid,
         
     | 
| 
       243 
293 
     | 
    
         
             
                                                                                 surface,
         
     | 
| 
         @@ -249,7 +299,10 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       249 
299 
     | 
    
         
             
                                                                                 is_curtain,
         
     | 
| 
       250 
300 
     | 
    
         
             
                                                                                 progress_fn,
         
     | 
| 
       251 
301 
     | 
    
         
             
                                                                                 return_properties,
         
     | 
| 
       252 
     | 
    
         
            -
                                                                                 raw_bisector = raw_bisector 
     | 
| 
      
 302 
     | 
    
         
            +
                                                                                 raw_bisector = raw_bisector,
         
     | 
| 
      
 303 
     | 
    
         
            +
                                                                                 n_batches = n_threads,
         
     | 
| 
      
 304 
     | 
    
         
            +
                                                                                 packed_bisectors = use_pack,
         
     | 
| 
      
 305 
     | 
    
         
            +
                                                                                 patch_indices = patch_indices)
         
     | 
| 
       253 
306 
     | 
    
         | 
| 
       254 
307 
     | 
    
         
             
                success = False
         
     | 
| 
       255 
308 
     | 
    
         | 
| 
         @@ -279,6 +332,7 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       279 
332 
     | 
    
         | 
| 
       280 
333 
     | 
    
         
             
                if success and return_properties is not None and len(return_properties):
         
     | 
| 
       281 
334 
     | 
    
         
             
                    log.debug(f'{name} requested properties: {return_properties}')
         
     | 
| 
      
 335 
     | 
    
         
            +
                    assert isinstance(returns, tuple)
         
     | 
| 
       282 
336 
     | 
    
         
             
                    properties = returns[1]
         
     | 
| 
       283 
337 
     | 
    
         
             
                    realisation = index if use_index_as_realisation else None
         
     | 
| 
       284 
338 
     | 
    
         
             
                    property_collection = rqp.PropertyCollection(support = gcs)
         
     | 
| 
         @@ -339,17 +393,18 @@ def find_faces_to_represent_surface_regular_wrapper( 
     | 
|
| 
       339 
393 
     | 
    
         
             
                            if grid_pc is None:
         
     | 
| 
       340 
394 
     | 
    
         
             
                                grid_pc = rqp.PropertyCollection()
         
     | 
| 
       341 
395 
     | 
    
         
             
                                grid_pc.set_support(support = grid)
         
     | 
| 
       342 
     | 
    
         
            -
                             
     | 
| 
       343 
     | 
    
         
            -
             
     | 
| 
       344 
     | 
    
         
            -
             
     | 
| 
       345 
     | 
    
         
            -
             
     | 
| 
       346 
     | 
    
         
            -
             
     | 
| 
       347 
     | 
    
         
            -
             
     | 
| 
       348 
     | 
    
         
            -
             
     | 
| 
       349 
     | 
    
         
            -
             
     | 
| 
       350 
     | 
    
         
            -
             
     | 
| 
       351 
     | 
    
         
            -
             
     | 
| 
       352 
     | 
    
         
            -
             
     | 
| 
      
 396 
     | 
    
         
            +
                            assert array.ndim == (2 if is_curtain else 3)
         
     | 
| 
      
 397 
     | 
    
         
            +
                            grid_pc.add_cached_array_to_imported_list(array,
         
     | 
| 
      
 398 
     | 
    
         
            +
                                                                      f"from find_faces function for {surface.title}",
         
     | 
| 
      
 399 
     | 
    
         
            +
                                                                      f'{surface.title} {p_name}',
         
     | 
| 
      
 400 
     | 
    
         
            +
                                                                      discrete = True,
         
     | 
| 
      
 401 
     | 
    
         
            +
                                                                      property_kind = "grid bisector",
         
     | 
| 
      
 402 
     | 
    
         
            +
                                                                      facet_type = 'direction',
         
     | 
| 
      
 403 
     | 
    
         
            +
                                                                      facet = 'raw' if raw_bisector else
         
     | 
| 
      
 404 
     | 
    
         
            +
                                                                      ('vertical' if is_curtain else 'sloping'),
         
     | 
| 
      
 405 
     | 
    
         
            +
                                                                      realization = realisation,
         
     | 
| 
      
 406 
     | 
    
         
            +
                                                                      indexable_element = "columns" if is_curtain else "cells",
         
     | 
| 
      
 407 
     | 
    
         
            +
                                                                      pre_packed = False if is_curtain else use_pack)
         
     | 
| 
       353 
408 
     | 
    
         
             
                        elif p_name == 'grid shadow':
         
     | 
| 
       354 
409 
     | 
    
         
             
                            if grid_pc is None:
         
     | 
| 
       355 
410 
     | 
    
         
             
                                grid_pc = rqp.PropertyCollection()
         
     | 
    
        resqpy/olio/read_nexus_fault.py
    CHANGED
    
    | 
         @@ -64,7 +64,10 @@ def load_nexus_fault_mult_table_from_list(file_as_list): 
     | 
|
| 
       64 
64 
     | 
    
         
             
                                    outdata[mask] = np.concatenate(d_elems)
         
     | 
| 
       65 
65 
     | 
    
         
             
                                    df = pd.DataFrame(outdata)
         
     | 
| 
       66 
66 
     | 
    
         
             
                                    for column in df.columns:
         
     | 
| 
       67 
     | 
    
         
            -
                                         
     | 
| 
      
 67 
     | 
    
         
            +
                                        try:
         
     | 
| 
      
 68 
     | 
    
         
            +
                                            df[column] = pd.to_numeric(df[column], errors = "coerce")
         
     | 
| 
      
 69 
     | 
    
         
            +
                                        except ValueError:
         
     | 
| 
      
 70 
     | 
    
         
            +
                                            pass
         
     | 
| 
       68 
71 
     | 
    
         
             
                                    df.columns = ['i1', 'i2', 'j1', 'j2', 'k1', 'k2', 'mult']
         
     | 
| 
       69 
72 
     | 
    
         
             
                                    df['grid'] = grid
         
     | 
| 
       70 
73 
     | 
    
         
             
                                    df['name'] = name
         
     | 
| 
         @@ -114,7 +117,10 @@ def load_nexus_fault_mult_table_from_list(file_as_list): 
     | 
|
| 
       114 
117 
     | 
    
         
             
                            outdata[mask] = np.concatenate(d_elems)
         
     | 
| 
       115 
118 
     | 
    
         
             
                            df = pd.DataFrame(outdata)
         
     | 
| 
       116 
119 
     | 
    
         
             
                            for column in df.columns:
         
     | 
| 
       117 
     | 
    
         
            -
                                 
     | 
| 
      
 120 
     | 
    
         
            +
                                try:
         
     | 
| 
      
 121 
     | 
    
         
            +
                                    df[column] = pd.to_numeric(df[column], errors = "coerce")
         
     | 
| 
      
 122 
     | 
    
         
            +
                                except ValueError:
         
     | 
| 
      
 123 
     | 
    
         
            +
                                    pass
         
     | 
| 
       118 
124 
     | 
    
         
             
                            df.columns = ['i1', 'i2', 'j1', 'j2', 'k1', 'k2', 'mult']
         
     | 
| 
       119 
125 
     | 
    
         
             
                            df['grid'] = grid
         
     | 
| 
       120 
126 
     | 
    
         
             
                            df['name'] = name
         
     | 
    
        resqpy/olio/relperm.py
    CHANGED
    
    | 
         @@ -91,7 +91,7 @@ class RelPerm(DataFrame): 
     | 
|
| 
       91 
91 
     | 
    
         
             
                        processed_phase_combo_checks.get(processed_phase_combo)(df)
         
     | 
| 
       92 
92 
     | 
    
         
             
                        # ensure that missing capillary pressure values are stored as np.nan
         
     | 
| 
       93 
93 
     | 
    
         
             
                        if 'Pc' in df.columns:
         
     | 
| 
       94 
     | 
    
         
            -
                            df['Pc'].replace('None', np.nan 
     | 
| 
      
 94 
     | 
    
         
            +
                            df['Pc'] = df['Pc'].replace('None', np.nan)
         
     | 
| 
       95 
95 
     | 
    
         
             
                        # convert all values in the dataframe to numeric type
         
     | 
| 
       96 
96 
     | 
    
         
             
                        df[df.columns] = df[df.columns].apply(pd.to_numeric, errors = 'coerce')
         
     | 
| 
       97 
97 
     | 
    
         
             
                        # ensure that no other column besides Pc has missing values
         
     | 
    
        resqpy/olio/transmission.py
    CHANGED
    
    | 
         @@ -260,10 +260,10 @@ def half_cell_t_irregular(grid, 
     | 
|
| 
       260 
260 
     | 
    
         
             
                        zero_length_mask = np.logical_or(np.any(np.isnan(half_axis_vectors), axis = -1),
         
     | 
| 
       261 
261 
     | 
    
         
             
                                                         half_axis_length_sqr < tolerance_sqr)
         
     | 
| 
       262 
262 
     | 
    
         
             
                        minus_face_t = np.where(
         
     | 
| 
       263 
     | 
    
         
            -
                            zero_length_mask, np. 
     | 
| 
      
 263 
     | 
    
         
            +
                            zero_length_mask, np.nan,
         
     | 
| 
       264 
264 
     | 
    
         
             
                            perm_k * np.sum(half_axis_vectors * minus_face_areas, axis = -1) / half_axis_length_sqr)
         
     | 
| 
       265 
265 
     | 
    
         
             
                        plus_face_t = np.where(
         
     | 
| 
       266 
     | 
    
         
            -
                            zero_length_mask, np. 
     | 
| 
      
 266 
     | 
    
         
            +
                            zero_length_mask, np.nan,
         
     | 
| 
       267 
267 
     | 
    
         
             
                            perm_k * np.sum(half_axis_vectors * plus_face_areas, axis = -1) / half_axis_length_sqr)
         
     | 
| 
       268 
268 
     | 
    
         | 
| 
       269 
269 
     | 
    
         
             
                    elif axis == 1:  # j
         
     | 
| 
         @@ -303,10 +303,10 @@ def half_cell_t_irregular(grid, 
     | 
|
| 
       303 
303 
     | 
    
         
             
                        half_axis_length_sqr = np.sum(half_axis_vectors * half_axis_vectors, axis = -1)
         
     | 
| 
       304 
304 
     | 
    
         
             
                        zero_length_mask = (half_axis_length_sqr < tolerance_sqr)
         
     | 
| 
       305 
305 
     | 
    
         
             
                        minus_face_t = np.where(
         
     | 
| 
       306 
     | 
    
         
            -
                            zero_length_mask, np. 
     | 
| 
      
 306 
     | 
    
         
            +
                            zero_length_mask, np.nan,
         
     | 
| 
       307 
307 
     | 
    
         
             
                            perm_j * np.sum(half_axis_vectors * minus_face_areas, axis = -1) / half_axis_length_sqr)
         
     | 
| 
       308 
308 
     | 
    
         
             
                        plus_face_t = np.where(
         
     | 
| 
       309 
     | 
    
         
            -
                            zero_length_mask, np. 
     | 
| 
      
 309 
     | 
    
         
            +
                            zero_length_mask, np.nan,
         
     | 
| 
       310 
310 
     | 
    
         
             
                            perm_j * np.sum(half_axis_vectors * plus_face_areas, axis = -1) / half_axis_length_sqr)
         
     | 
| 
       311 
311 
     | 
    
         | 
| 
       312 
312 
     | 
    
         
             
                    else:  # i
         
     | 
| 
         @@ -345,10 +345,10 @@ def half_cell_t_irregular(grid, 
     | 
|
| 
       345 
345 
     | 
    
         
             
                        half_axis_length_sqr = np.sum(half_axis_vectors * half_axis_vectors, axis = -1)
         
     | 
| 
       346 
346 
     | 
    
         
             
                        zero_length_mask = (half_axis_length_sqr < tolerance_sqr)
         
     | 
| 
       347 
347 
     | 
    
         
             
                        minus_face_t = np.where(
         
     | 
| 
       348 
     | 
    
         
            -
                            zero_length_mask, np. 
     | 
| 
      
 348 
     | 
    
         
            +
                            zero_length_mask, np.nan,
         
     | 
| 
       349 
349 
     | 
    
         
             
                            perm_i * np.sum(half_axis_vectors * minus_face_areas, axis = -1) / half_axis_length_sqr)
         
     | 
| 
       350 
350 
     | 
    
         
             
                        plus_face_t = np.where(
         
     | 
| 
       351 
     | 
    
         
            -
                            zero_length_mask, np. 
     | 
| 
      
 351 
     | 
    
         
            +
                            zero_length_mask, np.nan,
         
     | 
| 
       352 
352 
     | 
    
         
             
                            perm_i * np.sum(half_axis_vectors * plus_face_areas, axis = -1) / half_axis_length_sqr)
         
     | 
| 
       353 
353 
     | 
    
         | 
| 
       354 
354 
     | 
    
         
             
                    if axis != 0 and ntg is not None:
         
     | 
| 
         @@ -417,14 +417,14 @@ def half_cell_t_vertical_prism(vpg, 
     | 
|
| 
       417 
417 
     | 
    
         
             
                # compute transmissibilities
         
     | 
| 
       418 
418 
     | 
    
         
             
                tr = np.zeros((vpg.cell_count, 5), dtype = float)
         
     | 
| 
       419 
419 
     | 
    
         
             
                # vertical
         
     | 
| 
       420 
     | 
    
         
            -
                tr[:, 0] = np.where(half_thickness < tolerance, np. 
     | 
| 
      
 420 
     | 
    
         
            +
                tr[:, 0] = np.where(half_thickness < tolerance, np.nan, (perm_k.reshape(
         
     | 
| 
       421 
421 
     | 
    
         
             
                    (vpg.nk, -1)) * triangle_areas / half_thickness)).flatten()
         
     | 
| 
       422 
422 
     | 
    
         
             
                tr[:, 1] = tr[:, 0]
         
     | 
| 
       423 
423 
     | 
    
         
             
                # horizontal
         
     | 
| 
       424 
424 
     | 
    
         
             
                # TODO: compute dip adjustments for non-vertical transmissibilities
         
     | 
| 
       425 
425 
     | 
    
         
             
                dt_full = np.empty((vpg.nk, vpg.cell_count // vpg.nk, 3), dtype = float)
         
     | 
| 
       426 
426 
     | 
    
         
             
                dt_full[:] = d_t
         
     | 
| 
       427 
     | 
    
         
            -
                tr[:, 2:] = np.where(dt_full < tolerance, np. 
     | 
| 
      
 427 
     | 
    
         
            +
                tr[:, 2:] = np.where(dt_full < tolerance, np.nan,
         
     | 
| 
       428 
428 
     | 
    
         
             
                                     triple_perm_horizontal.reshape((vpg.nk, -1, 3)) * a_t.reshape((1, -1, 3)) / dt_full).reshape(
         
     | 
| 
       429 
429 
     | 
    
         
             
                                         (-1, 3))
         
     | 
| 
       430 
430 
     | 
    
         
             
                if ntg is not None:
         
     | 
    
        resqpy/olio/triangulation.py
    CHANGED
    
    | 
         @@ -25,7 +25,7 @@ import resqpy.olio.vector_utilities as vec 
     | 
|
| 
       25 
25 
     | 
    
         | 
| 
       26 
26 
     | 
    
         
             
            def _dt_scipy(points: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
         
     | 
| 
       27 
27 
     | 
    
         
             
                """Calculates the Delaunay triangulation for an array of points and the convex hull indices.
         
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
       29 
29 
     | 
    
         
             
                arguments:
         
     | 
| 
       30 
30 
     | 
    
         
             
                    points (np.ndarray): coordinates of the points to triangulate; array has shape
         
     | 
| 
       31 
31 
     | 
    
         
             
                        (npoints, ndim)
         
     | 
| 
         @@ -48,7 +48,7 @@ def _dt_scipy(points: np.ndarray) -> Tuple[np.ndarray, np.ndarray]: 
     | 
|
| 
       48 
48 
     | 
    
         | 
| 
       49 
49 
     | 
    
         | 
| 
       50 
50 
     | 
    
         
             
            def _dt_simple(po, plot_fn = None, progress_fn = None, container_size_factor = None):
         
     | 
| 
       51 
     | 
    
         
            -
                # returns  
     | 
| 
      
 51 
     | 
    
         
            +
                # returns Delaunay triangulation of po and list of hull point indices, using a simple algorithm
         
     | 
| 
       52 
52 
     | 
    
         | 
| 
       53 
53 
     | 
    
         
             
                def flip(ei):
         
     | 
| 
       54 
54 
     | 
    
         
             
                    nonlocal fm, e, t, te, p, nt, p_i, ne
         
     | 
| 
         @@ -115,7 +115,7 @@ def _dt_simple(po, plot_fn = None, progress_fn = None, container_size_factor = N 
     | 
|
| 
       115 
115 
     | 
    
         
             
                if n_p < 3:
         
     | 
| 
       116 
116 
     | 
    
         
             
                    return None, None  # not enough points
         
     | 
| 
       117 
117 
     | 
    
         
             
                elif n_p == 3:
         
     | 
| 
       118 
     | 
    
         
            -
                    return np.array([0, 1, 2], dtype =  
     | 
| 
      
 118 
     | 
    
         
            +
                    return np.array([0, 1, 2], dtype = np.int32).reshape((1, 3)), np.array([0, 1, 2], dtype = np.int32)
         
     | 
| 
       119 
119 
     | 
    
         | 
| 
       120 
120 
     | 
    
         
             
                if progress_fn is not None:
         
     | 
| 
       121 
121 
     | 
    
         
             
                    progress_fn(0.0)
         
     | 
| 
         @@ -133,19 +133,20 @@ def _dt_simple(po, plot_fn = None, progress_fn = None, container_size_factor = N 
     | 
|
| 
       133 
133 
     | 
    
         
             
                p[-1] = (min_xy[0] + 0.5 * csf * dxy[0], max_xy[1] + 0.8 * csf * dxy[1])
         
     | 
| 
       134 
134 
     | 
    
         | 
| 
       135 
135 
     | 
    
         
             
                # triangle vertex indices
         
     | 
| 
       136 
     | 
    
         
            -
                 
     | 
| 
      
 136 
     | 
    
         
            +
                t_type = np.int32 if n_p < 2_147_483_648 else np.int64
         
     | 
| 
      
 137 
     | 
    
         
            +
                t = np.empty((2 * n_p + 2, 3), dtype = t_type)  # empty space for triangle vertex indices
         
     | 
| 
       137 
138 
     | 
    
         
             
                t[0] = (n_p, n_p + 1, n_p + 2)  # initial set of one containing triangle
         
     | 
| 
       138 
139 
     | 
    
         
             
                nt = 1  # number of triangles so far populated
         
     | 
| 
       139 
140 
     | 
    
         | 
| 
       140 
141 
     | 
    
         
             
                # edges: list of indices of triangles and edge within triangle; -1 indicates no triangle using edge
         
     | 
| 
       141 
     | 
    
         
            -
                e = np.full((3 * n_p + 6, 2, 2), fill_value = -1, dtype =  
     | 
| 
      
 142 
     | 
    
         
            +
                e = np.full((3 * n_p + 6, 2, 2), fill_value = -1, dtype = t_type)
         
     | 
| 
       142 
143 
     | 
    
         
             
                e[:3, 0, 0] = 0
         
     | 
| 
       143 
144 
     | 
    
         
             
                for edge in range(3):
         
     | 
| 
       144 
145 
     | 
    
         
             
                    e[edge, 0, 1] = edge
         
     | 
| 
       145 
146 
     | 
    
         
             
                ne = 3  # number of edges so far in use
         
     | 
| 
       146 
147 
     | 
    
         | 
| 
       147 
148 
     | 
    
         
             
                # edge indices (in e) for each triangle, first axis indexed in sync with t
         
     | 
| 
       148 
     | 
    
         
            -
                te = np.empty((2 * n_p + 2, 3), dtype =  
     | 
| 
      
 149 
     | 
    
         
            +
                te = np.empty((2 * n_p + 2, 3), dtype = t_type)  # empty space for triangle edge indices
         
     | 
| 
       149 
150 
     | 
    
         
             
                te[0] = (0, 1, 2)
         
     | 
| 
       150 
151 
     | 
    
         | 
| 
       151 
152 
     | 
    
         
             
                # mask tracking which edges have been flipped
         
     | 
| 
         @@ -233,7 +234,7 @@ def _dt_simple(po, plot_fn = None, progress_fn = None, container_size_factor = N 
     | 
|
| 
       233 
234 
     | 
    
         | 
| 
       234 
235 
     | 
    
         | 
| 
       235 
236 
     | 
    
         
             
            def dt(p, algorithm = "scipy", plot_fn = None, progress_fn = None, container_size_factor = 100.0, return_hull = False):
         
     | 
| 
       236 
     | 
    
         
            -
                """Returns the  
     | 
| 
      
 237 
     | 
    
         
            +
                """Returns the Delaunay Triangulation of 2D point set p.
         
     | 
| 
       237 
238 
     | 
    
         | 
| 
       238 
239 
     | 
    
         
             
                arguments:
         
     | 
| 
       239 
240 
     | 
    
         
             
                   p (numpy float array of shape (N, 2): the x,y coordinates of the points
         
     | 
| 
         @@ -252,7 +253,7 @@ def dt(p, algorithm = "scipy", plot_fn = None, progress_fn = None, container_siz 
     | 
|
| 
       252 
253 
     | 
    
         | 
| 
       253 
254 
     | 
    
         
             
                returns:
         
     | 
| 
       254 
255 
     | 
    
         
             
                   numpy int array of shape (M, 3) - being the indices into the first axis of p of the 3 points
         
     | 
| 
       255 
     | 
    
         
            -
                      per triangle in the  
     | 
| 
      
 256 
     | 
    
         
            +
                      per triangle in the Delaunay Triangulation - and if return_hull is True, another int array
         
     | 
| 
       256 
257 
     | 
    
         
             
                      of shape (B,) - being indices into p of the clockwise ordered points on the boundary of
         
     | 
| 
       257 
258 
     | 
    
         
             
                      the triangulation
         
     | 
| 
       258 
259 
     | 
    
         | 
| 
         @@ -260,7 +261,7 @@ def dt(p, algorithm = "scipy", plot_fn = None, progress_fn = None, container_siz 
     | 
|
| 
       260 
261 
     | 
    
         
             
                   the plot_fn, progress_fn and container_size_factor arguments are only used by the 'simple' algorithm;
         
     | 
| 
       261 
262 
     | 
    
         
             
                   if points p are 3D, the projection onto the xy plane is used for the triangulation
         
     | 
| 
       262 
263 
     | 
    
         
             
                """
         
     | 
| 
       263 
     | 
    
         
            -
                assert p.ndim == 2 and p.shape[1] >= 2, 'bad points shape for 2D  
     | 
| 
      
 264 
     | 
    
         
            +
                assert p.ndim == 2 and p.shape[1] >= 2, 'bad points shape for 2D Delaunay Triangulation'
         
     | 
| 
       264 
265 
     | 
    
         | 
| 
       265 
266 
     | 
    
         
             
                if not algorithm:
         
     | 
| 
       266 
267 
     | 
    
         
             
                    algorithm = 'scipy'
         
     | 
| 
         @@ -273,7 +274,7 @@ def dt(p, algorithm = "scipy", plot_fn = None, progress_fn = None, container_siz 
     | 
|
| 
       273 
274 
     | 
    
         
             
                                               progress_fn = progress_fn,
         
     | 
| 
       274 
275 
     | 
    
         
             
                                               container_size_factor = container_size_factor)
         
     | 
| 
       275 
276 
     | 
    
         
             
                else:
         
     | 
| 
       276 
     | 
    
         
            -
                    raise Exception(f'unrecognised  
     | 
| 
      
 277 
     | 
    
         
            +
                    raise Exception(f'unrecognised Delaunay Triangulation algorithm name: {algorithm}')
         
     | 
| 
       277 
278 
     | 
    
         | 
| 
       278 
279 
     | 
    
         
             
                assert tri.ndim == 2 and tri.shape[1] == 3
         
     | 
| 
       279 
280 
     | 
    
         | 
| 
         @@ -303,11 +304,11 @@ def ccc(p1, p2, p3): 
     | 
|
| 
       303 
304 
     | 
    
         | 
| 
       304 
305 
     | 
    
         | 
| 
       305 
306 
     | 
    
         
             
            def voronoi(p, t, b, aoi: rql.Polyline):
         
     | 
| 
       306 
     | 
    
         
            -
                """Returns dual Voronoi diagram for a  
     | 
| 
      
 307 
     | 
    
         
            +
                """Returns dual Voronoi diagram for a Delaunay triangulation.
         
     | 
| 
       307 
308 
     | 
    
         | 
| 
       308 
309 
     | 
    
         
             
                arguments:
         
     | 
| 
       309 
     | 
    
         
            -
                   p (numpy float array of shape (N, 2)): seed points used in the  
     | 
| 
       310 
     | 
    
         
            -
                   t (numpy int array of shape (M, 3)): the  
     | 
| 
      
 310 
     | 
    
         
            +
                   p (numpy float array of shape (N, 2)): seed points used in the Delaunay triangulation
         
     | 
| 
      
 311 
     | 
    
         
            +
                   t (numpy int array of shape (M, 3)): the Delaunay triangulation of p as returned by dt()
         
     | 
| 
       311 
312 
     | 
    
         
             
                   b (numpy int array of shape (B,)): clockwise sorted list of indices into p of the boundary
         
     | 
| 
       312 
313 
     | 
    
         
             
                      points of the triangulation t
         
     | 
| 
       313 
314 
     | 
    
         
             
                   aoi (lines.Polyline): area of interest; a closed clockwise polyline that must strictly contain
         
     | 
| 
         @@ -328,7 +329,7 @@ def voronoi(p, t, b, aoi: rql.Polyline): 
     | 
|
| 
       328 
329 
     | 
    
         | 
| 
       329 
330 
     | 
    
         
             
                # this code assumes that the Voronoi polygon for a seed point visits the circumcentres of
         
     | 
| 
       330 
331 
     | 
    
         
             
                # all the triangles that make use of the point – currently understood to be always the case
         
     | 
| 
       331 
     | 
    
         
            -
                # for a  
     | 
| 
      
 332 
     | 
    
         
            +
                # for a Delaunay triangulation
         
     | 
| 
       332 
333 
     | 
    
         | 
| 
       333 
334 
     | 
    
         
             
                def __aoi_intervening_nodes(aoi_count, c_count, seg_a, seg_c):
         
     | 
| 
       334 
335 
     | 
    
         
             
                    nodes = []
         
     | 
| 
         @@ -501,7 +502,7 @@ def voronoi(p, t, b, aoi: rql.Polyline): 
     | 
|
| 
       501 
502 
     | 
    
         
             
                    return trimmed_ci
         
     | 
| 
       502 
503 
     | 
    
         | 
| 
       503 
504 
     | 
    
         
             
                def __veroni_cells(aoi_count, aoi_intersect_segments, b, c, c_count, ca_count, cah_count, caho_count, cahon_count,
         
     | 
| 
       504 
     | 
    
         
            -
                                   hull_count, out_pair_intersect_segments, p, t, tc_outwith_aoi):
         
     | 
| 
      
 505 
     | 
    
         
            +
                                   hull_count, out_pair_intersect_segments, p, t, tc_outwith_aoi, t_type):
         
     | 
| 
       505 
506 
     | 
    
         
             
                    # list of voronoi cells (each a numpy list of node indices into c extended with aoi points etc)
         
     | 
| 
       506 
507 
     | 
    
         
             
                    v = []
         
     | 
| 
       507 
508 
     | 
    
         
             
                    # for each seed point build the voronoi cell
         
     | 
| 
         @@ -550,7 +551,7 @@ def voronoi(p, t, b, aoi: rql.Polyline): 
     | 
|
| 
       550 
551 
     | 
    
         
             
                                                              ci_for_p, out_pair_intersect_segments)
         
     | 
| 
       551 
552 
     | 
    
         | 
| 
       552 
553 
     | 
    
         
             
                        #  remove circumcircle centres that are outwith area of interest
         
     | 
| 
       553 
     | 
    
         
            -
                        ci_for_p = np.array([ti for ti in ci_for_p if ti >= c_count or ti not in tc_outwith_aoi], dtype =  
     | 
| 
      
 554 
     | 
    
         
            +
                        ci_for_p = np.array([ti for ti in ci_for_p if ti >= c_count or ti not in tc_outwith_aoi], dtype = t_type)
         
     | 
| 
       554 
555 
     | 
    
         | 
| 
       555 
556 
     | 
    
         
             
                        # find azimuths of vectors from seed point to circumcircle centres and aoi boundary points
         
     | 
| 
       556 
557 
     | 
    
         
             
                        azi = [vec.azimuth(centre - p[p_i, :2]) for centre in c[ci_for_p, :2]]
         
     | 
| 
         @@ -581,7 +582,7 @@ def voronoi(p, t, b, aoi: rql.Polyline): 
     | 
|
| 
       581 
582 
     | 
    
         | 
| 
       582 
583 
     | 
    
         
             
                # check for concavities in hull
         
     | 
| 
       583 
584 
     | 
    
         
             
                if not hull.is_convex():
         
     | 
| 
       584 
     | 
    
         
            -
                    log.warning(' 
     | 
| 
      
 585 
     | 
    
         
            +
                    log.warning('Delaunay triangulation is not convex; Voronoi diagram construction might fail')
         
     | 
| 
       585 
586 
     | 
    
         | 
| 
       586 
587 
     | 
    
         
             
                # compute circumcircle centres
         
     | 
| 
       587 
588 
     | 
    
         
             
                c = np.zeros((t.shape[0], 2))
         
     | 
| 
         @@ -612,11 +613,12 @@ def voronoi(p, t, b, aoi: rql.Polyline): 
     | 
|
| 
       612 
613 
     | 
    
         
             
                caho_count = cah_count + 2 * o_count
         
     | 
| 
       613 
614 
     | 
    
         
             
                cahon_count = caho_count + hull_count
         
     | 
| 
       614 
615 
     | 
    
         
             
                assert cahon_count + hull_count == len(c)
         
     | 
| 
      
 616 
     | 
    
         
            +
                t_type = np.int32 if len(c) < 2_147_483_648 else np.int64
         
     | 
| 
       615 
617 
     | 
    
         | 
| 
       616 
618 
     | 
    
         
             
                #  compute intersection points between hull edge normals and aoi polyline
         
     | 
| 
       617 
619 
     | 
    
         
             
                # also extended virtual centres for hull edges
         
     | 
| 
       618 
620 
     | 
    
         
             
                extension_scaling = 1000.0 * np.sum((np.max(aoi.coordinates, axis = 0) - np.min(aoi.coordinates, axis = 0))[:2])
         
     | 
| 
       619 
     | 
    
         
            -
                aoi_intersect_segments = np.empty((hull_count,), dtype =  
     | 
| 
      
 621 
     | 
    
         
            +
                aoi_intersect_segments = np.empty((hull_count,), dtype = t_type)
         
     | 
| 
       620 
622 
     | 
    
         
             
                for ei in range(hull_count):
         
     | 
| 
       621 
623 
     | 
    
         
             
                    # use segment midpoint and normal methods of hull to project out
         
     | 
| 
       622 
624 
     | 
    
         
             
                    m = hull.segment_midpoint(ei)[:2]  # midpoint
         
     | 
| 
         @@ -638,8 +640,8 @@ def voronoi(p, t, b, aoi: rql.Polyline): 
     | 
|
| 
       638 
640 
     | 
    
         
             
                    c[cahon_count + ei] = hull.coordinates[ei, :2] + extension_scaling * vector
         
     | 
| 
       639 
641 
     | 
    
         | 
| 
       640 
642 
     | 
    
         
             
                # where cicrumcircle centres are outwith aoi, compute intersections of normals of wing edges with aoi
         
     | 
| 
       641 
     | 
    
         
            -
                out_pair_intersect_segments = np.empty((o_count, 2), dtype =  
     | 
| 
       642 
     | 
    
         
            -
                wing_hull_segments = np.empty((o_count, 2), dtype =  
     | 
| 
      
 643 
     | 
    
         
            +
                out_pair_intersect_segments = np.empty((o_count, 2), dtype = t_type)
         
     | 
| 
      
 644 
     | 
    
         
            +
                wing_hull_segments = np.empty((o_count, 2), dtype = t_type)
         
     | 
| 
       643 
645 
     | 
    
         
             
                for oi, ti in enumerate(tc_outwith_aoi):
         
     | 
| 
       644 
646 
     | 
    
         
             
                    tpi = __shorter_sides_p_i(p[t[ti]])
         
     | 
| 
       645 
647 
     | 
    
         
             
                    for wing in range(2):
         
     | 
| 
         @@ -658,7 +660,7 @@ def voronoi(p, t, b, aoi: rql.Polyline): 
     | 
|
| 
       658 
660 
     | 
    
         
             
                        tpi = (tpi + 1) % 3
         
     | 
| 
       659 
661 
     | 
    
         | 
| 
       660 
662 
     | 
    
         
             
                v = __veroni_cells(aoi_count, aoi_intersect_segments, b, c, c_count, ca_count, cah_count, caho_count, cahon_count,
         
     | 
| 
       661 
     | 
    
         
            -
                                   hull_count, out_pair_intersect_segments, p, t, tc_outwith_aoi)
         
     | 
| 
      
 663 
     | 
    
         
            +
                                   hull_count, out_pair_intersect_segments, p, t, tc_outwith_aoi, t_type)
         
     | 
| 
       662 
664 
     | 
    
         | 
| 
       663 
665 
     | 
    
         
             
                return c[:caho_count], v
         
     | 
| 
       664 
666 
     | 
    
         | 
| 
         @@ -703,7 +705,8 @@ def triangulated_polygons(p, v, centres = None): 
     | 
|
| 
       703 
705 
     | 
    
         
             
                    points[len(p):] = centres
         
     | 
| 
       704 
706 
     | 
    
         | 
| 
       705 
707 
     | 
    
         
             
                t_count = sum([len(x) for x in v])
         
     | 
| 
       706 
     | 
    
         
            -
                 
     | 
| 
      
 708 
     | 
    
         
            +
                t_type = np.int32 if len(points) < 2_147_483_648 else np.int64
         
     | 
| 
      
 709 
     | 
    
         
            +
                triangles = np.empty((t_count, 3), dtype = t_type)
         
     | 
| 
       707 
710 
     | 
    
         
             
                t_index = 0
         
     | 
| 
       708 
711 
     | 
    
         | 
| 
       709 
712 
     | 
    
         
             
                for cell, poly_vertices in enumerate(v):
         
     | 
| 
         @@ -711,7 +714,7 @@ def triangulated_polygons(p, v, centres = None): 
     | 
|
| 
       711 
714 
     | 
    
         
             
                    centre_i = len(p) + cell
         
     | 
| 
       712 
715 
     | 
    
         
             
                    if centres is None:
         
     | 
| 
       713 
716 
     | 
    
         
             
                        polygon = rql.Polyline(model,
         
     | 
| 
       714 
     | 
    
         
            -
                                               set_coord = p[np.array(poly_vertices, dtype =  
     | 
| 
      
 717 
     | 
    
         
            +
                                               set_coord = p[np.array(poly_vertices, dtype = t_type)],
         
     | 
| 
       715 
718 
     | 
    
         
             
                                               is_closed = True,
         
     | 
| 
       716 
719 
     | 
    
         
             
                                               set_crs = crs.uuid,
         
     | 
| 
       717 
720 
     | 
    
         
             
                                               title = 'v cell')
         
     | 
| 
         @@ -747,7 +750,7 @@ def reorient(points, rough = True, max_dip = None, use_linalg = True, sample = 5 
     | 
|
| 
       747 
750 
     | 
    
         
             
                notes:
         
     | 
| 
       748 
751 
     | 
    
         
             
                   the original points array is not modified by this function;
         
     | 
| 
       749 
752 
     | 
    
         
             
                   implicit xy & z units for points are assumed to be the same;
         
     | 
| 
       750 
     | 
    
         
            -
                   the function may typically be called prior to the  
     | 
| 
      
 753 
     | 
    
         
            +
                   the function may typically be called prior to the Delaunay triangulation, which uses an xy projection to
         
     | 
| 
       751 
754 
     | 
    
         
             
                   determine the triangulation;
         
     | 
| 
       752 
755 
     | 
    
         
             
                   the numpy linear algebra option seems to be memory intensive, not recommended;
         
     | 
| 
       753 
756 
     | 
    
         
             
                   downsampling will occur (for normal vector determination) when the number of points exceeds double that
         
     | 
| 
         @@ -865,9 +868,11 @@ def surrounding_xy_ring(p, 
     | 
|
| 
       865 
868 
     | 
    
         
             
                      being an angle to determine a z offset for the ring(s); a +ve angle results in a -ve z shift
         
     | 
| 
       866 
869 
     | 
    
         | 
| 
       867 
870 
     | 
    
         
             
                returns:
         
     | 
| 
       868 
     | 
    
         
            -
                   numpy float array 
     | 
| 
       869 
     | 
    
         
            -
                    
     | 
| 
       870 
     | 
    
         
            -
             
     | 
| 
      
 871 
     | 
    
         
            +
                   (numpy float array, float) pair:
         
     | 
| 
      
 872 
     | 
    
         
            +
                   - numpy float array of shape (N, 3) being xyz points in surrounding ring(s); z is set constant to
         
     | 
| 
      
 873 
     | 
    
         
            +
                     mean value of z in p (optionally adjussted based on saucer_angle);
         
     | 
| 
      
 874 
     | 
    
         
            +
                     N is count if inner_ring is False, 3 * count if True
         
     | 
| 
      
 875 
     | 
    
         
            +
                   - radius used for ring of additional points
         
     | 
| 
       871 
876 
     | 
    
         
             
                """
         
     | 
| 
       872 
877 
     | 
    
         | 
| 
       873 
878 
     | 
    
         
             
                def make_ring(count, centre, radius, saucer_angle):
         
     | 
| 
         @@ -895,8 +900,8 @@ def surrounding_xy_ring(p, 
     | 
|
| 
       895 
900 
     | 
    
         
             
                    inner_radius = p_radius * 1.1
         
     | 
| 
       896 
901 
     | 
    
         
             
                    assert radius > inner_radius
         
     | 
| 
       897 
902 
     | 
    
         
             
                    in_ring = make_ring(2 * count, centre, inner_radius, saucer_angle)
         
     | 
| 
       898 
     | 
    
         
            -
                    return np.concatenate((in_ring, ring), axis = 0)
         
     | 
| 
       899 
     | 
    
         
            -
                return ring
         
     | 
| 
      
 903 
     | 
    
         
            +
                    return np.concatenate((in_ring, ring), axis = 0), radius
         
     | 
| 
      
 904 
     | 
    
         
            +
                return ring, radius
         
     | 
| 
       900 
905 
     | 
    
         | 
| 
       901 
906 
     | 
    
         | 
| 
       902 
907 
     | 
    
         
             
            def edges(t):
         
     | 
| 
         @@ -917,7 +922,7 @@ def edges(t): 
     | 
|
| 
       917 
922 
     | 
    
         
             
                """
         
     | 
| 
       918 
923 
     | 
    
         | 
| 
       919 
924 
     | 
    
         
             
                assert t.ndim == 2 and t.shape[1] == 3
         
     | 
| 
       920 
     | 
    
         
            -
                all_edges = np.empty((len(t), 3, 2), dtype =  
     | 
| 
      
 925 
     | 
    
         
            +
                all_edges = np.empty((len(t), 3, 2), dtype = t.dtype)
         
     | 
| 
       921 
926 
     | 
    
         
             
                all_edges[:, :, 0] = t
         
     | 
| 
       922 
927 
     | 
    
         
             
                all_edges[:, :2, 1] = t[:, 1:]
         
     | 
| 
       923 
928 
     | 
    
         
             
                all_edges[:, 2, 1] = t[:, 0]
         
     | 
| 
         @@ -946,6 +951,7 @@ def triangles_using_edges(t, edges): 
     | 
|
| 
       946 
951 
     | 
    
         
             
                """Returns int array of shape (len(edges), 2) with indices of upto 2 triangles using each edge (-1 for unused)."""
         
     | 
| 
       947 
952 
     | 
    
         | 
| 
       948 
953 
     | 
    
         
             
                assert t.ndim == 2 and t.shape[1] == 3 and edges.ndim == 2 and edges.shape[1] == 2
         
     | 
| 
      
 954 
     | 
    
         
            +
                t_type = np.int32 if len(t) < 2_147_483_648 else np.int64
         
     | 
| 
       949 
955 
     | 
    
         
             
                ti = np.full((len(edges), 2), -1, dtype = int)
         
     | 
| 
       950 
956 
     | 
    
         
             
                for i in range(len(edges)):
         
     | 
| 
       951 
957 
     | 
    
         
             
                    te = triangles_using_edge(t, edges[i, 0], edges[i, 1])
         
     |