2 :filename: plot_fracture_orientations.py
3 :synopsis: Make plots of fracture orientations for the entire network and by family
5 :maintainer: Jeffrey Hyman and Matthew Sweeney
6 :moduleauthor: Jeffrey Hyman <jhyman@lanl.gov>, Matthew Sweeney <msweeney2796@lanl.gov>
12 import matplotlib.pyplot
as plt
17 """ Convert Fracture normal vectors to trend and plunge
21 normal_vectors : numpy array
22 Array of fracture normal vectors (n-fractures x 3)
27 Array of fracture trends
29 Array of fracture plunge
33 Conversion is based on the information found at http://www.geo.cornell.edu/geology/faculty/RWA/structure-lab-manual/chapter-2.pdf
38 n_1 = normal_vectors[:, 0]
39 n_2 = normal_vectors[:, 1]
40 n_3 = normal_vectors[:, 2]
43 trends = np.zeros(len(n_1))
44 plunges = np.zeros(len(n_1))
45 for i
in range(len(n_1)):
46 plunges[i] = m.degrees(m.asin(n_3[i]))
48 trends[i] = m.degrees(m.atan(n_2[i] / n_1[i]))
50 trends[i] = 180.0 + m.degrees(m.atan(n_2[i] / n_1[i]))
51 elif n_1[i] == 0.0
and n_2[i] >= 0.0:
53 elif n_1[i] == 0.0
and n_2[i] < 0.0:
56 return trends, plunges
60 """ Creates Stereonets and Rose Diagrams for Fractures by family and the entire network
65 General dictionary of output analysis code. Contains information on number of families, number of fractures, and colors.
67 families: list of fracture family dictionaries
68 Created by get_family_information
70 fractures: list of fracture dictionaries
71 Created by get_fracture_information
79 PDF files are dumped into dfnGen_output_report/figures. There is one figure for all fractures (all_fracture_centers.pdf) and one per family family_{family_id}_fracture_centers.pdf.
82 print(
"--> Plotting Rose Diagrams and Stereonets")
86 fig = plt.figure(figsize=(16, 8))
87 ax1 = fig.add_subplot(121, projection=
'stereonet')
89 ax2 = fig.add_subplot(122, projection=
'polar')
92 print(
"--> Plotting Entire Network Stereonet")
94 family_id = fam[
"Global Family"]
96 normal_vectors = np.zeros((fam[
"final_number_of_fractures"], 3))
97 for i, j
in enumerate(fam[
"fracture list - final"]):
98 normal_vectors[i, :] = fractures[j][
"normal"]
103 bin_edges = np.arange(-5, 366, 10)
104 num_of_trends, bin_edges = np.histogram(trends, bin_edges)
105 num_of_trends[0] += num_of_trends[-1]
107 half = np.sum(np.split(num_of_trends[:-1], 2), 0)
108 two_halves = np.concatenate([half, half])
116 label=f
"Family \# {family_id}")
118 if len(plunges) > 500:
119 print(
"Too Many Fractures")
120 idx = random.choices(range(len(plunges)), k=500)
121 ax1.line(plunges[idx],
134 if params[
"verbose"]:
135 print(
"--> Plotting Densities")
139 total_fractures += fam[
"final_number_of_fractures"]
141 normal_vectors = np.zeros((total_fractures, 3))
145 if not f[
"removed"]
and f[
"family"] > 0:
146 normal_vectors[accepted_cnt, :] = f[
"normal"]
150 ax1.density_contourf(plunges, trends, measurement=
'lines', cmap=
'Greys')
151 ax1.set_title(
'Density contour of trends and plunges', y=1.10, fontsize=24)
156 if params[
"verbose"]:
157 print(
"--> Plotting Entire Network Rose Diagram")
159 family_id = fam[
"Global Family"]
161 normal_vectors = np.zeros((fam[
"final_number_of_fractures"], 3))
162 for i, j
in enumerate(fam[
"fracture list - final"]):
163 normal_vectors[i, :] = fractures[j][
"normal"]
168 bin_edges = np.arange(-5, 366, 10)
169 num_of_trends, bin_edges = np.histogram(trends, bin_edges)
170 num_of_trends[0] += num_of_trends[-1]
172 half = np.sum(np.split(num_of_trends[:-1], 2), 0)
173 two_halves = np.concatenate([half, half])
175 ax2.bar(np.deg2rad(np.arange(0, 360,10)), two_halves, \
176 width=np.deg2rad(10), bottom = 0.0, color=fam[
"color"], edgecolor=
'k')
178 ax2.set_theta_zero_location(
'N')
179 ax2.set_theta_direction(-1)
180 ax2.set_thetagrids(np.arange(0, 360, 10), labels=np.arange(0, 360, 10))
181 ax2.set_title(
'Rose diagram of trends', y=1.10, fontsize=24)
183 fileout = f
"network_orientations.png"
184 if params[
"verbose"]:
185 print(f
"--> Saving File {fileout}")
187 plt.savefig(f
"{params['output_dir']}/network/{fileout}")
193 family_id = fam[
"Global Family"]
194 if params[
"verbose"]:
195 print(f
"--> Working on fracture family {family_id}")
198 normal_vectors = np.zeros((fam[
"final_number_of_fractures"], 3))
199 for i, j
in enumerate(fam[
"fracture list - final"]):
200 normal_vectors[i, :] = fractures[j][
"normal"]
205 bin_edges = np.arange(-5, 366, 10)
206 num_of_trends, bin_edges = np.histogram(trends, bin_edges)
207 num_of_trends[0] += num_of_trends[-1]
209 half = np.sum(np.split(num_of_trends[:-1], 2), 0)
210 two_halves = np.concatenate([half, half])
213 fig = plt.figure(figsize=(16, 8))
215 ax = fig.add_subplot(121, projection=
'stereonet')
220 color=params[
"final_color"],
223 ax.density_contourf(plunges, trends, measurement=
'lines', cmap=
'Greys')
224 ax.set_title(
'Density contour of trends and plunges',
229 ax = fig.add_subplot(122, projection=
'polar')
230 ax.bar(np.deg2rad(np.arange(0, 360, 10)),
232 width=np.deg2rad(10),
234 color=params[
"final_color"],
236 ax.set_theta_zero_location(
'N')
237 ax.set_theta_direction(-1)
238 ax.set_thetagrids(np.arange(0, 360, 10), labels=np.arange(0, 360, 10))
240 ax.set_title(
'Rose diagram of trends', y=1.10, fontsize=24)
243 fileout = f
"family_{family_id}_orienations.png"
245 tmp = fam[
"Distribution"]
246 fileout = f
"family_{family_id}_orienations.png"
248 if params[
"verbose"]:
249 print(f
"--> Saving File {fileout}")
251 plt.savefig(f
"{params['output_dir']}/family_{family_id}/{fileout}")
def plot_fracture_orientations(params, families, fractures)
def convert_to_trend_and_plunge(normal_vectors)