program test use sep_f90_lib_mod ! sepf90 library (for simple I/O) use nnnmo ! generic shift and scale programs use nmo_mod ! module containing shift and scale definitionstype(sep_90),pointer :: sepdata,velocity ! sep90 derived types real,pointer,dimension(:) :: offset ! trace offsets real,pointer,dimension(:,:) :: in_data,out_data ! cmp values real,pointer,dimension(:) :: vel_vals ! velocity values real,allocatable,dimension(:) :: t ! x/vel integer :: i2,stat,n1,interp real :: o1,d1 ! time axis parameters
call initpar() ! call getch("interp","d","inter") ! get interpolation type nullify(in_data,out_data,offset,vel_vals) ! nullify pointer arrays call init_vars(sepdata,velocity) ! set up SEP data call sep_reed("velocity",velocity) ! read in the velocity call get_trace_vector(velocity,vel_vals) ! put velocity in an array call sep_reed("in",sepdata) ! read in cmp gather call get_trace_slice(sepdata,in_data) ! copy values to an array o1=sepdata%o(1);d1=sepdata%d(1);n1=sepdata%n(1) ! allocate(out_data(size(in_data,1),size(in_data,2)))! create output space call nnnmo_init (.true., o1, o1, d1, n1) ! initiate nmo operator allocate(t(n1)) call get_key_values(sepdata,"aoffset",offset) ! get offset values do i2=1,size(in_data,dim=2) ! loop over traces t=offset(i2)/vel_vals ! init t
call nnnmo_step(interp,vofz_hyper_time,cos2D_ampl,t) stat=nnnmo_op(.false.,.false.,in_data(:,i2),out_data (:,i2))
end do call nnnmo_close () ! close nmo operator call put_trace_slice(sepdata,out_data) ! trace into septype call sep_rite("out",sepdata) ! write out dataset end program test
By performing this `spray' operation (L) followed by its adjoint, NMO (L'), we should recover something close to the input. Figure 1 shows the input trace, the modeled CMP gather, and the result of applying LL'.
Their are two primary advantages to the object-oriented style. First, it is virtually data independent, no portion of the code makes assumptions on data geometry. Second, because the implementation is highly modular, experimenting with the effect of constant vs. variable velocity, differing interpolation and anti-aliasing schemes, or push vs. pull operator implementation is simple. For example, suppose we wish to see the effect on recovering the original t(0) trace due to variable vs. constant velocity for both linear and nearest-neighbor interpolation. Only the input velocity trace and the interpolation parameter (command-line arguments in the case of simple.f90) need to be altered. Figure 2 shows the resulting CMP gathers while Figure 3 shows the resulting t(0) trace using the different velocity characterizations and interpolation schemes. As expected linear interpolation outperforms nearest-neighbor interpolation in recovering the amplitudes without generating high-frequency noise; also the adjoint is a slightly better approximation when we have constant velocity compared to a v(z) medium.
Rewriting the NMO ``spray and stack'' program for different kinds of transformation (DMO, post-stack and prestack migration, datuming, etc.) becomes a fairly simple exercise.