(09 de Septiembre, 2024)
El análisis de contacto es una técnica utilizada en la evaluación de recursos minerales para estudiar cómo cambian las leyes de mineralización (por ejemplo, la concentración de cobre) en las proximidades de los contactos entre diferentes unidades geológicas o litológicas. Este análisis es fundamental para entender cómo se distribuyen los minerales dentro de un depósito y ayuda a definir dominios geológicos y de estimación que reflejen las variaciones naturales en la mineralización.
En este post, comparto un ejemplo y código en Python el cual realiza el análisis de contacto para las leyes de cobre según sus diferentes litologías. El código es extensible a cualquier caso siempre y cuando se mantenga el formato del archivo de entrada.
Se requiere que el archivo de entrada tenga un ID, coordenadas X, Y, Z, el atributo geológico (por ejemplo litología en este caso), y la ley mineral (cobre en este caso). Puede descargar el archivo «compositos.txt» en el siguiente enlace:
El código esta elaborado para ser capaz de reconocer todos los posibles contactos entre unidades geológicas, independientes cuantas sean estas.
data = pd.read_csv('compositos.txt', sep='\t') litologias = data['lito'].unique() combinaciones = list(itertools.combinations(litologias, 2)) for lito_1, lito_2 in combinaciones: litologia_1 = data[data['lito'] == lito_1] litologia_2 = data[data['lito'] == lito_2] if litologia_1.empty or litologia_2.empty: continue tree_lito_2 = cKDTree(litologia_2[['x', 'y', 'z']]) distancias_minimas_1, _ = tree_lito_2.query(litologia_1[['x', 'y', 'z']]) leyes_correspondientes_1 = litologia_1['cu'].values resultados_1 = pd.DataFrame({ 'distancia': distancias_minimas_1, 'cu': leyes_correspondientes_1 }) resultados_1['intervalo'] = pd.cut(resultados_1['distancia'], bins=np.arange(0, 110, 10), right=False) ley_media_por_intervalo_1 = resultados_1.groupby('intervalo')['cu'].mean() tree_lito_1 = cKDTree(litologia_1[['x', 'y', 'z']]) distancias_minimas_2, _ = tree_lito_1.query(litologia_2[['x', 'y', 'z']]) leyes_correspondientes_2 = litologia_2['cu'].values resultados_2 = pd.DataFrame({ 'distancia': distancias_minimas_2, 'cu': leyes_correspondientes_2 }) resultados_2['intervalo'] = pd.cut(resultados_2['distancia'], bins=np.arange(0, 110, 10), right=False) ley_media_por_intervalo_2 = resultados_2.groupby('intervalo')['cu'].mean() if ley_media_por_intervalo_1.dropna().empty or ley_media_por_intervalo_2.dropna().empty: print(f"Combinación Lito {lito_1} vs Lito {lito_2} no tiene suficientes datos en ambas direcciones.") continue plt.figure(figsize=(6, 4)) plt.plot(ley_media_por_intervalo_1.index.categories.mid, ley_media_por_intervalo_1.values, marker='o', label=f'Lito {lito_1} respecto a Lito {lito_2}') plt.plot(-ley_media_por_intervalo_2.index.categories.mid, ley_media_por_intervalo_2.values, marker='x', label=f'Lito {lito_2} respecto a Lito {lito_1}') plt.xlabel('Intervalos de Distancia (m)') plt.ylabel('Ley Media de Cu (%)') plt.title(f'Distancia al contacto (Lito {lito_1} vs Lito {lito_2})') plt.axvline(0, color='black', linewidth=0.5) plt.ylim(0, max(ley_media_por_intervalo_1.max(), ley_media_por_intervalo_2.max()) * 1.1) plt.grid(False) plt.legend() plt.show()