Replies: 10 comments 4 replies
-
Just some thoughts to get started (I never did amplitude tomography myself):
|
Beta Was this translation helpful? Give feedback.
-
@halbmy hi, thank you. I will just leave the formulas while I'm struggling with this. The travel times are computed according to this formula Where:
The attenuation through the Q-factor is computed in the following way It is worth noting that attenuation is a frequency dependent. So we need to know with wich frequency we work. In practice that can be some central frequency of a signal. Where:
We can linearize it by taking the logarithms: finally we can try make the attenuation formula to very similar to travel times formula: |
Beta Was this translation helpful? Give feedback.
-
@halbmy it seems I was able to solve forward problem. But can't understand how to solve inverse problem when we know raypaths and we only need to invert attenuation. def calculate_attenuation(ray_nodes, mesh, vp_model, q_model, freq=50):
"""
Calculate attenuation along the ray path considering mesh cells
:param ray_nodes: ray node coordinates (Nx2 array)
:param mesh: computational mesh
:param vp_model: velocity model
:param q_model: Q-factor model
:param freq: signal frequency (Hz)
:return: attenuation coefficient, total path length
"""
total_attenuation = 1.0
total_length = 0.0
# Iterate through all ray segments
for i in range(len(ray_nodes)-1):
start_point = ray_nodes[i]
end_point = ray_nodes[i+1]
segment_length = np.linalg.norm(end_point - start_point)
# Find midpoint of the segment
mid_point = (start_point + end_point) / 2
# Find cell containing the midpoint
cell = mesh.findCell(mid_point)
if cell:
v = vp_model[cell.id()]
q = q_model[cell.id()]
alpha = np.pi * freq / (q * v)
total_attenuation *= np.exp(-alpha * segment_length)
total_length += segment_length
return total_attenuation, total_length
# Example usage for all rays
freq = 50 # Signal frequency (Hz)
attenuations = []
lengths = []
# Get ray paths
nodes = mgr.fop._core.mesh().positions(withSecNodes=True)
shots = mgr.fop.data.id("s") # Shot indices
recei = mgr.fop.data.id("g") # Receiver indices
for i in range(mgr.fop.data.size()):
# Get ray nodes
ray_nodes = nodes[mgr.fop.way(shots[i], recei[i])]
# Calculate attenuation
att, length = calculate_attenuation(ray_nodes, mesh_fwd, vp_model, q_model, freq)
attenuations.append(att)
lengths.append(length) |
Beta Was this translation helpful? Give feedback.
-
Don't know why I cant get satisfiable result: import numpy as np
import matplotlib.pyplot as plt
import pygimli as pg
import pygimli.meshtools as mt
from pygimli.physics import TravelTimeManager
import pygimli.physics.traveltime as tt
############### FORWARD MODELING ###################
# 1. Generate synthetic model
# Acquisition parameters
bh_spacing = 20.0
bh_length = 25.0
sensor_spacing = 2.5
world = mt.createRectangle(start=[0, -(bh_length + 3)], end=[bh_spacing, 0.0],
marker=0)
depth = -np.arange(sensor_spacing, bh_length + sensor_spacing, sensor_spacing)
sensors = np.zeros((len(depth) * 2, 2)) # two boreholes
sensors[len(depth):, 0] = bh_spacing # x
sensors[:, 1] = np.hstack([depth] * 2) # y
# Create forward model and mesh
c0 = mt.createCircle(pos=(7.0, -10.0), radius=3, nSegments=25, marker=1)
c1 = mt.createCircle(pos=(12.0, -18.0), radius=4, nSegments=25, marker=2)
geom = world + c0 + c1
for sen in sensors:
geom.createNode(sen)
mesh_fwd = mt.createMesh(geom, quality=34, area=0.25)
vp_model = np.array([2000., 2300, 2500])[mesh_fwd.cellMarkers()] # Velocity
q_model = np.array([100, 10, 1])[mesh_fwd.cellMarkers()] # Q-factor
# ax, cb = pg.show(mesh_fwd, vp_model, logScale=False,
# label=pg.unit('vel'), cMap=pg.cmap('vel'), nLevs=3)
# Model visualization
fig = plt.figure(figsize=(10, 8))
gs = fig.add_gridspec(1, 2, width_ratios=[1, 1])
ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1])
# Visualize models
pg.show(mesh_fwd, vp_model, ax=ax1, label="Vp [m/s]", cMap="viridis")
pg.show(mesh_fwd, q_model, ax=ax2, label="Q factor", cMap="jet_r", logScale=True)
plt.show()
# set mesh for inverse proble same as forward problem mesh
mesh = mesh_fwd
scheme = tt.createCrossholeData(sensors)
mgr = tt.TravelTimeManager()
mgr.applyData(scheme)
# mgr.setMesh(mesh, secNodes=4)
mgr.applyMesh(mesh, secNodes=4, ignoreRegionManager=True)
mgr.fop.createJacobian(1/vp_model)
t_calc = mgr.fop.response(1.0 / vp_model)
def calculate_attenuation(ray_nodes, mesh, vp_model, q_model, freq=50):
"""
Calculate attenuation along the ray path considering mesh cells
:param ray_nodes: ray node coordinates (Nx2 array)
:param mesh: computational mesh
:param vp_model: velocity model
:param q_model: Q-factor model
:param freq: signal frequency (Hz)
:return: attenuation coefficient, total path length
"""
total_attenuation = 1.0
total_length = 0.0
# Iterate through all ray segments
for i in range(len(ray_nodes)-1):
start_point = ray_nodes[i]
end_point = ray_nodes[i+1]
segment_length = np.linalg.norm(end_point - start_point)
# Find midpoint of the segment
mid_point = (start_point + end_point) / 2
# Find cell containing the midpoint
cell = mesh.findCell(mid_point)
if cell:
v = vp_model[cell.id()]
q = q_model[cell.id()]
alpha = np.pi * freq / (q * v)
total_attenuation *= np.exp(-alpha * segment_length)
total_length += segment_length
return total_attenuation, total_length
# Example usage for all rays
freq = 50 # Signal frequency (Hz)
attenuations = []
lengths = []
# Get ray paths
nodes = mgr.fop._core.mesh().positions(withSecNodes=True)
shots = mgr.fop.data.id("s") # Shot indices
recei = mgr.fop.data.id("g") # Receiver indices
for i in range(mgr.fop.data.size()):
# Get ray nodes
ray_nodes = nodes[mgr.fop.way(shots[i], recei[i])]
# Calculate attenuation
att, length = calculate_attenuation(ray_nodes, mesh_fwd, vp_model, q_model, freq)
attenuations.append(att)
lengths.append(length)
# Visualization of results
plt.figure(figsize=(10, 5))
plt.scatter(lengths, attenuations, c=t_calc, cmap='viridis')
plt.colorbar(label='Travel time (s)')
plt.xlabel('Ray path length (m)')
plt.ylabel('Attenuation coefficient')
plt.title('Attenuation vs ray path length')
plt.grid(True)
plt.show()
from matplotlib import cm
import matplotlib.colors as colors
from matplotlib.colorbar import ColorbarBase
# Normalize attenuation values for color scale
attenuations_normalized = (np.array(attenuations)-np.min(attenuations))/(np.max(attenuations)-np.min(attenuations))
# Create color map
cmap = cm.plasma_r
norm = colors.Normalize(vmin=np.min(attenuations), vmax=np.max(attenuations))
# Create figure with space for colorbar
fig = plt.figure(figsize=(10, 8))
gs = fig.add_gridspec(1, 3, width_ratios=[1, 1, 0.05])
ax1 = fig.add_subplot(gs[0])
ax2 = fig.add_subplot(gs[1])
cax = fig.add_subplot(gs[2])
# Visualize models
pg.show(mesh_fwd, vp_model, ax=ax1, label="Vp [m/s]", cMap="viridis")
pg.show(mesh_fwd, q_model, ax=ax2, label="Q factor", cMap="jet_r", logScale=True)
# Plot rays with attenuation-based coloring
for ray_idx in range(shots.size()):
ray_nodes = nodes[mgr.fop.way(shots[ray_idx], recei[ray_idx])]
ax1.plot(ray_nodes[:,0], ray_nodes[:,1],
linewidth=1.5,
c=cmap(attenuations_normalized[ray_idx]))
ax2.plot(ray_nodes[:,0], ray_nodes[:,1],
linewidth=1.5,
c=cmap(attenuations_normalized[ray_idx]))
# Add colorbar
cb = ColorbarBase(cax, cmap=cmap, norm=norm, orientation='vertical')
cb.set_label('Attenuation Coefficient', rotation=270, labelpad=15)
plt.suptitle("Vp and Q Models with Ray Paths (color = attenuation)")
plt.tight_layout()
plt.show()
############### INVERSE PROBLEM ###################
A = pg.matrix.MultRightMatrix(mgr.fop.jacobian(), 1/vp_model)
fop = pg.frameworks.LinearModelling(A)
dataVec = - np.log(attenuations) / (np.pi * freq)
errorVec = np.ones_like(dataVec) * 0.001
inv = pg.Inversion(fop, maxIter=5, verbose=True)
inv.errorVals = errorVec
inv_model = inv.run(dataVals=dataVec, startModel = 1/vp_model, showProgress=True, verbose=True, lam=20, maxIter=20, mesh=mesh)
# 7. Data fit analysis
fig, ax = plt.subplots(figsize=(8, 6))
ax.plot(dataVec, dataVec, 'bo', label='Measured')
ax.plot(dataVec, inv.response, 'rx', label='Predicted')
# ax.plot([min(d), max(d)], [min(d), max(d)], 'k--')
ax.set_xlabel("Measured (-ln(attenuation))")
ax.set_ylabel("Predicted (-ln(attenuation))")
ax.set_title("Data Fit")
ax.legend()
ax.grid(True)
plt.show()
ax,cbar = pg.show(mesh, 1/inv_model) At the end amplitudes coincide pretty good but the image is bad. |
Beta Was this translation helpful? Give feedback.
-
Thank you for the code. It is just the regularisation. You need to provide the mesh to the forward operator. Then it should work. |
Beta Was this translation helpful? Give feedback.
-
I would try the following
|
Beta Was this translation helpful? Give feedback.
-
I tried to write it down in my own words: the traveltime for one ray is expressed for all rays by matrix vector product amplitude for one ray expressed by Q (energy loss in one cycle) in a way element and for a sum Normalizing with So it can be expressed by a matrix-vector product using the model parameters In a pure forward modelling code this reads:
i.e. clearly depending on the traveltime and almost not on the Q factor. The full forward operator needed for inversion would be:
and one can obtain the same solution by
|
Beta Was this translation helpful? Give feedback.
-
Your forward response looks, on the contrary, like this which makes really sense. |
Beta Was this translation helpful? Give feedback.
-
One more comment: a frequency of 50Hz does not make much sense for this crosshole geometry. A velocity of 2000m/s would imply a wavelength of 40m, much bigger than the size of the model. You would need frequencies in the range of kHz. |
Beta Was this translation helpful? Give feedback.
-
@halbmy thank you for explanation. There is some things I can't understand. I have some messed up in my mind, I will try to ask some basics. The problem we are working on:
In my code I compute forward problem by hand using Is that ok? Because from my understanding if we apply forward operator on our data we should get the correct attenuation and "diagonal" image doesn't look like correct attenuation. Basically is there a way to run forward operator to get correct image for attenuated signals llike on this image? |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Hi,
I'm trying to do some experiments with amplitude tomography.
I've seen topics #311 and #736 and it seems that some expertise is required.
Forward problem:
Lets suppose that we know exactly velocity and attenuation (say Q-factor, bigger Q -> less attenuation).
For such velocity model we calculate raypaths.
For these raypaths we can calculate amplitude of waves for each Shot-Receiver pair using Q-model.
Inverse problem for Q-factor only:
We need to recover Q-model using true raypaths and amplitudes calculated from forward problem.
The difference between this description and #311 is that in the latter there is no raypaths involved in calculation of amplitudes but rather shot-receiver distances.
I'm trying to implement this in a single notebook.
The problems:
For now I follow crosswhole tutorial and I get:
Beta Was this translation helpful? Give feedback.
All reactions