Análisis de Contacto

LUIS ÁLVAREZ P.

(09 de Septiembre, 2024)

Tabla de contenidos

Introducción

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. 

Sobre el 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:

Combinaciones posibles

El código esta elaborado para ser capaz de reconocer todos los posibles contactos entre unidades geológicas, independientes cuantas sean estas. 

Código en Python

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()

Resultados

Compartir en facebook
Facebook
Compartir en twitter
Twitter
Compartir en linkedin
LinkedIn
Compartir en whatsapp
WhatsApp