Prima di tutto si puo' effettuare un test se i dati del pozzo possono essere inquadrati all'interno della multifrattalita'
Questo puo' essere fatto l'analisi di regolarita' locale tramite analisi di fluttuazione a momenti multipli (Multifractal Detrended Fluctuation Analysis, MF-DFA)
Se il segnale fosse monofrattale la curva sarebbe una linea orizzontale ma non e' il caso. Quindi il test mostra la presenza di trend multifrattale con q>0 (destra) influenzato dalle grandi fluttuazioni (picchi del grafico dei valori di Gamma o contrasti gelogici) o q<0 (sinistra) influenzati da regioni piu' omogenee o da rumore di fondo
nel grafico sottostante viene descritta l'intensita' della multifrattalita' (se non fossero dati multi frattali si ridurrebbe ad un punto. Piu' ampia e' l'apertura della curva maggiore e' l'intensita' della frattalita'
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import linregress
# ======================================================
# 0 — FUNZIONE MF-DFA MANUALE
# ======================================================
def mfdfa(series, qs, scales, order=1):
"""
Calcola l'esponente di Hurst generalizzato h(q) utilizzando l'algoritmo MF-DFA.
"""
N = len(series)
# 1. Integrazione del segnale (necessaria per il detrending)
Y = np.cumsum(series - np.mean(series))
h_q = []
for q in qs:
F_q_2 = [] # Momenti di fluttuazione di q-esimo ordine
for s in scales:
s = int(s)
# Suddivisione in segmenti di lunghezza s
segments = N // s
# Calcolo della varianza per tutti i segmenti
F_q_s_list = []
for i in range(segments):
idx = slice(i * s, (i + 1) * s)
Y_segment = Y[idx]
# 2. Detrending locale (regressione polinomiale di ordine 'order')
x_local = np.arange(s)
p = np.polyfit(x_local, Y_segment, order)
Y_fit = np.polyval(p, x_local)
# 3. Calcolo della varianza locale (residui al quadrato)
variance = np.mean((Y_segment - Y_fit)**2)
F_q_s_list.append(variance)
# 4. Calcolo della funzione di fluttuazione di q-esimo ordine
F_q_s_list = np.array(F_q_s_list)
if q != 2.0:
# Esecuzione del momento q-esimo (q/2 sulle varianze)
F_q = np.mean(F_q_s_list**(q / 2.0))**(1.0 / q)
else:
# Caso speciale q=2 (momento quadratico)
F_q = np.sqrt(np.mean(F_q_s_list))
F_q_2.append(F_q)
# 5. Regressione log-log: F_q(s) ~ s^h(q)
log_s = np.log10(scales)
log_F_q = np.log10(F_q_2)
# Filtra i valori infiniti o NaN che possono emergere da log(0)
valid_indices = np.isfinite(log_s) & np.isfinite(log_F_q)
if np.sum(valid_indices) > 1:
slope, _, _, _, _ = linregress(log_s[valid_indices], log_F_q[valid_indices])
h_q.append(slope)
else:
h_q.append(np.nan)
return np.array(h_q)
# ======================================================
# 1 — LETTURA FILE CSV E PREPARAZIONE DATI
# ======================================================
filename = "well_log.csv"
RIGHE_LIMITE = 12700
COLONNA_INDICE = 1
try:
df = pd.read_csv(filename, nrows=RIGHE_LIMITE)
except FileNotFoundError:
print(f"Errore: File '{filename}' non trovato.")
exit()
x = df.iloc[:, COLONNA_INDICE].values
x = pd.to_numeric(x, errors='coerce')
x = x[~np.isnan(x)]
# Riscalamento (opzionale)
xmin = np.min(x)
if xmin <= 0:
shift = abs(xmin) + 1e-6
x = x + shift
print(f"Riscalamento effettuato: shift = {shift:.6f}")
N = len(x)
print(f"Analisi eseguita su {N} campioni (Prime {RIGHE_LIMITE} righe del file).")
# ======================================================
# 2 — PARAMETRI MF-DFA
# ======================================================
# Scelta dell'intervallo q
Q_MIN = -5
Q_MAX = 5
Q_STEP = 0.5
qs = np.arange(Q_MIN, Q_MAX + Q_STEP, Q_STEP)
qs = qs[qs != 0] # Esclude q=0
# Scegliere un intervallo di scale logaritmico per una migliore regressione
min_scale = int(N / 50) # Scale minime per un detrending efficace (p.es. 50 campioni)
max_scale = int(N / 4) # Scala massima (1/4 della lunghezza totale)
scales = np.unique(np.logspace(np.log10(min_scale), np.log10(max_scale), num=50).astype(int))
ORDER = 1 # Ordine del polinomio di detrending locale
# ======================================================
# 3 — ESECUZIONE MF-DFA E CALCOLO h(q)
# ======================================================
print("Calcolo degli esponenti h(q)...")
hq = mfdfa(x, qs, scales, order=ORDER)
# Filtra i valori NaN (dovuti a una regressione fallita)
valid_hq = hq[np.isfinite(hq)]
valid_qs = qs[np.isfinite(hq)]
# ======================================================
# 4 — ANALISI E INTERPRETAZIONE DEI RISULTATI
# ======================================================
# 4a. Analisi monofattale (q=2)
if 2.0 in valid_qs:
q_mono_index = np.where(valid_qs == 2.0)[0][0]
hurst_monofractal = valid_hq[q_mono_index]
else:
# Interpolazione per q=2 se non è stato calcolato
hurst_monofractal = np.interp(2.0, valid_qs, valid_hq)
# 4b. Analisi della Multifrattalità
h_max = np.max(valid_hq)
h_min = np.min(valid_hq)
Delta_h = h_max - h_min
# ======================================================
# 5 — PLOT DEI RISULTATI
# ======================================================
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8), sharex=False)
# --- A) Grafico h(q) vs q (Test di Multifattalità)
ax1.plot(valid_qs, valid_hq, 'o-', color='darkblue', markersize=4)
ax1.axhline(hurst_monofractal, color='red', linestyle='--',
label=f'H monofattale (q=2): {hurst_monofractal:.3f}')
ax1.set_title('Esponente di Hurst Generalizzato $h(q)$')
ax1.set_xlabel('Momento di Fluttuazione $q$')
ax1.set_ylabel('Esponente di Scaling $h(q)$')
ax1.grid(True)
ax1.legend()
# --- B) Lo Spettro Multifrattale f(alpha) vs alpha (Singolarità)
# Calcolo dello Spettro tramite Trasformata di Legendre
tau_q = valid_qs * valid_hq - 1
alpha = np.gradient(tau_q, valid_qs)
f_alpha = valid_qs * alpha - tau_q
ax2.plot(alpha, f_alpha, 's-', color='green', markersize=4)
ax2.set_title('Spettro Multifrattale $f(\\alpha)$')
ax2.set_xlabel('Esponente di Singolarità $\\alpha$')
ax2.set_ylabel('Dimensione Frattale $f(\\alpha)$')
ax2.grid(True)
plt.tight_layout()
plt.show()
print("\n" + "=" * 50)
print(f"ANALISI MULTIFRATTALE (MF-DFA) - RISULTATI")
print(f"Δh = h_max - h_min = {Delta_h:.4f}")
if Delta_h > 0.1:
print("CONCLUSIONE: Il segnale è **fortemente multifrattale** (Δh > 0.1).")
print("La sua complessità non è uniforme: sono presenti strutture a diverse scale e diversi tipi di singolarità (anomalie e omogeneità).")
else:
print("CONCLUSIONE: Il segnale è prevalentemente **monofattale** (Δh <= 0.1).")
print(f"Esponente di Hurst Monofattale (q=2): H ≈ {hurst_monofractal:.3f}")
print("=" * 50)
Nessun commento:
Posta un commento