/* FILE: vidale.c * AUTHOR: Joseph R. Matarese * DATE: Decenber 18, 1992 * Copyright (c) 1992 Joseph R. Matarese and Massachusetts Institute of * Technology * * Permission is granted to copy or modify this code under the condition * that the above copyright notice is maintained. The author and MIT * make ABSOLUTELY NO WARRANTY regarding the fitness of this code for * any purpose. * */ #include <raytime.h> #include <par.h> extern void near_source(float *ttime, float *slow, icoord *nm, icoord *isrc, fcoord *scale, int order); extern void corner(float *ttime, float *slow,icoord *nm, icoord *iin, icoord *iout, fcoord *scale, struct s_ecount *ecount); extern void side(float *ttime, float *slow, icoord *nm, icoord *iin, icoord *iout, fcoord *scale, struct s_ecount *ecount); void rm_head(float *slow, icoord *ndim, icoord *isrc, int mzrcv, float dx, int *nzm); void vidale(float *ttime, float *slow1, icoord *isrc, icoord grid, float dx, int order, int mzrcv) { int iz_lo, iz_hi, ix_lo, ix_hi, iz, ix, node_src; int nzm; icoord iin, iout, dnm, *nm; fcoord dscale, *scale; short ascending, finished; struct s_ecount ecount; float sx, sz, sign, *trueslow, *slow; dscale.x = dx; dscale.y = 0.; dscale.z = dx; scale = &dscale; dnm.x = grid.x; dnm.y = 1; dnm.z = grid.z; nm = &dnm; /* Intialize ttime with maximum value */ for(ix=0; ix<grid.x*grid.z; ix++) ttime[ix] = Infinity; /* transpose slowness field for usage in vidale */ trueslow = (float *)calloc(grid.x*grid.z,sizeof(float)); for (ix=0; ix<grid.x; ix++) { for (iz=0; iz<grid.z; iz++) { trueslow[iz*grid.x + ix] = slow1[ix*grid.z + iz]; } } slow = trueslow; rm_head(slow,&grid,isrc,mzrcv,dx,&nzm); //for actual position of source not on grid: current no-use node_src = isrc->z*grid.x + isrc->x; sx = isrc->x*dx-isrc->x*dx; sz = isrc->z*dx-isrc->z*dx; if (sz < 0) sign = 1; else sign = -1; ttime[node_src] = sign*sqrt(sx*sx+sz*sz)*slow[node_src]; if(nm->y != 1) verr("only 2D models implemented"); ecount.corner = ecount.corner_min = ecount.side = 0; /*---------------------------------------------------------------------------* * Do near source region. *---------------------------------------------------------------------------*/ near_source(ttime,slow,nm,isrc,scale,order); iz_hi = min2(isrc->z+order,nm->z-1); iz_lo = max2(isrc->z-order,0); ix_hi = min2(isrc->x+order,nm->x-1); ix_lo = max2(isrc->x-order,0); /*---------------------------------------------------------------------------* * Loop over outer ring - verticals, then horizontals. *---------------------------------------------------------------------------*/ finished = FALSE; while(!finished) { finished = TRUE; if(ix_hi < nm->x-1) { finished = FALSE; iin.x = ix_hi; /* right-hand edge */ iout.x = ix_hi+1; ascending = FALSE; if(ttime[iz_lo*nm->x+iin.x] <= ttime[(iz_lo+1)*nm->x+iin.x]) { ttime[iz_lo*nm->x+iout.x] = ttime[iz_lo*nm->x+iin.x] + 0.5 * scale->x * (slow[iz_lo*nm->x+iout.x] + slow[iz_lo*nm->x+iin.x]); ecount.corner_min++; } if(ttime[iz_lo*nm->x+iin.x] < ttime[(iz_lo+1)*nm->x+iin.x]) { ascending = TRUE; iin.z = iz_lo; iout.z = iz_lo+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } for(iz=iz_lo+1; iz<=iz_hi-1; iz++) { iin.z = iz; if(ttime[iz*nm->x+iin.x] == ttime[(iz+1)*nm->x+iin.x]) { iout.z = iz; side(ttime,slow,nm,&iin,&iout,scale,&ecount); } if(ttime[iz*nm->x+iin.x] < ttime[(iz+1)*nm->x+iin.x]) { if(!ascending) { iout.z = iz; side(ttime,slow,nm,&iin,&iout,scale,&ecount); } ascending = TRUE; iout.z = iz+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } else ascending = FALSE; } if(ttime[iz_hi*nm->x+iin.x] <= ttime[(iz_hi-1)*nm->x+iin.x]) { ttime[iz_hi*nm->x+iout.x] = ttime[iz_hi*nm->x+iin.x] + 0.5 * scale->x * (slow[iz_hi*nm->x+iout.x] + slow[iz_hi*nm->x+iin.x]); ecount.corner_min++; } for(iz=iz_hi; iz>=iz_lo+1; iz--) { if(ttime[iz*nm->x+iin.x] < ttime[(iz-1)*nm->x+iin.x]) { iin.z = iz; iout.z = iz-1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } } } if(ix_lo > 0) { finished = FALSE; iin.x = ix_lo; /* left-hand edge */ iout.x = ix_lo-1; ascending = FALSE; if(ttime[iz_lo*nm->x+iin.x] <= ttime[(iz_lo+1)*nm->x+iin.x]) { ttime[iz_lo*nm->x+iout.x] = ttime[iz_lo*nm->x+iin.x] + 0.5 * scale->x * (slow[iz_lo*nm->x+iout.x] + slow[iz_lo*nm->x+iin.x]); ecount.corner_min++; } if(ttime[iz_lo*nm->x+iin.x] < ttime[(iz_lo+1)*nm->x+iin.x]) { ascending = TRUE; iin.z = iz_lo; iout.z = iz_lo+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } for(iz=iz_lo+1; iz<=iz_hi-1; iz++) { iin.z = iz; if(ttime[iz*nm->x+iin.x] == ttime[(iz+1)*nm->x+iin.x]) { iout.z = iz; side(ttime,slow,nm,&iin,&iout,scale,&ecount); } if(ttime[iz*nm->x+iin.x] < ttime[(iz+1)*nm->x+iin.x]) { if(!ascending) { iout.z = iz; side(ttime,slow,nm,&iin,&iout,scale,&ecount); } ascending = TRUE; iout.z = iz+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } else ascending = FALSE; } if(ttime[iz_hi*nm->x+iin.x] <= ttime[(iz_hi-1)*nm->x+iin.x]) { ttime[iz_hi*nm->x+iout.x] = ttime[iz_hi*nm->x+iin.x] + 0.5 * scale->x * (slow[iz_hi*nm->x+iout.x] + slow[iz_hi*nm->x+iin.x]); ecount.corner_min++; } for(iz=iz_hi; iz>=iz_lo+1; iz--) { if(ttime[iz*nm->x+iin.x] < ttime[(iz-1)*nm->x+iin.x]) { iin.z = iz; iout.z = iz-1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } } } if(iz_hi < nm->z-1) { finished = FALSE; iin.z = iz_hi; /* bottom edge */ iout.z = iz_hi+1; ascending = FALSE; if(ttime[iin.z*nm->x+ix_lo] <= ttime[iin.z*nm->x+ix_lo+1]) { ttime[iout.z*nm->x+ix_lo] = ttime[iin.z*nm->x+ix_lo] + 0.5 * scale->x * (slow[iout.z*nm->x+ix_lo] + slow[iin.z*nm->x+ix_lo]); ecount.corner_min++; } if(ttime[iin.z*nm->x+ix_lo] < ttime[iin.z*nm->x+ix_lo+1]) { ascending = TRUE; iin.x = ix_lo; iout.x = ix_lo+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } for(ix=ix_lo+1; ix<=ix_hi-1; ix++) { iin.x = ix; if(ttime[iin.z*nm->x+ix] == ttime[iin.z*nm->x+ix+1]) { iout.x = ix; side(ttime,slow,nm,&iin,&iout,scale,&ecount); } if(ttime[iin.z*nm->x+ix] < ttime[iin.z*nm->x+ix+1]) { if(!ascending) { iout.x = ix; side(ttime,slow,nm,&iin,&iout,scale,&ecount); } ascending = TRUE; iout.x = ix+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } else ascending = FALSE; } if(ttime[iin.z*nm->x+ix_hi] <= ttime[iin.z*nm->x+ix_hi-1]) { ttime[iout.z*nm->x+ix_hi] = ttime[iin.z*nm->x+ix_hi] + 0.5 * scale->x * (slow[iout.z*nm->x+ix_hi] + slow[iin.z*nm->x+ix_hi]); ecount.corner_min++; } for(ix=ix_hi; ix>=ix_lo+1; ix--) { if(ttime[iin.z*nm->x+ix] < ttime[iin.z*nm->x+ix-1]) { iin.x = ix; iout.x = ix-1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } } } if(iz_lo > 0) { finished = FALSE; iin.z = iz_lo; /* top edge */ iout.z = iz_lo-1; ascending = FALSE; if(ttime[iin.z*nm->x+ix_lo] <= ttime[iin.z*nm->x+ix_lo+1]) { ttime[iout.z*nm->x+ix_lo] = ttime[iin.z*nm->x+ix_lo] + 0.5 * scale->x * (slow[iout.z*nm->x+ix_lo] + slow[iin.z*nm->x+ix_lo]); ecount.corner_min++; } if(ttime[iin.z*nm->x+ix_lo] < ttime[iin.z*nm->x+ix_lo+1]) { ascending = TRUE; iin.x = ix_lo; iout.x = ix_lo+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } for(ix=ix_lo+1; ix<=ix_hi-1; ix++) { iin.x = ix; if(ttime[iin.z*nm->x+ix] == ttime[iin.z*nm->x+ix+1]) { iout.x = ix; side(ttime,slow,nm,&iin,&iout,scale,&ecount); } if(ttime[iin.z*nm->x+ix] < ttime[iin.z*nm->x+ix+1]) { if(!ascending) { iout.x = ix; side(ttime,slow,nm,&iin,&iout,scale,&ecount); } ascending = TRUE; iout.x = ix+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } else ascending = FALSE; } if(ttime[iin.z*nm->x+ix_hi] <= ttime[iin.z*nm->x+ix_hi-1]) { ttime[iout.z*nm->x+ix_hi] = ttime[iin.z*nm->x+ix_hi] + 0.5 * scale->x * (slow[iout.z*nm->x+ix_hi] + slow[iin.z*nm->x+ix_hi]); ecount.corner_min++; } for(ix=ix_hi; ix>=ix_lo+1; ix--) { if(ttime[iin.z*nm->x+ix] < ttime[iin.z*nm->x+ix-1]) { iin.x = ix; iout.x = ix-1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } } } if((ix_hi < nm->x-1) || (iz_hi < nm->z-1)) { /* bottom right corner */ iin.x = (ix_hi < nm->x-1) ? ix_hi : nm->x-2; iout.x = iin.x+1; iin.z = (iz_hi < nm->z-1) ? iz_hi : nm->z-2; iout.z = iin.z+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } if((ix_lo > 0) || (iz_hi < nm->z-1)) { /* bottom left corner */ iin.x = (ix_lo > 0) ? ix_lo : 1; iout.x = iin.x-1; iin.z = (iz_hi < nm->z-1) ? iz_hi : nm->z-2; iout.z = iin.z+1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } if((ix_hi < nm->x-1) || (iz_lo > 0)) { /* top right corner */ iin.x = (ix_hi < nm->x-1) ? ix_hi : nm->x-2; iout.x = iin.x+1; iin.z = (iz_lo > 0) ? iz_lo : 1; iout.z = iin.z-1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } if((ix_lo > 0) || (iz_lo > 0)) { /* top left corner */ iin.x = (ix_lo > 0) ? ix_lo : 1; iout.x = iin.x-1; iin.z = (iz_lo > 0) ? iz_lo : 1; iout.z = iin.z-1; corner(ttime,slow,nm,&iin,&iout,scale,&ecount); } ix_hi = min2(ix_hi+1,nm->x-1); ix_lo = max2(ix_lo-1,0); iz_hi = min2(iz_hi+1,nm->z-1); iz_lo = max2(iz_lo-1,0); } /* while(!finished) */ /* jm_message("debug",__FILE__,__LINE__, "errors:\n %s: %d\n %s: %d\n %s: %d", "corner minima",ecount.corner_min, "corner negative sqrts",ecount.corner, "side negative sqrts",ecount.side); */ return; } /* FILE: near_source.c * AUTHOR: Joseph R. Matarese * DATE: Decenber 18, 1992 * Copyright (c) 1992 Joseph R. Matarese and Massachusetts Institute of * Technology * * Permission is granted to copy or modify this code under the condition * that the above copyright notice is maintained. The author and MIT * make ABSOLUTELY NO WARRANTY regarding the fitness of this code for * any purpose. * */ /*---------------------------------------------------------------------------* * * Calculate near source traveltimes. * * * *---------------------------------------------------------------------------*/ void near_source(float *ttime, float *slow, icoord *nm, icoord *isrc, fcoord *scale, int order) { int ix_lo, ix_hi, iz_lo, iz_hi, ix, iz; float slow_0, ttime_0, dist; if(nm->y != 1) verr("only 2D models implemented"); /*---------------------------------------------------------------------------* * Boundaries of source region. *---------------------------------------------------------------------------*/ ix_lo = max2(isrc->x-order,0); ix_hi = min2(isrc->x+order,nm->x-1); iz_lo = max2(isrc->z-order,0); iz_hi = min2(isrc->z+order,nm->z-1); /*---------------------------------------------------------------------------* * Calculate traveltimes for source region. * We assume this region to nearly homogeneous. *---------------------------------------------------------------------------*/ slow_0 = slow[isrc->z*nm->x+isrc->x]; ttime_0 = ttime[isrc->z*nm->x+isrc->x]; for(iz=iz_lo; iz<=iz_hi; iz++) { for(ix=ix_lo; ix<=ix_hi; ix++) { dist = hypot((ix-isrc->x)*scale->x,(iz-isrc->z)*scale->z); ttime[iz*nm->x+ix] = 0.5*dist*(slow[iz*nm->x+ix] + slow_0) + ttime_0; } } return; } /* FILE: side.c * AUTHOR: Joseph R. Matarese * DATE: Decenber 18, 1992 * Copyright (c) 1992 Joseph R. Matarese and Massachusetts Institute of * Technology * * Permission is granted to copy or modify this code under the condition * that the above copyright notice is maintained. The author and MIT * make ABSOLUTELY NO WARRANTY regarding the fitness of this code for * any purpose. * */ /*---------------------------------------------------------------------------* * * Apply the side stencil. * *---------------------------------------------------------------------------*/ enum e_orientation { vertical, horizontal }; void side(float *ttime, float *slow, icoord *nm, icoord *iin, icoord *iout, fcoord *scale, struct s_ecount *ecount) { enum e_orientation orientation; float dt, slow_0, operand, ttnew, tttmp; static double c_sqrt2; static char initialized = (char)0; if(!initialized) { if(nm->y != 1) verr("only 2D models implemented"); if(scale->x != scale->z) verr("only uniform grid implemented"); c_sqrt2 = sqrt(2.); initialized = (char)1; } orientation = (iin->x == iout->x) ? horizontal : vertical; if(orientation == vertical) { dt = ttime[(iin->z+1)*nm->x+iin->x] - ttime[(iin->z-1)*nm->x+iin->x]; slow_0 = 0.25*(slow[(iin->z+1)*nm->x+iin->x] + slow[(iin->z-1)*nm->x+iin->x] + slow[iin->z*nm->x+iin->x] + slow[iin->z*nm->x+iout->x]); if((operand = scale->x*scale->x*slow_0*slow_0 - 0.25*dt*dt) < 0.) { slow_0 = 0.5*(slow[(iin->z-1)*nm->x+iin->x]+slow[iin->z*nm->x+iout->x]); ttnew = ttime[(iin->z-1)*nm->x+iin->x] + c_sqrt2*scale->x*slow_0; slow_0 = 0.5*(slow[(iin->z+1)*nm->x+iin->x]+slow[iin->z*nm->x+iout->x]); tttmp = ttime[(iin->z+1)*nm->x+iin->x] + c_sqrt2*scale->x*slow_0; if(tttmp < ttnew) ttnew = tttmp; slow_0 = 0.5*(slow[iin->z*nm->x+iin->x] + slow[iin->z*nm->x+iout->x]); tttmp = ttime[iin->z*nm->x+iin->x] + scale->x*slow_0; if(tttmp < ttnew) ttnew = tttmp; ecount->side++; } else ttnew = ttime[iin->z*nm->x+iin->x] + sqrt(operand); ttime[iin->z*nm->x+iout->x] = ttnew; } else { dt = ttime[iin->z*nm->x+iin->x+1] - ttime[iin->z*nm->x+iin->x-1]; slow_0 = 0.25*(slow[iin->z*nm->x+iin->x+1] + slow[iin->z*nm->x+iin->x-1] + slow[iin->z*nm->x+iin->x] + slow[iout->z*nm->x+iin->x]); if((operand = scale->x*scale->x*slow_0*slow_0 - 0.25*dt*dt) < 0.) { slow_0 = 0.5*(slow[iin->z*nm->x+iin->x-1] + slow[iout->z*nm->x+iin->x]); ttnew = ttime[iin->z*nm->x+iin->x-1] + c_sqrt2*scale->x*slow_0; slow_0 = 0.5*(slow[iin->z*nm->x+iin->x+1] + slow[iout->z*nm->x+iin->x]); tttmp = ttime[iin->z*nm->x+iin->x+1] + c_sqrt2*scale->x*slow_0; if(tttmp < ttnew) ttnew = tttmp; slow_0 = 0.5*(slow[iin->z*nm->x+iin->x] + slow[iout->z*nm->x+iin->x]); tttmp = ttime[iin->z*nm->x+iin->x] + scale->x*slow_0; if(tttmp < ttnew) ttnew = tttmp; ecount->side++; } else ttnew = ttime[iin->z*nm->x+iin->x] + sqrt(operand); ttime[iout->z*nm->x+iin->x] = ttnew; } return; } /* FILE: corner.c * AUTHOR: Joseph R. Matarese * DATE: Decenber 18, 1992 * Copyright (c) 1992 Joseph R. Matarese and Massachusetts Institute of * Technology * * Permission is granted to copy or modify this code under the condition * that the above copyright notice is maintained. The author and MIT * make ABSOLUTELY NO WARRANTY regarding the fitness of this code for * any purpose. * */ /*---------------------------------------------------------------------------* * * Apply the corner stencil. * *---------------------------------------------------------------------------*/ void corner(float *ttime, float *slow,icoord *nm, icoord *iin, icoord *iout, fcoord *scale, struct s_ecount *ecount) { float dt, slow_0, operand, ttnew, tttmp; static double c_sqrt2; static char initialized = (char)0; if(!initialized) { if(nm->y != 1) verr("only 2D models implemented"); if(scale->x != scale->z) verr("only uniform grid implemented"); c_sqrt2 = sqrt(2.); initialized = (char)1; } dt = ttime[iout->z*nm->x+iin->x] - ttime[iin->z*nm->x+iout->x]; slow_0 = 0.25*(slow[iout->z*nm->x+iin->x] + slow[iin->z*nm->x+iout->x] + slow[iout->z*nm->x+iout->x] + slow[iin->z*nm->x+iin->x]); if((operand = 2*scale->x*scale->x*slow_0*slow_0 - dt*dt) < 0.) { slow_0 = 0.5*(slow[iin->z*nm->x+iout->x] + slow[iout->z*nm->x+iout->x]); ttnew = ttime[iin->z*nm->x+iout->x] + scale->x*slow_0; slow_0 = 0.5*(slow[iout->z*nm->x+iin->x] + slow[iout->z*nm->x+iout->x]); tttmp = ttime[iout->z*nm->x+iin->x] + scale->x*slow_0; if(tttmp < ttnew) ttnew = tttmp; slow_0 = 0.5*(slow[iout->z*nm->x+iout->x] + slow[iin->z*nm->x+iin->x]); tttmp = ttime[iin->z*nm->x+iin->x] + c_sqrt2*scale->x*slow_0; if(tttmp < ttnew) ttnew = tttmp; ecount->corner++; } else ttnew = ttime[iin->z*nm->x+iin->x] + sqrt(operand); /*---------------------------------------------------------------------------* * Nonuniform grid? * scale2->x = scale->x * scale->x; scale2->z = scale->z * scale->z; scale2_plus = scale2->z + scale2->x; scale2_minus = scale2->z + scale2->x; ttnew = ttime[iin->z*nm->x+iin->x] + (scale2_minus * dt + 2 * scale->z * scale->x * sqrt(scale2_plus * slow_0 * slow_0 - dt * dt)) / scale2_plus; *---------------------------------------------------------------------------*/ if(ttnew < ttime[iout->z*nm->x+iout->x]) ttime[iout->z*nm->x+iout->x] = ttnew; return; } void rm_head(float *slow, icoord *ndim, icoord *isrc, int mzrcv, float dx, int *nzm) { int iz, ix, k, l, i, izn, lprev, nz, nx; float brd, val, dz; iz = isrc->z; ix = isrc->x; nz = ndim->z; nx = ndim->x; dz = dx; if (iz == 0) { ndim->z = 2; return;} if (iz >= mzrcv) { brd = slow[iz*nx+ix]; val = slow[(iz-1)*nx+ix]; while ((brd == val) && iz < nz-1) brd = slow[++iz*nx+ix]; lprev = iz; for (l = iz; l > 0; l--) { for (k = 0; k < nx; k++) { if (slow[l*nx+k] == brd) { slow[l*nx+k] = val; lprev = l; } } if (lprev-l) l = 0; } iz = isrc->z; } else { brd = slow[iz*nx+ix]; val = slow[(iz+1)*nx+ix]; while (brd == val && iz > 0) brd = slow[--iz*nx+ix]; if (iz < nz) { lprev = iz; for (l = iz; l < nz; l++) { for (k = 0; k < nx; k++) { if (slow[l*nx+k] == brd) { slow[l*nx+k] = val; lprev = l; } } if (lprev-l) l = nz; } } iz = mzrcv; } *nzm = iz+1; return; }