geological_model.py 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. """Recreate a model of a geothermal reservoir in Utah.
  2. Click on an object and press "i" to get info about it.
  3. (Credits: A. Pollack, SCRF)"""
  4. from vedo import printc, dataurl, settings
  5. from vedo import Line, Lines, Points, Plotter
  6. import pandas as pd
  7. settings.use_depth_peeling = True
  8. # Load surfaces, import the file from github
  9. printc("...loading data...", invert=1, end='')
  10. url = "https://raw.githubusercontent.com/ahinoamp/Example3DGeologicModelUsingVTKPlotter/master/"
  11. landSurfacePD = pd.read_csv(url+"land_surface_vertices.csv")
  12. vertices_175CPD = pd.read_csv(url+"175C_vertices.csv")
  13. vertices_225CPD = pd.read_csv(url+"225C_vertices.csv")
  14. microseismic = pd.read_csv(url+"Microseismic.csv")
  15. Negro_Mag_Fault_verticesPD = pd.read_csv(url+"Negro_Mag_Fault_vertices.csv")
  16. Opal_Mound_Fault_verticesPD= pd.read_csv(url+"Opal_Mound_Fault_vertices.csv")
  17. top_granitoid_verticesPD = pd.read_csv(url+"top_granitoid_vertices.csv")
  18. # The well path and different logs for the well paths
  19. well_5832_path= pd.read_csv(url+"path5832.csv")
  20. pressure_well = pd.read_csv(url+"pressure5832.csv")
  21. temp_well = pd.read_csv(url+"temperature5832.csv")
  22. nphi_well = pd.read_csv(url+"nphi5832.csv")
  23. # Since most of the wells in the area were just vertical, I split them into two files:
  24. # One file with the top of the wells and the other with the bottom point of the wellbore
  25. wellsmin = pd.read_csv(url+"MinPointsWells.csv")
  26. wellsmax = pd.read_csv(url+"MaxPointsWells.csv")
  27. # Project boundary area on the surface
  28. border = pd.read_csv(url+"FORGE_Border.csv")
  29. #############################################
  30. ## land surface: a mesh with varying color
  31. printc("analyzing...", invert=1, end='')
  32. # create a mesh object from the 2D Delaunay triangulation of the point cloud
  33. landSurface = Points(landSurfacePD.values).generate_delaunay2d()
  34. # in order to color it by the elevation, we use the z values of the mesh
  35. zvals = landSurface.vertices[:, 2]
  36. landSurface.cmap("terrain", zvals, vmin=1100)
  37. landSurface.name = "Land Surface" # give the object a name
  38. # Create a plotter and add landSurface to it
  39. plt = Plotter(axes=dict(xtitle='km', ytitle=' ', ztitle='km*1.5', yzgrid=False),
  40. bg2='lb', size=(1200,900)) # screen size
  41. plt += landSurface
  42. plt += landSurface.isolines(5).lw(1).c('k')
  43. #############################################
  44. ## Different meshes with constant colors
  45. # Mesh of 175 C isotherm
  46. vertices_175C = Points(vertices_175CPD.values).generate_delaunay2d()
  47. vertices_175C.name = "175C temperature isosurface"
  48. plt += vertices_175C.c("orange").opacity(0.3)
  49. # Mesh of 225 C isotherm
  50. vertices_225CT = Points(vertices_225CPD.values).generate_delaunay2d()
  51. vertices_225CT.name = "225C temperature isosurface"
  52. plt += vertices_225CT.c("red").opacity(0.4)
  53. # Negro fault, mode=fit is used because point cloud is not in xy plane
  54. Negro_Mag_Fault_vertices = Points(Negro_Mag_Fault_verticesPD.values).generate_delaunay2d(mode='fit')
  55. Negro_Mag_Fault_vertices.name = "Negro Fault"
  56. plt += Negro_Mag_Fault_vertices.c("f").opacity(0.6)
  57. # Opal fault
  58. Opal_Mound_Fault_vertices = Points(Opal_Mound_Fault_verticesPD.values).generate_delaunay2d(mode='fit')
  59. Opal_Mound_Fault_vertices.name = "Opal Mound Fault"
  60. plt += Opal_Mound_Fault_vertices.c("g").opacity(0.6)
  61. # Top Granite, (shift it a bit to avoid overlapping)
  62. xyz = top_granitoid_verticesPD.values - [0,0,20]
  63. top_granitoid_vertices = Points(xyz).generate_delaunay2d().texture(dataurl+'textures/paper2.jpg')
  64. top_granitoid_vertices.name = "Top of granite surface"
  65. plt += top_granitoid_vertices
  66. ###################################################
  67. printc("plotting...", invert=1)
  68. # Microseismic
  69. microseismicxyz = microseismic[["xloc", "yloc", "zloc"]].values
  70. scals = microseismic[["mw"]]
  71. microseismic_pts = Points(microseismicxyz).cmap("jet", scals).ps(5)
  72. microseismic_pts.name = "Microseismic events"
  73. plt += microseismic_pts
  74. # FORGE Boundary. Since the boundary area did not have a Z column,
  75. # I assigned a Z value for where I wanted it to appear
  76. border["zcoord"] = 1650
  77. borderxyz = border[["xcoord", "ycoord", "zcoord"]]
  78. boundary = Line(borderxyz.values).extrude(zshift=120, cap=False)
  79. boundary.lw(0).texture(dataurl+'textures/wood1.jpg')
  80. boundary.name = "FORGE area boundary"
  81. plt += boundary
  82. # The path of well 58_32
  83. Well1 = Line(well_5832_path[["X", "Y", "Z"]].values).color("k").lw(2)
  84. Well1.name = "Well 58-32"
  85. plt += Well1
  86. # A porosity log in the well
  87. xyz = nphi_well[["X", "Y", "Z"]].values
  88. porosity = nphi_well["Nphi"].values
  89. Well2 = Line(xyz).cmap("hot", porosity).lw(3)
  90. Well2.name = "Porosity log well 58-32"
  91. plt += Well2
  92. # This well data is actually represented by points since as of right now,
  93. xyz = pressure_well[["X", "Y", "Z"]].values
  94. pressure = pressure_well["Pressure"].values
  95. Well3 = Line(xyz).cmap("cool", pressure).lw(3)
  96. Well3.name = "Pressure log well 58-32"
  97. plt += Well3
  98. # Temperature log
  99. xyz = temp_well[["X", "Y", "Z"]].values
  100. temp = temp_well["Temperature"].values
  101. Well4 = Line(xyz).cmap("seismic", temp).lw(3)
  102. Well4.name = "Temperature log well 58-32"
  103. plt += Well4
  104. # defining the start and end of the lines that will be representing the wellbores
  105. Wells = Lines(
  106. wellsmin[["x", "y", "z"]].values, # start points
  107. wellsmax[["x", "y", "z"]].values, # end points
  108. )
  109. Wells.color("gray").lw(3)
  110. Wells.name = "Pre-existing wellbores"
  111. plt += Wells
  112. for a in plt.objects:
  113. # change scale to kilometers in x and y, but expand z scale by 1.5!
  114. a.scale([0.001, 0.001, 0.001*1.5])
  115. ###########################################################################
  116. ## show the plot
  117. plt += __doc__
  118. plt.show(viewup="z", zoom=1.2)
  119. #plt.export("page.html") # k3d is the default
  120. plt.close()