resqpy 4.16.11__tar.gz → 4.17.1__tar.gz

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.
Files changed (200) hide show
  1. {resqpy-4.16.11 → resqpy-4.17.1}/PKG-INFO +1 -1
  2. {resqpy-4.16.11 → resqpy-4.17.1}/pyproject.toml +1 -1
  3. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/__init__.py +1 -1
  4. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/fault/_grid_connection_set.py +224 -62
  5. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_grid.py +4 -0
  6. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid_surface/__init__.py +4 -0
  7. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid_surface/_blocked_well_populate.py +5 -5
  8. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid_surface/_find_faces.py +731 -212
  9. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/model/_hdf5.py +3 -3
  10. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/triangulation.py +17 -13
  11. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/vector_utilities.py +175 -1
  12. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/wellspec_keywords.py +16 -10
  13. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/grid_property_collection.py +10 -10
  14. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/rq_import/_import_vdb_ensemble.py +12 -13
  15. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/surface/_mesh.py +4 -0
  16. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/surface/_surface.py +40 -24
  17. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/surface/_tri_mesh.py +8 -7
  18. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/surface/_triangulated_patch.py +71 -51
  19. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/_blocked_well.py +28 -25
  20. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/_trajectory.py +2 -2
  21. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/blocked_well_frame.py +1 -1
  22. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/well_object_funcs.py +5 -5
  23. {resqpy-4.16.11 → resqpy-4.17.1}/LICENSE +0 -0
  24. {resqpy-4.16.11 → resqpy-4.17.1}/README.md +0 -0
  25. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/crs.py +0 -0
  26. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/__init__.py +0 -0
  27. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_add_edges_per_column_property_array.py +0 -0
  28. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_add_faults.py +0 -0
  29. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_add_one_blocked_well_property.py +0 -0
  30. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_add_one_grid_property_array.py +0 -0
  31. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_add_single_cell_grid.py +0 -0
  32. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_add_wells_from_ascii_file.py +0 -0
  33. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_add_zone_by_layer_property.py +0 -0
  34. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_coarsened_grid.py +0 -0
  35. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_common.py +0 -0
  36. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_copy_grid.py +0 -0
  37. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_drape_to_surface.py +0 -0
  38. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_extract_box.py +0 -0
  39. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_extract_box_for_well.py +0 -0
  40. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_fault_throw_scaling.py +0 -0
  41. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_gather_ensemble.py +0 -0
  42. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_interpolated_grid.py +0 -0
  43. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_local_depth_adjustment.py +0 -0
  44. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_refined_grid.py +0 -0
  45. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_tilted_grid.py +0 -0
  46. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_unsplit_grid.py +0 -0
  47. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_zonal_grid.py +0 -0
  48. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/derived_model/_zone_layer_ranges_from_array.py +0 -0
  49. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/fault/__init__.py +0 -0
  50. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/fault/_gcs_functions.py +0 -0
  51. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/__init__.py +0 -0
  52. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_cell_properties.py +0 -0
  53. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_connection_sets.py +0 -0
  54. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_create_grid_xml.py +0 -0
  55. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_defined_geometry.py +0 -0
  56. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_extract_functions.py +0 -0
  57. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_face_functions.py +0 -0
  58. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_faults.py +0 -0
  59. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_grid_types.py +0 -0
  60. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_intervals_info.py +0 -0
  61. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_moved_functions.py +0 -0
  62. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_pillars.py +0 -0
  63. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_pixel_maps.py +0 -0
  64. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_points_functions.py +0 -0
  65. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_regular_grid.py +0 -0
  66. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_transmissibility.py +0 -0
  67. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_write_hdf5_from_caches.py +0 -0
  68. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_write_nexus_corp.py +0 -0
  69. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid/_xyz.py +0 -0
  70. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid_surface/_grid_skin.py +0 -0
  71. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid_surface/_grid_surface.py +0 -0
  72. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid_surface/_trajectory_intersects.py +0 -0
  73. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/grid_surface/grid_surface_cuda.py +0 -0
  74. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/lines/__init__.py +0 -0
  75. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/lines/_common.py +0 -0
  76. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/lines/_polyline.py +0 -0
  77. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/lines/_polyline_set.py +0 -0
  78. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/model/__init__.py +0 -0
  79. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/model/_catalogue.py +0 -0
  80. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/model/_context.py +0 -0
  81. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/model/_forestry.py +0 -0
  82. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/model/_grids.py +0 -0
  83. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/model/_model.py +0 -0
  84. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/model/_xml.py +0 -0
  85. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/multi_processing/__init__.py +0 -0
  86. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/multi_processing/_multiprocessing.py +0 -0
  87. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/multi_processing/wrappers/__init__.py +0 -0
  88. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/multi_processing/wrappers/blocked_well_mp.py +0 -0
  89. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/multi_processing/wrappers/grid_surface_mp.py +0 -0
  90. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/multi_processing/wrappers/mesh_mp.py +0 -0
  91. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/__init__.py +0 -0
  92. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/ab_toolbox.py +0 -0
  93. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/base.py +0 -0
  94. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/box_utilities.py +0 -0
  95. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/class_dict.py +0 -0
  96. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/consolidation.py +0 -0
  97. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/data/build.py +0 -0
  98. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/data/properties.json +0 -0
  99. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/dataframe.py +0 -0
  100. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/exceptions.py +0 -0
  101. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/factors.py +0 -0
  102. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/fine_coarse.py +0 -0
  103. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/grid_functions.py +0 -0
  104. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/intersection.py +0 -0
  105. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/keyword_files.py +0 -0
  106. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/load_data.py +0 -0
  107. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/point_inclusion.py +0 -0
  108. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/random_seed.py +0 -0
  109. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/read_nexus_fault.py +0 -0
  110. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/relperm.py +0 -0
  111. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/simple_lines.py +0 -0
  112. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/time.py +0 -0
  113. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/trademark.py +0 -0
  114. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/transmission.py +0 -0
  115. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/uuid.py +0 -0
  116. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/vdb.py +0 -0
  117. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/volume.py +0 -0
  118. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/write_data.py +0 -0
  119. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/write_hdf5.py +0 -0
  120. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/xml_et.py +0 -0
  121. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/xml_namespaces.py +0 -0
  122. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/olio/zmap_reader.py +0 -0
  123. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/__init__.py +0 -0
  124. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/_utils.py +0 -0
  125. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/boundary_feature.py +0 -0
  126. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/boundary_feature_interpretation.py +0 -0
  127. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/earth_model_interpretation.py +0 -0
  128. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/fault_interpretation.py +0 -0
  129. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/fluid_boundary_feature.py +0 -0
  130. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/frontier_feature.py +0 -0
  131. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/generic_interpretation.py +0 -0
  132. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/genetic_boundary_feature.py +0 -0
  133. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/geobody_boundary_interpretation.py +0 -0
  134. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/geobody_feature.py +0 -0
  135. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/geobody_interpretation.py +0 -0
  136. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/geologic_unit_feature.py +0 -0
  137. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/horizon_interpretation.py +0 -0
  138. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/organization_feature.py +0 -0
  139. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/rock_fluid_unit_feature.py +0 -0
  140. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/structural_organization_interpretation.py +0 -0
  141. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/tectonic_boundary_feature.py +0 -0
  142. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/wellbore_feature.py +0 -0
  143. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/organize/wellbore_interpretation.py +0 -0
  144. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/__init__.py +0 -0
  145. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/_collection_add_part.py +0 -0
  146. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/_collection_create_xml.py +0 -0
  147. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/_collection_get_attributes.py +0 -0
  148. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/_collection_support.py +0 -0
  149. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/_property.py +0 -0
  150. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/attribute_property_set.py +0 -0
  151. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/property_collection.py +0 -0
  152. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/property_common.py +0 -0
  153. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/property_kind.py +0 -0
  154. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/string_lookup.py +0 -0
  155. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/well_interval_property.py +0 -0
  156. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/well_interval_property_collection.py +0 -0
  157. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/well_log.py +0 -0
  158. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/property/well_log_collection.py +0 -0
  159. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/rq_import/__init__.py +0 -0
  160. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/rq_import/_add_ab_properties.py +0 -0
  161. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/rq_import/_add_surfaces.py +0 -0
  162. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/rq_import/_grid_from_cp.py +0 -0
  163. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/rq_import/_import_nexus.py +0 -0
  164. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/rq_import/_import_vdb_all_grids.py +0 -0
  165. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/strata/__init__.py +0 -0
  166. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/strata/_binary_contact_interpretation.py +0 -0
  167. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/strata/_geologic_unit_interpretation.py +0 -0
  168. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/strata/_strata_common.py +0 -0
  169. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/strata/_stratigraphic_column.py +0 -0
  170. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/strata/_stratigraphic_column_rank.py +0 -0
  171. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/strata/_stratigraphic_unit_feature.py +0 -0
  172. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/strata/_stratigraphic_unit_interpretation.py +0 -0
  173. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/surface/__init__.py +0 -0
  174. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/surface/_base_surface.py +0 -0
  175. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/surface/_combined_surface.py +0 -0
  176. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/surface/_pointset.py +0 -0
  177. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/surface/_tri_mesh_stencil.py +0 -0
  178. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/time_series/__init__.py +0 -0
  179. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/time_series/_any_time_series.py +0 -0
  180. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/time_series/_from_nexus_summary.py +0 -0
  181. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/time_series/_functions.py +0 -0
  182. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/time_series/_geologic_time_series.py +0 -0
  183. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/time_series/_time_duration.py +0 -0
  184. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/time_series/_time_series.py +0 -0
  185. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/unstructured/__init__.py +0 -0
  186. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/unstructured/_hexa_grid.py +0 -0
  187. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/unstructured/_prism_grid.py +0 -0
  188. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/unstructured/_pyramid_grid.py +0 -0
  189. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/unstructured/_tetra_grid.py +0 -0
  190. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/unstructured/_unstructured_grid.py +0 -0
  191. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/weights_and_measures/__init__.py +0 -0
  192. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/weights_and_measures/nexus_units.py +0 -0
  193. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/weights_and_measures/weights_and_measures.py +0 -0
  194. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/__init__.py +0 -0
  195. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/_deviation_survey.py +0 -0
  196. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/_md_datum.py +0 -0
  197. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/_wellbore_frame.py +0 -0
  198. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/_wellbore_marker.py +0 -0
  199. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/_wellbore_marker_frame.py +0 -0
  200. {resqpy-4.16.11 → resqpy-4.17.1}/resqpy/well/well_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: resqpy
3
- Version: 4.16.11
3
+ Version: 4.17.1
4
4
  Summary: Python API for working with RESQML models
5
5
  Home-page: https://github.com/bp/resqpy
6
6
  License: MIT
@@ -9,7 +9,7 @@ build-backend = "poetry.masonry.api"
9
9
 
10
10
  [tool.poetry]
11
11
  name = "resqpy"
12
- version = "4.16.11" # Set at build time
12
+ version = "4.17.1" # Set at build time
13
13
  description = "Python API for working with RESQML models"
14
14
  authors = ["BP"]
15
15
  license = "MIT"
@@ -28,6 +28,6 @@
28
28
 
29
29
  import logging
30
30
 
31
- __version__ = "4.16.11" # Set at build time
31
+ __version__ = "4.17.1" # Set at build time
32
32
  log = logging.getLogger(__name__)
33
33
  log.info(f"Imported resqpy version {__version__}")
@@ -10,6 +10,7 @@ import math as maths
10
10
  import numpy as np
11
11
  import pandas as pd
12
12
 
13
+ import resqpy.grid as grr
13
14
  import resqpy.fault
14
15
  import resqpy.olio.read_nexus_fault as rnf
15
16
  import resqpy.olio.trademark as tm
@@ -118,7 +119,7 @@ class GridConnectionSet(BaseResqpy):
118
119
  self.cell_index_pairs = None #: shape (count, 2); dtype int; index normalized for flattened array
119
120
  self.cell_index_pairs_null_value = -1 #: integer null value for array above
120
121
  self.grid_index_pairs = None #: shape (count, 2); dtype int; optional; used if more than one grid referenced
121
- self.face_index_pairs = None #: shape (count, 2); dtype int32; local to cell, ie. range 0 to 5
122
+ self.face_index_pairs = None #: shape (count, 2); dtype int8; local to cell, ie. range 0 to 5
122
123
  self.face_index_pairs_null_value = -1 #: integer null value for array above
123
124
  # NB face index values 0..5 usually mean [K-, K+, J+, I+, J-, I-] respectively but there is some ambiguity
124
125
  # over I & J in the Energistics RESQML Usage Guide; see comments in DevOps backlog item 269001 for more info
@@ -129,17 +130,18 @@ class GridConnectionSet(BaseResqpy):
129
130
  self.feature_list = None #: ordered list, actually of interpretations, indexed by feature_indices
130
131
  # feature list contains tuples: (content_type, uuid, title) for fault features (or other interpretations)
131
132
  self.property_collection = None #: optional property.PropertyCollection
133
+ self.cell_index_dtype = np.int32 #: set to int64 if any grid is big, otherwise int32
132
134
 
133
135
  # NB: RESQML documentation is not clear which order is correct; should be kept consistent with same data in property.py
134
136
  # face_index_map maps from (axis, p01) to face index value in range 0..5
135
137
  # this is the default as indicated on page 139 (but not p. 180) of the RESQML Usage Gude v2.0.1
136
138
  # also assumes K is generally increasing downwards
137
139
  # see DevOps backlog item 269001 discussion for more information
138
- # self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype = int)
139
- self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype = int) # order: top, base, J-, I+, J+, I-
140
+ # self.face_index_map = np.array([[0, 1], [4, 2], [5, 3]], dtype = np.int8)
141
+ self.face_index_map = np.array([[0, 1], [2, 4], [5, 3]], dtype = np.int8) # order: top, base, J-, I+, J+, I-
140
142
  # and the inverse, maps from 0..5 to (axis, p01)
141
- # self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype = int)
142
- self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype = int)
143
+ # self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 1], [2, 1], [1, 0], [2, 0]], dtype = np.int8)
144
+ self.face_index_inverse_map = np.array([[0, 0], [0, 1], [1, 0], [2, 1], [1, 1], [2, 0]], dtype = np.int8)
143
145
  # note: the rework_face_pairs() method, below, overwrites the face indices based on I, J cell indices
144
146
  if not title:
145
147
  title = feature_name
@@ -196,6 +198,110 @@ class GridConnectionSet(BaseResqpy):
196
198
  self.cache_arrays()
197
199
  if find_properties:
198
200
  self.extract_property_collection()
201
+ self._set_cell_index_dtype()
202
+
203
+ @classmethod
204
+ def from_faces_indices(cls,
205
+ grid,
206
+ k_faces_kji0,
207
+ j_faces_kji0,
208
+ i_faces_kji0,
209
+ remove_duplicates = True,
210
+ k_properties = None,
211
+ j_properties = None,
212
+ i_properties = None,
213
+ feature_name = None,
214
+ feature_type = 'fault',
215
+ create_organizing_objects_where_needed = True,
216
+ title = None,
217
+ originator = None,
218
+ extra_metadata = None):
219
+ """Create a GridConnectionSet given a grid and 3 list-like arrays identifying faces by indices.
220
+
221
+ arguments:
222
+ - grid (Grid): the single grid to be referenced by the grid connection set
223
+ - k_faces_kji0 (numpy int array of shape (Nk, 3)): indices of cells on negative side of desired K faces
224
+ - j_faces_kji0 (numpy int array of shape (Nj, 3)): indices of cells on negative side of desired J faces
225
+ - i_faces_kji0 (numpy int array of shape (Ni, 3)): indices of cells on negative side of desired I faces
226
+ - remove_duplicates (bool, default True): if True, indices are sorted and duplicates removed
227
+ - k_properties (list of 1D numpy arrays, optional): if present and remove_duplicates is True, each array
228
+ is sorted and has elements removed to keep them compatible with the indices
229
+ - j_properties (list of 1D numpy arrays, optional): if present and remove_duplicates is True, each array
230
+ is sorted and has elements removed to keep them compatible with the indices
231
+ - i_properties (list of 1D numpy arrays, optional): if present and remove_duplicates is True, each array
232
+ is sorted and has elements removed to keep them compatible with the indices
233
+ - feature_name (string, optional): the feature name to use when setting from faces
234
+ - feature_type (string, default 'fault'): 'fault', 'horizon' or 'geobody boundary'
235
+ - create_organizing_objects_where_needed (boolean, default True): if True, a fault interpretation object
236
+ and tectonic boundary feature object will be created if such objects do not exist for the feature;
237
+ if False, missing organizational objects will cause an error to be logged
238
+ - title (str, optional): the citation title to use for a new grid connection set
239
+ - originator (str, optional): the name of the person creating the new grid connection set, defaults to login id
240
+ - extra_metadata (dict, optional): string key, value pairs to add as extra metadata for the grid connection set
241
+
242
+ returns:
243
+ - a new GridConnectionSet populated based on the faces indices
244
+
245
+ notes:
246
+ - this method only supports creation of single grid connection sets
247
+ - the faces indices are for cells on the negative side of the face
248
+ - the paired cell is implicitly the neighbouring cell in the positive direction of the axis
249
+ - the indices must therefore not include the last cell in the axis, though this is not checked
250
+ - if properties are passed, they should be passed in list variables which have their elements
251
+ replaced; individual property arrays should therefore be extracted from the lists afterwards
252
+ """
253
+ assert isinstance(grid, grr.Grid)
254
+
255
+ gcs = cls(grid.model, title = title, originator = originator, extra_metadata = extra_metadata)
256
+
257
+ gcs._sort_out_organizing_objects(feature_type, feature_name, create_organizing_objects_where_needed)
258
+
259
+ nj_ni = grid.nj * grid.ni
260
+ if k_faces_kji0 is not None and len(k_faces_kji0) > 0:
261
+ ci = grid.natural_cell_indices(k_faces_kji0)
262
+ if remove_duplicates:
263
+ ci = _sort_and_remove_duplicates(ci, k_properties)
264
+ cip = np.empty((ci.size, 2), dtype = gcs.cell_index_dtype)
265
+ cip[:, 0] = ci
266
+ cip[:, 1] = ci + nj_ni
267
+ fip = np.empty(cip.shape, dtype = np.int8)
268
+ fip[:, 0] = gcs.face_index_map[0, 1]
269
+ fip[:, 1] = gcs.face_index_map[0, 0]
270
+ else:
271
+ cip = np.empty((0, 2), dtype = gcs.cell_index_dtype)
272
+ fip = np.empty((0, 2), dtype = np.int8)
273
+ if j_faces_kji0 is not None and len(j_faces_kji0) > 0:
274
+ ci = grid.natural_cell_indices(j_faces_kji0)
275
+ if remove_duplicates:
276
+ ci = _sort_and_remove_duplicates(ci, j_properties)
277
+ j_cip = np.empty((ci.size, 2), dtype = gcs.cell_index_dtype)
278
+ j_cip[:, 0] = ci
279
+ j_cip[:, 1] = ci + grid.ni
280
+ j_fip = np.empty(j_cip.shape, dtype = np.int8)
281
+ j_fip[:, 0] = gcs.face_index_map[1, 1]
282
+ j_fip[:, 1] = gcs.face_index_map[1, 0]
283
+ cip = np.concatenate((cip, j_cip), axis = 0)
284
+ fip = np.concatenate((fip, j_fip), axis = 0)
285
+ del j_cip, j_fip
286
+ if i_faces_kji0 is not None and len(i_faces_kji0) > 0:
287
+ ci = grid.natural_cell_indices(i_faces_kji0)
288
+ if remove_duplicates:
289
+ ci = _sort_and_remove_duplicates(ci, i_properties)
290
+ i_cip = np.empty((ci.size, 2), dtype = gcs.cell_index_dtype)
291
+ i_cip[:, 0] = ci
292
+ i_cip[:, 1] = ci + 1
293
+ i_fip = np.empty(i_cip.shape, dtype = np.int8)
294
+ i_fip[:, 0] = gcs.face_index_map[2, 1]
295
+ i_fip[:, 1] = gcs.face_index_map[2, 0]
296
+ cip = np.concatenate((cip, i_cip), axis = 0)
297
+ fip = np.concatenate((fip, i_fip), axis = 0)
298
+ del i_cip, i_fip
299
+ gcs.cell_index_pairs = cip
300
+ gcs.face_index_pairs = fip
301
+ gcs.count = len(gcs.cell_index_pairs)
302
+ gcs.feature_indices = np.zeros(gcs.count, dtype = np.int8)
303
+ assert len(gcs.face_index_pairs) == gcs.count
304
+ return gcs
199
305
 
200
306
  @classmethod
201
307
  def from_gcs_uuid_list(cls,
@@ -357,6 +463,14 @@ class GridConnectionSet(BaseResqpy):
357
463
  self.property_collection = rqp.PropertyCollection(support = self)
358
464
  return self.property_collection
359
465
 
466
+ def _set_cell_index_dtype(self):
467
+ """Determines whether to use int32 or int64 for normalised cell indices."""
468
+ self.cell_index_dtype = np.int32
469
+ for g in self.grid_list:
470
+ if g.is_big():
471
+ self.cell_index_dtype = np.int64
472
+ break
473
+
360
474
  def set_pairs_from_kelp(self,
361
475
  kelp_0,
362
476
  kelp_1,
@@ -394,7 +508,7 @@ class GridConnectionSet(BaseResqpy):
394
508
  k_layer = np.zeros((grid.nk - 1, grid.ni), dtype = bool)
395
509
  else:
396
510
  k_layer = np.zeros((grid.nk - 1, grid.nj), dtype = bool)
397
- kelp_a = np.array(kelp_k, dtype = int).T
511
+ kelp_a = np.array(kelp_k, dtype = np.int32).T
398
512
  k_layer[kelp_a[0], kelp_a[1]] = True
399
513
  k_faces = np.zeros((grid.nk - 1, grid.nj, grid.ni), dtype = bool)
400
514
  if axis == 'J':
@@ -408,7 +522,7 @@ class GridConnectionSet(BaseResqpy):
408
522
  j_layer = np.zeros((grid.nj - 1, grid.ni), dtype = bool)
409
523
  else:
410
524
  j_layer = np.zeros((grid.nk, grid.nj - 1), dtype = bool)
411
- kelp_a = np.array(kelp_j, dtype = int).T
525
+ kelp_a = np.array(kelp_j, dtype = np.int32).T
412
526
  j_layer[kelp_a[0], kelp_a[1]] = True
413
527
  j_faces = np.zeros((grid.nk, grid.nj - 1, grid.ni), dtype = bool)
414
528
  if axis == 'K':
@@ -422,7 +536,7 @@ class GridConnectionSet(BaseResqpy):
422
536
  i_layer = np.zeros((grid.nj, grid.ni - 1), dtype = bool)
423
537
  else:
424
538
  i_layer = np.zeros((grid.nk, grid.ni - 1), dtype = bool)
425
- kelp_a = np.array(kelp_i, dtype = int).T
539
+ kelp_a = np.array(kelp_i, dtype = np.int32).T
426
540
  i_layer[kelp_a[0], kelp_a[1]] = True
427
541
  i_faces = np.zeros((grid.nk, grid.nj, grid.ni - 1), dtype = bool)
428
542
  if axis == 'K':
@@ -438,24 +552,13 @@ class GridConnectionSet(BaseResqpy):
438
552
  create_organizing_objects_where_needed,
439
553
  feature_type = feature_type)
440
554
 
441
- def set_pairs_from_face_masks(
442
- self,
443
- k_faces,
444
- j_faces,
445
- i_faces,
446
- feature_name,
447
- create_organizing_objects_where_needed,
448
- feature_type = 'fault', # other feature_type values: 'horizon', 'geobody boundary'
449
- k_sides = None,
450
- j_sides = None,
451
- i_sides = None):
452
- """Sets cell_index_pairs and face_index_pairs based on triple face masks, using simple no throw pairing."""
453
-
555
+ def _sort_out_organizing_objects(self, feature_type, feature_name, create_organizing_objects_where_needed):
556
+ """Finds or creates interpretation and feature objects."""
454
557
  assert feature_type in ['fault', 'horizon', 'geobody boundary']
455
558
  if feature_name is None:
456
- feature_name = 'feature from face masks' # not sure this default is wise
559
+ feature_name = 'feature from faces' # not sure this default is wise
457
560
  if len(self.grid_list) > 1:
458
- log.warning('setting grid connection set pairs from face masks for first grid in list only')
561
+ log.warning('setting grid connection set pairs from faces for first grid in list only')
459
562
  grid = self.grid_list[0]
460
563
  if feature_type == 'fault':
461
564
  feature_flavour = 'TectonicBoundaryFeature'
@@ -512,6 +615,23 @@ class GridConnectionSet(BaseResqpy):
512
615
  log.error('no interpretation found for feature: ' + feature_name)
513
616
  return
514
617
  self.feature_list = [('obj_' + interpretation_flavour, fi_uuid, str(feature_name))]
618
+
619
+ def set_pairs_from_face_masks(
620
+ self,
621
+ k_faces,
622
+ j_faces,
623
+ i_faces,
624
+ feature_name,
625
+ create_organizing_objects_where_needed,
626
+ feature_type = 'fault', # other feature_type values: 'horizon', 'geobody boundary'
627
+ k_sides = None,
628
+ j_sides = None,
629
+ i_sides = None):
630
+ """Sets cell_index_pairs and face_index_pairs based on triple face masks, using simple no throw pairing."""
631
+
632
+ self._sort_out_organizing_objects(feature_type, feature_name, create_organizing_objects_where_needed)
633
+
634
+ grid = self.grid_list[0]
515
635
  cell_pair_list = []
516
636
  face_pair_list = []
517
637
  nj_ni = grid.nj * grid.ni
@@ -548,10 +668,10 @@ class GridConnectionSet(BaseResqpy):
548
668
  else:
549
669
  cell_pair_list.append((cell, cell + 1))
550
670
  face_pair_list.append((self.face_index_map[2, 1], self.face_index_map[2, 0]))
551
- self.cell_index_pairs = np.array(cell_pair_list, dtype = int)
552
- self.face_index_pairs = np.array(face_pair_list, dtype = int)
671
+ self.cell_index_pairs = np.array(cell_pair_list, dtype = self.cell_index_dtype)
672
+ self.face_index_pairs = np.array(face_pair_list, dtype = np.int8)
553
673
  self.count = len(self.cell_index_pairs)
554
- self.feature_indices = np.zeros(self.count, dtype = int)
674
+ self.feature_indices = np.zeros(self.count, dtype = np.int8)
555
675
  assert len(self.face_index_pairs) == self.count
556
676
 
557
677
  def set_pairs_from_faces_df(self,
@@ -609,9 +729,9 @@ class GridConnectionSet(BaseResqpy):
609
729
  if success:
610
730
  feature_index += 1
611
731
 
612
- self.feature_indices = np.array(fi_list, dtype = int)
613
- self.cell_index_pairs = np.array(cell_pair_list, dtype = int)
614
- self.face_index_pairs = np.array(face_pair_list, dtype = int)
732
+ self.feature_indices = np.array(fi_list, dtype = np.int32)
733
+ self.cell_index_pairs = np.array(cell_pair_list, dtype = self.cell_index_dtype)
734
+ self.face_index_pairs = np.array(face_pair_list, dtype = np.int8)
615
735
  self.count = len(self.cell_index_pairs)
616
736
  assert len(self.face_index_pairs) == self.count
617
737
  if create_mult_prop and self.count > 0:
@@ -696,7 +816,7 @@ class GridConnectionSet(BaseResqpy):
696
816
  singleton.cell_index_pairs, singleton.face_index_pairs = \
697
817
  self.raw_list_of_cell_face_pairs_for_feature_index(feature_index)
698
818
  singleton.count = singleton.cell_index_pairs.shape[0]
699
- singleton.feature_indices = np.zeros((singleton.count,), dtype = int)
819
+ singleton.feature_indices = np.zeros((singleton.count,), dtype = np.int32)
700
820
  singleton.feature_list = [self.feature_list[feature_index]]
701
821
  return singleton
702
822
 
@@ -823,7 +943,7 @@ class GridConnectionSet(BaseResqpy):
823
943
  cache_array = True,
824
944
  object = self,
825
945
  array_attribute = 'cell_index_pairs',
826
- dtype = 'int')
946
+ dtype = 'int64' if self.cell_index_dtype is np.int64 else 'int32')
827
947
 
828
948
  if self.face_index_pairs is None:
829
949
  log.debug('caching face index pairs from hdf5')
@@ -834,7 +954,7 @@ class GridConnectionSet(BaseResqpy):
834
954
  cache_array = True,
835
955
  object = self,
836
956
  array_attribute = 'face_index_pairs',
837
- dtype = 'int32')
957
+ dtype = 'int8')
838
958
 
839
959
  if len(self.grid_list) > 1 and self.grid_index_pairs is None:
840
960
  grid_index_node = rqet.find_tag(self.root, 'GridIndexPairs')
@@ -845,7 +965,7 @@ class GridConnectionSet(BaseResqpy):
845
965
  cache_array = True,
846
966
  object = self,
847
967
  array_attribute = 'grid_index_pairs',
848
- dtype = 'int')
968
+ dtype = 'int32' if len(self.grid_list) > 127 else 'int8')
849
969
 
850
970
  if self.feature_list is None:
851
971
  return
@@ -854,18 +974,18 @@ class GridConnectionSet(BaseResqpy):
854
974
  if self.feature_indices is None:
855
975
  log.debug('caching feature indices')
856
976
  elements_node = rqet.find_nested_tags(interp_root, ['InterpretationIndices', 'Elements'])
857
- # elements_node = rqet.find_nested_tags(interp_root, ['FaultIndices', 'Elements'])
977
+ # elements_node = rqet.find_nested_tags(interp_root, ['FaultIndices', 'Elements'])
858
978
  h5_key_pair = self.model.h5_uuid_and_path_for_node(elements_node, tag = 'Values')
859
979
  assert h5_key_pair is not None
860
980
  self.model.h5_array_element(h5_key_pair,
861
981
  cache_array = True,
862
982
  object = self,
863
983
  array_attribute = 'feature_indices',
864
- dtype = 'uint32')
984
+ dtype = 'int32')
865
985
  assert self.feature_indices.shape == (self.count,)
866
986
 
867
987
  cl_node = rqet.find_nested_tags(interp_root, ['InterpretationIndices', 'CumulativeLength'])
868
- # cl_node = rqet.find_nested_tags(interp_root, ['FaultIndices', 'CumulativeLength'])
988
+ # cl_node = rqet.find_nested_tags(interp_root, ['FaultIndices', 'CumulativeLength'])
869
989
  h5_key_pair = self.model.h5_uuid_and_path_for_node(cl_node, tag = 'Values')
870
990
  assert h5_key_pair is not None
871
991
  self.model.h5_array_element(h5_key_pair,
@@ -873,8 +993,8 @@ class GridConnectionSet(BaseResqpy):
873
993
  object = self,
874
994
  array_attribute = 'fi_cl',
875
995
  dtype = 'uint32')
876
- assert self.fi_cl.shape == (
877
- self.count,), 'connection set face pair(s) not assigned to exactly one feature' # rough check
996
+ assert self.fi_cl.shape == (self.count,), \
997
+ 'connection set face pair(s) not assigned to exactly one feature' # rough check
878
998
 
879
999
  # delattr(self, 'fi_cl') # assumed to be one-to-one mapping, so cumulative length is discarded
880
1000
 
@@ -1196,7 +1316,7 @@ class GridConnectionSet(BaseResqpy):
1196
1316
  # uuid/InterpretationIndices/elements (N,) uint32
1197
1317
  h5_reg.register_dataset(self.uuid, 'InterpretationIndices/elements', self.feature_indices)
1198
1318
  # uuid/InterpretationIndices/cumulativeLength (N,) uint32
1199
- one_to_one = np.arange(1, self.count + 1, dtype = int)
1319
+ one_to_one = np.arange(1, self.count + 1, dtype = np.uint32)
1200
1320
  h5_reg.register_dataset(self.uuid, 'InterpretationIndices/cumulativeLength', one_to_one)
1201
1321
 
1202
1322
  h5_reg.write(file_name, mode = mode)
@@ -1371,11 +1491,16 @@ class GridConnectionSet(BaseResqpy):
1371
1491
  include_both_sides = False,
1372
1492
  use_minus = False,
1373
1493
  trans_mult_uuid = None):
1374
- """Creates a Nexus include file holding MULT keywords and data. trans_mult_uuid (optional) is the uuid of a property on the gcs containing transmissibility multiplier values. If not provided values of 1.0 will be used."""
1494
+ """Creates a Nexus include file holding MULT keywords and data.
1495
+
1496
+ note:
1497
+ trans_mult_uuid (optional) is the uuid of a property on the gcs containing transmissibility multiplier values;
1498
+ If not provided values of 1.0 will be used
1499
+ """
1375
1500
  if trans_mult_uuid is not None:
1376
1501
  self.extract_property_collection()
1377
- assert self.property_collection.part_in_collection(self.model.part_for_uuid(
1378
- trans_mult_uuid)), f'trans_mult_uuid provided is not part of collection {trans_mult_uuid}'
1502
+ assert self.property_collection.part_in_collection(self.model.part_for_uuid(trans_mult_uuid)), \
1503
+ f'trans_mult_uuid provided is not part of collection {trans_mult_uuid}'
1379
1504
  tmult_array = self.property_collection.cached_part_array_ref(self.model.part_for_uuid(trans_mult_uuid))
1380
1505
  assert tmult_array is not None
1381
1506
  else:
@@ -1421,26 +1546,39 @@ class GridConnectionSet(BaseResqpy):
1421
1546
  feature_name = self.feature_list[feature_index][2].split()[0].upper()
1422
1547
  cell_index_pairs, face_index_pairs = self.list_of_cell_face_pairs_for_feature_index(feature_index)
1423
1548
  if tmult_array is not None:
1424
- feature_mask = np.where(self.feature_indices == feature_index, 1, 0)
1549
+ feature_mask = (self.feature_indices == feature_index)
1425
1550
  feat_mult_array = np.extract(feature_mask, tmult_array)
1426
1551
  else:
1427
1552
  feat_mult_array = np.ones(shape = (cell_index_pairs.shape[0],), dtype = float)
1428
1553
  for side in sides:
1429
- both = np.empty((cell_index_pairs.shape[0], 6), dtype = int) # axis, polarity, k, j, i, tmult
1554
+ both = np.empty((cell_index_pairs.shape[0], 5), dtype = np.int32) # axis, polarity, k, j, i
1430
1555
  both[:, :2] = face_index_pairs[:, side, :] # axis, polarity
1431
- both[:, 2:-1] = cell_index_pairs[:, side, :] # k, j, i
1432
- both[:, -1] = feat_mult_array.flatten()
1433
- df = pd.DataFrame(both, columns = ['axis', 'polarity', 'k', 'j', 'i', 'tmult'])
1434
- df = df.sort_values(by = ['axis', 'polarity', 'j', 'i', 'k', 'tmult'])
1435
- both_sorted = np.empty(both.shape, dtype = int)
1436
- both_sorted[:] = df
1437
- cell_indices = both_sorted[:, 2:-1]
1438
- face_indices = np.empty((both_sorted.shape[0], 2), dtype = int)
1439
- face_indices[:, :] = both_sorted[:, :2]
1440
- tmult_values = both_sorted[:, -1]
1441
- del both_sorted
1556
+ both[:, 2:] = cell_index_pairs[:, side, :] # k, j, i
1557
+ # both[:, -1] = feat_mult_array.flatten()
1558
+ # df = pd.DataFrame(both, columns = ['axis', 'polarity', 'k', 'j', 'i', 'tmult'])
1559
+ # df = df.sort_values(by = ['axis', 'polarity', 'j', 'i', 'k', 'tmult'])
1560
+ # both_sorted = np.empty(both.shape, dtype = np.int32)
1561
+ # both_sorted[:] = df
1562
+ si = np.argsort(both[:, 2]) # k
1563
+ msi = si
1564
+ both = both[si]
1565
+ si = np.argsort(both[:, 4], kind = 'stable') # i
1566
+ msi = msi[si]
1567
+ both = both[si]
1568
+ si = np.argsort(both[:, 3], kind = 'stable') # j
1569
+ msi = msi[si]
1570
+ both = both[si]
1571
+ si = np.argsort(both[:, 1], kind = 'stable') # polarity
1572
+ msi = msi[si]
1573
+ both = both[si]
1574
+ si = np.argsort(both[:, 0], kind = 'stable') # axis
1575
+ msi = msi[si]
1576
+ both = both[si]
1577
+ cell_indices = both[:, 2:]
1578
+ face_indices = np.empty((both.shape[0], 2), dtype = np.int8)
1579
+ face_indices[:, :] = both[:, :2]
1580
+ tmult_values = feat_mult_array[msi]
1442
1581
  del both
1443
- del df
1444
1582
  k = None
1445
1583
  i = j = k2 = axis = polarity = None # only needed to placate flake8 which whinges incorrectly otherwise
1446
1584
  for row in range(cell_indices.shape[0]):
@@ -1692,7 +1830,7 @@ class GridConnectionSet(BaseResqpy):
1692
1830
  combined_values = property_value_by_column_edge.copy()
1693
1831
  else:
1694
1832
  combined_values = None
1695
- combined_index = np.full((fault_by_column_edge_mask.shape), -1, dtype = int)
1833
+ combined_index = np.full((fault_by_column_edge_mask.shape), -1, dtype = np.int32)
1696
1834
  combined_index = np.where(fault_by_column_edge_mask, feature, combined_index)
1697
1835
  sum_unmasked = np.sum(fault_by_column_edge_mask)
1698
1836
  else:
@@ -1802,7 +1940,7 @@ class GridConnectionSet(BaseResqpy):
1802
1940
  def sorted_paired_cell_face_index_position(cell_face_index, a_or_b):
1803
1941
  # pair one side (a_or_b) of cell_face_index with its position, then sort
1804
1942
  count = len(cell_face_index)
1805
- sp = np.empty((count, 2), dtype = int)
1943
+ sp = np.empty((count, 2), dtype = np.int32)
1806
1944
  sp[:, 0] = cell_face_index[:, a_or_b]
1807
1945
  sp[:, 1] = np.arange(count)
1808
1946
  t = [tuple(r) for r in sp] # could use numpy fields based sort instead of tuple list?
@@ -1985,19 +2123,19 @@ class GridConnectionSet(BaseResqpy):
1985
2123
  for k0 in range(entry['k1'], entry['k2'] + 1):
1986
2124
  for j0 in range(entry['j1'], entry['j2'] + 1):
1987
2125
  for i0 in range(entry['i1'], entry['i2'] + 1):
1988
- neighbour = np.array([k0, j0, i0], dtype = int)
2126
+ neighbour = np.array([k0, j0, i0], dtype = np.int32)
1989
2127
  if fp:
1990
2128
  neighbour[axis] += 1
1991
2129
  else:
1992
2130
  neighbour[axis] -= 1
1993
2131
  fi_list.append(feature_index)
1994
- cell_pair_list.append((grid.natural_cell_index(
1995
- (k0, j0, i0)), grid.natural_cell_index(neighbour)))
2132
+ cell_pair_list.append((grid.natural_cell_index((k0, j0, i0)), \
2133
+ grid.natural_cell_index(neighbour)))
1996
2134
  face_pair_list.append((self.face_index_map[axis, fp], self.face_index_map[axis, 1 - fp]))
1997
2135
  if create_mult_prop:
1998
2136
  mult_list.append(multiplier)
1999
2137
  if fi_root is not None and fault_const_mult and fault_mult_value is not None:
2000
- #patch extra_metadata into xml for new fault interpretation object
2138
+ # patch extra_metadata into xml for new fault interpretation object
2001
2139
  rqet.create_metadata_xml(fi_root, {"Transmissibility multiplier": str(fault_mult_value)})
2002
2140
  return True, const_mult
2003
2141
 
@@ -2162,3 +2300,27 @@ def _copy_organisation_objects(target_model, source_model, gcs):
2162
2300
  for _, uuid, _ in gcs.feature_list:
2163
2301
  target_model.copy_uuid_from_other_model(source_model,
2164
2302
  uuid) # will copy related features as well as interpretations
2303
+
2304
+
2305
+ def _sort_and_remove_duplicates(a, props = None):
2306
+ """Return copy of 1D array a, sorted and with duplicates removed; secondary arrays can be kept in alignment."""
2307
+ if a is None or a.size <= 1:
2308
+ return a
2309
+ assert a.ndim == 1
2310
+ si = None
2311
+ no_props = (props is None or len(props) == 0)
2312
+ if no_props:
2313
+ a = np.sort(a)
2314
+ else:
2315
+ si = np.argsort(a)
2316
+ a = a[si]
2317
+ m = np.empty(a.size, dtype = bool)
2318
+ m[0] = True
2319
+ m[1:] = (a[1:] != a[:-1])
2320
+ if np.all(m):
2321
+ return a
2322
+ if not no_props:
2323
+ for i in range(len(props)):
2324
+ p = props[i][si]
2325
+ props[i] = p[m]
2326
+ return a[m]
@@ -265,6 +265,10 @@ class Grid(BaseResqpy):
265
265
  return np.count_nonzero(self.array_cell_geometry_is_defined)
266
266
  return None
267
267
 
268
+ def is_big(self):
269
+ """Returns True if number of cells exceeds 2^31 - 1, otherwise False."""
270
+ return (np.prod(self.extent_kji) >= 2_147_483_648)
271
+
268
272
  def natural_cell_index(self, cell_kji0):
269
273
  """Returns a single integer for the cell, being the index into a flattened array."""
270
274
 
@@ -20,11 +20,13 @@ __all__ = [
20
20
  "find_faces_to_represent_surface_staffa",
21
21
  "find_faces_to_represent_surface_regular",
22
22
  "find_faces_to_represent_surface_regular_optimised",
23
+ "find_faces_to_represent_surface_regular_dense_optimised",
23
24
  "find_faces_to_represent_surface",
24
25
  "bisector_from_faces",
25
26
  "column_bisector_from_faces",
26
27
  "shadow_from_faces",
27
28
  "get_boundary",
29
+ "get_boundary_dict",
28
30
  "_where_true",
29
31
  "_first_true",
30
32
  "intersect_numba",
@@ -56,11 +58,13 @@ from ._find_faces import (
56
58
  find_faces_to_represent_surface_staffa,
57
59
  find_faces_to_represent_surface_regular,
58
60
  find_faces_to_represent_surface_regular_optimised,
61
+ find_faces_to_represent_surface_regular_dense_optimised,
59
62
  find_faces_to_represent_surface,
60
63
  bisector_from_faces,
61
64
  column_bisector_from_faces,
62
65
  shadow_from_faces,
63
66
  get_boundary,
67
+ get_boundary_dict,
64
68
  _where_true,
65
69
  _first_true,
66
70
  intersect_numba,
@@ -118,7 +118,7 @@ def populate_blocked_well_from_trajectory(blocked_well,
118
118
  if xyz is None:
119
119
  log.error('failed to lazily find intersection of trajectory with top surface of grid')
120
120
  return None
121
- cell_kji0 = np.array((0, col_ji0[0], col_ji0[1]), dtype = int)
121
+ cell_kji0 = np.array((0, col_ji0[0], col_ji0[1]), dtype = np.int32)
122
122
  axis = 0
123
123
  polarity = 0
124
124
 
@@ -133,7 +133,7 @@ def populate_blocked_well_from_trajectory(blocked_well,
133
133
  else:
134
134
  log.debug(f"skin intersection x,y,z: {xyz}; knot: {entry_knot}; cell kji0: {cell_kji0}; face: "
135
135
  f"{'KJI'[axis]}{'-+'[polarity]}")
136
- cell_kji0 = np.array(cell_kji0, dtype = int)
136
+ cell_kji0 = np.array(cell_kji0, dtype = np.int32)
137
137
 
138
138
  previous_kji0 = cell_kji0.copy()
139
139
  previous_kji0[axis] += polarity * 2 - 1 # note: previous may legitimately be 'beyond' edge of grid
@@ -244,9 +244,9 @@ def populate_blocked_well_from_trajectory(blocked_well,
244
244
 
245
245
  blocked_well.node_mds = np.array(node_mds_list, dtype = float)
246
246
  blocked_well.node_count = node_count
247
- blocked_well.grid_indices = np.array(grid_indices_list, dtype = int)
248
- blocked_well.cell_indices = np.array(cell_indices_list, dtype = int)
249
- blocked_well.face_pair_indices = np.array(face_pairs_list, dtype = int)
247
+ blocked_well.grid_indices = np.array(grid_indices_list, dtype = np.int32)
248
+ blocked_well.cell_indices = np.array(cell_indices_list, dtype = np.int64)
249
+ blocked_well.face_pair_indices = np.array(face_pairs_list, dtype = np.int8)
250
250
  blocked_well.cell_count = cell_count
251
251
  blocked_well.grid_list = [grid]
252
252