diff --git a/raytime3d/Makefile b/raytime3d/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..1bed95dcdef7cd3fb664ca9017a3bad0b38788b3
--- /dev/null
+++ b/raytime3d/Makefile
@@ -0,0 +1,72 @@
+# Makefile
+
+include ../Make_include
+
+########################################################################
+# define general include and system library
+ALLINC  = -I.
+LIBS    += -L$L -lgenfft -lm $(LIBSM)
+#LIBS    += -L$L -lgenfft -lm -lc
+#OPTC = -g -Wall -fsignaling-nans -O0
+#OPTC += -fopenmp -Waddress
+#OPTC += -g -O0
+#OPTC := $(subst -O3 -ffast-math, -O1 -g ,$(OPTC))
+#PGI options for compiler feedback
+#OPTC += -Mprof=lines
+#LDFLAGS += -Mprof=lines
+
+#		side.c \
+#		corner.c \
+#		near_source.c \
+#		Grid2Time1.c \
+
+all: raytime3d
+
+PRG = raytime3d
+
+SRCC	= $(PRG).c \
+		vidale3d.c \
+		src3d.c \
+		getParameters.c  \
+		getWaveletInfo.c  \
+		writeSrcRecPos.c  \
+		readModel.c  \
+		getWaveletHeaders.c  \
+		verbosepkg.c  \
+        getModelInfo.c  \
+		wallclock_time.c  \
+        recvPar.c  \
+        writesufile.c  \
+        name_ext.c  \
+		atopkge.c \
+		docpkge.c \
+		threadAffinity.c \
+		getpars.c
+
+OBJC	= $(SRCC:%.c=%.o)
+
+$(PRG):	$(OBJC) raytime.h
+	$(CC) $(LDFLAGS) $(CFLAGS) $(OPTC) -o Raytime $(OBJC) $(LIBS)
+
+install: raytime 
+	cp Raytime $B
+
+clean:
+		rm -f core $(OBJC) $(OBJM) Raytime 
+
+realclean:
+		rm -f core $(OBJC) $(OBJM) $(PRG) $B/Raytime 
+
+
+print:	Makefile $(SRC)
+	$(PRINT) $?
+	@touch print
+
+count:
+	@wc $(SRC)
+
+tar:
+	@tar cf $(PRG).tar Makefile $(SRC) && compress $(PRG).tar
+
+
+
diff --git a/raytime3d/SUsegy.h b/raytime3d/SUsegy.h
new file mode 100644
index 0000000000000000000000000000000000000000..a9133b999320911b29505909c2e4cd5f33b83dc5
--- /dev/null
+++ b/raytime3d/SUsegy.h
@@ -0,0 +1,391 @@
+/* This file is property of the Colorado School of Mines.
+ 
+ Copyright © 2007, Colorado School of Mines,
+ All rights reserved.
+ 
+ 
+ Redistribution and use in source and binary forms, with or 
+ without modification, are permitted provided that the following 
+ conditions are met:
+ 
+ *  Redistributions of source code must retain the above copyright 
+ notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above 
+ copyright notice, this list of conditions and the following 
+ disclaimer in the documentation and/or other materials provided 
+ with the distribution.
+ *  Neither the name of the Colorado School of Mines nor the names of
+ its contributors may be used to endorse or promote products 
+ derived from this software without specific prior written permission.
+ 
+ Warranty Disclaimer:
+ THIS SOFTWARE IS PROVIDED BY THE COLORADO SCHOOL OF MINES AND CONTRIBUTORS 
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+ COLORADO SCHOOL OF MINES OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ POSSIBILITY OF SUCH DAMAGE.
+ 
+ 
+ Export Restriction Disclaimer:
+ We believe that CWP/SU: Seismic Un*x is a low technology product that does
+ not appear on the Department of Commerce CCL list of restricted exports.
+ Accordingly, we believe that our product meets the qualifications of
+ an ECCN (export control classification number) of EAR99 and we believe
+ it fits the qualifications of NRR (no restrictions required), and
+ is thus not subject to export restrictions of any variety.
+ 
+ Approved Reference Format:
+ In publications, please refer to SU as per the following example:
+ Cohen, J. K. and Stockwell, Jr. J. W., (200_), CWP/SU: Seismic Un*x 
+ Release No. __: an open source software  package for seismic 
+ research and processing, 
+ Center for Wave Phenomena, Colorado School of Mines.
+ 
+ Articles about SU in peer-reviewed journals:
+ Saeki, T., (1999), A guide to Seismic Un*x (SU)(2)---examples of data processing (part 1), data input and preparation of headers, Butsuri-Tansa (Geophysical Exploration), vol. 52, no. 5, 465-477.
+ Stockwell, Jr. J. W. (1999), The CWP/SU: Seismic Un*x Package, Computers and Geosciences, May 1999.
+ Stockwell, Jr. J. W. (1997), Free Software in Education: A case study of CWP/SU: Seismic Un*x, The Leading Edge, July 1997.
+ Templeton, M. E., Gough, C.A., (1998), Web Seismic Un*x: Making seismic reflection processing more accessible, Computers and Geosciences.
+ 
+ Acknowledgements:
+ SU stands for CWP/SU:Seismic Un*x, a processing line developed at Colorado 
+ School of Mines, partially based on Stanford Exploration Project (SEP) 
+ software.
+ */
+
+/* segy.h - include file for SEGY traces
+ *
+ * declarations for:
+ *	typedef struct {} segy - the trace identification header
+ *	typedef struct {} bhed - binary header
+ *
+ * Note:
+ *	If header words are added, run the makefile in this directory
+ *	to recreate hdr.h.
+ *
+ * Reference:
+ *	K. M. Barry, D. A. Cavers and C. W. Kneale, "Special Report:
+ *		Recommended Standards for Digital Tape Formats",
+ *		Geophysics, vol. 40, no. 2 (April 1975), P. 344-352.
+ *	
+ * $Author: john $
+ * $Source: /usr/local/cwp/src/su/include/RCS/segy.h,v $
+ * $Revision: 1.23 $ ; $Date: 1998/03/26 23:48:18 $
+ */ 
+
+/* #define SU_NFLTS	800000	 Arbitrary limit on data array size	*/
+
+/**
+* This segyhdr has been redefined and uses an integer (32 bit) for number of samples (ns) 
+*  Jan Thorbecke 
+**/
+
+
+/* TYPEDEFS */
+typedef struct {	/* segy - trace identification header */
+
+	int tracl;	/* trace sequence number within line */
+
+	int tracr;	/* trace sequence number within reel */
+
+	int fldr;	/* field record number */
+
+	int tracf;	/* trace number within field record */
+
+	int ep;	/* energy source point number */
+
+	int cdp;	/* CDP ensemble number */
+
+	int cdpt;	/* trace number within CDP ensemble */
+
+	short trid;	/* trace identification code:
+			1 = seismic data
+			2 = dead
+			3 = dummy
+			4 = time break
+			5 = uphole
+			6 = sweep
+			7 = timing
+			8 = water break
+			9---, N = optional use (N = 32,767)
+
+			Following are CWP id flags:
+
+			 9 = autocorrelation
+
+			10 = Fourier transformed - no packing
+			     xr[0],xi[0], ..., xr[N-1],xi[N-1]
+
+			11 = Fourier transformed - unpacked Nyquist
+			     xr[0],xi[0],...,xr[N/2],xi[N/2]
+
+			12 = Fourier transformed - packed Nyquist
+	 		     even N:
+			     xr[0],xr[N/2],xr[1],xi[1], ...,
+				xr[N/2 -1],xi[N/2 -1]
+				(note the exceptional second entry)
+			     odd N:
+			     xr[0],xr[(N-1)/2],xr[1],xi[1], ...,
+				xr[(N-1)/2 -1],xi[(N-1)/2 -1],xi[(N-1)/2]
+				(note the exceptional second & last entries)
+
+			13 = Complex signal in the time domain
+			     xr[0],xi[0], ..., xr[N-1],xi[N-1]
+
+			14 = Fourier transformed - amplitude/phase
+			     a[0],p[0], ..., a[N-1],p[N-1]
+
+			15 = Complex time signal - amplitude/phase
+			     a[0],p[0], ..., a[N-1],p[N-1]
+
+			16 = Real part of complex trace from 0 to Nyquist
+
+			17 = Imag part of complex trace from 0 to Nyquist
+
+			18 = Amplitude of complex trace from 0 to Nyquist
+
+			19 = Phase of complex trace from 0 to Nyquist
+
+			21 = Wavenumber time domain (k-t)
+
+			22 = Wavenumber frequency (k-omega)
+
+			23 = Envelope of the complex time trace
+
+			24 = Phase of the complex time trace
+
+			25 = Frequency of the complex time trace
+
+			30 = Depth-Range (z-x) traces
+
+			43 = Seismic Data, Vertical Component 
+
+			44 = Seismic Data, Horizontal Component 1 
+
+			45 = Seismic Data, Horizontal Component 2 
+
+			46 = Seismic Data, Radial Component
+
+			47 = Seismic Data, Transverse Component  
+
+			101 = Seismic data packed to bytes (by supack1)
+			
+			102 = Seismic data packed to 2 bytes (by supack2)
+			*/
+
+	short nvs;	/* number of vertically summed traces (see vscode
+			   in bhed structure) */
+
+	short nhs;	/* number of horizontally summed traces (see vscode
+			   in bhed structure) */
+
+	short duse;	/* data use:
+				1 = production
+				2 = test */
+
+	int offset;	/* distance from source point to receiver
+			   group (negative if opposite to direction
+			   in which the line was shot) */
+
+	int gelev;	/* receiver group elevation from sea level
+			   (above sea level is positive) */
+
+	int selev;	/* source elevation from sea level
+			   (above sea level is positive) */
+
+	int sdepth;	/* source depth (positive) */
+
+	int gdel;	/* datum elevation at receiver group */
+
+	int sdel;	/* datum elevation at source */
+
+	int swdep;	/* water depth at source */
+
+	int gwdep;	/* water depth at receiver group */
+
+	short scalel;	/* scale factor for previous 7 entries
+			   with value plus or minus 10 to the
+			   power 0, 1, 2, 3, or 4 (if positive,
+			   multiply, if negative divide) */
+
+	short scalco;	/* scale factor for next 4 entries
+			   with value plus or minus 10 to the
+			   power 0, 1, 2, 3, or 4 (if positive,
+			   multiply, if negative divide) */
+
+	int  sx;	/* X source coordinate */
+
+	int  sy;	/* Y source coordinate */
+
+	int  gx;	/* X group coordinate */
+
+	int  gy;	/* Y group coordinate */
+
+	short counit;	/* coordinate units code:
+				for previous four entries
+				1 = length (meters or feet)
+				2 = seconds of arc (in this case, the
+				X values are longitude and the Y values
+				are latitude, a positive value designates
+				the number of seconds east of Greenwich
+				or north of the equator */
+
+	short wevel;	/* weathering velocity */
+
+	short swevel;	/* subweathering velocity */
+
+	short sut;	/* uphole time at source */
+
+	short gut;	/* uphole time at receiver group */
+
+	short sstat;	/* source static correction */
+
+	short gstat;	/* group static correction */
+
+	short tstat;	/* total static applied */
+
+	short laga;	/* lag time A, time in ms between end of 240-
+			   byte trace identification header and time
+			   break, positive if time break occurs after
+			   end of header, time break is defined as
+			   the initiation pulse which maybe recorded
+			   on an auxiliary trace or as otherwise
+			   specified by the recording system */
+
+	short lagb;	/* lag time B, time in ms between the time break
+			   and the initiation time of the energy source,
+			   may be positive or negative */
+
+	short delrt;	/* delay recording time, time in ms between
+			   initiation time of energy source and time
+			   when recording of data samples begins
+			   (for deep water work if recording does not
+			   start at zero time) */
+
+	short muts;	/* mute time--start */
+
+	short mute;	/* mute time--end */
+
+	short igc;	/* instrument gain constant */
+
+	int ns;	        /* number of samples in this trace */
+
+	unsigned short dt;	/* sample interval; in micro-seconds */
+
+	short gain;	/* gain type of field instruments code:
+				1 = fixed
+				2 = binary
+				3 = floating point
+				4 ---- N = optional use */
+
+	short igi;	/* instrument early or initial gain */
+
+	short corr;	/* correlated:
+				1 = no
+				2 = yes */
+
+	short sfs;	/* sweep frequency at start */
+
+	short sfe;	/* sweep frequency at end */
+
+	short slen;	/* sweep length in ms */
+
+	short styp;	/* sweep type code:
+				1 = linear
+				2 = cos-squared
+				3 = other */
+
+	short stas;	/* sweep trace length at start in ms */
+
+	short stae;	/* sweep trace length at end in ms */
+
+	short tatyp;	/* taper type: 1=linear, 2=cos^2, 3=other */
+
+	short afilf;	/* alias filter frequency if used */
+
+	short afils;	/* alias filter slope */
+
+	short nofilf;	/* notch filter frequency if used */
+
+	short nofils;	/* notch filter slope */
+
+	short lcf;	/* low cut frequency if used */
+
+	short hcf;	/* high cut frequncy if used */
+
+	short lcs;	/* low cut slope */
+
+	short hcs;	/* high cut slope */
+
+	short year;	/* year data recorded */
+
+	short day;	/* day of year */
+
+	short hour;	/* hour of day (24 hour clock) */
+
+	short minute;	/* minute of hour */
+
+	short sec;	/* second of minute */
+
+	short timbas;	/* time basis code:
+				1 = local
+				2 = GMT
+				3 = other */
+
+	short trwf;	/* trace weighting factor, defined as 1/2^N
+			   volts for the least sigificant bit */
+
+	short grnors;	/* geophone group number of roll switch
+			   position one */
+
+	short grnofr;	/* geophone group number of trace one within
+			   original field record */
+
+	short grnlof;	/* geophone group number of last trace within
+			   original field record */
+
+	short gaps;	/* gap size (total number of groups dropped) */
+
+	short otrav;	/* overtravel taper code:
+				1 = down (or behind)
+				2 = up (or ahead) */
+
+	/* local assignments */
+
+	short mark;	/* mark selected traces */
+
+	float d1;	/* sample spacing for non-seismic data */
+
+	float f1;	/* first sample location for non-seismic data */
+
+	float d2;	/* sample spacing between traces */
+
+	float f2;	/* first trace location */
+
+	float ungpow;	/* negative of power used for dynamic
+			   range compression */
+
+	float unscale;	/* reciprocal of scaling factor to normalize
+			   range */
+
+	int ntr; 	/* number of traces */
+
+/*        short shortpad;   alignment padding */
+
+	short unass[14];	/* unassigned--NOTE: last entry causes 
+			   a break in the word alignment, if we REALLY
+			   want to maintain 240 bytes, the following
+			   entry should be an odd number of short/UINT2
+			   OR do the insertion above the "mark" keyword
+			   entry */
+
+} SUsegy;
+
+
diff --git a/raytime3d/atopkge.c b/raytime3d/atopkge.c
new file mode 100644
index 0000000000000000000000000000000000000000..ef0b21803a52fb2ee021b6d73938d44bcefb0f92
--- /dev/null
+++ b/raytime3d/atopkge.c
@@ -0,0 +1,444 @@
+/*                        
+ 
+ This file is property of the Colorado School of Mines.
+ 
+ Copyright (C) 2007, Colorado School of Mines,
+ All rights reserved.
+ 
+ 
+ Redistribution and use in source and binary forms, with or 
+ without modification, are permitted provided that the following 
+ conditions are met:
+ 
+ *  Redistributions of source code must retain the above copyright 
+ notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above 
+ copyright notice, this list of conditions and the following 
+ disclaimer in the documentation and/or other materials provided 
+ with the distribution.
+ *  Neither the name of the Colorado School of Mines nor the names of
+ its contributors may be used to endorse or promote products 
+ derived from this software without specific prior written permission.
+ 
+ Warranty Disclaimer:
+ THIS SOFTWARE IS PROVIDED BY THE COLORADO SCHOOL OF MINES AND CONTRIBUTORS 
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+ COLORADO SCHOOL OF MINES OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ POSSIBILITY OF SUCH DAMAGE.
+ 
+ 
+ Export Restriction Disclaimer:
+ We believe that CWP/SU: Seismic Un*x is a low technology product that does
+ not appear on the Department of Commerce CCL list of restricted exports.
+ Accordingly, we believe that our product meets the qualifications of
+ an ECCN (export control classification number) of EAR99 and we believe
+ it fits the qualifications of NRR (no restrictions required), and
+ is thus not subject to export restrictions of any variety.
+ 
+ Approved Reference Format:
+ In publications, please refer to SU as per the following example:
+ Cohen, J. K. and Stockwell, Jr. J. W., (200_), CWP/SU: Seismic Un*x 
+ Release No. __: an open source software  package for seismic 
+ research and processing, 
+ Center for Wave Phenomena, Colorado School of Mines.
+ 
+ Articles about SU in peer-reviewed journals:
+ Saeki, T., (1999), A guide to Seismic Un*x (SU)(2)---examples of data processing (part 1), data input and preparation of headers, Butsuri-Tansa (Geophysical Exploration), vol. 52, no. 5, 465-477.
+ Stockwell, Jr. J. W. (1999), The CWP/SU: Seismic Un*x Package, Computers and Geosciences, May 1999.
+ Stockwell, Jr. J. W. (1997), Free Software in Education: A case study of CWP/SU: Seismic Un*x, The Leading Edge, July 1997.
+ Templeton, M. E., Gough, C.A., (1998), Web Seismic Un*x: Making seismic reflection processing more accessible, Computers and Geosciences.
+ 
+ Acknowledgements:
+ SU stands for CWP/SU:Seismic Un*x, a processing line developed at Colorado 
+ School of Mines, partially based on Stanford Exploration Project (SEP) 
+ software.
+ */
+
+/*********************** self documentation **********************/
+/***************************************************************************
+ATOPKGE - convert ascii to arithmetic and with error checking
+
+ 
+eatoh		ascii to short
+eatou		ascii to unsigned short
+eatoi		ascii to int
+eatop		ascii to unsigned
+eatol		ascii to long
+eatov		ascii to unsigned long
+eatof		ascii to float
+eatod		ascii to double
+
+****************************************************************************
+Function Prototypes:
+short eatoh(char *s);
+unsigned short eatou(char *s);
+int eatoi(char *s);
+unsigned int eatop(char *s);
+long eatol(char *s);
+unsigned long eatov(char *s);
+float eatof(char *s);
+double eatod(char *s);
+
+****************************************************************************
+Input:
+s		string 
+
+Returned:	type indicated
+ 
+****************************************************************************
+Notes:
+Each of these routines acts like atoi, but has error checking:
+
+This is a major revision of the tedious code required before
+vendors implemented the ANSI C strtol, strtoul and strtod.
+
+In addition to the size checks for each integer type, a
+specific test on errno is required.  For example, INT_MAX
+may (and probably does) equal LONG_MAX.  In this case,
+if fed a number exceeding INT_MAX (and LONG_MAX), strtol
+will make a quiet return with the wrong answer and it is up
+to the user to check if errno == ERANGE.
+
+Size limits are machine dependent and are read from the
+ANSI C include files limits.h and float.h.
+
+Bug Report: With NeXT c and Gnucc, when x > DBL_MAX (x <-DBL_MAX),
+the return value from strtod was +Infinity (-Infinity), not HUGE_VAL
+and more important, errno was not set to ERANGE.  To cope with this,
+I put explicit size checks in eatod (which would not be needed if
+errno were set as it should be in ANSI C.    jkc 01/29/94
+
+On IBM RS6000, the return value from strtod was +-Inf on
+overflow, but errno was set correctly.
+
+****************************************************************************
+References:
+For old code:
+Plum: Reliable Data Structures in C, p. 2-17.
+Kernighan and Ritchie: The C Programming Language, p. 58.
+
+CWP: Jack K. Cohen, Brian Sumner
+ 
+For new code:
+ANSI C routines with a little help from Jack
+
+****************************************************************************
+Author: Jack Cohen, Center for Wave Phenomena, 1994.
+***************************************************************************/
+/**************** end self doc ********************************/
+
+#include "par.h"
+#include <float.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <errno.h>
+
+/* eatoh - convert string s to short integer {SHRT_MIN:SHRT_MAX} */
+short eatoh(char *s)
+{
+	long n = strtol(s, NULL, 10);
+	
+	if ( (n > SHRT_MAX) || (n < SHRT_MIN) || (errno == ERANGE) )
+		err("%s: eatoh: overflow", __FILE__);
+
+	return (short) n;
+}
+
+
+/* eatou - convert string s to unsigned short integer {0:USHRT_MAX} */
+unsigned short eatou(char *s)
+{
+	unsigned long n = strtoul(s, NULL, 10);
+
+	if ( (n > USHRT_MAX) || (errno == ERANGE) )
+		err("%s: eatou: overflow", __FILE__);
+
+	return (unsigned short) n;
+}
+
+
+/* eatoi - convert string s to integer {INT_MIN:INT_MAX} */
+int eatoi(char *s)
+{
+	long n = strtol(s, NULL, 10);
+
+	if ( (n > INT_MAX) || (n < INT_MIN) || (errno == ERANGE) )
+		err("%s: eatoi: overflow", __FILE__);
+
+	return (int) n;
+}
+
+
+/* eatop - convert string s to unsigned integer {0:UINT_MAX} */
+unsigned int eatop(char *s)
+{
+	unsigned long n = strtoul(s, NULL, 10);
+
+	if ( (n > UINT_MAX) || (errno == ERANGE) )
+		err("%s: eatop: overflow", __FILE__);
+
+	return (unsigned int) n;
+}
+
+
+/* eatol - convert string s to long integer {LONG_MIN:LONG_MAX} */
+long eatol(char *s)
+{
+	long n = strtol(s, NULL, 10);
+
+	if (errno == ERANGE)
+		err("%s: eatol: overflow", __FILE__);
+
+	return n;
+}
+
+
+/* eatov - convert string s to unsigned long {0:ULONG_MAX} */
+unsigned long eatov(char *s)
+{
+	unsigned long n = strtoul(s, NULL, 10);
+
+	if (errno == ERANGE)
+		err("%s: eatov: overflow", __FILE__);
+
+	return n;
+}
+
+
+/* eatof - convert string s to float {-FLT_MAX:FLT_MAX} */
+float eatof(char *s)
+{
+	float x = strtod(s, NULL);
+
+	if ( (x > FLT_MAX) || (x < -FLT_MAX) || (errno == ERANGE) )
+		err("%s: eatof: overflow", __FILE__);
+
+	return (float) x;
+}
+
+
+/* eatod - convert string s to double {-DBL_MAX:DBL_MAX} */
+double eatod(char *s)
+{
+	double x = strtod(s, NULL);
+
+	/* errno == ERANGE suffices if compiler sets errno on overflow */
+	if ( (errno == ERANGE) || (x > DBL_MAX) || (x < -DBL_MAX) )
+		err("%s: eatod: overflow", __FILE__);
+
+	return x;
+}
+
+
+/**************************************************************************
+ERRPKGE - routines for reporting errors
+
+err	print warning on application program error and die
+warn	print warning on application program error
+syserr	print warning on application program error using errno and die
+
+***************************************************************************
+Function Prototypes:
+void err (char *fmt, ...);
+void warn (char *fmt, ...);
+void syserr (char *fmt, ...);
+
+***************************************************************************
+Return: void
+
+***************************************************************************
+Notes:
+fmt		a printf format string ("\n" not needed)
+...		the variables referenced in the format string
+
+Examples:
+	err("Cannot divide %f by %f", x, y);
+	warn("fmax = %f exceeds half nyquist= %f", fmax, 0.25/dt);
+ 
+	if (NULL == (fp = fopen(xargv[1], "r")))
+ 		err("can't open %s", xargv[1]);
+ 	...
+ 	if (-1 == close(fd))
+ 		err("close failed");
+
+***************************************************************************
+References:
+Kernighan and Pike, "The UNIX Programming Environment", page 207.
+Also Rochkind, "Advanced UNIX Programming", page 13.
+
+***************************************************************************
+Authors:SEP: Jeff Thorson, Stew Levin	CWP: Shuki Ronen, Jack Cohen
+**************************************************************************/
+
+
+void err(char *fmt, ...)
+{
+	va_list args;
+
+ 
+	if (EOF == fflush(stdout)) {
+		fprintf(stderr, "\nerr: fflush failed on stdout");
+	}
+	fprintf(stderr, "\n%s: ", xargv[0]);
+	va_start(args,fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+	fprintf(stderr, "\n");
+	exit(EXIT_FAILURE);
+}
+
+
+void warn(char *fmt, ...)
+{
+	va_list args;
+
+	if (EOF == fflush(stdout)) {
+		fprintf(stderr, "\nwarn: fflush failed on stdout");
+	}
+	fprintf(stderr, "\n%s: ", xargv[0]);
+	va_start(args,fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+	fprintf(stderr, "\n");
+	return;
+}
+
+
+void syserr(char *fmt, ...)
+{
+    va_list args;
+
+    if (EOF == fflush(stdout)) {
+        fprintf(stderr, "\nsyserr: fflush failed on stdout");
+    }
+    fprintf(stderr, "\n%s: ", xargv[0]);
+    va_start(args,fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+    fprintf(stderr, " (%s)\n", strerror(errno));
+    exit(EXIT_FAILURE);
+}
+
+#ifdef TEST
+main(int argc, char **argv)
+{
+	char s[BUFSIZ];
+	short nh;
+	unsigned short nu;
+	int ni;
+	unsigned int np;
+	long nl;
+	unsigned long nv;
+
+	initargs(argc, argv);
+
+
+	/* Test code for eatoh */
+	if (SHRT_MAX == LONG_MAX) {
+	    warn("Warning: eatoh not used on this machine.\n");
+	} else {
+	    warn("\n");
+	}
+	strcpy(s, "0");
+	nh = eatoh(s);
+	warn("eatoh(%s) = %hd\n", s, nh);
+
+	strcpy(s, "32767");
+	nh = eatoh(s);
+	warn("eatoh(%s) = %hd\n", s, nh);
+
+	strcpy(s, "-32768");
+	nh = eatoh(s);
+	warn("eatoh(%s) = %hd\n", s, nh);
+
+
+	/* Test code for eatou */
+	if (USHRT_MAX == ULONG_MAX) {
+	    warn("Warning: eatou not used on this machine.\n");
+	} else {
+	    warn("\n");
+	}
+	strcpy(s, "0");
+	nu = eatou(s);
+	warn("eatou(%s) = %hu\n", s, nu);
+
+	strcpy(s, "65535");
+	nu = eatou(s);
+	warn("eatou(%s) = %hu\n", s, nu);
+
+
+	/* Test code for eatoi */
+	if (INT_MAX == LONG_MAX) {
+	    warn("Warning: eatoi not used on this machine.\n");
+	} else {
+	    warn("\n");
+	}
+	strcpy(s, "0");
+	ni = eatoi(s);
+	warn("eatoi(%s) = %d\n", s, ni);
+
+	strcpy(s, "2147483647");
+	ni = eatoi(s);
+	warn("eatoi(%s) = %d\n", s, ni);
+
+
+	strcpy(s, "-2147483648");
+	ni = eatoi(s);
+	warn("eatoi(%s) = %d\n", s, ni);
+
+
+	/* Test code for eatop */
+	if (INT_MAX == LONG_MAX) {
+	    warn("Warning: eatop not used on this machine.\n");
+	} else {
+	    warn("\n");
+	}
+	strcpy(s, "0");
+	np = eatop(s);
+	warn("eatop(%s) = %lu\n", s, np);
+
+	strcpy(s, "4294967295");
+	np = eatop(s);
+	warn("eatop(%s) = %lu\n", s, np);
+
+
+	/* Test code for eatol */
+	warn("\n");
+	strcpy(s, "0");
+	nl = eatol(s);
+	warn("eatol(%s) = %ld\n", s, nl);
+
+	strcpy(s, "2147483647");
+	nl = eatol(s);
+	warn("eatol(%s) = %ld\n", s, nl);
+
+	strcpy(s, "-2147483648");
+	nl = eatol(s);
+	warn("eatol(%s) = %ld\n", s, nl);
+
+
+	/* Test code for eatov */
+	strcpy(s, "0");
+	nv = eatov(s);
+	warn("eatov(%s) = %lu\n", s, nv);
+
+	strcpy(s, "4294967295");
+	nv = eatov(s);
+	warn("eatov(%s) = %lu\n", s, nv);
+
+	warn("Now we feed in 4294967296, expecting fatal error exit\n");
+	strcpy(s, "4294967296");
+	nv = eatov(s);
+	warn("eatov(%s) = %lu\n", s, nv);
+
+	return EXIT_SUCCESS;
+}
+#endif
diff --git a/raytime3d/docpkge.c b/raytime3d/docpkge.c
new file mode 100644
index 0000000000000000000000000000000000000000..a74b4c331cbb3c882fd311ef5dacbda776c14e04
--- /dev/null
+++ b/raytime3d/docpkge.c
@@ -0,0 +1,188 @@
+/*                 
+ This file is property of the Colorado School of Mines.
+ 
+ Copyright (C) 2007, Colorado School of Mines,
+ All rights reserved.
+ 
+ 
+ Redistribution and use in source and binary forms, with or 
+ without modification, are permitted provided that the following 
+ conditions are met:
+ 
+ *  Redistributions of source code must retain the above copyright 
+ notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above 
+ copyright notice, this list of conditions and the following 
+ disclaimer in the documentation and/or other materials provided 
+ with the distribution.
+ *  Neither the name of the Colorado School of Mines nor the names of
+ its contributors may be used to endorse or promote products 
+ derived from this software without specific prior written permission.
+ 
+ Warranty Disclaimer:
+ THIS SOFTWARE IS PROVIDED BY THE COLORADO SCHOOL OF MINES AND CONTRIBUTORS 
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+ COLORADO SCHOOL OF MINES OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ POSSIBILITY OF SUCH DAMAGE.
+ 
+ 
+ Export Restriction Disclaimer:
+ We believe that CWP/SU: Seismic Un*x is a low technology product that does
+ not appear on the Department of Commerce CCL list of restricted exports.
+ Accordingly, we believe that our product meets the qualifications of
+ an ECCN (export control classification number) of EAR99 and we believe
+ it fits the qualifications of NRR (no restrictions required), and
+ is thus not subject to export restrictions of any variety.
+ 
+ Approved Reference Format:
+ In publications, please refer to SU as per the following example:
+ Cohen, J. K. and Stockwell, Jr. J. W., (200_), CWP/SU: Seismic Un*x 
+ Release No. __: an open source software  package for seismic 
+ research and processing, 
+ Center for Wave Phenomena, Colorado School of Mines.
+ 
+ Articles about SU in peer-reviewed journals:
+ Saeki, T., (1999), A guide to Seismic Un*x (SU)(2)---examples of data processing (part 1), data input and preparation of headers, Butsuri-Tansa (Geophysical Exploration), vol. 52, no. 5, 465-477.
+ Stockwell, Jr. J. W. (1999), The CWP/SU: Seismic Un*x Package, Computers and Geosciences, May 1999.
+ Stockwell, Jr. J. W. (1997), Free Software in Education: A case study of CWP/SU: Seismic Un*x, The Leading Edge, July 1997.
+ Templeton, M. E., Gough, C.A., (1998), Web Seismic Un*x: Making seismic reflection processing more accessible, Computers and Geosciences.
+ 
+ Acknowledgements:
+ SU stands for CWP/SU:Seismic Un*x, a processing line developed at Colorado 
+ School of Mines, partially based on Stanford Exploration Project (SEP) 
+ software.
+ */
+
+/*********************** self documentation **********************/
+/*************************************************************************** 
+DOCPKGE - Function to implement the CWP self-documentation facility
+
+requestdoc	give selfdoc on user request (i.e. when name of main is typed)
+pagedoc		print self documentation string
+
+**************************************************************************** 
+Function Prototypes:
+void requestdoc(flag);
+void pagedoc();
+
+**************************************************************************** 
+requestoc:
+Input:
+flag		integer specifying i.o. cases
+
+pagedoc():
+Returns:	the self-documentation, an array of strings
+
+**************************************************************************** 
+Notes:
+requestdoc:
+In the usual case, stdin is used to pass in data.  However,
+some programs (eg. synthetic data generators) don't use stdin
+to pass in data and some programs require two or more arguments
+besides the command itself (eg. sudiff) and don't use stdin.
+In this last case, we give selfdoc whenever too few arguments
+are given, since these usages violate the usual SU syntax.
+In all cases, selfdoc can be requested by giving only the
+program name.
+
+The flag argument distinguishes these cases:
+            flag = 0; fully defaulted, no stdin
+            flag = 1; usual case
+            flag = n > 1; no stdin and n extra args required
+
+pagedoc:
+Intended to be called by requesdoc(), but conceivably could be
+used directly as in:
+      if (xargc != 3) selfdoc();
+
+Based on earlier versions by:
+SEP: Einar Kjartansson, Stew Levin CWP: Jack Cohen, Shuki Ronen
+HRC: Lyle
+
+**************************************************************************** 
+Author: Jack K. Cohen, Center for Wave Phenomena
+****************************************************************************/
+/**************** end self doc ********************************/
+
+#include "par.h"
+
+#ifndef EXIT_FAILURE
+#define EXIT_FAILURE (1)
+#endif
+#ifndef EXIT_SUCCESS
+#define EXIT_SUCCESS (0)
+#endif
+
+ 
+/*  definitions of global variables */
+int xargc; char **xargv;
+
+
+void requestdoc(int flag)
+/*************************************************************************** 
+print selfdocumentation as directed by the user-specified flag
+**************************************************************************** 
+Notes:
+In the usual case, stdin is used to pass in data.  However,
+some programs (eg. synthetic data generators) don't use stdin
+to pass in data and some programs require two or more arguments
+besides the command itself (eg. sudiff) and don't use stdin.
+In this last case, we give selfdoc whenever too few arguments
+are given, since these usages violate the usual SU syntax.
+In all cases, selfdoc can be requested by giving only the
+program name.
+
+The flag argument distinguishes these cases:
+            flag = 0; fully defaulted, no stdin
+            flag = 1; usual case
+            flag = n > 1; no stdin and n extra args required
+
+pagedoc:
+Intended to be called by pagedoc(), but conceivably could be
+used directly as in:
+      if (xargc != 3) selfdoc();
+
+**************************************************************************** 
+Authors: Jack Cohen, Center for Wave Phenomena, 1993, based on on earlier
+versions by:
+SEP: Einar Kjartansson, Stew Levin CWP: Jack Cohen, Shuki Ronen
+HRC: Lyle
+****************************************************************************/
+{
+        switch(flag) {
+        case 1:
+                if (xargc == 1 && isatty(STDIN)) pagedoc();
+        break;
+        case 0:
+                if (xargc == 1 && isatty(STDIN) && isatty(STDOUT)) pagedoc();
+        break;
+        default:
+                if (xargc <= flag) pagedoc();
+        break;
+        }
+        return;
+}
+
+
+void pagedoc(void)
+{
+        extern char *sdoc[];
+	char **p = sdoc;
+        FILE *fp;
+
+        fflush(stdout);
+        fp = popen("more -22 1>&2", "w");
+	while(*p) (void)fprintf(fp, "%s\n", *p++);
+        pclose(fp);
+
+        exit(EXIT_FAILURE);
+}
+/*----------------------End of Package--------------------------------*/
diff --git a/raytime3d/getModelInfo.c b/raytime3d/getModelInfo.c
new file mode 100644
index 0000000000000000000000000000000000000000..378a1b50ebac46e5b7b8a8bef4b5365ac15bef9d
--- /dev/null
+++ b/raytime3d/getModelInfo.c
@@ -0,0 +1,109 @@
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <math.h>
+#include "par.h"
+#include "segy.h"
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define NINT(x) ((int)((x)>0.0?(x)+0.5:(x)-0.5))
+
+/**
+*  reads gridded model file to compute minimum and maximum values and sampling intervals
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands 
+**/
+
+int getModelInfo(char *file_name, int *n1, int *n2, float *d1, float *d2, float *f1, float *f2, float *min, float *max, int *axis, int zeroch, int verbose)
+{
+    FILE    *fp;
+    size_t  nread, trace_sz;
+    off_t   bytes;
+    int     ret, i, one_shot, ntraces;
+    float   *trace, cmin;
+    segy    hdr;
+    
+    fp = fopen( file_name, "r" );
+    assert( fp != NULL);
+    nread = fread( &hdr, 1, TRCBYTES, fp );
+    assert(nread == TRCBYTES);
+    ret = fseeko( fp, 0, SEEK_END );
+    if (ret<0) perror("fseeko");
+    bytes = ftello( fp );
+
+    *n1 = hdr.ns;
+    *d1 = hdr.d1;
+    *d2 = hdr.d2;
+    *f1 = hdr.f1;
+    *f2 = hdr.f2;
+
+    if ( NINT(100.0*((*d1)/(*d2)))!=100 ) {
+        verr("dx and dz are different in the model !");
+    }
+    if ( NINT(1000.0*(*d1))==0 ) {
+        if(!getparfloat("dx",d1)) {
+            verr("dx is equal to zero use parameter dx= to set value");
+        }
+        *d2 = *d1;
+    }
+    trace_sz = sizeof(float)*(*n1)+TRCBYTES;
+    ntraces  = (int) (bytes/trace_sz);
+    *n2 = ntraces;
+
+    /* check to find out min and max values gather */
+
+    one_shot = 1;
+    trace = (float *)malloc(trace_sz);
+    fseeko( fp, TRCBYTES, SEEK_SET );
+    nread = fread( trace, sizeof(float), hdr.ns, fp );
+    assert (nread == hdr.ns);
+    fseeko( fp, TRCBYTES, SEEK_SET );
+
+    if (hdr.trid == TRID_DEPTH)  *axis = 1; /* samples are z-axis */
+    else *axis = 0; /* sample direction respresents the x-axis */
+
+    i=0; cmin=trace[0];
+    while ( ( (cmin==0.0) && zeroch) && (i<hdr.ns) ) cmin=trace[i++];
+
+    *max = cmin;
+    *min = cmin;
+    /* keep on reading traces until there are no more traces (nread==0) */
+    while (one_shot) {
+        nread = fread( trace, sizeof(float), hdr.ns, fp );
+        assert (nread == hdr.ns);
+        for (i=0;i<(*n1);i++) {
+            *max = MAX(trace[i],*max);
+            cmin = MIN(trace[i],*min);
+            if (zeroch) {
+                if (cmin!=0.0) *min = MIN(*min, cmin);
+            }
+            else {
+                *min = cmin;
+            }
+        }
+        nread = fread( &hdr, 1, TRCBYTES, fp );
+        if (nread==0) break;
+    }
+    fclose(fp);
+    free(trace);
+
+    if (verbose>2) {
+        vmess("For file %s", file_name);
+        vmess("nz=%d nx=%d", *n1, *n2);
+        vmess("dz=%f dx=%f", *d1, *d2);
+        vmess("min=%f max=%f", *min, *max);
+        vmess("zstart=%f xstart=%f", *f1, *f2);
+        if (*axis) vmess("sample represent z-axis\n");
+        else vmess("sample represent x-axis\n");
+    }
+    return 0;
+}
+
diff --git a/raytime3d/getParameters.c b/raytime3d/getParameters.c
new file mode 100644
index 0000000000000000000000000000000000000000..89d1d34585a977f9ba6fd58eff936bf4396e4ea2
--- /dev/null
+++ b/raytime3d/getParameters.c
@@ -0,0 +1,305 @@
+#include<stdlib.h>
+#include<stdio.h>
+#include<math.h>
+#include<assert.h>
+#include"par.h"
+#include"raytime.h"
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define NINT(x) ((int)((x)>0.0?(x)+0.5:(x)-0.5))
+
+/**
+*
+*  The routine getParameters reads in all parameters to set up a FD modeling.
+*  Model and source parameters are used to calculate stability and dispersion relations
+*  Source and receiver positions are calculated and checked if they fit into the model.
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands
+**/
+
+int getModelInfo(char *file_name, int *n1, int *n2, float *d1, float *d2, float *f1, float *f2, float *min, float *max, int *axis, int zeroch, int verbose);
+
+int recvPar(recPar *rec, float sub_x0, float sub_z0, float dx, float dz, int nx, int nz);
+
+int getParameters(modPar *mod, recPar *rec, srcPar *src, shotPar *shot, rayPar *ray, int verbose)
+{
+	int nx, nz, nsrc, ix, axis, is0;
+	int idzshot, idxshot;
+	int src_ix0, src_iz0, src_ix1, src_iz1;
+	float cp_min, cp_max;
+	float sub_x0,sub_z0;
+	float srcendx, srcendz, dx, dz;
+	float xsrc, zsrc, dxshot, dzshot;
+	float dxrcv,dzrcv,dxspread,dzspread;
+	float xmax, zmax;
+	float xsrc1, xsrc2, zsrc1, zsrc2;
+	float *xsrca, *zsrca;
+	float rsrc, oxsrc, ozsrc, dphisrc, ncsrc;
+	size_t nsamp;
+	int nxsrc, nzsrc;
+	int is;
+	char *src_positions;
+
+	if (!getparint("verbose",&verbose)) verbose=0;
+
+	if (!getparstring("file_cp",&mod->file_cp)) {
+		verr("parameter file_cp required!");
+	}
+	if (!getparstring("file_rcv",&rec->file_rcv)) rec->file_rcv="recv.su";
+	if (!getparint("src_at_rcv",&src->src_at_rcv)) src->src_at_rcv=1;
+	
+	/* read model parameters, which are used to set up source and receivers and check stability */
+	
+	getModelInfo(mod->file_cp, &nz, &nx, &dz, &dx, &sub_z0, &sub_x0, &cp_min, &cp_max, &axis, 1, verbose);
+	mod->cp_max = cp_max;
+	mod->cp_min = cp_min;
+	mod->dz = dz;
+	mod->dx = dx;
+	mod->nz = nz;
+	mod->nx = nx;
+	
+    /* origin of model in real (non-grid) coordinates */
+	mod->x0 = sub_x0;
+	mod->z0 = sub_z0;
+	xmax = sub_x0+(nx-1)*dx;
+	zmax = sub_z0+(nz-1)*dz;
+
+	if (verbose) {
+		vmess("*******************************************");
+		vmess("*************** model info ****************");
+		vmess("*******************************************");
+		vmess("nz      = %8d   nx      = %8d", nz, nx);
+		vmess("dz      = %8.4f   dx      = %8.4f", dz, dx);
+		vmess("zmin    = %8.4f   zmax    = %8.4f", sub_z0, zmax);
+		vmess("xmin    = %8.4f   xmax    = %8.4f", sub_x0, xmax);
+		vmess("min(cp) = %9.3f  max(cp) = %9.3f", cp_min, cp_max);
+	}
+
+	/* define the number and type of shots to model */
+	/* each shot can have multiple sources arranged in different ways */
+    
+	if (!getparfloat("xsrc",&xsrc)) xsrc=sub_x0+((nx-1)*dx)/2.0;
+	if (!getparfloat("zsrc",&zsrc)) zsrc=sub_z0;
+	if (!getparint("nxshot",&shot->nx)) shot->nx=1;
+	if (!getparint("nzshot",&shot->nz)) shot->nz=1;
+	if (!getparfloat("dxshot",&dxshot)) dxshot=dx;
+	if (!getparfloat("dzshot",&dzshot)) dzshot=dz;
+
+	shot->n = (shot->nx)*(shot->nz);
+
+	if (shot->nx>1) {
+		idxshot=MAX(0,NINT(dxshot/dx));
+	}
+	else {
+		idxshot=0.0;
+	}
+	if (shot->nz>1) {
+        idzshot=MAX(0,NINT(dzshot/dz));
+    }
+    else {
+        idzshot=0.0;
+    }
+
+	/* calculate the shot positions */
+	
+	src_ix0=MAX(0,NINT((xsrc-sub_x0)/dx));
+	src_ix0=MIN(src_ix0,nx);
+	src_iz0=MAX(0,NINT((zsrc-sub_z0)/dz));
+	src_iz0=MIN(src_iz0,nz);
+	srcendx=(shot->nx-1)*dxshot+xsrc;
+	srcendz=(shot->nz-1)*dzshot+zsrc;
+	src_ix1=MAX(0,NINT((srcendx-sub_x0)/dx));
+	src_ix1=MIN(src_ix1,nx);
+	src_iz1=MAX(0,NINT((srcendz-sub_z0)/dz));
+	src_iz1=MIN(src_iz1,nz);
+
+	shot->x = (int *)calloc(shot->nx,sizeof(int));
+	shot->z = (int *)calloc(shot->nz,sizeof(int));
+	for (is=0; is<shot->nx; is++) {
+		shot->x[is] = src_ix0+is*idxshot;
+		if (shot->x[is] > nx-1) shot->nx = is-1;
+	}
+	for (is=0; is<shot->nz; is++) {
+        shot->z[is] = src_iz0+is*idzshot;
+        if (shot->z[is] > nz-1) shot->nz = is-1;
+    }
+
+	/* check if source array is defined */
+	
+	nxsrc = countparval("xsrca");
+	nzsrc = countparval("zsrca");
+	if (nxsrc != nzsrc) {
+		verr("Number of sources in array xsrca (%d), zsrca(%d) are not equal",nxsrc, nzsrc);
+	}
+
+	/* check if sources on a circle are defined */
+	
+	if (getparfloat("rsrc", &rsrc)) {
+		if (!getparfloat("dphisrc",&dphisrc)) dphisrc=2.0;
+		if (!getparfloat("oxsrc",&oxsrc)) oxsrc=0.0;
+		if (!getparfloat("ozsrc",&ozsrc)) ozsrc=0.0;
+		ncsrc = NINT(360.0/dphisrc);
+        src->n = nsrc;
+		
+		src->x = (int *)malloc(ncsrc*sizeof(int));
+		src->z = (int *)malloc(ncsrc*sizeof(int));
+
+		for (ix=0; ix<ncsrc; ix++) {
+			src->x[ix] = NINT((oxsrc-sub_x0+rsrc*cos(((ix*dphisrc)/360.0)*(2.0*M_PI)))/dx);
+			src->z[ix] = NINT((ozsrc-sub_z0+rsrc*sin(((ix*dphisrc)/360.0)*(2.0*M_PI)))/dz);
+			if (verbose>4) fprintf(stderr,"Source on Circle: xsrc[%d]=%d zsrc=%d\n", ix, src->x[ix], src->z[ix]);
+		}
+		
+	}
+    
+    /* TO DO propagate src_positions parameter and structure through code */
+    
+	if (!getparstring("src_positions",&src_positions)) src_positions="single";
+	src->random=0;
+	src->plane=0;
+	src->array=0;
+	src->single=0;
+	if (strstr(src_positions, "single")) src->single=1;
+	else if (strstr(src_positions, "array")) src->array=1;
+	else if (strstr(src_positions, "random")) src->random=1;
+	else if (strstr(src_positions, "plane")) src->plane=1;
+	else src->single=1;
+    
+	/* to maintain functionality of older parameters usage */
+	if (!getparint("src_random",&src->random)) src->random=0;
+	if (!getparint("plane_wave",&src->plane)) src->plane=0;
+	
+	if (src->random) {
+		src->plane=0;
+		src->array=0;
+		src->single=0;
+	}
+	if (src->plane) {
+		src->random=0;
+		src->array=0;
+		src->single=0;
+	}
+
+		
+	/* number of sources per shot modeling */
+
+	if (!getparint("src_window",&src->window)) src->window=0;
+	if (!getparint("distribution",&src->distribution)) src->distribution=0;
+	if (!getparfloat("amplitude", &src->amplitude)) src->amplitude=0.0;
+	if (src->random && nxsrc==0) {
+		if (!getparint("nsrc",&nsrc)) nsrc=1;
+		if (!getparfloat("xsrc1", &xsrc1)) xsrc1=sub_x0;
+		if (!getparfloat("xsrc2", &xsrc2)) xsrc2=xmax;
+		if (!getparfloat("zsrc1", &zsrc1)) zsrc1=sub_z0;
+		if (!getparfloat("zsrc2", &zsrc2)) zsrc2=zmax;
+		dxshot = xsrc2-xsrc1;
+		dzshot = zsrc2-zsrc1;
+		src->x = (int *)malloc(nsrc*sizeof(int));
+		src->z = (int *)malloc(nsrc*sizeof(int));
+		nsamp = 0;
+
+	}
+	else if (nxsrc != 0) {
+		/* source array is defined */
+		nsrc=nxsrc;
+		src->x = (int *)malloc(nsrc*sizeof(int));
+		src->z = (int *)malloc(nsrc*sizeof(int));
+		xsrca = (float *)malloc(nsrc*sizeof(float));
+		zsrca = (float *)malloc(nsrc*sizeof(float));
+		getparfloat("xsrca", xsrca);
+		getparfloat("zsrca", zsrca);
+		for (is=0; is<nsrc; is++) {
+			src->x[is] = NINT((xsrca[is]-sub_x0)/dx);
+			src->z[is] = NINT((zsrca[is]-sub_z0)/dz);
+			if (verbose>3) fprintf(stderr,"Source Array: xsrc[%d]=%f zsrc=%f\n", is, xsrca[is], zsrca[is]);
+		}
+		src->random = 1;
+		free(xsrca);
+		free(zsrca);
+	}
+	else {
+		if (src->plane) { if (!getparint("nsrc",&nsrc)) nsrc=1;}
+		else nsrc=1;
+
+		if (nsrc > nx) {
+			vwarn("Number of sources used in plane wave is larger than ");
+			vwarn("number of gridpoints in X. Plane wave will be clipped to the edges of the model");
+			nsrc = mod->nx;
+		}
+
+	/* for a source defined on mutliple gridpoint calculate p delay factor */
+
+		src->x = (int *)malloc(nsrc*sizeof(int));
+		src->z = (int *)malloc(nsrc*sizeof(int));
+		is0 = -1*floor((nsrc-1)/2);
+		for (is=0; is<nsrc; is++) {
+			src->x[is] = is0 + is;
+			src->z[is] = 0;
+		}
+		
+	}
+
+	src->n=nsrc;
+
+	if (verbose) {
+		if (src->n>1) {
+			vmess("*******************************************");
+			vmess("*********** source array info *************");
+			vmess("*******************************************");
+			vmess("Areal source array is defined with %d sources.",nsrc);
+			vmess("Memory requirement for sources = %.2f MB.",sizeof(float)*(nsamp/(1024.0*1024.0)));
+		}
+		if (src->random) {
+		vmess("Sources are placed at random locations in domain: ");
+		vmess(" x[%.2f : %.2f]  z[%.2f : %.2f] ", xsrc1, xsrc2, zsrc1, zsrc2);
+		}
+	}
+
+	/* define receivers */
+
+	if (!getparint("sinkdepth",&rec->sinkdepth)) rec->sinkdepth=0;
+	if (!getparint("sinkdepth_src",&src->sinkdepth)) src->sinkdepth=0;
+	if (!getparint("sinkvel",&rec->sinkvel)) rec->sinkvel=0;
+	if (!getparint("max_nrec",&rec->max_nrec)) rec->max_nrec=15000;
+	if (!getparfloat("dxspread",&dxspread)) dxspread=0;
+	if (!getparfloat("dzspread",&dzspread)) dzspread=0;
+    if (!getparint("nt",&rec->nt)) rec->nt=1024;
+
+	/* calculates the receiver coordinates */
+	
+	recvPar(rec, sub_x0, sub_z0, dx, dz, nx, nz);
+
+	if (verbose) {
+		if (rec->n) {
+			dxrcv = rec->xr[MIN(1,rec->n-1)]-rec->xr[0];
+			dzrcv = rec->zr[MIN(1,rec->n-1)]-rec->zr[0];
+			vmess("*******************************************");
+			vmess("************* receiver info ***************");
+			vmess("*******************************************");
+			vmess("ntrcv   = %d nrcv    = %d ", rec->nt, rec->n);
+			vmess("dzrcv   = %f dxrcv   = %f ", dzrcv, dxrcv);
+			vmess("Receiver array at coordinates: ");
+			vmess("zmin    = %f zmax    = %f ", rec->zr[0]+sub_z0, rec->zr[rec->n-1]+sub_z0);
+			vmess("xmin    = %f xmax    = %f ", rec->xr[0]+sub_x0, rec->xr[rec->n-1]+sub_x0);
+			vmess("which are gridpoints: ");
+			vmess("izmin   = %d izmax   = %d ", rec->z[0], rec->z[rec->n-1]);
+			vmess("ixmin   = %d ixmax   = %d ", rec->x[0], rec->x[rec->n-1]);
+			fprintf(stderr,"\n");
+		}
+		else {
+		 	vmess("*************** no receivers **************");
+		}
+	}
+
+    /* Ray tracing parameters */
+    if (!getparint("smoothwindow",&ray->smoothwindow)) ray->smoothwindow=0;
+    if (!getparint("useT2",&ray->useT2)) ray->useT2=0;
+    if (!getparint("geomspread",&ray->geomspread)) ray->geomspread=1;
+    if (!getparint("nraystep",&ray->nray)) ray->nray=5;
+
+	return 0;
+}
+
diff --git a/raytime3d/getWaveletHeaders.c b/raytime3d/getWaveletHeaders.c
new file mode 100644
index 0000000000000000000000000000000000000000..5bff37528015722251741fcdb434db218e06ed90
--- /dev/null
+++ b/raytime3d/getWaveletHeaders.c
@@ -0,0 +1,52 @@
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <math.h>
+#include "segy.h"
+
+/**
+*  reads file which contain the source wavelets and reads receiver positions  
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands 
+**/
+
+int getWaveletHeaders(char *file_src, int n1, int n2, float *gx, float *sx, float *gelev, float *selev, int verbose)
+{
+    FILE   *fp;
+    size_t nread;
+    int   ix;
+	size_t trace_sz;
+	off_t offset;
+	float scl, scll;
+    segy hdr;
+    
+    if (file_src == NULL) return 0; /* Input pipe can not be handled */
+    else fp = fopen( file_src, "r" );
+    assert( fp != NULL);
+    nread = fread( &hdr, 1, TRCBYTES, fp );
+    assert(nread == TRCBYTES);
+	if (hdr.scalco < 0) scl = 1.0/fabs(hdr.scalco);
+	else if (hdr.scalco == 0) scl = 1.0;
+	else scl = hdr.scalco;
+	if (hdr.scalel < 0) scll = 1.0/fabs(hdr.scalel);
+	else if (hdr.scalel == 0) scll = 1.0;
+	else scll = hdr.scalel;
+	trace_sz = (size_t)sizeof(float)*(n1)+TRCBYTES;
+
+	for (ix=0; ix<n2; ix++) {
+		offset = ix*trace_sz;
+    	fseeko( fp, offset, SEEK_SET );
+    	nread = fread( &hdr, 1, TRCBYTES, fp );
+    	assert(nread == TRCBYTES);
+		gx[ix] = hdr.gx*scl;
+        sx[ix] = hdr.sx*scl;
+        gelev[ix] = -1.0*hdr.gelev*scll;
+		selev[ix] = -1.0*hdr.selev*scll;
+	}
+    fclose(fp);
+    return 0;
+}
+
diff --git a/raytime3d/getWaveletInfo.c b/raytime3d/getWaveletInfo.c
new file mode 100644
index 0000000000000000000000000000000000000000..2f3734aae6c38e54653fab909ec5e936a157d8ce
--- /dev/null
+++ b/raytime3d/getWaveletInfo.c
@@ -0,0 +1,138 @@
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <math.h>
+#include "segy.h"
+
+/**
+*  reads file which contain the source wavelets and computes sampling interval
+*  and tries to estimate the maximum frequency content.
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands 
+**/
+
+#ifndef COMPLEX
+typedef struct _complexStruct { /* complex number */
+    float r,i;
+} complex;
+typedef struct _dcomplexStruct { /* complex number */
+    double r,i;
+} dcomplex;
+#endif/* complex */
+
+int optncr(int n);
+void rc1fft(float *rdata, complex *cdata, int n, int sign);
+
+#define     MAX(x,y) ((x) > (y) ? (x) : (y))
+#define     MIN(x,y) ((x) < (y) ? (x) : (y))
+#define NINT(x) ((int)((x)>0.0?(x)+0.5:(x)-0.5))
+
+int getWaveletInfo(char *file_src, int *n1, int *n2, float *d1, float *d2, float *f1, float *f2, float *fmax, int *nxm, int verbose)
+{
+    FILE    *fp;
+    size_t  nread, trace_sz;
+    off_t   bytes;
+    int     ret, one_shot, ntraces;
+    int     optn, nfreq, i, iwmax;
+    float   *trace;
+	float   ampl, amplmax, tampl, tamplmax; 
+    complex *ctrace;
+    segy hdr;
+    
+    if (file_src == NULL) return 0; /* Input pipe can not be handled */
+    else fp = fopen( file_src, "r" );
+    assert( fp != NULL);
+    nread = fread( &hdr, 1, TRCBYTES, fp );
+    assert(nread == TRCBYTES);
+    ret = fseeko( fp, 0, SEEK_END );
+	if (ret<0) perror("fseeko");
+    bytes = ftello( fp );
+
+    *n1 = hdr.ns;
+    if (hdr.trid == 1 || hdr.dt != 0) {
+        *d1 = ((float) hdr.dt)*1.e-6;
+        *f1 = ((float) hdr.delrt)/1000.;
+		if (*d1 == 0.0) *d1 = hdr.d1;
+    }
+    else {
+        *d1 = hdr.d1;
+        *f1 = hdr.f1;
+    }
+    *f2 = hdr.f2;
+
+    trace_sz = (size_t)(sizeof(float)*(*n1)+TRCBYTES);
+    ntraces  = (int) (bytes/trace_sz);
+	*n2 = ntraces;
+
+    /* check to find out number of traces in shot gather */
+
+	optn = optncr(*n1);
+	nfreq = optn/2 + 1;
+	ctrace = (complex *)malloc(nfreq*sizeof(complex));
+    one_shot = 1;
+    trace = (float *)malloc(optn*sizeof(float));
+    fseeko( fp, TRCBYTES, SEEK_SET );
+
+    while (one_shot) {
+		memset(trace,0,optn*sizeof(float));
+        nread = fread( trace, sizeof(float), *n1, fp );
+        assert (nread == *n1);
+		tamplmax = 0.0;
+		for (i=0;i<(*n1);i++) {
+			tampl = fabsf(trace[i]);
+			if (tampl > tamplmax) tamplmax = tampl;
+		}
+		if (trace[0]*1e-3 > tamplmax) {
+			fprintf(stderr,"WARNING: file_src has a large amplitude %f at t=0\n", trace[0]);
+			fprintf(stderr,"This will introduce high frequencies and can cause dispersion.\n");
+		}
+
+		/* estimate maximum frequency assuming amplitude spectrum is smooth */
+		rc1fft(trace,ctrace,optn,1);
+
+		/* find maximum amplitude */
+		amplmax = 0.0;
+		iwmax = 0;
+		for (i=0;i<nfreq;i++) {
+			ampl = sqrt(ctrace[i].r*ctrace[i].r+ctrace[i].i*ctrace[i].i);
+			if (ampl > amplmax) {
+				amplmax = ampl;
+				iwmax = i;
+			}
+		}
+		/* from the maximum amplitude position look for the largest frequency
+         * which has an amplitude 400 times weaker than the maximum amplitude */
+		for (i=iwmax;i<nfreq;i++) {
+			ampl = sqrt(ctrace[i].r*ctrace[i].r+ctrace[i].i*ctrace[i].i);
+			if (400*ampl < amplmax) {
+				*fmax = (i-1)*(1.0/(optn*(*d1)));
+				break;
+			}
+		}
+
+        nread = fread( &hdr, 1, TRCBYTES, fp );
+        if (nread==0) break;
+    }
+	*nxm = (int)ntraces;
+
+	if (verbose>2) {
+		vmess("For file %s", file_src);
+		vmess("nt=%d nx=%d", *n1, *n2);
+		vmess("dt=%f dx=%f", *d1, *d2);
+		vmess("fmax=%f", *fmax);
+		vmess("tstart=%f", *f1);
+	}
+
+    fclose(fp);
+    free(trace);
+    free(ctrace);
+
+    return 0;
+}
diff --git a/raytime3d/getpars.c b/raytime3d/getpars.c
new file mode 100644
index 0000000000000000000000000000000000000000..5099c5801bef214253daf07667c1b3c55b1008b1
--- /dev/null
+++ b/raytime3d/getpars.c
@@ -0,0 +1,732 @@
+/* This file is property of the Colorado School of Mines.
+ 
+ Copyright (C) 2007, Colorado School of Mines,
+ All rights reserved.
+ 
+ 
+ Redistribution and use in source and binary forms, with or 
+ without modification, are permitted provided that the following 
+ conditions are met:
+ 
+ *  Redistributions of source code must retain the above copyright 
+ notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above 
+ copyright notice, this list of conditions and the following 
+ disclaimer in the documentation and/or other materials provided 
+ with the distribution.
+ *  Neither the name of the Colorado School of Mines nor the names of
+ its contributors may be used to endorse or promote products 
+ derived from this software without specific prior written permission.
+ 
+ Warranty Disclaimer:
+ THIS SOFTWARE IS PROVIDED BY THE COLORADO SCHOOL OF MINES AND CONTRIBUTORS 
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+ COLORADO SCHOOL OF MINES OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ POSSIBILITY OF SUCH DAMAGE.
+ 
+ 
+ Export Restriction Disclaimer:
+ We believe that CWP/SU: Seismic Un*x is a low technology product that does
+ not appear on the Department of Commerce CCL list of restricted exports.
+ Accordingly, we believe that our product meets the qualifications of
+ an ECCN (export control classification number) of EAR99 and we believe
+ it fits the qualifications of NRR (no restrictions required), and
+ is thus not subject to export restrictions of any variety.
+ 
+ Approved Reference Format:
+ In publications, please refer to SU as per the following example:
+ Cohen, J. K. and Stockwell, Jr. J. W., (200_), CWP/SU: Seismic Un*x 
+ Release No. __: an open source software  package for seismic 
+ research and processing, 
+ Center for Wave Phenomena, Colorado School of Mines.
+ 
+ Articles about SU in peer-reviewed journals:
+ Saeki, T., (1999), A guide to Seismic Un*x (SU)(2)---examples of data processing (part 1), data input and preparation of headers, Butsuri-Tansa (Geophysical Exploration), vol. 52, no. 5, 465-477.
+ Stockwell, Jr. J. W. (1999), The CWP/SU: Seismic Un*x Package, Computers and Geosciences, May 1999.
+ Stockwell, Jr. J. W. (1997), Free Software in Education: A case study of CWP/SU: Seismic Un*x, The Leading Edge, July 1997.
+ Templeton, M. E., Gough, C.A., (1998), Web Seismic Un*x: Making seismic reflection processing more accessible, Computers and Geosciences.
+ 
+ Acknowledgements:
+ SU stands for CWP/SU:Seismic Un*x, a processing line developed at Colorado 
+ School of Mines, partially based on Stanford Exploration Project (SEP) 
+ software.
+ */
+
+/*********************** self documentation **********************/
+/*****************************************************************************
+GETPARS - Functions to GET PARameterS from the command line. Numeric
+	parameters may be single values or arrays of int, uint,
+	short, ushort, long, ulong, float, or double.  Single character
+	strings (type string or char *) may also be gotten. 
+	Arrays of strings, delimited by, but not containing
+        commas are permitted.
+
+The functions are:
+
+initargs 	Makes command line args available to subroutines (re-entrant).
+		Every par program starts with this call!
+getparint		get integers
+getparuint		get unsigned integers
+getparshort		get short integers
+getparushort		get unsigned short integers
+getparlong		get long integers 
+getparulong		get unsigned long integers
+getparfloat		get float
+getpardouble		get double
+getparstring		get a single string
+getparstringarray	get string array (fields delimited by commas) 
+getpar			get parameter by type
+getnparint		get n'th occurrence of integer
+getnparuint		get n'th occurrence of unsigned int
+getnparshort		get n'th occurrence of short integer
+getnparushort		get n'th occurrence of unsigned short int
+getnparlong		get n'th occurrence of long integer
+getnparulong		get n'th occurrence of unsigned long int
+getnparfloat		get n'th occurrence of float integer
+getnpardouble		get n'th occurrence of double integer
+getnparstring		get n'th occurrence of string integer
+getnparstringarray	get n'th occurrence of string integer array
+getnpar			get n'th occurrence by type
+countparname		return the number of times a parameter names is used
+countparval		return the number of values in the last occurrence
+				of a parameter
+countnparval		return the number of values in the n'th occurrence
+				of a parameter
+getPar			Promax compatible version of getpar
+
+******************************************************************************
+Function Prototypes:
+void initargs (int argc, char **argv);
+int getparint (char *name, int *p);
+int getparuint (char *name, unsigned int *p);
+int getparshort (char *name, short *p);
+int getparushort (char *name, unsigned short *p);
+int getparlong (char *name, long *p);
+int getparulong (char *name, unsigned long *p);
+int getparfloat (char *name, float *p);
+int getpardouble (char *name, double *p);
+int getparstring (char *name, char **p);
+int getparstringarray (char *name, char **p);
+int getnparint (int n, char *name, int *p);
+int getnparuint (int n, char *name, unsigned int *p);
+int getnparshort (int n, char *name, short *p);
+int getnparushort (int n, char *name, unsigned short *p);
+int getnparlong (int n, char *name, long *p);
+int getnparulong (int n, char *name, unsigned long *p);
+int getnparfloat (int n, char *name, float *p);
+int getnpardouble (int n, char *name, double *p);
+int getnparstring (int n, char *name, char **p);
+int getnparstringarray (int n, char *name, char **p);
+int getnpar (int n, char *name, char *type, void *ptr);
+int countparname (char *name);
+int countparval (char *name);
+int countnparval (int n, char *name);
+void getPar(char *name, char *type, void *ptr);
+
+******************************************************************************
+Notes:
+Here are some usage examples:
+
+	... if integer n not specified, then default to zero. 
+	if (!getparint("n", &n)) n = 0;
+	
+	... if array of floats vx is specified, then
+	if (nx=countparval("vx")) {
+		... allocate space for array
+		vx = (float *)malloc(nx*sizeof(float));
+		... and get the floats
+		getparfloat("vx",vx);
+	}
+	
+The command line for the above examples might look like:
+	progname n=35 vx=3.21,4,9.5
+	Every par program starts with this call!
+
+More examples are provided in the DTEST code at the end of this file.
+
+The functions: eatoh, eatou, eatol, eatov, eatoi, eatop used
+below are versions of atoi that check for overflow.  The source
+file for these functions is atopkge.c.
+
+******************************************************************************	
+Authors:
+Rob Clayton & Jon Claerbout, Stanford University, 1979-1985
+Shuki Ronen & Jack Cohen, Colorado School of Mines, 1985-1990
+Dave Hale, Colorado School of Mines, 05/29/90
+Credit to John E. Anderson for re-entrant initargs 03/03/94
+*****************************************************************************/	
+/**************** end self doc ********************************/
+
+#include "par.h"
+
+#ifndef TRUE
+#define TRUE (1)
+#endif
+#ifndef FALSE
+#define FALSE (0)
+#endif
+
+/* parameter table */
+typedef struct {
+	char *name;		/* external name of parameter	*/
+	char *asciival;		/* ascii value of parameter	*/
+} pointer_table;
+
+/* global variables declared and used internally */
+static pointer_table *argtbl;	/* parameter table		*/
+static int nargs;		/* number of args that parse	*/
+static int tabled = FALSE;	/* true when parameters tabled 	*/
+static int targc;		/* total number of args		*/
+static char **targv;		/* pointer to arg strings	*/
+static char *argstr;		/* storage for command line	*/
+
+/* functions declared and used internally */
+static int getparindex (int n, char *name);
+static void getparinit(void);
+static void tabulate (int argc, char **argv);
+static char *getpfname (void);
+static int white2null (char *str, int len);
+static int ccount (char c, char *s);
+static void strchop(char *s, char *t);
+
+/* make command line args available to subroutines -- re-entrant version */
+void initargs(int argc, char **argv)
+{
+	xargc = argc; xargv = argv;
+	if(tabled==TRUE){
+		free(argstr);
+		free(targv);
+		free(argtbl);
+	}
+	tabled =  FALSE;
+	return;
+}
+
+/* functions to get values for the last occurrence of a parameter name */
+int getparint (char *name, int *ptr)
+{
+	return getnpar(0,name,"i",ptr);
+}
+int getparuint (char *name, unsigned int *ptr)
+{
+	return getnpar(0,name,"p",ptr);
+}
+int getparshort (char *name, short *ptr)
+{
+	return getnpar(0,name,"h",ptr);
+}
+int getparushort (char *name, unsigned short *ptr)
+{
+	return getnpar(0,name,"u",ptr);
+}
+int getparlong (char *name, long *ptr)
+{
+	return getnpar(0,name,"l",ptr);
+}
+int getparulong (char *name, unsigned long *ptr)
+{
+	return getnpar(0,name,"v",ptr);
+}
+int getparfloat (char *name, float *ptr)
+{
+	return getnpar(0,name,"f",ptr);
+}
+int getpardouble (char *name, double *ptr)
+{
+	return getnpar(0,name,"d",ptr);
+}
+int getparstring (char *name, char **ptr)
+{
+	return getnpar(0,name,"s",ptr);
+}
+int getparstringarray (char *name, char **ptr)
+{
+	return getnpar(0,name,"a",ptr);
+}
+int getpar (char *name, char *type, void *ptr)
+{
+	return getnpar(0,name,type,ptr);
+}
+
+/* functions to get values for the n'th occurrence of a parameter name */
+int getnparint (int n, char *name, int *ptr)
+{
+	return getnpar(n,name,"i",ptr);
+}
+int getnparuint (int n, char *name, unsigned int *ptr)
+{
+	return getnpar(n,name,"p",ptr);
+}
+int getnparshort (int n, char *name, short *ptr)
+{
+	return getnpar(n,name,"h",ptr);
+}
+int getnparushort (int n, char *name, unsigned short *ptr)
+{
+	return getnpar(n,name,"u",ptr);
+}
+int getnparlong (int n, char *name, long *ptr)
+{
+	return getnpar(n,name,"l",ptr);
+}
+int getnparulong (int n, char *name, unsigned long *ptr)
+{
+	return getnpar(n,name,"v",ptr);
+}
+int getnparfloat (int n, char *name, float *ptr)
+{
+	return getnpar(n,name,"f",ptr);
+}
+int getnpardouble (int n, char *name, double *ptr)
+{
+	return getnpar(n,name,"d",ptr);
+}
+int getnparstring (int n, char *name, char **ptr)
+{
+	return getnpar(n,name,"s",ptr);
+}
+int getnparstringarray (int n, char *name, char **ptr)
+{
+	return getnpar(n,name,"a",ptr);
+}
+int getnpar (int n, char *name, char *type, void *ptr)
+{
+	int i;			/* index of name in symbol table	*/
+	int nval;		/* number of parameter values found	*/
+	char *aval;		/* ascii field of symbol		*/
+
+	if (xargc == 1) return 0;
+	if (!tabled) getparinit();/* Tabulate command line and parfile */
+	i = getparindex(n,name);/* Get parameter index */
+	if (i < 0) return 0;	/* Not there */
+	
+	/* 
+	 * handle string type as a special case, since a string 
+	 * may contain commas. 
+	 */
+	if (type[0]=='s') {
+		*((char**)ptr) = argtbl[i].asciival;
+		return 1;
+	} 
+
+	/* convert vector of ascii values to numeric values */
+	for (nval=0,aval=argtbl[i].asciival; *aval; nval++) {
+		switch (type[0]) {
+			case 'i':
+				*(int*)ptr = eatoi(aval);
+				ptr = (int*)ptr+1;
+				break;
+			case 'p':
+				*(unsigned int*)ptr = eatop(aval);
+				ptr = (unsigned int*)ptr+1;
+				break;
+			case 'h':
+				*(short*)ptr = eatoh(aval);
+				ptr = (short*)ptr+1;
+				break;
+			case 'u':
+				*(unsigned short*)ptr = eatou(aval);
+				ptr = (unsigned short*)ptr+1;
+				break;
+			case 'l':
+				*(long*)ptr = eatol(aval);
+				ptr = (long*)ptr+1;
+				break;
+			case 'v':
+				*(unsigned long*)ptr = eatov(aval);
+				ptr = (unsigned long*)ptr+1;
+				break;
+			case 'f':
+				*(float*)ptr = eatof(aval);
+				ptr = (float*)ptr+1;
+				break;
+			case 'd':
+				*(double*)ptr = eatod(aval);
+				ptr = (double*)ptr+1;
+				break;
+			case 'a':
+				{ char *tmpstr="";
+				   tmpstr = (char *)calloc(strlen(aval)+1,1);
+
+				   strchop(aval,tmpstr);
+				   *(char**)ptr = tmpstr;
+				   ptr=(char **)ptr + 1;
+				}
+				   break;
+			default:
+				err("%s: invalid parameter type = %s",
+					__FILE__,type);
+		}
+		while (*aval++ != ',') {
+			if (!*aval) break;
+		}
+	}
+	return nval;
+}
+/* Promax compatible version of getnpar */
+void getPar(char *name, char *type, void *ptr)
+{
+	(void) getnpar(0,name,type,ptr);
+	return;
+}
+
+/* return number of occurrences of parameter name */
+int countparname (char *name)
+{
+	int i,nname;
+
+	if (xargc == 1) return 0;
+	if (!tabled) getparinit();
+	for (i=0,nname=0; i<nargs; ++i)
+		if (!strcmp(name,argtbl[i].name)) ++nname;
+	return nname;
+}
+
+/* return number of values in n'th occurrence of parameter name */
+int countnparval (int n, char *name)
+{
+	int i;
+
+	if (xargc == 1) return 0;
+	if (!tabled) getparinit();
+	i = getparindex(n,name);
+	if (i>=0) 
+		return ccount(',',argtbl[i].asciival) + 1;
+	else
+		return 0;
+}
+
+/* return number of values in last occurrence of parameter name */
+int countparval (char *name)
+{
+	return countnparval(0,name);
+}
+
+
+
+/*
+ * Return the index of the n'th occurrence of a parameter name, 
+ * except if n==0, return the index of the last occurrence.
+ * Return -1 if the specified occurrence does not exist.
+ */
+static int getparindex (int n, char *name)
+{
+	int i;
+	if (n==0) {
+		for (i=nargs-1; i>=0; --i)
+			if (!strcmp(name,argtbl[i].name)) break;
+		return i;
+	} else {
+		for (i=0; i<nargs; ++i)
+			if (!strcmp(name,argtbl[i].name))
+				if (--n==0) break;
+		if (i<nargs)
+			return i;
+		else
+			return -1;
+	}
+}
+
+/* Initialize getpar */
+static void getparinit (void)
+{
+	static char *pfname;	/* name of parameter file		*/
+	FILE *pffd=NULL;	/* file id of parameter file		*/
+	int pflen;		/* length of parameter file in bytes	*/ 
+	static int pfargc;	/* arg count from parameter file	*/
+	int parfile;		/* parfile existence flag		*/
+	int argstrlen;
+	char *pargstr;		/* storage for parameter file args	*/
+	int nread;		/* bytes fread				*/
+	int i, j;		/* counters				*/
+
+
+	tabled = TRUE;		/* remember table is built		*/
+
+	/* Check if xargc was initiated */
+	if(!xargc)
+		err("%s: xargc=%d -- not initiated in main", __FILE__, xargc);
+
+	/* Space needed for command lines */
+	for (i = 1, argstrlen = 0; i < xargc; i++) {
+		argstrlen += strlen(xargv[i]) + 1;
+	}
+
+	/* Get parfile name if there is one */
+	/* parfile = (pfname = getpfname()) ? TRUE : FALSE; */
+	if ((pfname = getpfname())) {
+		parfile = TRUE;
+	} else {
+		parfile = FALSE;
+	}
+
+	if (parfile) {
+	 	pffd = fopen(pfname, "r");
+
+		/* Get the length */
+		fseek(pffd, 0, SEEK_END);
+		pflen = ftell(pffd);
+		rewind(pffd);
+		argstrlen += pflen;
+	} else {
+		pflen = 0;
+	}
+
+	/* Allocate space for command line and parameter file
+		plus nulls at the ends to help with parsing. */
+	/* argstr = (char *) calloc((size_t) (1+argstrlen+1), 1); */
+	/*argstr = (char *) ealloc1(1+argstrlen+1, 1);*/
+	argstr = (char *) calloc((size_t) (1+argstrlen+1), 1);
+
+	if (parfile) {
+		/* Read the parfile */
+		nread = fread(argstr + 1, 1, pflen, pffd);
+  		if (nread != pflen) {
+  	 	    err("%s: fread only %d bytes out of %d from %s",
+  					__FILE__,  nread, pflen, pfname);
+		}
+		fclose(pffd);
+
+		/* Zap whites in parfile to help in parsing */
+		pfargc = white2null(argstr, pflen);
+
+	} else {
+		pfargc = 0;
+	}
+
+	/* Total arg count */
+	targc = pfargc + xargc - 1;
+
+	/* Allocate space for total arg pointers */
+	targv = (char **) calloc(targc, sizeof(char*));
+
+	if (parfile) {
+		/* Parse the parfile.  Skip over multiple NULLs */
+		for (j = 1, i = 0; j < pflen; j++) {
+			if (argstr[j] && !argstr[j-1]) {
+			       targv[i++] = argstr + j;
+			}
+		}
+	} else {
+		i = 0;
+	}
+
+	/* Copy command line arguments */
+	for (j = 1, pargstr = argstr + pflen + 2; j < xargc; j++) {
+		strcpy(pargstr,xargv[j]);
+		targv[i++] = pargstr;
+		pargstr += strlen(xargv[j]) + 1;
+	}
+
+	/* Allocate space for the pointer table */
+	argtbl = (pointer_table*) calloc(targc, sizeof(pointer_table));
+
+	/* Tabulate targv */
+	tabulate(targc, targv);
+	
+	return;
+}
+
+#define PFNAME "par="
+/* Get name of parameter file */
+static char *getpfname (void)
+{
+	int i;
+	int pfnamelen;
+
+	pfnamelen = strlen(PFNAME);
+	for (i = xargc-1 ; i > 0 ; i--) {
+		if(!strncmp(PFNAME, xargv[i], pfnamelen)
+		    && strlen(xargv[i]) != pfnamelen) {
+			return xargv[i] + pfnamelen;
+		}	
+	}
+	return NULL;
+}
+
+#define iswhite(c)	((c) == ' ' || (c) == '\t' || (c) == '\n')
+
+/* 
+ * Replace the whites by (possibly multiple) nulls.  If we see a non-white
+ * and the previous char is a null, this signals the start of a string
+ * and we bump the count.  This routine returns a count of the strings.
+ */
+static int white2null (char *str, int len)
+{
+	int i;
+	int count;
+	int inquote = FALSE;
+
+	str[0] = '\0'; /* This line added by Dave Hale, 1/30/96. */
+	for (i = 1, count = 0; i < len; i++) {
+		if (str[i]=='"') inquote=(inquote==TRUE)?FALSE:TRUE;
+		if (!inquote) {
+			if (iswhite(str[i])) { /* Is this a new word ? */
+				str[i] = '\0';
+			} else if (!str[i-1]) { /* multiple whites */
+				count++;
+			}
+		}
+	}
+	for (i = 1, inquote=FALSE; i < len; i++) {
+		if (str[i]=='"') inquote=(inquote==TRUE)?FALSE:TRUE;
+		if (inquote) {
+			if (str[i+1]!='"') {
+				str[i] = str[i+1];
+			} else {
+				str[i] = '\0';
+				str[i+1] = '\0';
+				inquote = FALSE;
+			}
+		}
+	}
+	str[len] = '\0';
+	return count;
+}
+
+/* Install symbol table */
+static void tabulate (int argc, char **argv)
+{
+	int i;
+	char *eqptr;
+
+	for (i = 0, nargs = 0 ; i < argc; i++) {
+		eqptr = (char *)strchr(argv[i], '=');
+		if (eqptr) {
+			argtbl[nargs].name = argv[i];
+			argtbl[nargs].asciival = eqptr + 1;
+			*eqptr = (char)0;
+
+			/* Debugging dump */
+/* 			fprintf(stderr, */
+/* 			"argtbl[%d]: name=%s asciival=%s\n", */
+/* 			nargs,argtbl[nargs].name,argtbl[nargs].asciival); */
+
+			nargs++;
+		}
+	}
+	return;
+}
+
+/* Count characters in a string */
+static int ccount (char c, char *s)
+{
+	int i, count;
+	for (i = 0, count = 0; s[i] != 0; i++)
+		if(s[i] == c) count++;
+	return count;
+}
+
+static void strchop(char *s, char *t)
+/***********************************************************************
+strchop - chop off the tail end of a string "s" after a "," returning
+          the front part of "s" as "t".
+************************************************************************
+Notes:
+Based on strcpy in Kernighan and Ritchie's C [ANSI C] book, p. 106.
+************************************************************************
+Author: CWP: John Stockwell and Jack K. Cohen, July 1995
+***********************************************************************/
+{
+
+	while ( (*s != ',') && (*s != '\0') ) {
+		 *t++ = *s++;
+	}
+	*t='\0';
+}
+
+
+#ifdef TEST
+#define N 100
+main(int argc, char **argv)
+{
+	char *s;
+	short h, vh[N];
+	unsigned short u, vu[N];
+	long l, vl[N];
+	unsigned long v, vv[N];
+	int i, vi[N], ipar, npar, nval;
+	unsigned int p, vp[N];
+	float f, vf[N];
+	double d, vd[N];
+
+	initargs(argc, argv);
+
+	/* int parameters */
+	npar = countparname("i");
+	printf("\nnumber of i pars = %d\n",npar);
+	for (ipar=1; ipar<=npar; ++ipar) {
+		getnparint(ipar,"i",&i);
+		printf("occurrence %d of i=%d\n",ipar,i);
+	}
+	if (getparint("i", &i))	
+		printf("last occurrence of i=%d\n",i);
+	npar = countparname("vi");
+	printf("number of vi pars = %d\n",npar);
+	for (ipar=1; ipar<=npar; ++ipar) {
+		nval = countnparval(ipar,"vi");
+		printf("occurrence %d has %d values\n",ipar,nval);
+		nval = getnparint(ipar,"vi",vi);
+		printf("vi=");
+		for (i=0; i<nval; i++)
+			printf("%d%c",vi[i],i==nval-1?'\n':',');
+	}
+	if (npar>0) {
+		nval = countparval("vi");
+		printf("last occurrence has %d values\n",nval);
+		getparint("vi",vi);
+		printf("vi=");
+		for (i=0; i<nval; i++)
+			printf("%d%c",vi[i],i==nval-1?'\n':',');
+	}
+
+	/* float parameters */
+	npar = countparname("f");
+	printf("\nnumber of f pars = %d\n",npar);
+	for (ipar=1; ipar<=npar; ++ipar) {
+		getnparfloat(ipar,"f",&f);
+		printf("occurrence %d of f=%g\n",ipar,f);
+	}
+	if (getparfloat("f", &f))	
+		printf("last occurrence of f=%g\n",f);
+	npar = countparname("vf");
+	printf("number of vf pars = %d\n",npar);
+	for (ipar=1; ipar<=npar; ++ipar) {
+		nval = countnparval(ipar,"vf");
+		printf("occurrence %d has %d values\n",ipar,nval);
+		nval = getnparfloat(ipar,"vf",vf);
+		printf("vf=");
+		for (i=0; i<nval; i++)
+			printf("%g%c",vf[i],i==nval-1?'\n':',');
+	}
+	if (npar>0) {
+		nval = countparval("vf");
+		printf("last occurrence has %d values\n",nval);
+		getparfloat("vf",vf);
+		printf("vf=");
+		for (i=0; i<nval; i++)
+			printf("%g%c",vf[i],i==nval-1?'\n':',');
+	}
+
+	/* string parameters */
+	npar = countparname("s");
+	printf("\nnumber of s pars = %d\n",npar);
+	for (ipar=1; ipar<=npar; ++ipar) {
+		getnparstring(ipar,"s",&s);
+		printf("occurrence %d of s=%s\n",ipar,s);
+	}
+	if (getparstring("s", &s))	
+		printf("last occurrence of s=%s\n",s);
+	
+	return EXIT_SUCCESS;
+}
+#endif
+
diff --git a/raytime3d/name_ext.c b/raytime3d/name_ext.c
new file mode 100644
index 0000000000000000000000000000000000000000..8fa1e09d254153d4d783ab040cebfada4d82d3b7
--- /dev/null
+++ b/raytime3d/name_ext.c
@@ -0,0 +1,44 @@
+#include<stdlib.h>
+#include<string.h>
+#include<stdio.h>
+
+/**
+*  inserts a character string after the filename, before the extension
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands 
+**/
+
+
+void name_ext(char *filename, char *extension)
+{
+	char ext[100];
+
+	if (strstr(filename, ".su") != NULL) {
+		sprintf(ext,"%s.su", extension);
+		strcpy(strstr(filename, ".su"), ext);
+	}
+	else if (strstr(filename, ".segy") != NULL) {
+		sprintf(ext,"%s.segy", extension);
+		strcpy(strstr(filename, ".segy"), ext);
+	}
+	else if (strstr(filename, ".mat") != NULL) {
+		sprintf(ext,"%s.mat", extension);
+		strcpy(strstr(filename, ".mat"), ext);
+	}
+	else if (strstr(filename, ".hdf") != NULL) {
+		sprintf(ext,"%s.hdf", extension);
+		strcpy(strstr(filename, ".hdf"), ext);
+	}
+	else if (strrchr(filename, '.') != NULL) {
+		sprintf(ext,"%s.su", extension);
+		strcpy(strrchr(filename, '.'), ext);
+	}
+	else {
+		sprintf(ext,"%s.su", extension);
+		strcat(filename, ext);
+	}
+
+	return;
+}
diff --git a/raytime3d/par.h b/raytime3d/par.h
new file mode 100644
index 0000000000000000000000000000000000000000..fce76ed344382c6d5719737e5395fd8fb3ad0a5b
--- /dev/null
+++ b/raytime3d/par.h
@@ -0,0 +1,217 @@
+/* This file is property of the Colorado School of Mines.
+ 
+ Copyright © 2007, Colorado School of Mines,
+ All rights reserved.
+ 
+ 
+ Redistribution and use in source and binary forms, with or 
+ without modification, are permitted provided that the following 
+ conditions are met:
+ 
+ *  Redistributions of source code must retain the above copyright 
+ notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above 
+ copyright notice, this list of conditions and the following 
+ disclaimer in the documentation and/or other materials provided 
+ with the distribution.
+ *  Neither the name of the Colorado School of Mines nor the names of
+ its contributors may be used to endorse or promote products 
+ derived from this software without specific prior written permission.
+ 
+ Warranty Disclaimer:
+ THIS SOFTWARE IS PROVIDED BY THE COLORADO SCHOOL OF MINES AND CONTRIBUTORS 
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 
+ COLORADO SCHOOL OF MINES OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
+ POSSIBILITY OF SUCH DAMAGE.
+ 
+ 
+ Export Restriction Disclaimer:
+ We believe that CWP/SU: Seismic Un*x is a low technology product that does
+ not appear on the Department of Commerce CCL list of restricted exports.
+ Accordingly, we believe that our product meets the qualifications of
+ an ECCN (export control classification number) of EAR99 and we believe
+ it fits the qualifications of NRR (no restrictions required), and
+ is thus not subject to export restrictions of any variety.
+ 
+ Approved Reference Format:
+ In publications, please refer to SU as per the following example:
+ Cohen, J. K. and Stockwell, Jr. J. W., (200_), CWP/SU: Seismic Un*x 
+ Release No. __: an open source software  package for seismic 
+ research and processing, 
+ Center for Wave Phenomena, Colorado School of Mines.
+ 
+ Articles about SU in peer-reviewed journals:
+ Saeki, T., (1999), A guide to Seismic Un*x (SU)(2)---examples of data processing (part 1), data input and preparation of headers, Butsuri-Tansa (Geophysical Exploration), vol. 52, no. 5, 465-477.
+ Stockwell, Jr. J. W. (1999), The CWP/SU: Seismic Un*x Package, Computers and Geosciences, May 1999.
+ Stockwell, Jr. J. W. (1997), Free Software in Education: A case study of CWP/SU: Seismic Un*x, The Leading Edge, July 1997.
+ Templeton, M. E., Gough, C.A., (1998), Web Seismic Un*x: Making seismic reflection processing more accessible, Computers and Geosciences.
+ 
+ Acknowledgements:
+ SU stands for CWP/SU:Seismic Un*x, a processing line developed at Colorado 
+ School of Mines, partially based on Stanford Exploration Project (SEP) 
+ software.
+ .                       */
+/* par.h - include file for getpar, selfdoc, and error handling functions */
+
+#ifndef PAR_H
+#define PAR_H
+void verr(char *fmt, ...);
+void vmess(char *fmt, ...);
+void vwarn(char *fmt, ...);
+void vsyserr(char *fmt, ...);
+
+/* TYPEDEFS */
+typedef union { /* storage for arbitrary type */
+    char s[8];
+    short h;
+    unsigned short u;
+    long l;
+    unsigned long v;
+    int i;
+    unsigned int p;
+    float f;
+    double d;
+    unsigned int U:16;
+    unsigned int P:32;
+} Value;
+
+/* INCLUDES */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>	/* non-ANSI */
+#include <unistd.h>	/* non-ANSI */
+#include <sys/types.h>	/* non-ANSI */
+#include<string.h>
+
+
+/* GLOBAL DECLARATIONS */
+extern int xargc; extern char **xargv;
+
+
+/* TYPEDEFS */
+typedef char *cwp_String;
+
+typedef enum {BADFILETYPE = -1,
+	TTY, DISK, DIRECTORY, TAPE, PIPE, FIFO, SOCKET, SYMLINK} FileType;
+	
+/* DEFINES */
+
+/* getpar macros */
+#define MUSTGETPARINT(x,y) if(!getparint(x,y)) err("must specify %s=",x)
+#define MUSTGETPARFLOAT(x,y) if(!getparfloat(x,y)) err("must specify %s=",x)
+#define MUSTGETPARSTRING(x,y) if(!getparstring(x,y)) err("must specify %s=",x)
+
+#define STDIN (0)
+#define STDOUT (1)
+#define STDERR (2)
+
+/* FUNCTION PROTOTYPES */
+
+#ifdef __cplusplus  /* if C++, specify external C linkage */
+extern "C" {
+#endif
+
+/* getpar parameter parsing */
+void initargs (int argc, char **argv);
+int getparint (char *name, int *p);
+int getparuint (char *name, unsigned int *p);
+int getparshort (char *name, short *p);
+int getparushort (char *name, unsigned short *p);
+int getparlong (char *name, long *p);
+int getparulong (char *name, unsigned long *p);
+int getparfloat (char *name, float *p);
+int getpardouble (char *name, double *p);
+int getparstring (char *name, char **p);
+int getparstringarray (char *name, char **p);
+int getnparint (int n, char *name, int *p);
+int getnparuint (int n, char *name, unsigned int *p);
+int getnparshort (int n, char *name, short *p);
+int getnparushort (int n, char *name, unsigned short *p);
+int getnparlong (int n, char *name, long *p);
+int getnparulong (int n, char *name, unsigned long *p);
+int getnparfloat (int n, char *name, float *p);
+int getnpardouble (int n, char *name, double *p);
+int getnparstring (int n, char *name, char **p);
+int getnparstringarray (int n, char *name, char **p);
+int getnpar (int n, char *name, char *type, void *ptr);
+int countparname (char *name);
+int countparval (char *name);
+int countnparval (int n, char *name);
+
+/* For ProMAX */
+void getPar(char *name, char *type, void *ptr);
+
+/* errors and warnings */
+void err (char *fmt, ...);
+void syserr (char *fmt, ...);
+void warn (char *fmt, ...);
+
+/* self documentation */
+void pagedoc (void);
+void requestdoc (int i);
+
+/* system calls with error trapping */
+int ecreat(char *path, int perms);
+int efork(void);
+int eopen(char *path, int flags, int perms);
+int eclose(int fd);
+int eunlink(char *path);
+long elseek(int fd, long offset, int origin);
+int epipe(int fd[2]);
+int eread(int fd, char *buf, int nbytes);
+int ewrite(int fd, char *buf, int nbytes);
+
+/* system subroutine calls with error trapping */
+FILE *efopen(const char *file, const char *mode);
+FILE *efreopen(const char *file, const char *mode, FILE *stream1);
+FILE *efdopen(int fd, const char *mode);
+FILE *epopen(char *command, char *type);
+int efclose(FILE *stream);
+int epclose(FILE *stream);
+int efflush(FILE *stream);
+int eremove(const char *file);
+int erename(const char *oldfile, const char* newfile);
+int efseek(FILE *stream, long offset, int origin);
+void erewind(FILE *stream);
+long eftell(FILE *stream);
+FILE *etmpfile(void);
+char *etmpnam(char *namebuffer);
+void *emalloc(size_t size);
+void *erealloc(void *memptr, size_t size);
+void *ecalloc(size_t count, size_t size);
+size_t efread(void *bufptr, size_t size, size_t count, FILE *stream);
+size_t efwrite(void *bufptr, size_t size, size_t count, FILE *stream);
+
+#ifndef SUN_A
+int efgetpos(FILE *stream, fpos_t *position);
+int efsetpos(FILE *stream, const fpos_t *position);
+#endif
+
+/* string to numeric conversion with error checking */
+short eatoh(char *s);
+unsigned short eatou(char *s);
+int eatoi(char *s);
+unsigned int eatop(char *s);
+long eatol(char *s);
+unsigned long eatov(char *s);
+float eatof(char *s);
+double eatod(char *s);
+
+/* file type checking */
+FileType filestat(int fd);
+char *printstat(int fd);
+
+#ifdef __cplusplus  /* if C++ (external C linkage is being specified) */
+}
+#endif
+
+#endif /* PAR_H */
diff --git a/raytime3d/raytime.h b/raytime3d/raytime.h
new file mode 100644
index 0000000000000000000000000000000000000000..882c78b9a2eb0b945737dac10ae5c6f07aa55123
--- /dev/null
+++ b/raytime3d/raytime.h
@@ -0,0 +1,135 @@
+#include<stdlib.h>
+#include<stdio.h>
+#include<limits.h>
+#include<float.h>
+#include<math.h>
+
+#ifndef COMPLEX
+typedef struct _complexStruct { /* complex number */
+    float r,i;
+} complex;
+typedef struct _dcomplexStruct { /* complex number */
+    double r,i;
+} dcomplex;
+#endif/* complex */
+
+
+typedef struct _icoord { /* 3D coordinate integer */
+    int z;
+    int x;
+    int y;
+} icoord;
+
+typedef struct _fcoord { /* 3D coordinate float */
+    float z;
+    float x;
+    float y;
+} fcoord;
+
+struct s_ecount {
+  int       corner,corner_min,side;
+};
+
+typedef struct _receiverPar { /* Receiver Parameters */
+	char *file_rcv;
+	int n;
+	int nt;
+	int max_nrec;
+	int *z;
+	int *x;
+	float *zr;
+	float *xr;
+	int scale;
+	int sinkdepth;
+	int sinkvel;
+	float cp;
+	float rho;
+} recPar;
+
+typedef struct _modelPar { /* Model Parameters */
+	int sh;
+	char *file_cp;
+	float dz;
+	float dx;
+	float dt;
+	float z0;
+	float x0;
+	/* medium max/min values */
+	float cp_min;
+	float cp_max;
+	int nz;
+	int nx;
+} modPar;
+
+typedef struct _waveletPar { /* Wavelet Parameters */
+	char *file_src; /* general source */
+	int nsrcf;
+	int nt;
+	int ns;
+	int nx;
+	float dt;
+	float ds;
+	float fmax;
+	int random;
+	int seed;
+	int nst;
+	size_t *nsamp;
+} wavPar;
+
+typedef struct _sourcePar { /* Source Array Parameters */
+	int n;
+	int type;
+	int orient;
+	int *z;
+	int *x;
+	int single;	
+	int plane;
+	int circle;
+	int array;
+	int random;
+	int multiwav;
+	float angle;
+	float velo;
+	float amplitude;
+	int distribution;
+	int window;
+    int injectionrate;
+	int sinkdepth;
+	int src_at_rcv; /* Indicates that wavefield should be injected at receivers */
+} srcPar;
+
+typedef struct _shotPar { /* Shot Parameters */
+	int n;
+	int nx;
+	int nz;
+	int *z;
+	int *x;
+} shotPar;
+
+typedef struct _raypar { /* ray-tracing parameters */
+    int smoothwindow;
+    int useT2;
+    int geomspread;
+    int nray;
+} rayPar;
+
+#ifndef TRUE
+#  define TRUE 1
+#endif
+
+#ifndef FALSE
+#  define FALSE 0
+#endif
+
+#define equal(x,y) !strcmp(x,y)
+#define min2(a,b) (((a) < (b)) ? (a) : (b))
+#define max2(a,b) (((a) > (b)) ? (a) : (b))
+
+#define Infinity FLT_MAX
+
+#if __STDC_VERSION__ >= 199901L
+  /* "restrict" is a keyword */
+#else
+#define restrict 
+#endif
+
diff --git a/raytime3d/raytime3d.c b/raytime3d/raytime3d.c
new file mode 100644
index 0000000000000000000000000000000000000000..9b0c88d6e59fe63c13275cc139f7352bff266501
--- /dev/null
+++ b/raytime3d/raytime3d.c
@@ -0,0 +1,318 @@
+#include <DELPHI_IOc.h> 
+
+/*********************** self documentation **********************/
+char *sdoc[] = {
+" ",
+" RAYTIME3D - modeling of one-way traveltime for operators in 3D media",
+" ",
+" raytime3d file_vel= xsrc1= zsrc1= ysrc1= [optional parameters]",
+" ",
+" Required parameters:",
+" ",
+"   file_vel= ................ gridded velocity file ",
+"   xsrc1= ................... x-position of the source (m)",
+"   ysrc1= ................... y-position of the source (m)",
+"   zsrc1= ................... z-position of the source (m)",
+" ",
+" Optional parameters:",
+" ",
+" INPUT AND OUTPUT ",
+"   key=gy ................... input data sorting key",
+"   ny=1 ..................... if 2D file number of y traces (2D model)",
+"   nxmax=512 ................ maximum number of traces in input files",
+"   ntmax=1024 ............... maximum number of samples/trace in input files",
+"   file_out= ................ output file with traveltime cube",
+"   file_amp= ................ output file with approximate amplitudes",
+" RAY TRACING ",
+"   dT=0 ..................... put traces on one-way time grid with step dT",
+"   Tmin=first shot........... minimum time of one-way time grid",
+"   Tmax=last shot ........... maximum time of one-way time grid",
+"   hom=1 .................... 1: draw straight rays in homogeneous layers",
+" SOURCE POSITIONS ",
+"   xsrc2=xsrc1 .............. x-position of last source",
+"   dxsrc=0 .................. step in source x-direction",
+"   ysrc2=ysrc1 .............. y-position of last source",
+"   dysrc=0 .................. step in source y-direction",
+"   zsrc2=zsrc1 .............. z-position of last source",
+"   dzsrc=0 .................. step in source z-direction",
+" RECEIVER POSITIONS ",
+"   xrcv=0,(nx-1)*dx ......... x-position's of receivers (array)",
+"   yrcv=0,(ny-1)*dy ......... y-position's of receivers (array)",
+"   zrcv=0,0 ................. z-position's of receivers (array)",
+"   dxrcv=dx ................. step in receiver x-direction",
+"   dyrcv=dy ................. step in receiver y-direction",
+"   dzrcv=0 .................. step in receiver z-direction",
+"   dxspr=0 .................. step of receiver spread in x-direction",
+"   dyspr=0 .................. step of receiver spread in y-direction",
+"   lint=1 ................... linear interpolate between the rcv points",
+"   verbose=0 ................ verbose option",
+" ",
+"  raytime3d calculates the first arrival time at the defined receiver array ",
+"  for the defined shots at different depth and lateral positions.",
+"  Every new lateral position (with dxsrc) gives a new output gather.",
+" ",
+"  PROGRAM TO CALCULATE TRAVEL TIMES IN 3D MEDIA  ",
+"  AUTHORS: John E. Vidale(1986-1989), J. Hole(1990-1995) ",
+" ",
+" Translated to DELPHI environment: Jan Thorbecke 17-04-1996",
+" ",
+NULL};
+/**************** end self doc ***********************************/
+
+#define SQR2 1.414213562
+#define SQR3 1.732050808
+#define SQR6 2.449489743
+#define t0(x,y,z)   time0[nxy*(z) + nx*(y) + (x)]
+#define s0(x,y,z)   slow0[nxy*(z) + nx*(y) + (x)]
+
+void vidale3d(float *slow0, float *time0, int nz, int nx, int ny, float h, int xs, int ys, int zs, int NCUBE);
+void src3d(float *time0, float *slow0, int nz, int nx, int ny, float h, float ox, float oy, float oz, int *pxs, int *pys, int *pzs, int *cube);
+
+void main(int argc, char *argv[])
+{
+	int
+		nx,			/* x-dimension of mesh (LEFT-TO-RIGHT) */
+		ny,			/* y-dimension of mesh (FRONT-TO-BACK) */
+		nz,			/* z-dimension of mesh  (TOP-TO-BOTTOM) */
+		nxy, nxyz, xs, ys, zs, cube,
+		xx, yy, zz,	i, j;
+	float
+		h,		/* spatial mesh interval (units consistant with vel) */
+		*slow0, *time0;
+
+/* to read the delphi velocity file */
+	int32	type, dom1, dom2;
+	int     error, n1, n2, ret, size, nkeys, verbose;
+	int		ntmax, nxmax;
+	float	d1, d2, f1, f2, *tmpdata, c, scl, ox, oz, oy;
+	char	*file_vel, *file_out, *key;
+	segyhdr	*hdrs;
+
+/*---------------------------------------------------------------------------*
+ *  Read input parameters and query for any that are needed but missing.
+ *---------------------------------------------------------------------------*/
+
+	initargs(argc, argv);
+	requestdoc(1);
+
+	if (!getparint("verbose",&verbose)) verbose=0;
+	if (verbose) {
+		samess("Hole, J.A., and B.C. Zelt, 1995.  \"3-D finite-difference");
+		samess("reflection  traveltimes\".  Geophys. J. Int., 121, 427-434");
+	}
+	if(!getparstring("file_out",&file_out)) saerr("file_out not given");
+	if(!getparstring("file_vel", &file_vel)) {
+		sawarn("file_vel not defined, assuming homogeneous model");
+		if(!getparfloat("c",&c)) saerr("c not defined");
+		if(!getparint("nx",&nx)) saerr("nx not defined");
+		if(!getparint("ny",&ny)) saerr("ny not defined");
+		if(!getparint("nz",&nz)) saerr("nz not defined");
+		if(!getparfloat("h",&h)) saerr("h not defined");
+	}
+	if(!getparint("ny",&ny)) saerr("ny not defined");
+
+/*---------------------------------------------------------------------------*
+ *  Open velocity file
+ *---------------------------------------------------------------------------*/
+
+	if (file_vel != NULL) {
+		error = open_file(file_vel, GUESS_TYPE, DELPHI_READ);
+		if (error < 0 ) saerr("error in opening file %s", file_vel);
+		error = get_dims(file_vel, &n1, &n2, &type);
+		if (ret >= 0) {
+			if (!getparint("ntmax", &ntmax)) ntmax = n1;
+			if (!getparint("nxmax", &nxmax)) nxmax = n2;
+			if (verbose>=2 && (ntmax!=n1 || nxmax!=n2))
+		    	samess("dimensions overruled: %d x %d",ntmax,nxmax);
+		}
+		else {
+			if (!getparint("ntmax", &ntmax)) ntmax = 1024;
+			if (!getparint("nxmax", &nxmax)) nxmax = 512;
+			if (verbose>=2) samess("dimensions used: %d x %d",ntmax,nxmax);
+		}
+		size    = ntmax * nxmax;
+		tmpdata = alloc1float(size);
+		hdrs    = (segyhdr *) malloc(nxmax*sizeof(segyhdr));
+
+		if (!getparstring("key", &key)) {
+			ret = get_sort(file_vel);
+			if (ret < 0) key = "gy";
+			else key = getkey(ret);
+		}
+		if (verbose) samess("input sorting key is %s",key);
+		set_sukey(key);
+
+		ret = read_data(file_vel,tmpdata,size,&n1,&n2,&f1,&f2,&d1,&d2,
+			&type,hdrs);
+		if (ret < 0) saerr("error in reading data from file %s", file_vel);
+		if (hdrs[0].scalco < 0) scl = 1.0/fabs(hdrs[0].scalco);
+		else if (hdrs[0].scalco == 0) scl = 1.0;
+		else scl = hdrs[0].scalco;
+		get_axis(&dom1, &dom2);
+		if (d1 != d2) 
+			saerr("d1 != d2; this is not allowed in the calculation");
+		h = d1;
+		if (dom1 == SA_AXIS_Z) {
+			nx = n2; nz = n1; 
+			ox = hdrs[0].gx*scl; oy = hdrs[0].gy*scl; oz = f1;
+		}
+		else {
+			nx = n1; nz = n2; 
+			ox = f1; oy = hdrs[0].gy*scl; oz = f1;
+		}
+
+		slow0 = (float *)malloc(ny*n1*n2*sizeof(float));
+		if (slow0 == NULL) saerr("Out of memory for slow0 array!");
+		nxy = nx * ny;
+		if (verbose) samess("h = %.2f nx = %d nz = %d ny = %d", h, nx, nz, ny);
+
+		yy = 0;
+		while (ret >= 0) {
+			if (verbose==2) disp_info(file_vel,n1,n2,f1,f2,d1,d2,type);
+
+			if (dom1 == SA_AXIS_Z) {
+				if (n2 != nx || n1 != nz) saerr("dimensions changed");
+				for (i = 0; i < n2; i++) {
+					for (j = 0; j < n1; j++) 
+						slow0[j*nxy+yy*nx+i] = h/tmpdata[i*n1+j];
+				}
+			}
+			else {
+				if (n1 != nx || n2 != nz) saerr("dimensions changed");
+				for (i = 0; i < n2; i++) {
+					for (j = 0; j < n1; j++) 
+						slow0[i*nxy+yy*nx+j] = h/tmpdata[i*n1+j];
+				}
+			}
+
+			yy += 1;
+			ret = read_data(file_vel, tmpdata, size, &n1, &n2, &f1, &f2, 
+				&d1, &d2, &type, hdrs);
+		}
+		ret = close_file(file_vel);
+		if (ret < 0) sawarn("err %d on closing input file",ret);
+		free1float(tmpdata);
+		if (yy == 1) {
+			if(!getparint("ny",&ny)) samess("2D model defined");
+			else {
+				slow0 = (float *)realloc(slow0, ny*nx*nz*sizeof(float));
+				if (slow0 == NULL) saerr("Out of memory for slow0 array!");
+
+				samess("3D model defined from 2D model");
+				for (zz = 0; zz < nz; zz++) {
+					for (yy = 1; yy < ny; yy++) {
+						for (xx = 0; xx < nx; xx++) 
+							slow0[zz*nxy+yy*nx+xx] = slow0[zz*nxy+xx];
+					}
+				}
+			}
+		}
+
+	}
+	else {
+		nxy = nx * ny;
+		slow0 = (float *)malloc(nx*nz*ny*sizeof(float));
+		if (slow0 == NULL) saerr("Out of memory for slow0 array!");
+		scl = h/c;
+		ox = 0; oy = 0; oz = 0;
+		for (zz = 0; zz < nz; zz++) {
+			for (yy = 0; yy < ny; yy++) {
+				for (xx = 0; xx < nx; xx++) 
+					slow0[zz*nxy+yy*nx+xx] = scl;
+			}
+		}
+	}
+
+	nxy = nx * ny;
+	nxyz = nx * ny * nz;
+
+	/* ALLOCATE MAIN GRID FOR TIMES */
+	time0 = (float *) malloc(sizeof(float)*nxyz);
+	if(time0 == NULL) saerr("error in allocation of array time0");
+
+/*---------------------------------------------------------------------------*
+ *  Input the source locations.
+ *          and
+ *  Initialize the traveltime array.  Place t=0 at source position.
+ *---------------------------------------------------------------------------*/
+
+	src3d(time0, slow0, nz, nx, ny, h, ox, oy, oz, &xs, &ys, &zs, &cube);
+	if (verbose) samess("source positions xs = %d ys = %d zs = %d", xs,ys,zs);
+
+/*	for (zz = 0; zz < nz; zz++) {
+		for (yy = 0; yy < ny; yy++) {
+			for (xx = 0; xx < nx; xx++) 
+				if (time0[zz*nxy+yy*nx+xx] != 1e10) fprintf(stderr,"slow[%d,%d,%d] = %f\n", xx,yy,zz, time0[zz*nxy+yy*nx+xx]);
+		}
+	}
+*/
+
+/*---------------------------------------------------------------------------*
+ *  Read in receiver positions
+ *---------------------------------------------------------------------------*/
+
+/*---------------------------------------------------------------------------*
+ *  Check and set parameters
+ *---------------------------------------------------------------------------*/
+
+
+/*---------------------------------------------------------------------------*
+ *  Compute traveltimes.
+ *---------------------------------------------------------------------------*/
+
+	vidale3d(slow0, time0, nz, nx, ny, h, xs, ys, zs, cube);
+
+/*---------------------------------------------------------------------------*
+ *  Write output
+ *---------------------------------------------------------------------------*/
+
+/*
+	for (zz = 0; zz < nz; zz++) {
+		for (yy = 0; yy < ny; yy++) {
+			for (xx = 0; xx < nx; xx++) 
+				if (time0[zz*nxy+yy*nx+xx] != 1e10) fprintf(stderr,"slow[%d,%d,%d] = %f\n", xx,yy,zz, time0[zz*nxy+yy*nx+xx]);
+		}
+	}
+*/
+	ret = open_file(file_out, GUESS_TYPE, DELPHI_CREATE);
+	if (ret < 0 ) saerr("error in creating output file %s", file_out);
+
+	hdrs = (segyhdr *) malloc(ny*sizeof(segyhdr));
+	tmpdata = alloc1float(nxy);
+	f1   = ox;
+	f2   = oy;
+	d1   = h;
+	d2   = h;
+
+	gen_hdrs(hdrs,nx,ny,f1,f2,d1,d2,TRID_ZX);
+	for (i = 0; i < ny; i++) {
+		hdrs[i].scalco = -1000;
+		hdrs[i].scalel = -1000;
+/*		hdrs[i].offset = xi[0]*dx + is*ispr*dx - xsrc;*/
+		hdrs[i].sx     = (int)(ox+xs*h)*1000;
+		hdrs[i].sy     = (int)(oy+ys*h)*1000;
+		hdrs[i].gy     = (int)(oy+i*d2)*1000;
+		hdrs[i].sdepth = (int)(oz+zs*h)*1000;
+		hdrs[i].fldr   = 1;
+		hdrs[i].trwf   = ny;
+		for (j = 0; j < nx; j++) {
+			tmpdata[i*nx+j] = time0[i*nx+j];
+		}
+	}
+
+	if (ret < 0 ) sawarn("error on writing keys.");
+	ret = set_axis(dom1, dom2);
+	if (ret < 0 ) saerr("error on writing axis.");
+	ret = write_data(file_out,tmpdata,nx,ny,f1,f2,d1,d2,type,hdrs);
+	if (ret < 0 ) saerr("error on writing output file.");
+	ret = close_file(file_out);
+	if (ret < 0) saerr("err %d on closing output file",ret);
+
+	free(time0);
+	free(slow0);
+	free(hdrs);
+	free1float(tmpdata);
+
+	exit(0);
+
+}
diff --git a/raytime3d/readModel.c b/raytime3d/readModel.c
new file mode 100644
index 0000000000000000000000000000000000000000..27f1da715a50dbc36eac4827efe68434288ee9e7
--- /dev/null
+++ b/raytime3d/readModel.c
@@ -0,0 +1,80 @@
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE_SOURCE
+#define _LARGEFILE64_SOURCE
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <math.h>
+#include "segy.h"
+#include "par.h"
+#include "raytime.h"
+
+#define     MAX(x,y) ((x) > (y) ? (x) : (y))
+#define     MIN(x,y) ((x) < (y) ? (x) : (y))
+#define NINT(x) ((int)((x)>0.0?(x)+0.5:(x)-0.5))
+
+/**
+*  Reads gridded model files and compute from them medium parameters used in the FD kernels.
+*  The files read in contain the P (and S) wave velocity and density.
+*  The medium parameters calculated are lambda, mu, lambda+2mu, and 1/ro.
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands 
+**/
+
+
+int readModel(modPar mod, float *velocity, float *slowness, int nw)
+{
+    FILE    *fpcp;
+    size_t  nread;
+    int i, tracesToDo, j;
+	int nz, nx;
+    segy hdr;
+    
+
+	/* grid size and start positions for the components */
+	nz = mod.nz;
+	nx = mod.nx;
+
+/* open files and read first header */
+
+   	fpcp = fopen( mod.file_cp, "r" );
+   	assert( fpcp != NULL);
+   	nread = fread(&hdr, 1, TRCBYTES, fpcp);
+   	assert(nread == TRCBYTES);
+
+/* read all traces */
+
+	tracesToDo = mod.nx;
+	i = 0;
+	while (tracesToDo) {
+       	nread = fread(&velocity[i*nz], sizeof(float), hdr.ns, fpcp);
+       	assert (nread == hdr.ns);
+	    for (j=0;j<nz;j++) {
+		    if (velocity[i*nz+j]!=0.0) {
+               slowness[(i+nw)*nz+j+nw] = 1.0/velocity[i*nz+j];
+			}
+		}
+	    for (j=0;j<nw;j++) slowness[(i+nw)*nz+j] = slowness[(i+nw)*nz+nw];
+	    for (j=nz+nw;j<nz+2*nw;j++) slowness[(i+nw)*nz+j] = slowness[(i+nw)*nz+nz+nw-1];
+
+       	nread = fread(&hdr, 1, TRCBYTES, fpcp);
+       	if (nread==0) break;
+		i++;
+	}
+   	fclose(fpcp);
+
+	for (i=0;i<nw;i++) {
+	    for (j=0;j<nz+2*nw;j++) {
+	        slowness[(i)*nz+j]       = slowness[(nw)*nz+j];
+	        slowness[(nx+nw+i)*nz+j] = slowness[(nx+nw-1)*nz+j];
+        }
+    }
+
+    return 0;
+}
+
+
diff --git a/raytime3d/recvPar.c b/raytime3d/recvPar.c
new file mode 100644
index 0000000000000000000000000000000000000000..4ad9eae9be2f3c7bcbeb1ee061dc97d5a4ff9d77
--- /dev/null
+++ b/raytime3d/recvPar.c
@@ -0,0 +1,519 @@
+#include <stdio.h>
+#include <assert.h>
+#include <math.h>
+
+#include "raytime.h"
+#include "par.h"
+
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define NINT(x) ((int)((x)>0.0?(x)+0.5:(x)-0.5))
+
+/**
+*  Calculates the receiver positions based on the input parameters
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*
+*   Ammendments:
+*           Max Holicki changing the allocation receiver array (2-2016)
+*           The Netherlands 
+**/
+
+
+void name_ext(char *filename, char *extension);
+
+int recvPar(recPar *rec, float sub_x0, float sub_z0, float dx, float dz, int nx, int nz)
+{
+	float *xrcv1, *xrcv2, *zrcv1, *zrcv2;
+	int   i, ix, ir, verbose;
+	float dxrcv, dzrcv, *dxr, *dzr;
+	float rrcv, dphi, oxrcv, ozrcv, arcv;
+	double circ, h, a, b, e, s, xr, zr, dr, srun, phase;
+	float xrange, zrange, sub_x1, sub_z1;
+	int Nx1, Nx2, Nz1, Nz2, Ndx, Ndz, iarray, nrec, nh;
+	int nxrcv, nzrcv, ncrcv, nrcv, ntrcv, *nlrcv;
+	float *xrcva, *zrcva;
+	char* rcv_txt;
+	FILE *fp;
+
+	if (!getparint("verbose", &verbose)) verbose = 0;
+
+    /* Calculate Model Dimensions */
+    sub_x1=sub_x0+(nx-1)*dx;
+    sub_z1=sub_z0+(nz-1)*dz;
+
+/* Compute how many receivers are defined and then allocate the receiver arrays */
+
+    /* Receivers on a Circle */
+    if (getparfloat("rrcv",&rrcv)) {
+        if (!getparfloat("dphi",&dphi)) dphi=2.0;
+        ncrcv=NINT(360.0/dphi);
+        if (verbose) vmess("Total number of receivers on a circle: %d",ncrcv);
+    } 
+	else {
+		ncrcv=0;
+	}
+
+    /* Receivers from a File */
+    ntrcv=0;
+    if (!getparstring("rcv_txt",&rcv_txt)) rcv_txt=NULL;
+    if (rcv_txt!=NULL) {
+        /* Open text file */
+        fp=fopen(rcv_txt,"r");
+        assert(fp!=NULL);
+        /* Get number of lines */
+        while (!feof(fp)) if (fgetc(fp)=='\n') ntrcv++;
+        fseek(fp,-1,SEEK_CUR);
+        if (fgetc(fp)!='\n') ntrcv++; /* Checks if last line terminated by /n */
+        if (verbose) vmess("Number of receivers in rcv_txt file: %d",ntrcv);
+        rewind(fp);
+    }
+
+    /* Receiver Array */
+    nxrcv=countparval("xrcva");
+    nzrcv=countparval("zrcva");
+    if (nxrcv!=nzrcv) verr("Number of receivers in array xrcva (%d), zrcva(%d) are not equal",nxrcv,nzrcv);
+    if (verbose&&nxrcv) vmess("Total number of array receivers: %d",nxrcv);
+
+    /* Linear Receiver Arrays */
+	Nx1 = countparval("xrcv1");
+	Nx2 = countparval("xrcv2");
+	Nz1 = countparval("zrcv1");
+	Nz2 = countparval("zrcv2");
+    if (Nx1!=Nx2) verr("Number of receivers starting points in 'xrcv1' (%d) and number of endpoint in 'xrcv2' (%d) are not equal",Nx1,Nx2);
+    if (Nz1!=Nz2) verr("Number of receivers starting points in 'zrcv1' (%d) and number of endpoint in 'zrcv2' (%d) are not equal",Nz1,Nz2);
+    if (Nx1!=Nz2) verr("Number of receivers starting points in 'xrcv1' (%d) and number of endpoint in 'zrcv2' (%d) are not equal",Nx1,Nz2);
+
+    rec->max_nrec=ncrcv+ntrcv+nxrcv;
+
+	/* no receivers are defined use default linear array of receivers on top of model */
+    if (!rec->max_nrec && Nx1==0) Nx1=1; // Default is to use top of model to record data
+
+    if (Nx1) {
+        /* Allocate Start & End Points of Linear Arrays */
+        xrcv1=(float *)malloc(Nx1*sizeof(float));
+        xrcv2=(float *)malloc(Nx1*sizeof(float));
+        zrcv1=(float *)malloc(Nx1*sizeof(float));
+        zrcv2=(float *)malloc(Nx1*sizeof(float));
+        if (!getparfloat("xrcv1",xrcv1)) xrcv1[0]=sub_x0;
+        if (!getparfloat("xrcv2",xrcv2)) xrcv2[0]=sub_x1;
+        if (!getparfloat("zrcv1",zrcv1)) zrcv1[0]=sub_z0;
+        if (!getparfloat("zrcv2",zrcv2)) zrcv2[0]=zrcv1[0];
+
+		/* check if receiver arrays fit into model */
+		for (iarray=0; iarray<Nx1; iarray++) {
+			xrcv1[iarray] = MAX(sub_x0,      xrcv1[iarray]);
+			xrcv1[iarray] = MIN(sub_x0+nx*dx,xrcv1[iarray]);
+			xrcv2[iarray] = MAX(sub_x0,      xrcv2[iarray]);
+			xrcv2[iarray] = MIN(sub_x0+nx*dx,xrcv2[iarray]);
+			
+			zrcv1[iarray] = MAX(sub_z0,      zrcv1[iarray]);
+			zrcv1[iarray] = MIN(sub_z0+nz*dz,zrcv1[iarray]);
+			zrcv2[iarray] = MAX(sub_z0,      zrcv2[iarray]);
+			zrcv2[iarray] = MIN(sub_z0+nz*dz,zrcv2[iarray]);
+		}
+
+        /* Crop to Fit Model */
+/* Max's addtion still have to check if it has the same fucntionality */
+        for (iarray=0;iarray<Nx1;iarray++) {
+            if (xrcv1[iarray]<sub_x0) {
+                if (xrcv2[iarray]<sub_x0) {
+                    verr("Linear array %d outside model bounds",iarray);
+                }
+				else {
+                    vwarn("Cropping element %d of 'xrcv1' (%f) to model bounds (%f)",iarray,xrcv1[iarray],sub_x0);
+                    xrcv1[iarray]=sub_x0;
+                }
+            } 
+			else if (xrcv1[iarray] > sub_x1) {
+                verr("Linear array %d outside model bounds",iarray);
+            }
+            if ( (xrcv2[iarray] < xrcv1[iarray]) ) {
+                verr("Ill defined linear array %d, 'xrcv1' (%f) greater than 'xrcv2' (%f)",iarray,xrcv1[iarray],xrcv2[iarray]);
+            }
+			else if (xrcv2[iarray]>sub_x1) {
+                vwarn("Cropping element %d of 'xrcv2' (%f) to model bounds (%f)",iarray,xrcv2[iarray],sub_x1);
+                xrcv2[iarray]=sub_x1;
+            }
+
+            if (zrcv1[iarray] < sub_z0) {
+                if (zrcv2[iarray] < sub_z0) {
+                    verr("Linear array %d outside model bounds",iarray);
+                }
+				else {
+               		vwarn("Cropping element %d of 'zrcv1' (%f) to model bounds (%f)",iarray,zrcv1[iarray],sub_z0);
+                	zrcv1[iarray]=sub_z0;
+                }
+            }
+			else if (zrcv1[iarray] > sub_z1) {
+                verr("Linear array %d outside model bounds",iarray);
+            }
+            if ( (zrcv2[iarray] < zrcv1[iarray]) ) {
+                verr("Ill defined linear array %d, 'zrcv1' (%f) greater than 'zrcv2' (%f)",iarray,zrcv1[iarray],zrcv2[iarray]);
+            }
+			else if (zrcv2[iarray]>sub_z1) {
+                vwarn("Cropping element %d of 'xrcv2' (%f) to model bounds (%f)",iarray,zrcv2[iarray],sub_z1);
+                zrcv2[iarray]=sub_z1;
+            }
+        }
+
+        /* Get Sampling Rates */
+		Ndx = countparval("dxrcv");
+		Ndz = countparval("dzrcv");
+
+		dxr = (float *)malloc(Nx1*sizeof(float));
+		dzr = (float *)malloc(Nx1*sizeof(float));
+		if(!getparfloat("dxrcv", dxr)) dxr[0]=dx;
+		if(!getparfloat("dzrcv", dzr)) dzr[0]=0.0;
+		if ( (Ndx<=1) && (Ndz==0) ){ /* default values are set */
+			for (i=1; i<Nx1; i++) {
+				dxr[i] = dxr[0];
+				dzr[i] = dzr[0];
+			}
+			Ndx=1;
+			Ndz=1;
+		}
+		else if ( (Ndz==1) && (Ndx==0) ){ /* default values are set */
+			for (i=1; i<Nx1; i++) {
+				dxr[i] = dxr[0];
+				dzr[i] = dzr[0];
+			}
+			Ndz=1;
+			Ndx=1;
+		}
+		else { /* make sure that each array has dzrcv or dxrcv defined for each line or receivers */
+			if (Ndx!=Ndz) {
+				verr("Number of 'dxrcv' (%d) is not equal to number of 'dzrcv' (%d) or 1",Ndx,Ndz);
+			}
+			if (Ndx!=Nx1 && Ndx!=1) {
+				verr("Number of 'dxrcv' (%d) is not equal to number of starting points in 'xrcv1' (%d) or 1",Ndx,Nx1);
+			}
+		}
+
+		/* check consistency of receiver steps */
+        for (iarray=0; iarray<Ndx; iarray++) {
+            if (dxr[iarray]<0) {
+				dxr[i]=dx;
+				vwarn("'dxrcv' element %d (%f) is less than zero, changing it to %f'",iarray,dxr[iarray],dx);
+			}
+        }
+        for (iarray=0;iarray<Ndz;iarray++) {
+            if (dzr[iarray]<0) {
+				dzr[iarray]=dz;
+				vwarn("'dzrcv' element %d (%f) is less than zero, changing it to %f'",iarray,dzr[iarray],dz);
+			}
+        }
+        for (iarray=0;iarray<Ndx;iarray++){
+            if (dxr[iarray]==0 && dzr[iarray]==0) {
+                xrcv2[iarray]=xrcv1[iarray];
+				dxr[iarray]=1.;
+                vwarn("'dxrcv' element %d & 'dzrcv' element 1 are both 0.",iarray+1);
+                vmess("Placing 1 receiver at (%d,%d)",xrcv1[iarray],zrcv1[iarray]);
+            }
+        }
+        for (iarray=0;iarray<Ndx;iarray++){
+            if (xrcv1[iarray]==xrcv2[iarray] && dxr[iarray]!=0) {
+                dxr[iarray]=0.;
+                vwarn("Linear array %d: 'xrcv1'='xrcv2' and 'dxrcv' is not 0. Setting 'dxrcv'=0",iarray+1);
+            }
+        }
+        for (iarray=0;iarray<Ndx;iarray++){
+            if (zrcv1[iarray]==zrcv2[iarray] && dzr[iarray]!=0.){
+                dzr[iarray]=0.;
+                vwarn("Linear array %d: 'zrcv1'='zrcv2' and 'dzrcv' is not 0. Setting 'dzrcv'=0",iarray+1);
+            }
+        }
+
+        /* Calculate Number of Receivers */
+		nrcv = 0;
+        nlrcv=(int *)malloc(Nx1*sizeof(int));
+		for (iarray=0; iarray<Nx1; iarray++) {
+			xrange = (xrcv2[iarray]-xrcv1[iarray]); 
+			zrange = (zrcv2[iarray]-zrcv1[iarray]); 
+			if (dxr[iarray] != 0.0) {
+				nlrcv[iarray] = NINT(fabs(xrange/dxr[iarray]))+1;
+			}
+			else {
+				if (dzr[iarray] == 0) {
+					verr("For receiver array %d: receiver distance dzrcv is not given", iarray);
+				}
+				nlrcv[iarray] = NINT(fabs(zrange/dzr[iarray]))+1;
+			}
+            nrcv+=nlrcv[iarray];
+		}
+
+        /* Calculate Number of Receivers */
+/*
+        nlrcv=(int *)malloc(Nx1*sizeof(int));
+        if (!isnan(*xrcv1)) *nlrcv=MIN(NINT((*xrcv2-*xrcv1)/(*dxr)),NINT((*zrcv2-*zrcv1)/(*dzr)))+1;
+        else *nlrcv=0;
+        nrcv=*nlrcv;
+        if (verbose>4 && nlrcv[iarray]!=0) vmess("Linear receiver array 1 has final bounds: (X: %f -> %f,Z: %f ->
+%f)",xrcv1[iarray],xrcv1[iarray]+nlrcv[iarray]*(*dxr),zrcv1[iarray],zrcv1[iarray]+nlrcv[iarray]*(*dzr));
+        if (Ndx>1) {
+            for (iarray=1;iarray<Nx1;iarray++) {
+                if (!isnan(xrcv1[iarray])) {
+					nlrcv[iarray]=MIN(NINT((xrcv2[iarray]-xrcv1[iarray])/dxr[iarray]),NINT((zrcv2[iarray]-zrcv1[iarray])/dzr[iarray]))+1;
+				}
+                else {
+					nlrcv[iarray]=0;
+				}
+                nrcv+=nlrcv[iarray];
+                if (verbose>4&&nlrcv[iarray]!=0) vmess("Linear receiver array %d has final bounds: (X: %f -> %f,Z: %f ->
+%f)",iarray,xrcv1[iarray],xrcv1[iarray]+nlrcv[iarray]*dxr[iarray],zrcv1[iarray],zrcv1[iarray]+nlrcv[iarray]*dzr[iarray]);
+            }
+        }
+		 else {
+            for (iarray=1;iarray<Nx1;iarray++) {
+                if (!isnan(xrcv1[iarray])) nlrcv[iarray]=MIN(NINT((xrcv2[iarray]-xrcv1[iarray])/(*dxr)),NINT((zrcv2[iarray]-zrcv1[iarray])/(*dzr)))+1;
+                else nlrcv[iarray]=0;
+                nrcv+=nlrcv[iarray];
+                if (verbose>4&&nlrcv[iarray]!=0) vmess("Linear receiver array %d has final bounds: (X: %f -> %f,Z: %f ->
+%f)",iarray,xrcv1[iarray],xrcv1[iarray]+nlrcv[iarray]**dxr,zrcv1[iarray],zrcv1[iarray]+nlrcv[iarray]**dzr);
+            }
+        }
+*/
+        if (verbose) vmess("Total number of linear array receivers: %d",nrcv);
+        if (!nrcv) {
+            free(xrcv1);
+            free(xrcv2);
+            free(zrcv1);
+            free(zrcv2);
+            free(dxr);
+            free(dzr);
+            free(nlrcv);
+        }
+        rec->max_nrec+=nrcv;
+    } 
+	else {
+		nrcv=0;
+	}
+
+/* allocate the receiver arrays */
+
+    /* Total Number of Receivers */
+    if (verbose) vmess("Total number of receivers: %d",rec->max_nrec);
+
+    /* Allocate Arrays */
+    rec->x  = (int *)calloc(rec->max_nrec,sizeof(int));
+    rec->z  = (int *)calloc(rec->max_nrec,sizeof(int));
+    rec->xr = (float *)calloc(rec->max_nrec,sizeof(float));
+    rec->zr = (float *)calloc(rec->max_nrec,sizeof(float));
+
+/* read in the receiver postions */
+
+	nrec=0;
+    /* Receivers on a Circle */
+    if (ncrcv) {
+		if (!getparfloat("oxrcv",&oxrcv)) oxrcv=0.0;
+		if (!getparfloat("ozrcv",&ozrcv)) ozrcv=0.0;
+		if (!getparfloat("arcv",&arcv)) {
+			arcv=rrcv; 
+			for (ix=0; ix<ncrcv; ix++) {
+				rec->xr[ix] = oxrcv-sub_x0+rrcv*cos(((ix*dphi)/360.0)*(2.0*M_PI));
+				rec->zr[ix] = ozrcv-sub_z0+arcv*sin(((ix*dphi)/360.0)*(2.0*M_PI));
+				rec->x[ix] = NINT(rec->xr[ix]/dx);
+				rec->z[ix] = NINT(rec->zr[ix]/dz);
+				//rec->x[ix] = NINT((oxrcv-sub_x0+rrcv*cos(((ix*dphi)/360.0)*(2.0*M_PI)))/dx);
+				//rec->z[ix] = NINT((ozrcv-sub_z0+arcv*sin(((ix*dphi)/360.0)*(2.0*M_PI)))/dz);
+				if (verbose>4) fprintf(stderr,"Receiver Circle: xrcv[%d]=%f zrcv=%f\n", ix, rec->xr[ix]+sub_x0, rec->zr[ix]+sub_z0);
+			}
+		}
+		else { /* an ellipse */
+			/* simple numerical solution to find equidistant points on an ellipse */
+			nh  = (ncrcv)*1000; /* should be fine enough for most configurations */
+			h = 2.0*M_PI/nh;
+			a = MAX(rrcv, arcv);
+			b = MIN(rrcv, arcv);
+			e = sqrt(a*a-b*b)/a;
+			//fprintf(stderr,"a=%f b=%f e=%f\n", a, b, e);
+			circ = 0.0;
+			for (ir=0; ir<nh; ir++) {
+				s = sin(ir*h);
+				circ += sqrt(1.0-e*e*s*s);
+			}
+			circ = a*h*circ;
+			//fprintf(stderr,"circ = %f circle=%f\n", circ, 2.0*M_PI*rrcv);
+			/* define distance between receivers on ellipse */
+			dr = circ/ncrcv;
+			ix = 0;
+			srun = 0.0;
+			if (arcv >= rrcv) phase=0.0;
+			else phase=0.5*M_PI;
+			for (ir=0; ir<nh; ir++) {
+				s = sin(ir*h);
+				srun += sqrt(1.0-e*e*s*s);
+				if (a*h*srun >= ix*dr ) {
+					xr = rrcv*cos(ir*h+phase);
+					zr = arcv*sin(ir*h+phase);
+					rec->xr[ix] = oxrcv-sub_x0+xr;
+					rec->zr[ix] = ozrcv-sub_z0+zr;
+					rec->x[ix] = NINT(rec->xr[ix]/dx);
+					rec->z[ix] = NINT(rec->zr[ix]/dz);
+					if (verbose>4) fprintf(stderr,"Receiver Ellipse: xrcv[%d]=%f zrcv=%f\n", ix, rec->xr[ix]+sub_x0, rec->zr[ix]+sub_z0);
+					ix++;
+				}
+				if (ix == ncrcv) break;
+			}
+		}
+
+		/* check if receivers fit into the model otherwise clip to edges */
+		for (ix=0; ix<ncrcv; ix++) {
+			rec->x[ix] = MIN(nx-1, MAX(rec->x[ix], 0));
+			rec->z[ix] = MIN(nz-1, MAX(rec->z[ix], 0));
+		}
+		nrec += ncrcv;
+	}
+
+    /* Receiver Text File */
+
+    if (ntrcv) {
+		/* Allocate arrays */
+		xrcva = (float *)malloc(nrcv*sizeof(float));
+		zrcva = (float *)malloc(nrcv*sizeof(float));
+		/* Read in receiver coordinates */
+		for (i=0;i<nrcv;i++) {
+			if (fscanf(fp,"%e %e\n",&xrcva[i],&zrcva[i])!=2) vmess("Receiver Text File: Can not parse coordinates on line %d.",i);
+		}
+		/* Close file */
+		fclose(fp);
+		/* Process coordinates */
+		for (ix=0; ix<nrcv; ix++) {
+			rec->xr[nrec+ix] = xrcva[ix]-sub_x0;
+			rec->zr[nrec+ix] = zrcva[ix]-sub_z0;
+			rec->x[nrec+ix] = NINT((xrcva[ix]-sub_x0)/dx);
+			rec->z[nrec+ix] = NINT((zrcva[ix]-sub_z0)/dz);
+			if (verbose>4) vmess("Receiver Text Array: xrcv[%d]=%f zrcv=%f", ix, rec->xr[nrec+ix]+sub_x0, rec->zr[nrec+ix]+sub_z0);
+		}
+		free(xrcva);
+		free(zrcva);
+		nrec += ntrcv;
+	}
+
+    /* Receiver Array */
+	if (nxrcv != 0) {
+		/* receiver array is defined */
+		xrcva = (float *)malloc(nxrcv*sizeof(float));
+		zrcva = (float *)malloc(nxrcv*sizeof(float));
+		getparfloat("xrcva", xrcva);
+		getparfloat("zrcva", zrcva);
+		for (ix=0; ix<nxrcv; ix++) {
+			rec->xr[nrec+ix] = xrcva[ix]-sub_x0;
+			rec->zr[nrec+ix] = zrcva[ix]-sub_z0;
+			rec->x[nrec+ix] = NINT((xrcva[ix]-sub_x0)/dx);
+			rec->z[nrec+ix] = NINT((zrcva[ix]-sub_z0)/dz);
+			if (verbose>4) fprintf(stderr,"Receiver Array: xrcv[%d]=%f zrcv=%f\n", ix, rec->xr[nrec+ix]+sub_x0, rec->zr[nrec+ix]+sub_z0);
+		}
+		free(xrcva);
+		free(zrcva);
+		nrec += nxrcv;
+	}
+
+    /* Linear Receiver Arrays */
+    if (nrcv!=0) {
+		xrcv1 = (float *)malloc(Nx1*sizeof(float));
+		xrcv2 = (float *)malloc(Nx1*sizeof(float));
+		zrcv1 = (float *)malloc(Nx1*sizeof(float));
+		zrcv2 = (float *)malloc(Nx1*sizeof(float));
+		
+		if(!getparfloat("xrcv1", xrcv1)) xrcv1[0]=sub_x0;
+		if(!getparfloat("xrcv2", xrcv2)) xrcv2[0]=(nx-1)*dx+sub_x0;
+		if(!getparfloat("zrcv1", zrcv1)) zrcv1[0]=sub_z0;
+		if(!getparfloat("zrcv2", zrcv2)) zrcv2[0]=zrcv1[0];		
+		
+		Ndx = countparval("dxrcv");
+		Ndz = countparval("dzrcv");
+
+		dxr = (float *)malloc(Nx1*sizeof(float));
+		dzr = (float *)malloc(Nx1*sizeof(float));
+		if(!getparfloat("dxrcv", dxr)) dxr[0]=dx;
+		if(!getparfloat("dzrcv", dzr)) dzr[0]=0.0;
+		if ( (Ndx<=1) && (Ndz==0) ){ /* default values are set */
+			for (i=1; i<Nx1; i++) {
+				dxr[i] = dxr[0];
+				dzr[i] = dzr[0];
+			}
+			Ndx=1;
+		}
+		else if ( (Ndz==1) && (Ndx==0) ){ /* default values are set */
+			for (i=1; i<Nx1; i++) {
+				dxr[i] = dxr[0];
+				dzr[i] = dzr[0];
+			}
+			Ndz=1;
+		}
+		else { /* make sure that each array has dzrcv or dxrcv defined for each line or receivers */
+			if (Ndx>1) assert(Ndx==Nx1);
+			if (Ndz>1) assert(Ndz==Nx1);
+		}
+		
+/*
+		if ( (Ndx!=0) && (Ndz!=0) ) {
+			vwarn("Both dzrcv and dxrcv are set: dxrcv value is used");
+			Ndz=0;
+			for (i=0; i<Nx1; i++) dzr[i] = 0.0;
+		}
+*/
+		/* check if receiver arrays fit into model */
+		for (iarray=0; iarray<Nx1; iarray++) {
+			xrcv1[iarray] = MAX(sub_x0,      xrcv1[iarray]);
+			xrcv1[iarray] = MIN(sub_x0+nx*dx,xrcv1[iarray]);
+			xrcv2[iarray] = MAX(sub_x0,      xrcv2[iarray]);
+			xrcv2[iarray] = MIN(sub_x0+nx*dx,xrcv2[iarray]);
+			
+			zrcv1[iarray] = MAX(sub_z0,      zrcv1[iarray]);
+			zrcv1[iarray] = MIN(sub_z0+nz*dz,zrcv1[iarray]);
+			zrcv2[iarray] = MAX(sub_z0,      zrcv2[iarray]);
+			zrcv2[iarray] = MIN(sub_z0+nz*dz,zrcv2[iarray]);
+		}
+
+		/* calculate receiver array and store into rec->x,z */
+
+		for (iarray=0; iarray<Nx1; iarray++) {
+			xrange = (xrcv2[iarray]-xrcv1[iarray]); 
+			zrange = (zrcv2[iarray]-zrcv1[iarray]); 
+			if (dxr[iarray] != 0.0) {
+				nrcv = nlrcv[iarray];
+				dxrcv=dxr[iarray];
+				dzrcv = zrange/(nrcv-1);
+				if (dzrcv != dzr[iarray]) {
+					vwarn("For receiver array %d: calculated dzrcv=%f given=%f", iarray, dzrcv, dzr[iarray]);
+					vwarn("The calculated receiver distance %f is used", dzrcv);
+				}
+			}
+			else {
+				if (dzr[iarray] == 0) {
+					verr("For receiver array %d: receiver distance dzrcv is not given", iarray);
+				}
+				nrcv = nlrcv[iarray];
+				dxrcv = xrange/(nrcv-1);
+				dzrcv = dzr[iarray];
+				if (dxrcv != dxr[iarray]) {
+					vwarn("For receiver array %d: calculated dxrcv=%f given=%f", iarray, dxrcv, dxr[iarray]);
+					vwarn("The calculated receiver distance %f is used", dxrcv);
+				}
+			}
+
+			// calculate coordinates
+			for (ir=0; ir<nrcv; ir++) {
+				rec->xr[nrec]=xrcv1[iarray]-sub_x0+ir*dxrcv;
+				rec->zr[nrec]=zrcv1[iarray]-sub_z0+ir*dzrcv;
+
+				rec->x[nrec]=NINT((rec->xr[nrec])/dx);
+				rec->z[nrec]=NINT((rec->zr[nrec])/dz);
+				nrec++;
+			}
+		}
+		free(xrcv1);
+		free(xrcv2);
+		free(zrcv1);
+		free(zrcv2);
+		free(dxr);
+		free(dzr);
+        free(nlrcv);
+	}
+
+    rec->n=rec->max_nrec;
+	return 0;
+}
diff --git a/raytime3d/segy.h b/raytime3d/segy.h
new file mode 100644
index 0000000000000000000000000000000000000000..d0a0d769d1548115b04396076b4a15d5be0ee687
--- /dev/null
+++ b/raytime3d/segy.h
@@ -0,0 +1,849 @@
+/* Copyright (c) Colorado School of Mines, 2011.*/
+/* All rights reserved.                       */
+
+/* segy.h - include file for SEGY traces
+ *
+ * declarations for:
+ *	typedef struct {} segy - the trace identification header
+ *	typedef struct {} bhed - binary header
+ *
+ * Note:
+ *	If header words are added, run the makefile in this directory
+ *	to recreate hdr.h.
+ *
+ * Reference:
+ *	K. M. Barry, D. A. Cavers and C. W. Kneale, "Special Report:
+ *		Recommended Standards for Digital Tape Formats",
+ *		Geophysics, vol. 40, no. 2 (April 1975), P. 344-352.
+ *	
+ * $Author: john $
+ * $Source: /usr/local/cwp/src/su/include/RCS/segy.h,v $
+ * $Revision: 1.33 $ ; $Date: 2011/11/11 23:56:14 $
+ */ 
+
+#include <limits.h>
+#include "par.h"
+
+#ifndef SEGY_H
+#define SEGY_H
+#define TRCBYTES		240
+
+#define SU_NFLTS	32767	/* Arbitrary limit on data array size	*/
+
+
+/* TYPEDEFS */
+typedef struct {	/* segy - trace identification header */
+
+	int tracl;	/* Trace sequence number within line
+			   --numbers continue to increase if the
+			   same line continues across multiple
+			   SEG Y files.
+			   byte# 1-4
+			 */
+
+	int tracr;	/* Trace sequence number within SEG Y file
+			   ---each file starts with trace sequence
+			   one
+			   byte# 5-8
+			 */
+
+	int fldr;	/* Original field record number
+			   byte# 9-12 
+			*/
+
+	int tracf;	/* Trace number within original field record 
+			   byte# 13-16
+			*/
+
+	int ep;		/* energy source point number
+			   ---Used when more than one record occurs
+			   at the same effective surface location.
+			   byte# 17-20
+			 */
+
+	int cdp;	/* Ensemble number (i.e. CDP, CMP, CRP,...) 
+			   byte# 21-24
+			*/
+
+	int cdpt;	/* trace number within the ensemble
+			   ---each ensemble starts with trace number one.
+			   byte# 25-28
+			 */
+
+	short trid;	/* trace identification code:
+			-1 = Other
+		         0 = Unknown
+			 1 = Seismic data
+			 2 = Dead
+			 3 = Dummy
+			 4 = Time break
+			 5 = Uphole
+			 6 = Sweep
+			 7 = Timing
+			 8 = Water break
+			 9 = Near-field gun signature
+			10 = Far-field gun signature
+			11 = Seismic pressure sensor
+			12 = Multicomponent seismic sensor
+				- Vertical component
+			13 = Multicomponent seismic sensor
+				- Cross-line component 
+			14 = Multicomponent seismic sensor
+				- in-line component 
+			15 = Rotated multicomponent seismic sensor
+				- Vertical component
+			16 = Rotated multicomponent seismic sensor
+				- Transverse component
+			17 = Rotated multicomponent seismic sensor
+				- Radial component
+			18 = Vibrator reaction mass
+			19 = Vibrator baseplate
+			20 = Vibrator estimated ground force
+			21 = Vibrator reference
+			22 = Time-velocity pairs
+			23 ... N = optional use 
+				(maximum N = 32,767)
+
+			Following are CWP id flags:
+
+			109 = autocorrelation
+			110 = Fourier transformed - no packing
+			     xr[0],xi[0], ..., xr[N-1],xi[N-1]
+			111 = Fourier transformed - unpacked Nyquist
+			     xr[0],xi[0],...,xr[N/2],xi[N/2]
+			112 = Fourier transformed - packed Nyquist
+	 		     even N:
+			     xr[0],xr[N/2],xr[1],xi[1], ...,
+				xr[N/2 -1],xi[N/2 -1]
+				(note the exceptional second entry)
+			     odd N:
+			     xr[0],xr[(N-1)/2],xr[1],xi[1], ...,
+				xr[(N-1)/2 -1],xi[(N-1)/2 -1],xi[(N-1)/2]
+				(note the exceptional second & last entries)
+			113 = Complex signal in the time domain
+			     xr[0],xi[0], ..., xr[N-1],xi[N-1]
+			114 = Fourier transformed - amplitude/phase
+			     a[0],p[0], ..., a[N-1],p[N-1]
+			115 = Complex time signal - amplitude/phase
+			     a[0],p[0], ..., a[N-1],p[N-1]
+			116 = Real part of complex trace from 0 to Nyquist
+			117 = Imag part of complex trace from 0 to Nyquist
+			118 = Amplitude of complex trace from 0 to Nyquist
+			119 = Phase of complex trace from 0 to Nyquist
+			121 = Wavenumber time domain (k-t)
+			122 = Wavenumber frequency (k-omega)
+			123 = Envelope of the complex time trace
+			124 = Phase of the complex time trace
+			125 = Frequency of the complex time trace
+			130 = Depth-Range (z-x) traces
+			201 = Seismic data packed to bytes (by supack1)
+			202 = Seismic data packed to 2 bytes (by supack2)
+			   byte# 29-30
+			*/
+
+	short nvs;	/* Number of vertically summed traces yielding
+			   this trace. (1 is one trace, 
+			   2 is two summed traces, etc.)
+			   byte# 31-32
+			 */
+
+	short nhs;	/* Number of horizontally summed traces yielding
+			   this trace. (1 is one trace
+			   2 is two summed traces, etc.)
+			   byte# 33-34
+			 */
+
+	short duse;	/* Data use:
+				1 = Production
+				2 = Test
+			   byte# 35-36
+			 */
+
+	int offset;	/* Distance from the center of the source point 
+			   to the center of the receiver group 
+			   (negative if opposite to direction in which 
+			   the line was shot).
+			   byte# 37-40
+			 */
+
+	int gelev;	/* Receiver group elevation from sea level
+			   (all elevations above the Vertical datum are 
+			   positive and below are negative).
+			   byte# 41-44
+			 */
+
+	int selev;	/* Surface elevation at source.
+			   byte# 45-48
+			 */
+
+	int sdepth;	/* Source depth below surface (a positive number).
+			   byte# 49-52
+			 */
+
+	int gdel;	/* Datum elevation at receiver group.
+			   byte# 53-56
+			*/
+
+	int sdel;	/* Datum elevation at source.
+			   byte# 57-60
+			*/
+
+	int swdep;	/* Water depth at source.
+			   byte# 61-64
+			*/
+
+	int gwdep;	/* Water depth at receiver group.
+			   byte# 65-68
+			*/
+
+	short scalel;	/* Scalar to be applied to the previous 7 entries
+			   to give the real value. 
+			   Scalar = 1, +10, +100, +1000, +10000.
+			   If positive, scalar is used as a multiplier,
+			   if negative, scalar is used as a divisor.
+			   byte# 69-70
+			 */
+
+	short scalco;	/* Scalar to be applied to the next 4 entries
+			   to give the real value. 
+			   Scalar = 1, +10, +100, +1000, +10000.
+			   If positive, scalar is used as a multiplier,
+			   if negative, scalar is used as a divisor.
+			   byte# 71-72
+			 */
+
+	int  sx;	/* Source coordinate - X 
+			   byte# 73-76
+			*/
+
+	int  sy;	/* Source coordinate - Y 
+			   byte# 77-80
+			*/
+
+	int  gx;	/* Group coordinate - X 
+			   byte# 81-84
+			*/
+
+	int  gy;	/* Group coordinate - Y 
+			   byte# 85-88
+			*/
+
+	short counit;	/* Coordinate units: (for previous 4 entries and
+				for the 7 entries before scalel)
+			   1 = Length (meters or feet)
+			   2 = Seconds of arc
+			   3 = Decimal degrees
+			   4 = Degrees, minutes, seconds (DMS)
+
+			In case 2, the X values are longitude and 
+			the Y values are latitude, a positive value designates
+			the number of seconds east of Greenwich
+				or north of the equator
+
+			In case 4, to encode +-DDDMMSS
+			counit = +-DDD*10^4 + MM*10^2 + SS,
+			with scalco = 1. To encode +-DDDMMSS.ss
+			counit = +-DDD*10^6 + MM*10^4 + SS*10^2 
+			with scalco = -100.
+			   byte# 89-90
+			*/
+
+	short wevel;	/* Weathering velocity. 
+			   byte# 91-92
+			*/
+
+	short swevel;	/* Subweathering velocity. 
+			   byte# 93-94
+			*/
+
+	short sut;	/* Uphole time at source in milliseconds. 
+			   byte# 95-96
+			*/
+
+	short gut;	/* Uphole time at receiver group in milliseconds. 
+			   byte# 97-98
+			*/
+
+	short sstat;	/* Source static correction in milliseconds. 
+			   byte# 99-100
+			*/
+
+	short gstat;	/* Group static correction  in milliseconds.
+			   byte# 101-102
+			*/
+
+	short tstat;	/* Total static applied  in milliseconds.
+			   (Zero if no static has been applied.)
+			   byte# 103-104
+			*/
+
+	short laga;	/* Lag time A, time in ms between end of 240-
+			   byte trace identification header and time
+			   break, positive if time break occurs after
+			   end of header, time break is defined as
+			   the initiation pulse which maybe recorded
+			   on an auxiliary trace or as otherwise
+			   specified by the recording system 
+			   byte# 105-106
+			*/
+
+	short lagb;	/* lag time B, time in ms between the time break
+			   and the initiation time of the energy source,
+			   may be positive or negative 
+			   byte# 107-108
+			*/
+
+	short delrt;	/* delay recording time, time in ms between
+			   initiation time of energy source and time
+			   when recording of data samples begins
+			   (for deep water work if recording does not
+			   start at zero time) 
+			   byte# 109-110
+			*/
+
+	short muts;	/* mute time--start 
+			   byte# 111-112
+			*/
+
+	short mute;	/* mute time--end 
+			   byte# 113-114
+			*/
+
+	unsigned short ns;	/* number of samples in this trace 
+			   byte# 115-116
+			*/
+
+	unsigned short dt;	/* sample interval; in micro-seconds
+			   byte# 117-118
+			*/
+
+	short gain;	/* gain type of field instruments code:
+				1 = fixed
+				2 = binary
+				3 = floating point
+				4 ---- N = optional use 
+			   byte# 119-120
+			*/
+
+	short igc;	/* instrument gain constant 
+			   byte# 121-122
+			*/
+
+	short igi;	/* instrument early or initial gain 
+			   byte# 123-124
+			*/
+
+	short corr;	/* correlated:
+				1 = no
+				2 = yes 
+			   byte# 125-126
+			*/
+
+	short sfs;	/* sweep frequency at start 
+			   byte# 127-128
+			*/
+
+	short sfe;	/* sweep frequency at end
+			   byte# 129-130
+			*/
+
+	short slen;	/* sweep length in ms 
+			   byte# 131-132
+			*/
+
+	short styp;	/* sweep type code:
+				1 = linear
+				2 = cos-squared
+				3 = other
+			   byte# 133-134
+			*/
+
+	short stas;	/* sweep trace length at start in ms
+			   byte# 135-136
+			*/
+
+	short stae;	/* sweep trace length at end in ms 
+			   byte# 137-138
+			*/
+
+	short tatyp;	/* taper type: 1=linear, 2=cos^2, 3=other 
+			   byte# 139-140
+			*/
+
+	short afilf;	/* alias filter frequency if used 
+			   byte# 141-142
+			*/
+
+	short afils;	/* alias filter slope
+			   byte# 143-144
+			*/
+
+	short nofilf;	/* notch filter frequency if used
+			   byte# 145-146
+			*/
+
+	short nofils;	/* notch filter slope
+			   byte# 147-148
+			*/
+
+	short lcf;	/* low cut frequency if used
+			   byte# 149-150
+			*/
+
+	short hcf;	/* high cut frequncy if used
+			   byte# 151-152
+			*/
+
+	short lcs;	/* low cut slope
+			   byte# 153-154
+			*/
+
+	short hcs;	/* high cut slope
+			   byte# 155-156
+			*/
+
+	short year;	/* year data recorded
+			   byte# 157-158
+			*/
+
+	short day;	/* day of year
+			   byte# 159-160
+			*/
+
+	short hour;	/* hour of day (24 hour clock) 
+			   byte# 161-162
+			*/
+
+	short minute;	/* minute of hour
+			   byte# 163-164
+			*/
+
+	short sec;	/* second of minute
+			   byte# 165-166
+			*/
+
+	short timbas;	/* time basis code:
+				1 = local
+				2 = GMT
+				3 = other
+			   byte# 167-168
+			*/
+
+	short trwf;	/* trace weighting factor, defined as 1/2^N
+			   volts for the least sigificant bit
+			   byte# 169-170
+			*/
+
+	short grnors;	/* geophone group number of roll switch
+			   position one
+			   byte# 171-172
+			*/
+
+	short grnofr;	/* geophone group number of trace one within
+			   original field record
+			   byte# 173-174
+			*/
+
+	short grnlof;	/* geophone group number of last trace within
+			   original field record
+			   byte# 175-176
+			*/
+
+	short gaps;	/* gap size (total number of groups dropped)
+			   byte# 177-178
+			*/
+
+	short otrav;	/* overtravel taper code:
+				1 = down (or behind)
+				2 = up (or ahead)
+			   byte# 179-180
+			*/
+
+#ifdef SLTSU_SEGY_H  /* begin Unocal SU segy.h differences */
+
+
+	/* cwp local assignments */
+	float d1;	/* sample spacing for non-seismic data
+			   byte# 181-184
+			*/
+
+	float f1;	/* first sample location for non-seismic data
+			   byte# 185-188
+			*/
+
+	float d2;	/* sample spacing between traces
+			   byte# 189-192
+			*/
+
+	float f2;	/* first trace location
+			   byte# 193-196
+			*/
+
+	float ungpow;	/* negative of power used for dynamic
+			   range compression
+			   byte# 197-200
+			*/
+
+	float unscale;	/* reciprocal of scaling factor to normalize
+			   range
+			   byte# 201-204
+			*/
+
+	short mark;	/* mark selected traces
+			   byte# 205-206
+			*/
+
+	/* SLTSU local assignments */ 
+	short mutb;	/* mute time at bottom (start time)
+			   bottom mute ends at last sample
+			   byte# 207-208
+			*/
+	float dz;	/* depth sampling interval in (m or ft)
+			if =0.0, input are time samples
+			   byte# 209-212
+			*/
+
+	float fz;	/* depth of first sample in (m or ft)
+			   byte# 213-116
+			*/
+
+	short n2;	/* number of traces per cdp or per shot
+			   byte# 217-218
+			*/
+
+        short shortpad; /* alignment padding
+			   byte# 219-220
+			*/
+
+	int ntr; 	/* number of traces
+			   byte# 221-224
+			*/
+
+	/* SLTSU local assignments end */ 
+
+	short unass[8];	/* unassigned
+			   byte# 225-240
+			*/
+
+#else
+
+	/* cwp local assignments */
+	float d1;	/* sample spacing for non-seismic data
+			   byte# 181-184
+			*/
+
+	float f1;	/* first sample location for non-seismic data
+			   byte# 185-188
+			*/
+
+	float d2;	/* sample spacing between traces
+			   byte# 189-192
+			*/
+
+	float f2;	/* first trace location
+			   byte# 193-196
+			*/
+
+	float ungpow;	/* negative of power used for dynamic
+			   range compression
+			   byte# 197-200
+			*/
+
+	float unscale;	/* reciprocal of scaling factor to normalize
+			   range
+			   byte# 201-204
+			*/
+
+	int ntr; 	/* number of traces
+			   byte# 205-208
+			*/
+
+	short mark;	/* mark selected traces
+			   byte# 209-210
+			*/
+
+        short shortpad; /* alignment padding
+			   byte# 211-212
+			*/
+
+
+	short unass[14];	/* unassigned--NOTE: last entry causes 
+			   a break in the word alignment, if we REALLY
+			   want to maintain 240 bytes, the following
+			   entry should be an odd number of short/UINT2
+			   OR do the insertion above the "mark" keyword
+			   entry
+			   byte# 213-240
+			*/
+#endif
+
+} segy;
+
+
+typedef struct {	/* bhed - binary header */
+
+	int jobid;	/* job identification number */
+
+	int lino;	/* line number (only one line per reel) */
+
+	int reno;	/* reel number */
+
+	short ntrpr;	/* number of data traces per record */
+
+        short nart;	/* number of auxiliary traces per record */
+
+	unsigned short hdt; /* sample interval in micro secs for this reel */
+
+	unsigned short dto; /* same for original field recording */
+
+	unsigned short hns; /* number of samples per trace for this reel */
+
+	unsigned short nso; /* same for original field recording */
+
+	short format;	/* data sample format code:
+				1 = floating point, 4 byte (32 bits)
+				2 = fixed point, 4 byte (32 bits)
+				3 = fixed point, 2 byte (16 bits)
+				4 = fixed point w/gain code, 4 byte (32 bits)
+				5 = IEEE floating point, 4 byte (32 bits)
+				8 = two's complement integer, 1 byte (8 bits)
+			*/
+
+	short fold;	/* CDP fold expected per CDP ensemble */
+
+	short tsort;	/* trace sorting code: 
+				1 = as recorded (no sorting)
+				2 = CDP ensemble
+				3 = single fold continuous profile
+				4 = horizontally stacked */
+
+	short vscode;	/* vertical sum code:
+				1 = no sum
+				2 = two sum ...
+				N = N sum (N = 32,767) */
+
+	short hsfs;	/* sweep frequency at start */
+
+	short hsfe;	/* sweep frequency at end */
+
+	short hslen;	/* sweep length (ms) */
+
+	short hstyp;	/* sweep type code:
+				1 = linear
+				2 = parabolic
+				3 = exponential
+				4 = other */
+
+	short schn;	/* trace number of sweep channel */
+
+	short hstas;	/* sweep trace taper length at start if
+			   tapered (the taper starts at zero time
+			   and is effective for this length) */
+
+	short hstae;	/* sweep trace taper length at end (the ending
+			   taper starts at sweep length minus the taper
+			   length at end) */
+
+	short htatyp;	/* sweep trace taper type code:
+				1 = linear
+				2 = cos-squared
+				3 = other */
+
+	short hcorr;	/* correlated data traces code:
+				1 = no
+				2 = yes */
+
+	short bgrcv;	/* binary gain recovered code:
+				1 = yes
+				2 = no */
+
+	short rcvm;	/* amplitude recovery method code:
+				1 = none
+				2 = spherical divergence
+				3 = AGC
+				4 = other */
+
+	short mfeet;	/* measurement system code:
+				1 = meters
+				2 = feet */
+
+	short polyt;	/* impulse signal polarity code:
+				1 = increase in pressure or upward
+				    geophone case movement gives
+				    negative number on tape
+				2 = increase in pressure or upward
+				    geophone case movement gives
+				    positive number on tape */
+
+	short vpol;	/* vibratory polarity code:
+				code	seismic signal lags pilot by
+				1	337.5 to  22.5 degrees
+				2	 22.5 to  67.5 degrees
+				3	 67.5 to 112.5 degrees
+				4	112.5 to 157.5 degrees
+				5	157.5 to 202.5 degrees
+				6	202.5 to 247.5 degrees
+				7	247.5 to 292.5 degrees
+				8	293.5 to 337.5 degrees */
+
+	short hunass[170];	/* unassigned */
+
+} bhed;
+
+/* DEFINES */
+#define gettr(x)	fgettr(stdin, (x))
+#define vgettr(x)	fvgettr(stdin, (x))
+#define puttr(x)	fputtr(stdout, (x))
+#define vputtr(x)	fvputtr(stdout, (x))
+#define gettra(x, y)    fgettra(stdin, (x), (y))
+
+
+/* TOTHER represents "other"					*/
+#define		TOTHER		-1	
+/* TUNK represents time traces of an unknown type		*/
+#define		TUNK		0
+/* TREAL represents real time traces 				*/
+#define		TREAL		1
+/* TDEAD represents dead time traces 				*/
+#define		TDEAD		2
+/* TDUMMY represents dummy time traces 				*/
+#define		TDUMMY		3
+/* TBREAK represents time break traces 				*/
+#define		TBREAK		4
+/* UPHOLE represents uphole traces 				*/
+#define		UPHOLE		5
+/* SWEEP represents sweep traces 				*/
+#define		SWEEP		6
+/* TIMING represents timing traces 				*/
+#define		TIMING		7
+/* WBREAK represents timing traces 				*/
+#define		WBREAK		8
+/* NFGUNSIG represents near field gun signature 		*/
+#define		NFGUNSIG	9	
+/* FFGUNSIG represents far field gun signature	 		*/
+#define		FFGUNSIG	10
+/* SPSENSOR represents seismic pressure sensor	 		*/
+#define		SPSENSOR	11
+/* TVERT represents multicomponent seismic sensor 
+	- vertical component */
+#define		TVERT		12
+/* TXLIN represents multicomponent seismic sensor 
+	- cross-line component */
+#define		TXLIN		13
+/* TINLIN represents multicomponent seismic sensor 
+	- in-line component */
+#define		TINLIN	14
+/* ROTVERT represents rotated multicomponent seismic sensor 
+	- vertical component */
+#define		ROTVERT		15
+/* TTRANS represents rotated multicomponent seismic sensor 
+	- transverse component */
+#define		TTRANS		16
+/* TRADIAL represents rotated multicomponent seismic sensor 
+	- radial component */
+#define		TRADIAL		17
+/* VRMASS represents vibrator reaction mass */
+#define		VRMASS		18
+/* VBASS represents vibrator baseplate */
+#define		VBASS		19
+/* VEGF represents vibrator estimated ground force */
+#define		VEGF		20
+/* VREF represents vibrator reference */
+#define		VREF		21
+
+/*** CWP trid assignments ***/
+/* ACOR represents autocorrelation  */
+#define		ACOR		109
+/* FCMPLX represents fourier transformed - no packing 
+   xr[0],xi[0], ..., xr[N-1],xi[N-1] */
+#define		FCMPLX		110
+/* FUNPACKNYQ represents fourier transformed - unpacked Nyquist
+   xr[0],xi[0],...,xr[N/2],xi[N/2] */
+#define		FUNPACKNYQ	111
+/* FTPACK represents fourier transformed - packed Nyquist
+   even N: xr[0],xr[N/2],xr[1],xi[1], ...,
+	xr[N/2 -1],xi[N/2 -1]
+   (note the exceptional second entry)
+    odd N:
+     xr[0],xr[(N-1)/2],xr[1],xi[1], ...,
+     xr[(N-1)/2 -1],xi[(N-1)/2 -1],xi[(N-1)/2]
+   (note the exceptional second & last entries)
+*/
+#define		FTPACK		112
+/* TCMPLX represents complex time traces 			*/
+#define		TCMPLX		113
+/* FAMPH represents freq domain data in amplitude/phase form	*/
+#define		FAMPH		114
+/* TAMPH represents time domain data in amplitude/phase form	*/
+#define		TAMPH		115
+/* REALPART represents the real part of a trace to Nyquist	*/
+#define		REALPART	116
+/* IMAGPART represents the real part of a trace to Nyquist	*/
+#define		IMAGPART	117
+/* AMPLITUDE represents the amplitude of a trace to Nyquist	*/
+#define		AMPLITUDE	118
+/* PHASE represents the phase of a trace to Nyquist		*/
+#define		PHASE		119
+/* KT represents wavenumber-time domain data 			*/
+#define		KT		121
+/* KOMEGA represents wavenumber-frequency domain data		*/
+#define		KOMEGA		122
+/* ENVELOPE represents the envelope of the complex time trace	*/
+#define		ENVELOPE	123
+/* INSTPHASE represents the phase of the complex time trace	*/
+#define		INSTPHASE	124
+/* INSTFREQ represents the frequency of the complex time trace	*/
+#define		INSTFREQ	125
+/* DEPTH represents traces in depth-range (z-x)			*/
+#define		TRID_DEPTH	130
+/* 3C data...  v,h1,h2=(11,12,13)+32 so a bitmask will convert  */
+/* between conventions */
+/* CHARPACK represents byte packed seismic data from supack1	*/
+#define		CHARPACK	201
+/* SHORTPACK represents 2 byte packed seismic data from supack2	*/
+#define		SHORTPACK	202
+
+
+#define ISSEISMIC(id) (( (id)==TUNK || (id)==TREAL || (id)==TDEAD || (id)==TDUMMY || (id)==TBREAK || (id)==UPHOLE || (id)==SWEEP || (id)==TIMING || (id)==WBREAK || (id)==NFGUNSIG || (id)==FFGUNSIG || (id)==SPSENSOR || (id)==TVERT || (id)==TXLIN || (id)==TINLIN || (id)==ROTVERT || (id)==TTRANS || (id)==TRADIAL || (id)==ACOR ) ? cwp_true : cwp_false ) 
+
+/* FUNCTION PROTOTYPES */
+#ifdef __cplusplus /* if C++, specify external linkage to C functions */
+extern "C" {
+#endif
+
+/* get trace and put trace */
+int fgettr(FILE *fp, segy *tp);
+int fvgettr(FILE *fp, segy *tp);
+void fputtr(FILE *fp, segy *tp);
+void fvputtr(FILE *fp, segy *tp);
+int fgettra(FILE *fp, segy *tp, int itr);
+
+/* get gather and put gather */
+segy **fget_gather(FILE *fp, cwp_String *key,cwp_String *type,Value *n_val,
+                        int *nt,int *ntr, float *dt,int *first);
+segy **get_gather(cwp_String *key, cwp_String *type, Value *n_val,
+			int *nt, int *ntr, float *dt, int *first);
+segy **fput_gather(FILE *fp, segy **rec,int *nt, int *ntr);
+segy **put_gather(segy **rec,int *nt, int *ntr);
+
+/* hdrpkge */
+void gethval(const segy *tp, int index, Value *valp);
+void puthval(segy *tp, int index, Value *valp);
+void getbhval(const bhed *bhp, int index, Value *valp);
+void putbhval(bhed *bhp, int index, Value *valp);
+void gethdval(const segy *tp, char *key, Value *valp);
+void puthdval(segy *tp, char *key, Value *valp);
+char *hdtype(const char *key);
+char *getkey(const int index);
+int getindex(const char *key);
+void swaphval(segy *tp, int index);
+void swapbhval(bhed *bhp, int index);
+void printheader(const segy *tp);
+
+void tabplot(segy *tp, int itmin, int itmax);
+
+#ifdef __cplusplus /* if C++, end external linkage specification */
+}
+#endif
+
+#endif
diff --git a/raytime3d/src3d.c b/raytime3d/src3d.c
new file mode 100644
index 0000000000000000000000000000000000000000..1dadfa5746b00a8bb5504f16de26188c06da5c97
--- /dev/null
+++ b/raytime3d/src3d.c
@@ -0,0 +1,208 @@
+#include <cwp.h>
+#include <su.h>
+#include <fcntl.h>
+
+#define t0(x,y,z)   time0[nxy*(z) + nx*(y) + (x)]
+#define s0(x,y,z)   slow0[nxy*(z) + nx*(y) + (x)]
+#define	SQR(x)	((x) * (x))
+#define	DIST(x,y,z,x1,y1,z1)	sqrt(SQR(x-(x1))+SQR(y-(y1)) + SQR(z-(z1)))
+
+/* definitions from saerrpkge.c */
+extern void saerr(char *fmt, ...);
+extern void sawarn(char *fmt, ...);
+extern void samess(char *fmt, ...);
+
+void src3d(float *time0, float *slow0, int nz, int nx, int ny, float h, float ox, float oy, float oz, int *pxs, int *pys, int *pzs, int *cube)
+{
+	int
+		srctype=1,	/* if 1, source is a point;
+						2, source is on the walls of the data volume;
+						3, source on wall, time field known; */
+		srcwall,	/* if 1, source on x=0 wall, if 2, on x=nx-1 wall
+						if 3, source on y=0 wall, if 4, on y=ny-1 wall
+						if 5, source on z=0 wall, if 6, on z=nz-1 wall */
+		xs,			/* shot x position (in grid points) */
+		ys,			/* shot y position */
+		zs,			/* shot depth */
+		xx, yy, zz,	/* Used to loop around xs, ys, zs coordinates	*/
+		ii, i, j, k, 
+		wfint, ofint,
+		nxy, nyz, nxz, nxyz, nwall,
+		NCUBE=2;
+	float
+		fxs,	/* shot position in X (in real units)*/
+		fys,	/* shot position in Y (in real units)*/
+		fzs,	/* shot position in Z (in real units)*/
+		*wall,
+		/* maximum offset (real units) to compute */
+		/* used in linear velocity gradient cube source */
+		rx, ry, rz, dvz, dv, v0,
+		rzc, rxyc, rz1, rxy1, rho, theta1, theta2,
+		xsrc1, ysrc1, zsrc1;
+	char
+		*oldtfile,	/* file through which old travel times are input */
+		*wallfile;   /* file containing input wall values of traveltimes */
+
+
+	if(!getparint("NCUBE",&NCUBE)) NCUBE=2;
+
+	if(!getparint("srctype",&srctype)) srctype=1;
+	if(srctype==1) {
+		if(!getparfloat("xsrc1",&xsrc1)) saerr("xsrc1 not given");
+		if(!getparfloat("ysrc1",&ysrc1)) saerr("ysrc1 not given");
+		if(!getparfloat("zsrc1",&zsrc1)) saerr("zsrc1 not given");
+		fxs = (xsrc1-ox)/h;
+		fys = (ysrc1-oy)/h;
+		fzs = (zsrc1-oz)/h;
+		xs = (int)(fxs + 0.5);
+		ys = (int)(fys + 0.5);
+		zs = (int)(fzs + 0.5);
+		if(xs<2 || ys<2 || zs<2 || xs>nx-3 || ys>ny-3 || zs>nz-3){
+			sawarn("Source near an edge, beware of traveltime errors");
+			sawarn("for raypaths that travel parallel to edge ");
+			sawarn("while wavefronts are strongly curved, (JV, 8/17/88)\n");
+		}
+		*pxs = xs; *pys = ys, *pzs = zs, *cube = NCUBE;
+	}
+	else if (srctype==2)  {
+		if (!getparint("srcwall",&srcwall)) saerr("srcwall not given");
+		if (!getparstring("wallfile",&wallfile)) saerr("wallfile not given");
+		if((wfint=open(wallfile,O_RDONLY,0664))<=1) {
+			fprintf(stderr,"cannot open %s\n",wallfile);
+			exit(-1);
+		}
+	}
+	else if (srctype==3)  {
+		if (!getparint("srcwall",&srcwall)) saerr("srcwall not given");
+		if (!getparstring("oldtfile",&oldtfile)) saerr("oldtfile not given");
+		if((ofint=open(oldtfile,O_RDONLY,0664))<=1) {
+			fprintf(stderr,"cannot open %s\n",oldtfile);
+			exit(-1);
+		}
+	}
+	else  {
+		saerr("ERROR: incorrect value of srctype");
+	}
+
+	nxy = nx * ny;
+	nyz = ny * nz;
+	nxz = nx * nz;
+	nxyz = nx * ny * nz;
+
+
+	/* SET TIMES TO DUMMY VALUE */
+	for(i=0;i<nxyz;i++) time0[i] = 1.0e10;
+
+	if (srctype == 1) {			/*  VIDALE'S POINT SOURCE */
+		/* FILL IN CUBE AROUND SOURCE POINT */
+		/* HOLE'S NEW LINEAR VELOCITY GRADIENT CUBE (APRIL 1991)*/
+		v0 = h/s0(xs,ys,zs);
+		for (xx = xs-NCUBE; xx <= xs+NCUBE; xx++) {
+			if (xx < 0 || xx >= nx)	continue; 
+			for (yy = ys-NCUBE; yy <= ys+NCUBE; yy++) {
+				if (yy < 0 || yy >= ny)	continue; 
+				for (zz = zs-NCUBE; zz <= zs+NCUBE; zz++) {
+					if (zz < 0 || zz >= nz)	continue; 
+					if (zz == zs)
+					  dvz = 1/s0(xx,yy,zz+1)-1/s0(xs,ys,zs);
+					else
+					  dvz = (1/s0(xx,yy,zz)-1/s0(xs,ys,zs))/(zz-zs);
+					dv = fabs(dvz);
+					if (dv == 0.)  {
+					  t0(xx,yy,zz) = s0(xs,ys,zs)*DIST(fxs,fys,fzs,xx,yy,zz);
+					  continue;
+					}
+					rzc = -v0/dv;
+					rx = h*(xx - fxs);
+					ry = h*(yy - fys);
+					rz = h*(zz - fzs);
+					rz1 = rz*dvz/dv;
+					rxy1 = sqrt(rx*rx+ry*ry+rz*rz-rz1*rz1);
+					if (rxy1<=h/1.e6)
+					  t0(xx,yy,zz) = fabs(log((v0+dv*rz1)/v0)/dv);
+					else {
+					  rxyc = (rz1*rz1+rxy1*rxy1-2*rz1*rzc)/(2*rxy1);
+					  rho = sqrt(rzc*rzc+rxyc*rxyc);
+					  theta1 = asin(-rzc/rho);
+					  /* can't handle asin(1.) ! */
+					  if (fabs(rz1-rzc)>=rho)  rho=1.0000001*fabs(rz1-rzc);
+					  theta2 = asin((rz1-rzc)/rho);
+					  if (rxyc<0) theta1=PI-theta1;
+					  if (rxyc<rxy1) theta2=PI-theta2;
+					  t0(xx,yy,zz) = log(tan(theta2/2)/tan(theta1/2)) / dv;
+				        }
+				}
+			}
+		}
+	}
+	else if (srctype == 2) {		/*  HOLE'S EXTERNAL SOURCE */
+
+		/* FILL IN WALLS' TIMES FROM EXTERNAL DATAFILE */
+		read (wfint,wall,4*nwall);	/* READ X=0 WALL */
+		if (wall[0]>-1.e-20) {
+			ii = 0;
+			for (k=0; k<nz; k++) {
+				for (j=0; j<ny; j++) {
+					t0(0,j,k) = wall[ii];
+					ii++;
+				}
+			}
+		}
+		read (wfint,wall,4*nwall);	/* READ X=NX-1 WALL */
+		if (wall[0]>-1.e-20) {
+			ii = 0;
+			for (k=0; k<nz; k++) {
+				for (j=0; j<ny; j++) {
+					t0(nx-1,j,k) = wall[ii];
+					ii++;
+				}
+			}
+		}
+		read (wfint,wall,4*nwall);	/* READ Y=0 WALL */
+		if (wall[0]>-1.e-20) {
+			ii = 0;
+			for (k=0; k<nz; k++) {
+				for (i=0; i<nx; i++) {
+					t0(i,0,k) = wall[ii];
+					ii++;
+				}
+			}
+		}
+		read (wfint,wall,4*nwall);	/* READ Y=NY-1 WALL */
+		if (wall[0]>-1.e-20) {
+			ii = 0;
+			for (k=0; k<nz; k++) {
+				for (i=0; i<nx; i++) {
+					t0(i,ny-1,k) = wall[ii];
+					ii++;
+				}
+			}
+		}
+		read (wfint,wall,4*nwall);	/* READ Z=0 WALL */
+		if (wall[0]>-1.e-20) {
+			ii = 0;
+			for (j=0; j<ny; j++) {
+				for (i=0; i<nx; i++) {
+					t0(i,j,0) = wall[ii];
+					ii++;
+				}
+			}
+		}
+		read (wfint,wall,4*nwall);	/* READ Z=NZ-1 WALL */
+		if (wall[0]>-1.e-20) {
+			ii = 0;
+			for (j=0; j<ny; j++) {
+				for (i=0; i<nx; i++) {
+					t0(i,j,nz-1) = wall[ii];
+					ii++;
+				}
+			}
+		}
+	}
+	else if (srctype == 3) {                /*  HOLE'S REDO OLD TIMES */
+	        /* READ IN OLD TIME FILE */
+	        if (srctype == 3)  read(ofint,time0,nxyz*4);
+	}
+
+	return;
+}
diff --git a/raytime3d/threadAffinity.c b/raytime3d/threadAffinity.c
new file mode 100644
index 0000000000000000000000000000000000000000..49ca7e9d45bb953c9e63601c217d2deef69afcd1
--- /dev/null
+++ b/raytime3d/threadAffinity.c
@@ -0,0 +1,109 @@
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#ifdef __USE_GNU
+#include <omp.h>
+#include <sched.h>
+#else /* for OSX */
+#include <sched.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#define CPU_SETSIZE	1024
+#define SYSCTL_CORE_COUNT   "machdep.cpu.core_count"
+void vmess(char *fmt, ...);
+
+typedef struct cpu_set {
+  uint32_t    count;
+} cpu_set_t;
+
+static inline void
+CPU_ZERO(cpu_set_t *cs) { cs->count = 0; }
+
+static inline void
+CPU_SET(int num, cpu_set_t *cs) { cs->count |= (1 << num); }
+
+static inline int
+CPU_ISSET(int num, cpu_set_t *cs) { return (cs->count & (1 << num)); }
+
+int sched_getaffinity(pid_t pid, size_t cpu_size, cpu_set_t *cpu_set)
+{
+  int32_t core_count = 0;
+  size_t  len = sizeof(core_count);
+  int ret = sysctlbyname(SYSCTL_CORE_COUNT, &core_count, &len, 0, 0);
+  if (ret) {
+    printf("error while get core count %d\n", ret);
+    return -1;
+  }
+  cpu_set->count = 0;
+  for (int i = 0; i < core_count; i++) {
+    cpu_set->count |= (1 << i);
+  }
+
+  return 0;
+}
+#endif
+
+/* Borrowed from util-linux-2.13-pre7/schedutils/taskset.c */
+
+static char *cpuset_to_cstr(cpu_set_t *mask, char *str)
+{
+  char *ptr = str;
+  int i, j, entry_made = 0;
+  for (i = 0; i < CPU_SETSIZE; i++) {
+    if (CPU_ISSET(i, mask)) {
+      int run = 0;
+      entry_made = 1;
+      for (j = i + 1; j < CPU_SETSIZE; j++) {
+        if (CPU_ISSET(j, mask)) run++;
+        else break;
+      }
+      if (!run)
+        sprintf(ptr, "%d,", i);
+      else if (run == 1) {
+        sprintf(ptr, "%d,%d,", i, i + 1);
+        i++;
+      } else {
+        sprintf(ptr, "%d-%d,", i, i + run);
+        i += run;
+      }
+      while (*ptr != 0) ptr++;
+    }
+  }
+  ptr -= entry_made;
+  *ptr = 0;
+  return(str);
+}
+
+void threadAffinity(void)
+{
+  int thread;
+  cpu_set_t coremask;
+  char clbuf[7 * CPU_SETSIZE], hnbuf[64];
+  char prefix[200];
+
+  memset(clbuf, 0, sizeof(clbuf));
+  memset(hnbuf, 0, sizeof(hnbuf));
+  (void)gethostname(hnbuf, sizeof(hnbuf));
+
+  strcpy(prefix,"Hello world from");
+
+//  #pragma omp parallel private(thread, coremask, clbuf)
+/* for use inside parallel region */
+  #pragma omp critical
+  {
+#ifdef __USE_GNU
+    thread = omp_get_thread_num();
+#else
+    thread = 1;
+#endif
+    (void)sched_getaffinity(0, sizeof(coremask), &coremask);
+    cpuset_to_cstr(&coremask, clbuf);
+    vmess("%s thread %d, on %s. (core affinity = %s)", prefix, thread, hnbuf, clbuf);
+
+  }
+  return;
+}
+
diff --git a/raytime3d/verbosepkg.c b/raytime3d/verbosepkg.c
new file mode 100644
index 0000000000000000000000000000000000000000..483e5f92bd5e1c1a495c66b7a63b9e8113943897
--- /dev/null
+++ b/raytime3d/verbosepkg.c
@@ -0,0 +1,77 @@
+#include <stdio.h>
+#include <stdarg.h>
+#include "par.h"
+#include <string.h>
+#ifdef _CRAYMPP
+#include <intrinsics.h>
+#endif
+
+/**
+*  functions to print out verbose, error and warning messages to stderr.
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands 
+**/
+
+
+void verr(char *fmt, ...)
+{
+	va_list args;
+
+	if (EOF == fflush(stderr)) {
+		fprintf(stderr, "\nverr: fflush failed on stderr");
+	}
+	fprintf(stderr, "    Error in %s: ", xargv[0]);
+#ifdef _CRAYMPP
+        fprintf(stderr, "PE %d: ", _my_pe());
+#elif defined(SGI)
+        fprintf(stderr, "PE %d: ", mp_my_threadnum());
+#endif
+	va_start(args,fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+	fprintf(stderr, "\n");
+
+	exit(EXIT_FAILURE);
+}
+
+void vwarn(char *fmt, ...)
+{
+	va_list args;
+
+	if (EOF == fflush(stderr)) {
+		fprintf(stderr, "\nvwarn: fflush failed on stderr");
+	}
+	fprintf(stderr, "    Warning in %s: ", xargv[0]);
+#ifdef _CRAYMPP
+        fprintf(stderr, "PE %d: ", _my_pe());
+#elif defined(SGI)
+        fprintf(stderr, "PE %d: ", mp_my_threadnum());
+#endif
+	va_start(args,fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+	fprintf(stderr, "\n");
+	return;
+}
+
+void vmess(char *fmt, ...)
+{
+	va_list args;
+
+	if (EOF == fflush(stderr)) {
+		fprintf(stderr, "\nvmess: fflush failed on stderr");
+	}
+	fprintf(stderr, "    %s: ", xargv[0]);
+#ifdef _CRAYMPP
+        fprintf(stderr, "PE %d: ", _my_pe());
+#elif defined(SGI)
+        fprintf(stderr, "PE %d: ", mp_my_threadnum());
+#endif
+	va_start(args,fmt);
+	vfprintf(stderr, fmt, args);
+	va_end(args);
+	fprintf(stderr, "\n");
+	return;
+}
diff --git a/raytime3d/vidale3d.c b/raytime3d/vidale3d.c
new file mode 100644
index 0000000000000000000000000000000000000000..06b4b388274def5752a95ab1f0bbb1b881b47c11
--- /dev/null
+++ b/raytime3d/vidale3d.c
@@ -0,0 +1,1440 @@
+#include <cwp.h>
+#include <su.h>
+
+#define SQR2 1.414213562
+#define SQR3 1.732050808
+#define SQR6 2.449489743
+#define t0(x,y,z)   time0[nxy*(z) + nx*(y) + (x)]
+#define s0(x,y,z)   slow0[nxy*(z) + nx*(y) + (x)]
+
+/* definitions from saerrpkge.c */
+extern void saerr(char *fmt, ...);
+extern void sawarn(char *fmt, ...);
+extern void samess(char *fmt, ...);
+
+struct sorted
+	{ float time; int i1, i2;};
+
+int compar(struct sorted *a,struct sorted *b);
+
+float fdhne(float t1,float t2,float t3,float t4,float t5,float ss0,float s1,float s2,float s3);
+float fdh3d(float t1,float t2,float t3,float t4,float t5,float t6,float t7,float ss0,float s1,float s2,float s3,float s4,float s5,float s6,float s7);
+float fdh2d(float t1,float t2,float t3,float ss0,float s1,float s2,float s3);
+float fdhnf(float t1,float t2,float t3,float t4,float t5,float ss0,float s1);
+
+void vidale3d(float *slow0, float *time0, int nz, int nx, int ny, float h, int xs, int ys, int zs, int NCUBE)
+{
+	int
+		srctype=1,	/* if 1, source is a point;
+						2, source is on the walls of the data volume;
+						3, source on wall, time field known; */
+		srcwall,	/* if 1, source on x=0 wall, if 2, on x=nx-1 wall
+						if 3, source on y=0 wall, if 4, on y=ny-1 wall
+						if 5, source on z=0 wall, if 6, on z=nz-1 wall */
+		iplus=1,	/* rate of expansion of "cube" in the */
+		iminus=1,	/*    plus/minus x/y/z direction */
+		jplus=1,
+		jminus=1,
+		kplus=1,
+		kminus=1,
+		igrow,		/* counter for "cube" growth */
+		X1, X2, lasti, index, ii, i, j, k, radius, 
+		nxy, nyz, nxz, nxyz, nwall,
+		/* counters for the position of the sides of current cube */
+		x1, x2, y1, y2, z1, z2,
+		/* flags set to 1 until a side has been reached */
+		dx1=1, dx2=1, dy1=1, dy2=1, dz1=1, dz2=1, rad0=1,
+		maxrad,		/* maximum radius to compute */
+		reverse=1,	/* will automatically do up to this number of
+						reverse propagation steps to fix waves that travel 
+						back into expanding cube */
+		headpref=6,	/* if headpref starts > 0, will determine 
+						model wall closest to source and will prefer to start
+						reverse calculations on opposite wall */
+		/* counters for detecting head waves on sides of current cube */
+		head,headw[7], verbose;
+	float
+		*wall,
+		guess, try,
+		/* maximum offset (real units) to compute */
+		maxoff = -1.,
+		/* used to detect head waves:  if headwave operator decreases 
+		   the previously-computed traveltime by at least 
+		   headtest*<~time_across_cell> then the headwave counter is 
+		   triggered */
+		fhead,headtest=1.e-3;
+
+	/* ARRAY TO ORDER SIDE FOR SOLUTION IN THE RIGHT ORDER */
+	struct sorted *sort;
+
+	if (!getparint("verbose",&verbose)) verbose=0;
+	if(!getparfloat("maxoff",&maxoff)) maxoff = -1.;
+	if(!getparint("iminus",&iminus)) iminus=1;
+	if(!getparint("iplus",&iplus)) iplus=1;
+	if(!getparint("jminus",&jminus)) jminus=1;
+	if(!getparint("jplus",&jplus)) jplus=1;
+	if(!getparint("kminus",&kminus)) kminus=1;
+	if(!getparint("kplus",&kplus)) kplus=1;
+	if(!getparint("reverse",&reverse)) reverse=0;
+	if(!getparint("headpref",&headpref)) headpref=6;
+	if(!getparint("NCUBE",&NCUBE)) NCUBE=2;
+
+	/* SET MAXIMUM RADIUS TO COMPUTE */
+	if (maxoff > 0.) {
+		maxrad = maxoff/h + 1;
+		sawarn("WARNING: Computing only to max radius = %d",maxrad);
+	}
+	else maxrad = 99999999;
+
+	nxy = nx * ny;
+	nyz = ny * nz;
+	nxz = nx * nz;
+	nxyz = nx * ny * nz;
+
+	/* MAKE ARRAY SORT LARGE ENOUGH FOR ANY SIDE */
+	if(nx <= ny && nx <= nz)  {
+		sort = (struct sorted *) malloc(sizeof(struct sorted)*ny*nz);
+		nwall = nyz;
+	}
+	else if(ny <= nx && ny <= nz)  {
+		sort = (struct sorted *) malloc(sizeof(struct sorted)*nx*nz);
+		nwall = nxz;
+	}
+	else  {
+		sort = (struct sorted *) malloc(sizeof(struct sorted)*nx*ny);
+		nwall = nxy;
+	}
+	wall = (float *) malloc(4*nwall);
+	if(sort == NULL || wall == NULL) 
+		saerr("error in allocation of arrays sort and wall");
+
+	if(!getparint("srctype",&srctype)) srctype=1;
+	if(srctype==1) {
+		/* SETS LOCATION OF THE SIDES OF THE CUBE	*/
+		radius = NCUBE;
+		if(xs > NCUBE) x1 = xs - (NCUBE + 1);
+		else{ x1 = -1; dx1 = 0;}
+		if(xs < nx-(NCUBE + 1)) x2 = xs + (NCUBE + 1);
+		else{ x2 = nx; dx2 = 0;}
+		if(ys > NCUBE) y1 = ys - (NCUBE + 1);
+		else{ y1 = -1; dy1 = 0;}
+		if(ys < ny-(NCUBE + 1)) y2 = ys + (NCUBE + 1);
+		else{ y2 = ny; dy2 = 0;}
+		if(zs > NCUBE) z1 = zs - (NCUBE + 1);
+		else{ z1 = -1; dz1 = 0;}
+		if(zs < nz-(NCUBE + 1)) z2 = zs + (NCUBE + 1);
+		else{ z2 = nz; dz2 = 0;}
+	}
+	else {
+		if (!getparint("srcwall",&srcwall)) saerr("srcwall not given");
+		/* SET LOCATIONS OF SIDES OF THE CUBE SO THAT CUBE IS A FACE  */
+		radius = 1;
+		if (srcwall == 1)	x2=1;
+		else	{  x2=nx;	dx2=0;  }
+		if (srcwall == 2)	x1=nx-2;
+		else	{  x1= -1;	dx1=0;  }
+		if (srcwall == 3)	y2=1;
+		else	{  y2=ny;	dy2=0;  }
+		if (srcwall == 4)	y1=ny-2;
+		else	{  y1= -1;	dy1=0;  }
+		if (srcwall == 5)	z2=1;
+		else	{  z2=nz;	dz2=0;  }
+		if (srcwall == 6)	z1=nz-2;
+		else	{  z1= -1;	dz1=0;  }
+	}
+
+
+	if (headpref>0) {	/* HOLE - PREFERRED REVERSE DIRECTION */
+		head = nx*ny*nz;
+		if (nx>5 && x2<=head)   {headpref=2;  head=x2;}
+		if (nx>5 && (nx-1-x1)<=head)   {headpref=1;  head=nx-1-x1;}
+		if (ny>5 && y2<=head)   {headpref=4;  head=y2;}
+		if (ny>5 && (ny-1-y1)<=head)   {headpref=3;  head=ny-1-y1;}
+		if (nz>5 && z2<=head)   {headpref=6;  head=z2;}
+		if (nz>5 && (nz-1-z1)<=head)   {headpref=5;  head=nz-1-z1;}
+	}
+
+	/* BIGGER LOOP - HOLE - ALLOWS AUTOMATIC REVERSE PROPAGATION IF 
+		HEAD WAVES ARE ENCOUNTERED ON FACES OF EXPANDING CUBE, 
+		ALLOWING WAVES TO TRAVEL BACK INTO THE CUBE */
+
+	while ( reverse > -1 )  {
+
+		headw[1]=0; headw[2]=0; headw[3]=0; headw[4]=0;
+		headw[5]=0; headw[6]=0;
+
+	/* BIG LOOP */
+	while(rad0 && (dx1 || dx2 || dy1 || dy2 || dz1 || dz2))  {
+
+		/* CALCULATE ON PRIMARY (time0) GRID */
+
+		/* TOP SIDE */
+      for (igrow=1;igrow<=kminus;igrow++) {  
+	if(dz1){
+		ii = 0;
+		for(j=y1+1; j<=y2-1; j++){
+			for(i=x1+1; i<=x2-1; i++){
+				sort[ii].time = t0(i,j,z1+1);
+				sort[ii].i1 = i;
+				sort[ii].i2 = j;
+				ii++;
+			}
+		}
+		qsort((char *)sort,ii,sizeof(struct sorted),compar);
+		for(i=0;i<ii;i++){
+			X1 = sort[i].i1;
+			X2 = sort[i].i2;
+			index = z1*nxy + X2*nx + X1;
+			lasti = (z1+1)*nxy + X2*nx + X1;
+			fhead = 0.;
+			guess = time0[index];
+                        if(time0[index+1] < 1.e9 && time0[index+nx+1] < 1.e9
+			   && time0[index+nx] < 1.e9 && X2<ny-1  && X1<nx-1 ) {
+			  try = fdh3d(              t0(X1,X2,z1+1),
+				      t0(X1+1,X2,z1+1),t0(X1+1,X2+1,z1+1),t0(X1,X2+1,z1+1),
+				      t0(X1+1,X2,z1  ),t0(X1+1,X2+1,z1  ),t0(X1,X2+1,z1  ),
+				      s0(X1,X2,z1), s0(X1,X2,z1+1),
+				      s0(X1+1,X2,z1+1),s0(X1+1,X2+1,z1+1),s0(X1,X2+1,z1+1),
+				      s0(X1+1,X2,z1  ),s0(X1+1,X2+1,z1  ),s0(X1,X2+1,z1  ));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-1] < 1.e9 && time0[index+nx-1] < 1.e9
+			   && time0[index+nx] < 1.e9 && X2<ny-1  && X1>0 ) {
+			  try = fdh3d(              t0(X1,X2,z1+1),
+				      t0(X1-1,X2,z1+1),t0(X1-1,X2+1,z1+1),t0(X1,X2+1,z1+1),
+				      t0(X1-1,X2,z1  ),t0(X1-1,X2+1,z1  ),t0(X1,X2+1,z1  ),
+				      s0(X1,X2,z1), s0(X1,X2,z1+1),
+				      s0(X1-1,X2,z1+1),s0(X1-1,X2+1,z1+1),s0(X1,X2+1,z1+1),
+				      s0(X1-1,X2,z1  ),s0(X1-1,X2+1,z1  ),s0(X1,X2+1,z1  ));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index+1] < 1.e9 && time0[index-nx+1] < 1.e9
+			   && time0[index-nx] < 1.e9 && X2>0  && X1<nx-1 ) {
+			  try = fdh3d(              t0(X1,X2,z1+1),
+				      t0(X1+1,X2,z1+1),t0(X1+1,X2-1,z1+1),t0(X1,X2-1,z1+1),
+				      t0(X1+1,X2,z1  ),t0(X1+1,X2-1,z1  ),t0(X1,X2-1,z1  ),
+				      s0(X1,X2,z1), s0(X1,X2,z1+1),
+				      s0(X1+1,X2,z1+1),s0(X1+1,X2-1,z1+1),s0(X1,X2-1,z1+1),
+				      s0(X1+1,X2,z1  ),s0(X1+1,X2-1,z1  ),s0(X1,X2-1,z1  ));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-1] < 1.e9 && time0[index-nx-1] < 1.e9
+			   && time0[index-nx] < 1.e9 && X2>0  && X1>0 ) {
+			  try = fdh3d(              t0(X1,X2,z1+1),
+				      t0(X1-1,X2,z1+1),t0(X1-1,X2-1,z1+1),t0(X1,X2-1,z1+1),
+				      t0(X1-1,X2,z1  ),t0(X1-1,X2-1,z1  ),t0(X1,X2-1,z1  ),
+				      s0(X1,X2,z1), s0(X1,X2,z1+1),
+				      s0(X1-1,X2,z1+1),s0(X1-1,X2-1,z1+1),s0(X1,X2-1,z1+1),
+				      s0(X1-1,X2,z1  ),s0(X1-1,X2-1,z1  ),s0(X1,X2-1,z1  ));
+			  if (try<guess) guess = try;
+			}
+			if(guess > 1.0e9){ 
+			  if(time0[index+1] < 1.e9 && X1<nx-1 && X2>y1+1 && X2<y2-1 )  {
+			      try = fdhne(t0(X1,X2,z1+1),t0(X1+1,X2,z1+1),t0(X1+1,X2,z1),
+					  t0(X1+1,X2-1,z1+1),t0(X1+1,X2+1,z1+1),
+					  s0(X1,X2,z1),
+					  s0(X1,X2,z1+1),s0(X1+1,X2,z1+1),s0(X1+1,X2,z1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-1] < 1.e9 && X1>0 && X2>y1+1 && X2<y2-1 )  {
+			      try = fdhne(t0(X1,X2,z1+1),t0(X1-1,X2,z1+1),t0(X1-1,X2,z1),
+					  t0(X1-1,X2-1,z1+1),t0(X1-1,X2+1,z1+1),
+					  s0(X1,X2,z1),
+					  s0(X1,X2,z1+1),s0(X1-1,X2,z1+1),s0(X1-1,X2,z1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nx] < 1.e9 && X2<ny-1 && X1>x1+1 && X1<x2-1 )  {
+			      try = fdhne(t0(X1,X2,z1+1),t0(X1,X2+1,z1+1),t0(X1,X2+1,z1),
+					  t0(X1-1,X2+1,z1+1),t0(X1+1,X2+1,z1+1),
+					  s0(X1,X2,z1),
+					  s0(X1,X2,z1+1),s0(X1,X2+1,z1+1),s0(X1,X2+1,z1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nx] < 1.e9 && X2>0 && X1>x1+1 && X1<x2-1 )  {
+			      try = fdhne(t0(X1,X2,z1+1),t0(X1,X2-1,z1+1),t0(X1,X2-1,z1),
+					  t0(X1-1,X2-1,z1+1),t0(X1+1,X2-1,z1+1),
+					  s0(X1,X2,z1),
+					  s0(X1,X2,z1+1),s0(X1,X2-1,z1+1),s0(X1,X2-1,z1) );
+			    if (try<guess)  guess = try;
+			  }
+		        } 
+			  if(time0[index+1] < 1.e9 && X1<nx-1 )  {
+			    try = fdh2d(t0(X1,X2,z1+1),t0(X1+1,X2,z1+1),t0(X1+1,X2,z1),
+					  s0(X1,X2,z1),
+					  s0(X1,X2,z1+1),s0(X1+1,X2,z1+1),s0(X1+1,X2,z1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-1] < 1.e9 && X1>0 )  {
+			    try = fdh2d(t0(X1,X2,z1+1),t0(X1-1,X2,z1+1),t0(X1-1,X2,z1),
+					  s0(X1,X2,z1),
+					  s0(X1,X2,z1+1),s0(X1-1,X2,z1+1),s0(X1-1,X2,z1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nx] < 1.e9 && X2<ny-1 )  {
+			    try = fdh2d(t0(X1,X2,z1+1),t0(X1,X2+1,z1+1),t0(X1,X2+1,z1),
+					  s0(X1,X2,z1),
+					  s0(X1,X2,z1+1),s0(X1,X2+1,z1+1),s0(X1,X2+1,z1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nx] < 1.e9 && X2>0 )  {
+			    try = fdh2d(t0(X1,X2,z1+1),t0(X1,X2-1,z1+1),t0(X1,X2-1,z1),
+					  s0(X1,X2,z1),
+					  s0(X1,X2,z1+1),s0(X1,X2-1,z1+1),s0(X1,X2-1,z1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+1] < 1.e9 && time0[index+nx+1] < 1.e9
+			     && time0[index+nx] < 1.e9 && X2<ny-1  && X1<nx-1 ) {
+			    try = fdh2d(t0(X1+1,X2,z1),t0(X1+1,X2+1,z1),t0(X1,X2+1,z1),
+					s0(X1,X2,z1),
+					s0(X1+1,X2,z1),s0(X1+1,X2+1,z1),s0(X1,X2+1,z1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index+1] < 1.e9 && time0[index-nx+1] < 1.e9
+			     && time0[index-nx] < 1.e9 && X2>0  && X1<nx-1 ) {
+			    try = fdh2d(t0(X1+1,X2,z1),t0(X1+1,X2-1,z1),t0(X1,X2-1,z1),
+					s0(X1,X2,z1),
+					s0(X1+1,X2,z1),s0(X1+1,X2-1,z1),s0(X1,X2-1,z1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-1] < 1.e9 && time0[index+nx-1] < 1.e9
+			     && time0[index+nx] < 1.e9 && X2<ny-1  && X1>0 ) {
+			    try = fdh2d(t0(X1-1,X2,z1),t0(X1-1,X2+1,z1),t0(X1,X2+1,z1),
+					s0(X1,X2,z1),
+					s0(X1-1,X2,z1),s0(X1-1,X2+1,z1),s0(X1,X2+1,z1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-1] < 1.e9 && time0[index-nx-1] < 1.e9
+			     && time0[index-nx] < 1.e9 && X2>0  && X1>0 ) {
+			    try = fdh2d(t0(X1-1,X2,z1),t0(X1-1,X2-1,z1),t0(X1,X2-1,z1),
+					s0(X1,X2,z1),
+					s0(X1-1,X2,z1),s0(X1-1,X2-1,z1),s0(X1,X2-1,z1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if(guess > 1.0e9){ 
+			  if ( X1>x1+1 && X1<x2-1 && X2>y1+1 && X2<y2-1 ) {
+			    try = fdhnf(t0(X1,X2,z1+1),
+					  t0(X1+1,X2,z1+1),t0(X1,X2+1,z1+1),
+					  t0(X1-1,X2,z1+1),t0(X1,X2-1,z1+1),
+					  s0(X1,X2,z1),
+					  s0(X1,X2,z1+1) );
+			    if (try<guess)  guess = try;
+			  }
+			} 
+                          try = t0(X1,X2,z1+1) + .5*(s0(X1,X2,z1)+s0(X1,X2,z1+1));
+			  if (try<guess)  guess = try;
+                          if ( time0[index+1]<1.e9 && X1<nx-1 )  {
+			    try = t0(X1+1,X2,z1) + .5*(s0(X1,X2,z1)+s0(X1+1,X2,z1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-1]<1.e9 && X1>0 )  {
+			    try = t0(X1-1,X2,z1) + .5*(s0(X1,X2,z1)+s0(X1-1,X2,z1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index+nx]<1.e9 && X2<ny-1 )  {
+			    try = t0(X1,X2+1,z1) + .5*(s0(X1,X2,z1)+s0(X1,X2+1,z1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-nx]<1.e9 && X2>0 )  {
+			    try = t0(X1,X2-1,z1) + .5*(s0(X1,X2,z1)+s0(X1,X2-1,z1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if (guess<time0[index])  {
+				time0[index] = guess;
+				if (fhead>headtest)  headw[5]++;
+			}
+		}
+		if(z1 == 0) dz1 = 0;
+		z1--;
+	}
+      }
+		/* BOTTOM SIDE */
+      for (igrow=1;igrow<=kplus;igrow++) {  
+	if(dz2){
+		ii = 0;
+		for(j=y1+1; j<=y2-1; j++){
+			for(i=x1+1; i<=x2-1; i++){
+				sort[ii].time = t0(i,j,z2-1);
+				sort[ii].i1 = i;
+				sort[ii].i2 = j;
+				ii++;
+			}
+		}
+		qsort((char *)sort,ii,sizeof(struct sorted),compar);
+		for(i=0;i<ii;i++){
+			X1 = sort[i].i1;
+			X2 = sort[i].i2;
+			index = z2*nxy + X2*nx + X1;
+			lasti = (z2-1)*nxy + X2*nx + X1;
+			fhead = 0.;
+			guess = time0[index];
+                        if(time0[index+1] < 1.e9 && time0[index+nx+1] < 1.e9
+			   && time0[index+nx] < 1.e9 && X2<ny-1  && X1<nx-1 ) {
+			  try = fdh3d(              t0(X1,X2,z2-1),
+				      t0(X1+1,X2,z2-1),t0(X1+1,X2+1,z2-1),t0(X1,X2+1,z2-1),
+				      t0(X1+1,X2,z2  ),t0(X1+1,X2+1,z2  ),t0(X1,X2+1,z2  ),
+				      s0(X1,X2,z2), s0(X1,X2,z2-1),
+				      s0(X1+1,X2,z2-1),s0(X1+1,X2+1,z2-1),s0(X1,X2+1,z2-1),
+				      s0(X1+1,X2,z2  ),s0(X1+1,X2+1,z2  ),s0(X1,X2+1,z2  ));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-1] < 1.e9 && time0[index+nx-1] < 1.e9
+			   && time0[index+nx] < 1.e9 && X2<ny-1  && X1>0 ) {
+			  try = fdh3d(              t0(X1,X2,z2-1),
+				      t0(X1-1,X2,z2-1),t0(X1-1,X2+1,z2-1),t0(X1,X2+1,z2-1),
+				      t0(X1-1,X2,z2  ),t0(X1-1,X2+1,z2  ),t0(X1,X2+1,z2  ),
+				      s0(X1,X2,z2), s0(X1,X2,z2-1),
+				      s0(X1-1,X2,z2-1),s0(X1-1,X2+1,z2-1),s0(X1,X2+1,z2-1),
+				      s0(X1-1,X2,z2  ),s0(X1-1,X2+1,z2  ),s0(X1,X2+1,z2  ));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index+1] < 1.e9 && time0[index-nx+1] < 1.e9
+			   && time0[index-nx] < 1.e9 && X2>0  && X1<nx-1 ) {
+			  try = fdh3d(              t0(X1,X2,z2-1),
+				      t0(X1+1,X2,z2-1),t0(X1+1,X2-1,z2-1),t0(X1,X2-1,z2-1),
+				      t0(X1+1,X2,z2  ),t0(X1+1,X2-1,z2  ),t0(X1,X2-1,z2  ),
+				      s0(X1,X2,z2), s0(X1,X2,z2-1),
+				      s0(X1+1,X2,z2-1),s0(X1+1,X2-1,z2-1),s0(X1,X2-1,z2-1),
+				      s0(X1+1,X2,z2  ),s0(X1+1,X2-1,z2  ),s0(X1,X2-1,z2  ));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-1] < 1.e9 && time0[index-nx-1] < 1.e9
+			   && time0[index-nx] < 1.e9 && X2>0  && X1>0 ) {
+			  try = fdh3d(              t0(X1,X2,z2-1),
+				      t0(X1-1,X2,z2-1),t0(X1-1,X2-1,z2-1),t0(X1,X2-1,z2-1),
+				      t0(X1-1,X2,z2  ),t0(X1-1,X2-1,z2  ),t0(X1,X2-1,z2  ),
+				      s0(X1,X2,z2), s0(X1,X2,z2-1),
+				      s0(X1-1,X2,z2-1),s0(X1-1,X2-1,z2-1),s0(X1,X2-1,z2-1),
+				      s0(X1-1,X2,z2  ),s0(X1-1,X2-1,z2  ),s0(X1,X2-1,z2  ));
+			  if (try<guess) guess = try;
+			}
+                        if(guess > 1.0e9){ 
+			  if(time0[index+1] < 1.e9 && X1<nx-1 && X2>y1+1 && X2<y2-1 )  {
+			      try = fdhne(t0(X1,X2,z2-1),t0(X1+1,X2,z2-1),t0(X1+1,X2,z2),
+					  t0(X1+1,X2-1,z2-1),t0(X1+1,X2+1,z2-1),
+					  s0(X1,X2,z2),
+					  s0(X1,X2,z2-1),s0(X1+1,X2,z2-1),s0(X1+1,X2,z2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-1] < 1.e9 && X1>0 && X2>y1+1 && X2<y2-1 )  {
+			      try = fdhne(t0(X1,X2,z2-1),t0(X1-1,X2,z2-1),t0(X1-1,X2,z2),
+					  t0(X1-1,X2-1,z2-1),t0(X1-1,X2+1,z2-1),
+					  s0(X1,X2,z2),
+					  s0(X1,X2,z2-1),s0(X1-1,X2,z2-1),s0(X1-1,X2,z2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nx] < 1.e9 && X2<ny-1 && X1>x1+1 && X1<x2-1 )  {
+			      try = fdhne(t0(X1,X2,z2-1),t0(X1,X2+1,z2-1),t0(X1,X2+1,z2),
+					  t0(X1-1,X2+1,z2-1),t0(X1+1,X2+1,z2-1),
+					  s0(X1,X2,z2),
+					  s0(X1,X2,z2-1),s0(X1,X2+1,z2-1),s0(X1,X2+1,z2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nx] < 1.e9 && X2>0 && X1>x1+1 && X1<x2-1 )  {
+			      try = fdhne(t0(X1,X2,z2-1),t0(X1,X2-1,z2-1),t0(X1,X2-1,z2),
+					  t0(X1-1,X2-1,z2-1),t0(X1+1,X2-1,z2-1),
+					  s0(X1,X2,z2),
+					  s0(X1,X2,z2-1),s0(X1,X2-1,z2-1),s0(X1,X2-1,z2) );
+			    if (try<guess)  guess = try;
+			  }
+		        }
+			  if(time0[index+1] < 1.e9 && X1<nx-1 )  {
+			    try = fdh2d(t0(X1,X2,z2-1),t0(X1+1,X2,z2-1),t0(X1+1,X2,z2),
+					  s0(X1,X2,z2),
+					  s0(X1,X2,z2-1),s0(X1+1,X2,z2-1),s0(X1+1,X2,z2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-1] < 1.e9 && X1>0 )  {
+			    try = fdh2d(t0(X1,X2,z2-1),t0(X1-1,X2,z2-1),t0(X1-1,X2,z2),
+					  s0(X1,X2,z2),
+					  s0(X1,X2,z2-1),s0(X1-1,X2,z2-1),s0(X1-1,X2,z2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nx] < 1.e9 && X2<ny-1 )  {
+			    try = fdh2d(t0(X1,X2,z2-1),t0(X1,X2+1,z2-1),t0(X1,X2+1,z2),
+					  s0(X1,X2,z2),
+					  s0(X1,X2,z2-1),s0(X1,X2+1,z2-1),s0(X1,X2+1,z2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nx] < 1.e9 && X2>0 )  {
+			    try = fdh2d(t0(X1,X2,z2-1),t0(X1,X2-1,z2-1),t0(X1,X2-1,z2),
+					  s0(X1,X2,z2),
+					  s0(X1,X2,z2-1),s0(X1,X2-1,z2-1),s0(X1,X2-1,z2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+1] < 1.e9 && time0[index+nx+1] < 1.e9
+			     && time0[index+nx] < 1.e9 && X2<ny-1  && X1<nx-1 ) {
+			    try = fdh2d(t0(X1+1,X2,z2),t0(X1+1,X2+1,z2),t0(X1,X2+1,z2),
+					s0(X1,X2,z2),
+					s0(X1+1,X2,z2),s0(X1+1,X2+1,z2),s0(X1,X2+1,z2) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index+1] < 1.e9 && time0[index-nx+1] < 1.e9
+			     && time0[index-nx] < 1.e9 && X2>0  && X1<nx-1 ) {
+			    try = fdh2d(t0(X1+1,X2,z2),t0(X1+1,X2-1,z2),t0(X1,X2-1,z2),
+					s0(X1,X2,z2),
+					s0(X1+1,X2,z2),s0(X1+1,X2-1,z2),s0(X1,X2-1,z2) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-1] < 1.e9 && time0[index+nx-1] < 1.e9
+			     && time0[index+nx] < 1.e9 && X2<ny-1  && X1>0 ) {
+			    try = fdh2d(t0(X1-1,X2,z2),t0(X1-1,X2+1,z2),t0(X1,X2+1,z2),
+					s0(X1,X2,z2),
+					s0(X1-1,X2,z2),s0(X1-1,X2+1,z2),s0(X1,X2+1,z2) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-1] < 1.e9 && time0[index-nx-1] < 1.e9
+			     && time0[index-nx] < 1.e9 && X2>0  && X1>0 ) {
+			    try = fdh2d(t0(X1-1,X2,z2),t0(X1-1,X2-1,z2),t0(X1,X2-1,z2),
+					s0(X1,X2,z2),
+					s0(X1-1,X2,z2),s0(X1-1,X2-1,z2),s0(X1,X2-1,z2) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if(guess > 1.0e9){ 
+			  if ( X1>x1+1 && X1<x2-1 && X2>y1+1 && X2<y2-1 ) {
+			    try = fdhnf(t0(X1,X2,z2-1),
+					  t0(X1+1,X2,z2-1),t0(X1,X2+1,z2-1),
+					  t0(X1-1,X2,z2-1),t0(X1,X2-1,z2-1),
+					  s0(X1,X2,z2),
+					  s0(X1,X2,z2-1) );
+			    if (try<guess)  guess = try;
+			  }
+			} 
+			  try = t0(X1,X2,z2-1) + .5*(s0(X1,X2,z2)+s0(X1,X2,z2-1));
+			  if (try<guess)  guess = try;
+                          if ( time0[index+1]<1.e9 && X1<nx-1 )  {
+			    try = t0(X1+1,X2,z2) + .5*(s0(X1,X2,z2)+s0(X1+1,X2,z2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-1]<1.e9 && X1>0 )  {
+			    try = t0(X1-1,X2,z2) + .5*(s0(X1,X2,z2)+s0(X1-1,X2,z2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index+nx]<1.e9 && X2<ny-1 )  {
+			    try = t0(X1,X2+1,z2) + .5*(s0(X1,X2,z2)+s0(X1,X2+1,z2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-nx]<1.e9 && X2>0 )  {
+			    try = t0(X1,X2-1,z2) + .5*(s0(X1,X2,z2)+s0(X1,X2-1,z2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if (guess<time0[index]) {
+				time0[index] = guess;
+				if (fhead>headtest)  headw[6]++;
+			}
+		}
+		if(z2 == nz-1) dz2 = 0;
+		z2++;
+	}
+      }
+		/* FRONT SIDE */
+      for (igrow=1;igrow<=jminus;igrow++) {  
+	if(dy1){
+		ii = 0;
+		for(k=z1+1; k<=z2-1; k++){
+			for(i=x1+1; i<=x2-1; i++){
+				sort[ii].time = t0(i,y1+1,k);
+				sort[ii].i1 = i;
+				sort[ii].i2 = k;
+				ii++;
+			}
+		}
+		qsort((char *)sort,ii,sizeof(struct sorted),compar);
+		for(i=0;i<ii;i++){
+			X1 = sort[i].i1;
+			X2 = sort[i].i2;
+			index = X2*nxy + y1*nx + X1;
+			lasti = X2*nxy + (y1+1)*nx + X1;
+			fhead = 0.;
+			guess = time0[index];
+			if(time0[index+1] < 1.e9 && time0[index+nxy+1] < 1.e9
+			   && time0[index+nxy] < 1.e9 && X2<nz-1  && X1<nx-1 ) {
+			  try = fdh3d(              t0(X1,y1+1,X2),
+				      t0(X1+1,y1+1,X2),t0(X1+1,y1+1,X2+1),t0(X1,y1+1,X2+1),
+				      t0(X1+1,y1  ,X2),t0(X1+1,y1  ,X2+1),t0(X1,y1  ,X2+1),
+				      s0(X1,y1,X2), s0(X1,y1+1,X2),
+				      s0(X1+1,y1+1,X2),s0(X1+1,y1+1,X2+1),s0(X1,y1+1,X2+1),
+				      s0(X1+1,y1  ,X2),s0(X1+1,y1  ,X2+1),s0(X1,y1  ,X2+1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-1] < 1.e9 && time0[index+nxy-1] < 1.e9
+			   && time0[index+nxy] < 1.e9 && X2<nz-1  && X1>0 ) {
+			  try = fdh3d(              t0(X1,y1+1,X2),
+				      t0(X1-1,y1+1,X2),t0(X1-1,y1+1,X2+1),t0(X1,y1+1,X2+1),
+				      t0(X1-1,y1  ,X2),t0(X1-1,y1  ,X2+1),t0(X1,y1  ,X2+1),
+				      s0(X1,y1,X2), s0(X1,y1+1,X2),
+				      s0(X1-1,y1+1,X2),s0(X1-1,y1+1,X2+1),s0(X1,y1+1,X2+1),
+				      s0(X1-1,y1  ,X2),s0(X1-1,y1  ,X2+1),s0(X1,y1  ,X2+1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index+1] < 1.e9 && time0[index-nxy+1] < 1.e9
+			   && time0[index-nxy] < 1.e9 && X2>0  && X1<nx-1 ) {
+			  try = fdh3d(              t0(X1,y1+1,X2),
+				      t0(X1+1,y1+1,X2),t0(X1+1,y1+1,X2-1),t0(X1,y1+1,X2-1),
+				      t0(X1+1,y1  ,X2),t0(X1+1,y1  ,X2-1),t0(X1,y1  ,X2-1),
+				      s0(X1,y1,X2), s0(X1,y1+1,X2),
+				      s0(X1+1,y1+1,X2),s0(X1+1,y1+1,X2-1),s0(X1,y1+1,X2-1),
+				      s0(X1+1,y1  ,X2),s0(X1+1,y1  ,X2-1),s0(X1,y1  ,X2-1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-1] < 1.e9 && time0[index-nxy-1] < 1.e9
+			   && time0[index-nxy] < 1.e9 && X2>0  && X1>0 ) {
+			  try = fdh3d(              t0(X1,y1+1,X2),
+				      t0(X1-1,y1+1,X2),t0(X1-1,y1+1,X2-1),t0(X1,y1+1,X2-1),
+				      t0(X1-1,y1  ,X2),t0(X1-1,y1  ,X2-1),t0(X1,y1  ,X2-1),
+				      s0(X1,y1,X2), s0(X1,y1+1,X2),
+				      s0(X1-1,y1+1,X2),s0(X1-1,y1+1,X2-1),s0(X1,y1+1,X2-1),
+				      s0(X1-1,y1  ,X2),s0(X1-1,y1  ,X2-1),s0(X1,y1  ,X2-1));
+			  if (try<guess) guess = try;
+			}
+			if(guess > 1.0e9){ 
+			  if(time0[index+1] < 1.e9 && X1<nx-1 && X2>z1+1 && X2<z2-1 )  {
+			      try = fdhne(t0(X1,y1+1,X2),t0(X1+1,y1+1,X2),t0(X1+1,y1,X2),
+					  t0(X1+1,y1+1,X2-1),t0(X1+1,y1+1,X2+1),
+					  s0(X1,y1,X2),
+					  s0(X1,y1+1,X2),s0(X1+1,y1+1,X2),s0(X1+1,y1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-1] < 1.e9 && X1>0 && X2>z1+1 && X2<z2-1 )  {
+			      try = fdhne(t0(X1,y1+1,X2),t0(X1-1,y1+1,X2),t0(X1-1,y1,X2),
+					  t0(X1-1,y1+1,X2-1),t0(X1-1,y1+1,X2+1),
+					  s0(X1,y1,X2),
+					  s0(X1,y1+1,X2),s0(X1-1,y1+1,X2),s0(X1-1,y1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nxy] < 1.e9 && X2<nz-1 && X1>x1+1 && X1<x2-1 )  {
+			      try = fdhne(t0(X1,y1+1,X2),t0(X1,y1+1,X2+1),t0(X1,y1,X2+1),
+					  t0(X1-1,y1+1,X2+1),t0(X1+1,y1+1,X2+1),
+					  s0(X1,y1,X2),
+					  s0(X1,y1+1,X2),s0(X1,y1+1,X2+1),s0(X1,y1,X2+1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nxy] < 1.e9 && X2>0 && X1>x1+1 && X1<x2-1 )  {
+			      try = fdhne(t0(X1,y1+1,X2),t0(X1,y1+1,X2-1),t0(X1,y1,X2-1),
+					  t0(X1-1,y1+1,X2-1),t0(X1+1,y1+1,X2-1),
+					  s0(X1,y1,X2),
+					  s0(X1,y1+1,X2),s0(X1,y1+1,X2-1),s0(X1,y1,X2-1) );
+			    if (try<guess)  guess = try;
+			  }
+		        } 
+			  if(time0[index+1] < 1.e9 && X1<nx-1 )  {
+			    try = fdh2d(t0(X1,y1+1,X2),t0(X1+1,y1+1,X2),t0(X1+1,y1,X2),
+					  s0(X1,y1,X2),
+					  s0(X1,y1+1,X2),s0(X1+1,y1+1,X2),s0(X1+1,y1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-1] < 1.e9 && X1>0 )  {
+			    try = fdh2d(t0(X1,y1+1,X2),t0(X1-1,y1+1,X2),t0(X1-1,y1,X2),
+					  s0(X1,y1,X2),
+					  s0(X1,y1+1,X2),s0(X1-1,y1+1,X2),s0(X1-1,y1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nxy] < 1.e9 && X2<nz-1 )  {
+			    try = fdh2d(t0(X1,y1+1,X2),t0(X1,y1+1,X2+1),t0(X1,y1,X2+1),
+					  s0(X1,y1,X2),
+					  s0(X1,y1+1,X2),s0(X1,y1+1,X2+1),s0(X1,y1,X2+1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nxy] < 1.e9 && X2>0 )  {
+			    try = fdh2d(t0(X1,y1+1,X2),t0(X1,y1+1,X2-1),t0(X1,y1,X2-1),
+					  s0(X1,y1,X2),
+					  s0(X1,y1+1,X2),s0(X1,y1+1,X2-1),s0(X1,y1,X2-1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+1] < 1.e9 && time0[index+nxy+1] < 1.e9
+			     && time0[index+nxy] < 1.e9 && X2<nz-1  && X1<nx-1 ) {
+			    try = fdh2d(t0(X1+1,y1,X2),t0(X1+1,y1,X2+1),t0(X1,y1,X2+1),
+					s0(X1,y1,X2),
+					s0(X1+1,y1,X2),s0(X1+1,y1,X2+1),s0(X1,y1,X2+1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index+1] < 1.e9 && time0[index-nxy+1] < 1.e9
+			     && time0[index-nxy] < 1.e9 && X2>0  && X1<nx-1 ) {
+			    try = fdh2d(t0(X1+1,y1,X2),t0(X1+1,y1,X2-1),t0(X1,y1,X2-1),
+					s0(X1,y1,X2),
+					s0(X1+1,y1,X2),s0(X1+1,y1,X2-1),s0(X1,y1,X2-1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-1] < 1.e9 && time0[index+nxy-1] < 1.e9
+			     && time0[index+nxy] < 1.e9 && X2<nz-1  && X1>0 ) {
+			    try = fdh2d(t0(X1-1,y1,X2),t0(X1-1,y1,X2+1),t0(X1,y1,X2+1),
+					s0(X1,y1,X2),
+					s0(X1-1,y1,X2),s0(X1-1,y1,X2+1),s0(X1,y1,X2+1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-1] < 1.e9 && time0[index-nxy-1] < 1.e9
+			     && time0[index-nxy] < 1.e9 && X2>0  && X1>0 ) {
+			    try = fdh2d(t0(X1-1,y1,X2),t0(X1-1,y1,X2-1),t0(X1,y1,X2-1),
+					s0(X1,y1,X2),
+					s0(X1-1,y1,X2),s0(X1-1,y1,X2-1),s0(X1,y1,X2-1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if(guess > 1.0e9){ 
+			  if ( X1>x1+1 && X1<x2-1 && X2>z1+1 && X2<z2-1 ) {
+			    try = fdhnf(t0(X1,y1+1,X2),
+					  t0(X1+1,y1+1,X2),t0(X1,y1+1,X2+1),
+					  t0(X1-1,y1+1,X2),t0(X1,y1+1,X2-1),
+					  s0(X1,y1,X2),
+					  s0(X1,y1+1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			} 
+			  try = t0(X1,y1+1,X2) + .5*(s0(X1,y1,X2)+s0(X1,y1+1,X2));
+			  if (try<guess)  guess = try;
+                          if ( time0[index+1]<1.e9 && X1<nx-1 )  {
+			    try = t0(X1+1,y1,X2) + .5*(s0(X1,y1,X2)+s0(X1+1,y1,X2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-1]<1.e9 && X1>0 )  {
+			    try = t0(X1-1,y1,X2) + .5*(s0(X1,y1,X2)+s0(X1-1,y1,X2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index+nxy]<1.e9 && X2<nz-1 )  {
+			    try = t0(X1,y1,X2+1) + .5*(s0(X1,y1,X2)+s0(X1,y1,X2+1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-nxy]<1.e9 && X2>0 )  {
+			    try = t0(X1,y1,X2-1) + .5*(s0(X1,y1,X2)+s0(X1,y1,X2-1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if (guess<time0[index]) {
+				time0[index] = guess;
+				if (fhead>headtest)  headw[3]++;
+			}
+		}
+		if(y1 == 0) dy1 = 0;
+		y1--;
+	}
+      }
+		/* BACK SIDE */
+      for (igrow=1;igrow<=jplus;igrow++) {  
+	if(dy2){
+		ii = 0;
+		for(k=z1+1; k<=z2-1; k++){
+			for(i=x1+1; i<=x2-1; i++){
+				sort[ii].time = t0(i,y2-1,k);
+				sort[ii].i1 = i;
+				sort[ii].i2 = k;
+				ii++;
+			}
+		}
+		qsort((char *)sort,ii,sizeof(struct sorted),compar);
+		for(i=0;i<ii;i++){
+			X1 = sort[i].i1;
+			X2 = sort[i].i2;
+			index = X2*nxy + y2*nx + X1;
+			lasti = X2*nxy + (y2-1)*nx + X1;
+			fhead = 0.;
+			guess = time0[index];
+			if(time0[index+1] < 1.e9 && time0[index+nxy+1] < 1.e9
+			   && time0[index+nxy] < 1.e9 && X2<nz-1  && X1<nx-1 ) {
+			  try = fdh3d(              t0(X1,y2-1,X2),
+				      t0(X1+1,y2-1,X2),t0(X1+1,y2-1,X2+1),t0(X1,y2-1,X2+1),
+				      t0(X1+1,y2  ,X2),t0(X1+1,y2  ,X2+1),t0(X1,y2  ,X2+1),
+				      s0(X1,y2,X2), s0(X1,y2-1,X2),
+				      s0(X1+1,y2-1,X2),s0(X1+1,y2-1,X2+1),s0(X1,y2-1,X2+1),
+				      s0(X1+1,y2  ,X2),s0(X1+1,y2  ,X2+1),s0(X1,y2  ,X2+1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-1] < 1.e9 && time0[index+nxy-1] < 1.e9
+			   && time0[index+nxy] < 1.e9 && X2<nz-1  && X1>0 ) {
+			  try = fdh3d(              t0(X1,y2-1,X2),
+				      t0(X1-1,y2-1,X2),t0(X1-1,y2-1,X2+1),t0(X1,y2-1,X2+1),
+				      t0(X1-1,y2  ,X2),t0(X1-1,y2  ,X2+1),t0(X1,y2  ,X2+1),
+				      s0(X1,y2,X2), s0(X1,y2-1,X2),
+				      s0(X1-1,y2-1,X2),s0(X1-1,y2-1,X2+1),s0(X1,y2-1,X2+1),
+				      s0(X1-1,y2  ,X2),s0(X1-1,y2  ,X2+1),s0(X1,y2  ,X2+1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index+1] < 1.e9 && time0[index-nxy+1] < 1.e9
+			   && time0[index-nxy] < 1.e9 && X2>0  && X1<nx-1 ) {
+			  try = fdh3d(              t0(X1,y2-1,X2),
+				      t0(X1+1,y2-1,X2),t0(X1+1,y2-1,X2-1),t0(X1,y2-1,X2-1),
+				      t0(X1+1,y2  ,X2),t0(X1+1,y2  ,X2-1),t0(X1,y2  ,X2-1),
+				      s0(X1,y2,X2), s0(X1,y2-1,X2),
+				      s0(X1+1,y2-1,X2),s0(X1+1,y2-1,X2-1),s0(X1,y2-1,X2-1),
+				      s0(X1+1,y2  ,X2),s0(X1+1,y2  ,X2-1),s0(X1,y2  ,X2-1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-1] < 1.e9 && time0[index-nxy-1] < 1.e9
+			   && time0[index-nxy] < 1.e9 && X2>0  && X1>0 ) {
+			  try = fdh3d(              t0(X1,y2-1,X2),
+				      t0(X1-1,y2-1,X2),t0(X1-1,y2-1,X2-1),t0(X1,y2-1,X2-1),
+				      t0(X1-1,y2  ,X2),t0(X1-1,y2  ,X2-1),t0(X1,y2  ,X2-1),
+				      s0(X1,y2,X2), s0(X1,y2-1,X2),
+				      s0(X1-1,y2-1,X2),s0(X1-1,y2-1,X2-1),s0(X1,y2-1,X2-1),
+				      s0(X1-1,y2  ,X2),s0(X1-1,y2  ,X2-1),s0(X1,y2  ,X2-1));
+			  if (try<guess) guess = try;
+			}
+			if(guess > 1.0e9){ 
+			  if(time0[index+1] < 1.e9 && X1<nx-1 && X2>z1+1 && X2<z2-1 )  {
+			      try = fdhne(t0(X1,y2-1,X2),t0(X1+1,y2-1,X2),t0(X1+1,y2,X2),
+					  t0(X1+1,y2-1,X2-1),t0(X1+1,y2-1,X2+1),
+					  s0(X1,y2,X2),
+					  s0(X1,y2-1,X2),s0(X1+1,y2-1,X2),s0(X1+1,y2,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-1] < 1.e9 && X1>0 && X2>z1+1 && X2<z2-1 )  {
+			      try = fdhne(t0(X1,y2-1,X2),t0(X1-1,y2-1,X2),t0(X1-1,y2,X2),
+					  t0(X1-1,y2-1,X2-1),t0(X1-1,y2-1,X2+1),
+					  s0(X1,y2,X2),
+					  s0(X1,y2-1,X2),s0(X1-1,y2-1,X2),s0(X1-1,y2,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nxy] < 1.e9 && X2<nz-1 && X1>x1+1 && X1<x2-1 )  {
+			      try = fdhne(t0(X1,y2-1,X2),t0(X1,y2-1,X2+1),t0(X1,y2,X2+1),
+					  t0(X1-1,y2-1,X2+1),t0(X1+1,y2-1,X2+1),
+					  s0(X1,y2,X2),
+					  s0(X1,y2-1,X2),s0(X1,y2-1,X2+1),s0(X1,y2,X2+1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nxy] < 1.e9 && X2>0 && X1>x1+1 && X1<x2-1 )  {
+			      try = fdhne(t0(X1,y2-1,X2),t0(X1,y2-1,X2-1),t0(X1,y2,X2-1),
+					  t0(X1-1,y2-1,X2-1),t0(X1+1,y2-1,X2-1),
+					  s0(X1,y2,X2),
+					  s0(X1,y2-1,X2),s0(X1,y2-1,X2-1),s0(X1,y2,X2-1) );
+			    if (try<guess)  guess = try;
+			  }
+		        } 
+			  if(time0[index+1] < 1.e9 && X1<nx-1 )  {
+			    try = fdh2d(t0(X1,y2-1,X2),t0(X1+1,y2-1,X2),t0(X1+1,y2,X2),
+					  s0(X1,y2,X2),
+					  s0(X1,y2-1,X2),s0(X1+1,y2-1,X2),s0(X1+1,y2,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-1] < 1.e9 && X1>0 )  {
+			    try = fdh2d(t0(X1,y2-1,X2),t0(X1-1,y2-1,X2),t0(X1-1,y2,X2),
+					  s0(X1,y2,X2),
+					  s0(X1,y2-1,X2),s0(X1-1,y2-1,X2),s0(X1-1,y2,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nxy] < 1.e9 && X2<nz-1 )  {
+			    try = fdh2d(t0(X1,y2-1,X2),t0(X1,y2-1,X2+1),t0(X1,y2,X2+1),
+					  s0(X1,y2,X2),
+					  s0(X1,y2-1,X2),s0(X1,y2-1,X2+1),s0(X1,y2,X2+1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nxy] < 1.e9 && X2>0 )  {
+			    try = fdh2d(t0(X1,y2-1,X2),t0(X1,y2-1,X2-1),t0(X1,y2,X2-1),
+					  s0(X1,y2,X2),
+					  s0(X1,y2-1,X2),s0(X1,y2-1,X2-1),s0(X1,y2,X2-1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+1] < 1.e9 && time0[index+nxy+1] < 1.e9
+			     && time0[index+nxy] < 1.e9 && X2<nz-1  && X1<nx-1 ) {
+			    try = fdh2d(t0(X1+1,y2,X2),t0(X1+1,y2,X2+1),t0(X1,y2,X2+1),
+					s0(X1,y2,X2),
+					s0(X1+1,y2,X2),s0(X1+1,y2,X2+1),s0(X1,y2,X2+1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index+1] < 1.e9 && time0[index-nxy+1] < 1.e9
+			     && time0[index-nxy] < 1.e9 && X2>0  && X1<nx-1 ) {
+			    try = fdh2d(t0(X1+1,y2,X2),t0(X1+1,y2,X2-1),t0(X1,y2,X2-1),
+					s0(X1,y2,X2),
+					s0(X1+1,y2,X2),s0(X1+1,y2,X2-1),s0(X1,y2,X2-1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-1] < 1.e9 && time0[index+nxy-1] < 1.e9
+			     && time0[index+nxy] < 1.e9 && X2<nz-1  && X1>0 ) {
+			    try = fdh2d(t0(X1-1,y2,X2),t0(X1-1,y2,X2+1),t0(X1,y2,X2+1),
+					s0(X1,y2,X2),
+					s0(X1-1,y2,X2),s0(X1-1,y2,X2+1),s0(X1,y2,X2+1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-1] < 1.e9 && time0[index-nxy-1] < 1.e9
+			     && time0[index-nxy] < 1.e9 && X2>0  && X1>0 ) {
+			    try = fdh2d(t0(X1-1,y2,X2),t0(X1-1,y2,X2-1),t0(X1,y2,X2-1),
+					s0(X1,y2,X2),
+					s0(X1-1,y2,X2),s0(X1-1,y2,X2-1),s0(X1,y2,X2-1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if(guess > 1.0e9){ 
+			  if ( X1>x1+1 && X1<x2-1 && X2>z1+1 && X2<z2-1 ) {
+			    try = fdhnf(t0(X1,y2-1,X2),
+					  t0(X1+1,y2-1,X2),t0(X1,y2-1,X2+1),
+					  t0(X1-1,y2-1,X2),t0(X1,y2-1,X2-1),
+					  s0(X1,y2,X2),
+					  s0(X1,y2-1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			} 
+			  try = t0(X1,y2-1,X2) + .5*(s0(X1,y2,X2)+s0(X1,y2-1,X2));
+			  if (try<guess)  guess = try;
+                          if ( time0[index+1]<1.e9 && X1<nx-1 )  {
+			    try = t0(X1+1,y2,X2) + .5*(s0(X1,y2,X2)+s0(X1+1,y2,X2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-1]<1.e9 && X1>0 )  {
+			    try = t0(X1-1,y2,X2) + .5*(s0(X1,y2,X2)+s0(X1-1,y2,X2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index+nxy]<1.e9 && X2<nz-1 )  {
+			    try = t0(X1,y2,X2+1) + .5*(s0(X1,y2,X2)+s0(X1,y2,X2+1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-nxy]<1.e9 && X2>0 )  {
+			    try = t0(X1,y2,X2-1) + .5*(s0(X1,y2,X2)+s0(X1,y2,X2-1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if (guess<time0[index]) {
+				time0[index] = guess;
+				if (fhead>headtest)  headw[4]++;
+			}
+		}
+		if(y2 == ny-1) dy2 = 0;
+		y2++;
+	}
+      }
+		/* LEFT SIDE */
+      for (igrow=1;igrow<=iminus;igrow++) {  
+	if(dx1){
+		ii = 0;
+		for(k=z1+1; k<=z2-1; k++){
+			for(j=y1+1; j<=y2-1; j++){
+				sort[ii].time = t0(x1+1,j,k);
+				sort[ii].i1 = j;
+				sort[ii].i2 = k;
+				ii++;
+			}
+		}
+		qsort((char *)sort,ii,sizeof(struct sorted),compar);
+		for(i=0;i<ii;i++){
+			X1 = sort[i].i1;
+			X2 = sort[i].i2;
+			index = X2*nxy + X1*nx + x1;
+			lasti = X2*nxy + X1*nx + (x1+1);
+			fhead = 0.;
+			guess = time0[index];
+			if(time0[index+nx] < 1.e9 && time0[index+nxy+nx] < 1.e9
+			   && time0[index+nxy] < 1.e9 && X2<nz-1  && X1<ny-1 ) {
+			  try = fdh3d(              t0(x1+1,X1,X2),
+				      t0(x1+1,X1+1,X2),t0(x1+1,X1+1,X2+1),t0(x1+1,X1,X2+1),
+				      t0(x1  ,X1+1,X2),t0(x1  ,X1+1,X2+1),t0(x1  ,X1,X2+1),
+				      s0(x1,X1,X2), s0(x1+1,X1,X2),
+				      s0(x1+1,X1+1,X2),s0(x1+1,X1+1,X2+1),s0(x1+1,X1,X2+1),
+				      s0(x1  ,X1+1,X2),s0(x1  ,X1+1,X2+1),s0(x1  ,X1,X2+1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-nx] < 1.e9 && time0[index+nxy-nx] < 1.e9
+			   && time0[index+nxy] < 1.e9 && X2<nz-1  && X1>0 ) {
+			  try = fdh3d(              t0(x1+1,X1,X2),
+				      t0(x1+1,X1-1,X2),t0(x1+1,X1-1,X2+1),t0(x1+1,X1,X2+1),
+				      t0(x1  ,X1-1,X2),t0(x1  ,X1-1,X2+1),t0(x1  ,X1,X2+1),
+				      s0(x1,X1,X2), s0(x1+1,X1,X2),
+				      s0(x1+1,X1-1,X2),s0(x1+1,X1-1,X2+1),s0(x1+1,X1,X2+1),
+				      s0(x1  ,X1-1,X2),s0(x1  ,X1-1,X2+1),s0(x1  ,X1,X2+1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index+nx] < 1.e9 && time0[index-nxy+nx] < 1.e9
+			   && time0[index-nxy] < 1.e9 && X2>0  && X1<ny-1 ) {
+			  try = fdh3d(              t0(x1+1,X1,X2),
+				      t0(x1+1,X1+1,X2),t0(x1+1,X1+1,X2-1),t0(x1+1,X1,X2-1),
+				      t0(x1  ,X1+1,X2),t0(x1  ,X1+1,X2-1),t0(x1  ,X1,X2-1),
+				      s0(x1,X1,X2), s0(x1+1,X1,X2),
+				      s0(x1+1,X1+1,X2),s0(x1+1,X1+1,X2-1),s0(x1+1,X1,X2-1),
+				      s0(x1  ,X1+1,X2),s0(x1  ,X1+1,X2-1),s0(x1  ,X1,X2-1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-nx] < 1.e9 && time0[index-nxy-nx] < 1.e9
+			   && time0[index-nxy] < 1.e9 && X2>0  && X1>0 ) {
+			  try = fdh3d(              t0(x1+1,X1,X2),
+				      t0(x1+1,X1-1,X2),t0(x1+1,X1-1,X2-1),t0(x1+1,X1,X2-1),
+				      t0(x1  ,X1-1,X2),t0(x1  ,X1-1,X2-1),t0(x1  ,X1,X2-1),
+				      s0(x1,X1,X2), s0(x1+1,X1,X2),
+				      s0(x1+1,X1-1,X2),s0(x1+1,X1-1,X2-1),s0(x1+1,X1,X2-1),
+				      s0(x1  ,X1-1,X2),s0(x1  ,X1-1,X2-1),s0(x1  ,X1,X2-1));
+			  if (try<guess) guess = try;
+			}
+			if(guess > 1.0e9){ 
+			  if(time0[index+nx] < 1.e9 && X1<ny-1 && X2>z1+1 && X2<z2-1 )  {
+			      try = fdhne(t0(x1+1,X1,X2),t0(x1+1,X1+1,X2),t0(x1,X1+1,X2),
+					  t0(x1+1,X1+1,X2-1),t0(x1+1,X1+1,X2+1),
+					  s0(x1,X1,X2),
+					  s0(x1+1,X1,X2),s0(x1+1,X1+1,X2),s0(x1,X1+1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nx] < 1.e9 && X1>0 && X2>z1+1 && X2<z2-1 )  {
+			      try = fdhne(t0(x1+1,X1,X2),t0(x1+1,X1-1,X2),t0(x1,X1-1,X2),
+					  t0(x1+1,X1-1,X2-1),t0(x1+1,X1-1,X2+1),
+					  s0(x1,X1,X2),
+					  s0(x1+1,X1,X2),s0(x1+1,X1-1,X2),s0(x1,X1-1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nxy] < 1.e9 && X2<nz-1 && X1>y1+1 && X1<y2-1 )  {
+			      try = fdhne(t0(x1+1,X1,X2),t0(x1+1,X1,X2+1),t0(x1,X1,X2+1),
+					  t0(x1+1,X1-1,X2+1),t0(x1+1,X1+1,X2+1),
+					  s0(x1,X1,X2),
+					  s0(x1+1,X1,X2),s0(x1+1,X1,X2+1),s0(x1,X1,X2+1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nxy] < 1.e9 && X2>0 && X1>y1+1 && X1<y2-1 )  {
+			      try = fdhne(t0(x1+1,X1,X2),t0(x1+1,X1,X2-1),t0(x1,X1,X2-1),
+					  t0(x1+1,X1-1,X2-1),t0(x1+1,X1+1,X2-1),
+					  s0(x1,X1,X2),
+					  s0(x1+1,X1,X2),s0(x1+1,X1,X2-1),s0(x1,X1,X2-1) );
+			    if (try<guess)  guess = try;
+			  }
+		        } 
+			  if(time0[index+nx] < 1.e9 && X1<ny-1 )  {
+			    try = fdh2d(t0(x1+1,X1,X2),t0(x1+1,X1+1,X2),t0(x1,X1+1,X2),
+					  s0(x1,X1,X2),
+					  s0(x1+1,X1,X2),s0(x1+1,X1+1,X2),s0(x1,X1+1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nx] < 1.e9 && X1>0 )  {
+			    try = fdh2d(t0(x1+1,X1,X2),t0(x1+1,X1-1,X2),t0(x1,X1-1,X2),
+					  s0(x1,X1,X2),
+					  s0(x1+1,X1,X2),s0(x1+1,X1-1,X2),s0(x1,X1-1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nxy] < 1.e9 && X2<nz-1 )  {
+			    try = fdh2d(t0(x1+1,X1,X2),t0(x1+1,X1,X2+1),t0(x1,X1,X2+1),
+					  s0(x1,X1,X2),
+					  s0(x1+1,X1,X2),s0(x1+1,X1,X2+1),s0(x1,X1,X2+1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nxy] < 1.e9 && X2>0 )  {
+			    try = fdh2d(t0(x1+1,X1,X2),t0(x1+1,X1,X2-1),t0(x1,X1,X2-1),
+					  s0(x1,X1,X2),
+					  s0(x1+1,X1,X2),s0(x1+1,X1,X2-1),s0(x1,X1,X2-1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nx] < 1.e9 && time0[index+nxy+nx] < 1.e9
+			     && time0[index+nxy] < 1.e9 && X2<nz-1  && X1<ny-1 ) {
+			    try = fdh2d(t0(x1,X1+1,X2),t0(x1,X1+1,X2+1),t0(x1,X1,X2+1),
+					s0(x1,X1,X2),
+					s0(x1,X1+1,X2),s0(x1,X1+1,X2+1),s0(x1,X1,X2+1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index+nx] < 1.e9 && time0[index-nxy+nx] < 1.e9
+			     && time0[index-nxy] < 1.e9 && X2>0  && X1<ny-1 ) {
+			    try = fdh2d(t0(x1,X1+1,X2),t0(x1,X1+1,X2-1),t0(x1,X1,X2-1),
+					s0(x1,X1,X2),
+					s0(x1,X1+1,X2),s0(x1,X1+1,X2-1),s0(x1,X1,X2-1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-nx] < 1.e9 && time0[index+nxy-nx] < 1.e9
+			     && time0[index+nxy] < 1.e9 && X2<nz-1  && X1>0 ) {
+			    try = fdh2d(t0(x1,X1-1,X2),t0(x1,X1-1,X2+1),t0(x1,X1,X2+1),
+					s0(x1,X1,X2),
+					s0(x1,X1-1,X2),s0(x1,X1-1,X2+1),s0(x1,X1,X2+1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-nx] < 1.e9 && time0[index-nxy-nx] < 1.e9
+			     && time0[index-nxy] < 1.e9 && X2>0  && X1>0 ) {
+			    try = fdh2d(t0(x1,X1-1,X2),t0(x1,X1-1,X2-1),t0(x1,X1,X2-1),
+					s0(x1,X1,X2),
+					s0(x1,X1-1,X2),s0(x1,X1-1,X2-1),s0(x1,X1,X2-1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if(guess > 1.0e9){ 
+			  if ( X1>y1+1 && X1<y2-1 && X2>z1+1 && X2<z2-1 ) {
+			    try = fdhnf(t0(x1+1,X1,X2),
+					  t0(x1+1,X1+1,X2),t0(x1+1,X1,X2+1),
+					  t0(x1+1,X1-1,X2),t0(x1+1,X1,X2-1),
+					  s0(x1,X1,X2),
+					  s0(x1+1,X1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			} 
+			  try = t0(x1+1,X1,X2) + .5*(s0(x1,X1,X2)+s0(x1+1,X1,X2));
+			  if (try<guess)  guess = try;
+                          if ( time0[index+nx]<1.e9 && X1<ny-1 )  {
+			    try = t0(x1,X1+1,X2) + .5*(s0(x1,X1,X2)+s0(x1,X1+1,X2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-nx]<1.e9 && X1>0 )  {
+			    try = t0(x1,X1-1,X2) + .5*(s0(x1,X1,X2)+s0(x1,X1-1,X2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index+nxy]<1.e9 && X2<nz-1 )  {
+			    try = t0(x1,X1,X2+1) + .5*(s0(x1,X1,X2)+s0(x1,X1,X2+1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-nxy]<1.e9 && X2>0 )  {
+			    try = t0(x1,X1,X2-1) + .5*(s0(x1,X1,X2)+s0(x1,X1,X2-1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if (guess<time0[index]) {
+				time0[index] = guess;
+				if (fhead>headtest)  headw[1]++;
+			}
+		}
+		if(x1 == 0) dx1 = 0;
+		x1--;
+	}
+      }
+		/* RIGHT SIDE */
+      for (igrow=1;igrow<=iplus;igrow++) {  
+	if(dx2){
+		ii = 0;
+		for(k=z1+1; k<=z2-1; k++){
+			for(j=y1+1; j<=y2-1; j++){
+				sort[ii].time = t0(x2-1,j,k);
+				sort[ii].i1 = j;
+				sort[ii].i2 = k;
+				ii++;
+			}
+		}
+		qsort((char *)sort,ii,sizeof(struct sorted),compar);
+		for(i=0;i<ii;i++){
+			X1 = sort[i].i1;
+			X2 = sort[i].i2;
+			index = X2*nxy + X1*nx + x2;
+			lasti = X2*nxy + X1*nx + (x2-1);
+			fhead = 0.;
+			guess = time0[index];
+			if(time0[index+nx] < 1.e9 && time0[index+nxy+nx] < 1.e9
+			   && time0[index+nxy] < 1.e9 && X2<nz-1  && X1<ny-1 ) {
+			  try = fdh3d(              t0(x2-1,X1,X2),
+				      t0(x2-1,X1+1,X2),t0(x2-1,X1+1,X2+1),t0(x2-1,X1,X2+1),
+				      t0(x2  ,X1+1,X2),t0(x2  ,X1+1,X2+1),t0(x2  ,X1,X2+1),
+				      s0(x2,X1,X2), s0(x2-1,X1,X2),
+				      s0(x2-1,X1+1,X2),s0(x2-1,X1+1,X2+1),s0(x2-1,X1,X2+1),
+				      s0(x2  ,X1+1,X2),s0(x2  ,X1+1,X2+1),s0(x2  ,X1,X2+1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-nx] < 1.e9 && time0[index+nxy-nx] < 1.e9
+			   && time0[index+nxy] < 1.e9 && X2<nz-1  && X1>0 ) {
+			  try = fdh3d(              t0(x2-1,X1,X2),
+				      t0(x2-1,X1-1,X2),t0(x2-1,X1-1,X2+1),t0(x2-1,X1,X2+1),
+				      t0(x2  ,X1-1,X2),t0(x2  ,X1-1,X2+1),t0(x2  ,X1,X2+1),
+				      s0(x2,X1,X2), s0(x2-1,X1,X2),
+				      s0(x2-1,X1-1,X2),s0(x2-1,X1-1,X2+1),s0(x2-1,X1,X2+1),
+				      s0(x2  ,X1-1,X2),s0(x2  ,X1-1,X2+1),s0(x2  ,X1,X2+1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index+nx] < 1.e9 && time0[index-nxy+nx] < 1.e9
+			   && time0[index-nxy] < 1.e9 && X2>0  && X1<ny-1 ) {
+			  try = fdh3d(              t0(x2-1,X1,X2),
+				      t0(x2-1,X1+1,X2),t0(x2-1,X1+1,X2-1),t0(x2-1,X1,X2-1),
+				      t0(x2  ,X1+1,X2),t0(x2  ,X1+1,X2-1),t0(x2  ,X1,X2-1),
+				      s0(x2,X1,X2), s0(x2-1,X1,X2),
+				      s0(x2-1,X1+1,X2),s0(x2-1,X1+1,X2-1),s0(x2-1,X1,X2-1),
+				      s0(x2  ,X1+1,X2),s0(x2  ,X1+1,X2-1),s0(x2  ,X1,X2-1));
+			  if (try<guess) guess = try;
+			}
+			if(time0[index-nx] < 1.e9 && time0[index-nxy-nx] < 1.e9
+			   && time0[index-nxy] < 1.e9 && X2>0  && X1>0 ) {
+			  try = fdh3d(              t0(x2-1,X1,X2),
+				      t0(x2-1,X1-1,X2),t0(x2-1,X1-1,X2-1),t0(x2-1,X1,X2-1),
+				      t0(x2  ,X1-1,X2),t0(x2  ,X1-1,X2-1),t0(x2  ,X1,X2-1),
+				      s0(x2,X1,X2), s0(x2-1,X1,X2),
+				      s0(x2-1,X1-1,X2),s0(x2-1,X1-1,X2-1),s0(x2-1,X1,X2-1),
+				      s0(x2  ,X1-1,X2),s0(x2  ,X1-1,X2-1),s0(x2  ,X1,X2-1));
+			  if (try<guess) guess = try;
+			}
+			if(guess > 1.0e9){ 
+			  if(time0[index+nx] < 1.e9 && X1<ny-1 && X2>z1+1 && X2<z2-1 )  {
+			      try = fdhne(t0(x2-1,X1,X2),t0(x2-1,X1+1,X2),t0(x2,X1+1,X2),
+					  t0(x2-1,X1+1,X2-1),t0(x2-1,X1+1,X2+1),
+					  s0(x2,X1,X2),
+					  s0(x2-1,X1,X2),s0(x2-1,X1+1,X2),s0(x2,X1+1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nx] < 1.e9 && X1>0 && X2>z1+1 && X2<z2-1 )  {
+			      try = fdhne(t0(x2-1,X1,X2),t0(x2-1,X1-1,X2),t0(x2,X1-1,X2),
+					  t0(x2-1,X1-1,X2-1),t0(x2-1,X1-1,X2+1),
+					  s0(x2,X1,X2),
+					  s0(x2-1,X1,X2),s0(x2-1,X1-1,X2),s0(x2,X1-1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nxy] < 1.e9 && X2<nz-1 && X1>y1+1 && X1<y2-1 )  {
+			      try = fdhne(t0(x2-1,X1,X2),t0(x2-1,X1,X2+1),t0(x2,X1,X2+1),
+					  t0(x2-1,X1-1,X2+1),t0(x2-1,X1+1,X2+1),
+					  s0(x2,X1,X2),
+					  s0(x2-1,X1,X2),s0(x2-1,X1,X2+1),s0(x2,X1,X2+1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nxy] < 1.e9 && X2>0 && X1>y1+1 && X1<y2-1 )  {
+			      try = fdhne(t0(x2-1,X1,X2),t0(x2-1,X1,X2-1),t0(x2,X1,X2-1),
+					  t0(x2-1,X1-1,X2-1),t0(x2-1,X1+1,X2-1),
+					  s0(x2,X1,X2),
+					  s0(x2-1,X1,X2),s0(x2-1,X1,X2-1),s0(x2,X1,X2-1) );
+			    if (try<guess)  guess = try;
+			  }
+		        } 
+			  if(time0[index+nx] < 1.e9 && X1<ny-1 )  {
+			    try = fdh2d(t0(x2-1,X1,X2),t0(x2-1,X1+1,X2),t0(x2,X1+1,X2),
+					  s0(x2,X1,X2),
+					  s0(x2-1,X1,X2),s0(x2-1,X1+1,X2),s0(x2,X1+1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nx] < 1.e9 && X1>0 )  {
+			    try = fdh2d(t0(x2-1,X1,X2),t0(x2-1,X1-1,X2),t0(x2,X1-1,X2),
+					  s0(x2,X1,X2),
+					  s0(x2-1,X1,X2),s0(x2-1,X1-1,X2),s0(x2,X1-1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nxy] < 1.e9 && X2<nz-1 )  {
+			    try = fdh2d(t0(x2-1,X1,X2),t0(x2-1,X1,X2+1),t0(x2,X1,X2+1),
+					  s0(x2,X1,X2),
+					  s0(x2-1,X1,X2),s0(x2-1,X1,X2+1),s0(x2,X1,X2+1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index-nxy] < 1.e9 && X2>0 )  {
+			    try = fdh2d(t0(x2-1,X1,X2),t0(x2-1,X1,X2-1),t0(x2,X1,X2-1),
+					  s0(x2,X1,X2),
+					  s0(x2-1,X1,X2),s0(x2-1,X1,X2-1),s0(x2,X1,X2-1) );
+			    if (try<guess)  guess = try;
+			  }
+			  if(time0[index+nx] < 1.e9 && time0[index+nxy+nx] < 1.e9
+			     && time0[index+nxy] < 1.e9 && X2<nz-1  && X1<ny-1 ) {
+			    try = fdh2d(t0(x2,X1+1,X2),t0(x2,X1+1,X2+1),t0(x2,X1,X2+1),
+					s0(x2,X1,X2),
+					s0(x2,X1+1,X2),s0(x2,X1+1,X2+1),s0(x2,X1,X2+1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index+nx] < 1.e9 && time0[index-nxy+nx] < 1.e9
+			     && time0[index-nxy] < 1.e9 && X2>0  && X1<ny-1 ) {
+			    try = fdh2d(t0(x2,X1+1,X2),t0(x2,X1+1,X2-1),t0(x2,X1,X2-1),
+					s0(x2,X1,X2),
+					s0(x2,X1+1,X2),s0(x2,X1+1,X2-1),s0(x2,X1,X2-1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-nx] < 1.e9 && time0[index+nxy-nx] < 1.e9
+			     && time0[index+nxy] < 1.e9 && X2<nz-1  && X1>0 ) {
+			    try = fdh2d(t0(x2,X1-1,X2),t0(x2,X1-1,X2+1),t0(x2,X1,X2+1),
+					s0(x2,X1,X2),
+					s0(x2,X1-1,X2),s0(x2,X1-1,X2+1),s0(x2,X1,X2+1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if(time0[index-nx] < 1.e9 && time0[index-nxy-nx] < 1.e9
+			     && time0[index-nxy] < 1.e9 && X2>0  && X1>0 ) {
+			    try = fdh2d(t0(x2,X1-1,X2),t0(x2,X1-1,X2-1),t0(x2,X1,X2-1),
+					s0(x2,X1,X2),
+					s0(x2,X1-1,X2),s0(x2,X1-1,X2-1),s0(x2,X1,X2-1) );
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if(guess > 1.0e9){ 
+			  if ( X1>y1+1 && X1<y2-1 && X2>z1+1 && X2<z2-1 ) {
+			    try = fdhnf(t0(x2-1,X1,X2),
+					  t0(x2-1,X1+1,X2),t0(x2-1,X1,X2+1),
+					  t0(x2-1,X1-1,X2),t0(x2-1,X1,X2-1),
+					  s0(x2,X1,X2),
+					  s0(x2-1,X1,X2) );
+			    if (try<guess)  guess = try;
+			  }
+			} 
+			  try = t0(x2-1,X1,X2) + .5*(s0(x2,X1,X2)+s0(x2-1,X1,X2));
+			  if (try<guess)  guess = try;
+                          if ( time0[index+nx]<1.e9 && X1<ny-1 )  {
+			    try = t0(x2,X1+1,X2) + .5*(s0(x2,X1,X2)+s0(x2,X1+1,X2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-nx]<1.e9 && X1>0 )  {
+			    try = t0(x2,X1-1,X2) + .5*(s0(x2,X1,X2)+s0(x2,X1-1,X2));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index+nxy]<1.e9 && X2<nz-1 )  {
+			    try = t0(x2,X1,X2+1) + .5*(s0(x2,X1,X2)+s0(x2,X1,X2+1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			  if ( time0[index-nxy]<1.e9 && X2>0 )  {
+			    try = t0(x2,X1,X2-1) + .5*(s0(x2,X1,X2)+s0(x2,X1,X2-1));
+			    if (try<guess)  {fhead=(guess-try)/slow0[index]; guess=try;}
+			  }
+			if (guess<time0[index]) {
+				time0[index] = guess;
+				if (fhead>headtest)  headw[2]++;
+			}
+		}
+		if(x2 == nx-1) dx2 = 0;
+		x2++;
+	}
+      }
+
+		/* UPDATE RADIUS */
+		radius++;
+		if(radius%10 == 0 && verbose) samess("Completed radius = %d",radius);
+        if(radius == maxrad) rad0 = 0;
+
+	}	/* END BIG LOOP */
+
+
+	/* TEST IF REVERSE PROPAGATION IS NEEDED */
+
+	if (headw[1]==0 && headw[2]==0 && headw[3]==0 && headw[4]==0 
+		     && headw[5]==0 && headw[6]==0)
+		reverse=0;
+	else {
+		head=0;
+		if (headw[1]>0) {
+			if(verbose) samess("Head waves found on left: %d",headw[1]);
+			if (headw[1]>head)  {
+				head = headw[1];
+				srcwall = 1;
+			}
+		}
+		if (headw[2]>0) {
+			if(verbose) samess("Head waves found on right: %d",headw[2]);
+			if (headw[2]>head)  {
+				head = headw[2];
+				srcwall = 2;
+			}
+		}
+		if (headw[3]>0) {
+			if(verbose) samess("Head waves found on front: %d",headw[3]);
+			if (headw[3]>head)  {
+				head = headw[3];
+				srcwall = 3;
+			}
+		}
+		if (headw[4]>0) {
+			if(verbose) samess("Head waves found on back: %d",headw[4]);
+			if (headw[4]>head)  {
+				head = headw[4];
+				srcwall = 4;
+			}
+		}
+		if (headw[5]>0) {
+			if(verbose) samess("Head waves found on top: %d",headw[5]);
+			if (headw[5]>head)  {
+				head = headw[5];
+				srcwall = 5;
+			}
+		}
+		if (headw[6]>0) {
+			if(verbose) samess("Head waves found on bottom: %d",headw[6]);
+			if (headw[6]>head)  {
+				head = headw[6];
+				srcwall = 6;
+			}
+		}
+		if (headpref>0 && headw[headpref]>0) {
+			if(verbose) 
+				samess("Preference to restart on wall opposite source");
+			srcwall = headpref;
+		}
+		/* SET LOCATIONS OF SIDES OF THE CUBE SO THAT CUBE IS A FACE */
+		dx1=1; dx2=1; dy1=1; dy2=1; dz1=1; dz2=1; rad0=1;
+		radius = 1;
+		if (srcwall == 1)	{  x2=1;
+			samess("RESTART at left side of model");  }
+		else	{  x2=nx;	dx2=0;  }
+		if (srcwall == 2)	{ x1=nx-2;
+			samess("RESTART at right side of model");  }
+		else	{  x1= -1;	dx1=0;  }
+		if (srcwall == 3)	{ y2=1;
+			samess("RESTART at front side of model");  }
+		else	{  y2=ny;	dy2=0;  }
+		if (srcwall == 4)	{ y1=ny-2;
+			samess("RESTART at back side of model");  }
+		else	{  y1= -1;	dy1=0;  }
+		if (srcwall == 5)	{ z2=1;
+			samess("RESTART at top side of model");  }
+		else	{  z2=nz;	dz2=0;  }
+		if (srcwall == 6)	{ z1=nz-2;
+			samess("RESTART at bottom side of model");  }
+		else	{  z1= -1;	dz1=0;  }
+		if (reverse == 0)  
+			sawarn("RESTART CANCELLED by choice of input parameter `reverse`");
+	}
+	reverse--;
+
+	}	/* END BIGGER LOOP - HOLE */
+
+	free(sort);
+	free(wall);
+}
+
+int compar(struct sorted *a,struct sorted *b)
+{
+	if(a->time > b->time) return(1);
+	if(b->time > a->time) return(-1);
+	else return(0);
+}
+
+
+/* 3D TRANSMISSION STENCIL
+   STENCIL FROM VIDALE; CONDITIONS AND OTHER OPTIONS FROM HOLE
+   JAH 11/91 */
+float fdh3d(t1,t2,t3,t4,t5,t6,t7,ss0,s1,s2,s3,s4,s5,s6,s7)
+     float  t1,t2,t3,t4,t5,t6,t7,ss0,s1,s2,s3,s4,s5,s6,s7;
+     /* ss0 at newpoint; s1,t1 adjacent on oldface;
+	s2,t2 and s4,t4 on oldface adjacent to s1;
+	s3,t3 on oldface diametrically opposite newpoint;
+	s5,t5 on newface adjacent to newpoint AND to s2;
+	s6,t6 on newface diagonal to newpoint (adjacent to s3);
+	s7,t7 on newface adjacent to newpoint AND to s4
+	*/
+{
+  float x,slo;
+  double sqrt();
+  slo = .125*(ss0+s1+s2+s3+s4+s5+s6+s7);
+  x = 6.*slo*slo - (t4-t2)*(t4-t2) - (t2-t6)*(t2-t6) - (t6-t4)*(t6-t4)
+                 - (t7-t5)*(t7-t5) - (t5-t1)*(t5-t1) - (t1-t7)*(t1-t7);
+  if (x>=0.)  {
+    x = t3 + sqrt(.5*x);
+    if ( (x<t1) || (x<t2) || (x<t4) || (x<t5) || (x<t6) || (x<t7) )  
+      x = 1.e11;   /* ACAUSAL; ABORT */
+  }
+  else  x = 1.e11;   /* SQRT IMAGINARY; ABORT */
+  return(x);
+}
+
+/* 3D STENCIL FOR NEW EDGE
+   STENCIL FROM VIDALE; CONDITIONS AND OTHER OPTIONS FROM HOLE
+   JAH 11/91 */
+float fdhne(t1,t2,t3,t4,t5,ss0,s1,s2,s3)
+     float  t1,t2,t3,t4,t5,ss0,s1,s2,s3;
+     /* ss0 at newpoint; s1,t1 adjacent on oldface;
+	s2,t2 diagonal on oldface; s3,t3 adjacent on newface;
+	t4,t5 beside t2 on old face opposite each other */
+{
+  float x,slo;
+  double sqrt();
+  slo = .25*(ss0+s1+s2+s3);
+  x = 2.*slo*slo - (t3-t1)*(t3-t1) - .5*(t5-t4)*(t5-t4);
+  if (x>=0.)  {
+    x = t2 + sqrt(x);
+    if ( (x<t1) || (x<t3) || (x<t4) || (x<t5) )     /* ACAUSAL; ABORT */
+      x = 1.e11;
+  }
+  else  x = 1.e11;   /* SQRT IMAGINARY; ABORT */
+  return(x);
+}
+
+/* 2D TRANSMISSION STENCIL (FOR HEAD WAVES ON FACES OF GRID CELLS)
+   STENCIL FROM VIDALE (1988 2D PAPER); CONDITIONS AND OTHER OPTIONS FROM HOLE
+   JAH 11/91 */
+float fdh2d(t1,t2,t3,ss0,s1,s2,s3)
+     float  t1,t2,t3,ss0,s1,s2,s3;
+     /* ss0 at newpoint; s1,t1 & s3,t3 adjacent; s2,t2 diagonal
+      */
+{
+  float x,slo;
+  double sqrt();
+  slo = .25*(ss0+s1+s2+s3);
+  x = 2.*slo*slo - (t3-t1)*(t3-t1);
+  if (x>=0.)  {
+    x = t2 + sqrt(x);
+    if ( (x<t1) || (x<t3) )  x = 1.e11;   /* ACAUSAL; ABORT */
+  }
+  else  x = 1.e11;   /* SQRT IMAGINARY; ABORT */
+  return(x);
+}
+
+/* 3D STENCIL FOR NEW FACE
+   STENCIL FROM VIDALE; CONDITIONS AND OTHER OPTIONS FROM HOLE
+   JAH 11/91 */
+float fdhnf(t1,t2,t3,t4,t5,ss0,s1)
+     float  t1,t2,t3,t4,t5,ss0,s1;
+     /* ss0 at newpoint; s1,t1 adjacent on old face;
+	t2,t4 beside t1 on old face and opposite each other;
+	t3,t5 beside t1 on old face and opposite each other
+	*/
+{
+  float x,slo;
+  double sqrt();
+  slo = .5*(ss0+s1);
+  x = slo*slo - .25*( (t4-t2)*(t4-t2) + (t5-t3)*(t5-t3) );
+  if (x>=0.)  {
+    x = t1 + sqrt(x);
+    if ( (x<t2) || (x<t3) || (x<t4) || (x<t5) )     /* ACAUSAL; ABORT */
+      x = 1.e11;
+  }
+  else  x = 1.e11;   /* SQRT IMAGINARY; ABORT */
+  return(x);
+}
+
+
diff --git a/raytime3d/wallclock_time.c b/raytime3d/wallclock_time.c
new file mode 100644
index 0000000000000000000000000000000000000000..1e75530ccee3215724badefdd6144c2c59246dbc
--- /dev/null
+++ b/raytime3d/wallclock_time.c
@@ -0,0 +1,33 @@
+#include <time.h>
+#include <sys/time.h>
+#include <stdio.h>
+
+/**
+*  function used to calculate wallclock times
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands 
+**/
+
+double wallclock_time(void)
+{
+	struct timeval s_val;
+	static struct timeval b_val;
+	double time;
+	static int base=0;
+
+	gettimeofday(&s_val,0);
+
+	if (!base) {
+		b_val = s_val;
+		base = 1;
+		return 0.0;
+	}
+
+	time = (double)(s_val.tv_sec-b_val.tv_sec) + 
+		   (double)(1e-6*((double)s_val.tv_usec-(double)b_val.tv_usec));
+
+	return (double)time;
+}
+
diff --git a/raytime3d/writeSrcRecPos.c b/raytime3d/writeSrcRecPos.c
new file mode 100644
index 0000000000000000000000000000000000000000..faf297811e469314c8de0265f78b87543b27af9b
--- /dev/null
+++ b/raytime3d/writeSrcRecPos.c
@@ -0,0 +1,136 @@
+#include<stdlib.h>
+#include<stdio.h>
+#include<math.h>
+#include<assert.h>
+#include"par.h"
+#include"raytime.h"
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define NINT(x) ((int)((x)>0.0?(x)+0.5:(x)-0.5))
+
+/**
+* Writes the source and receiver positions into a gridded file,
+* which has the same size as the input gridded model files. 
+* Source positions have a value +1 and receivers -1.
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands 
+**/
+
+int writesufile(char *filename, float *data, int n1, int n2, float f1, float f2, float d1, float d2);
+
+int writeSrcRecPos(modPar *mod, recPar *rec, srcPar *src, shotPar *shot)
+{
+	FILE *fp;
+	float *dum, sub_x0, sub_z0, dx, dz;
+	int is, nx, nz, is0, ish, ix, iz, ndot, idx, idz;
+	char tmpname[1024];
+
+ 	ndot = 2;
+	nx = mod->nx;
+	nz = mod->nz;
+	dx = mod->dx;
+	dz = mod->dz;
+	sub_x0 = mod->x0;
+	sub_z0 = mod->z0;
+
+//    ibndx = mod.ioPx;
+//    ibndz = mod.ioPz;
+//    if (bnd.lef==4 || bnd.lef==2) ibndx += bnd.ntap;
+//    if (bnd.top==4 || bnd.top==2) ibndz += bnd.ntap;
+
+	/* write velocity field with positions of the sources */
+	dum = (float *)calloc(nx*nz, sizeof(float));
+	vmess("Positions: shot=%d src=%d rec=%d", shot->n, src->n, rec->n);
+	/* source positions for random shots */
+	if (src->random) {
+		sprintf(tmpname,"SrcPositions%d.txt",src->n);
+		fp = fopen(tmpname, "w+");
+		for (is=0; is<src->n; is++) {
+			for (idx=0; idx<=ndot; idx++) {
+				for (idz=0; idz<=ndot; idz++) {
+					dum[(MAX(0,src->x[is]-idx))*nz+MAX(0,src->z[is]-idz)] = 1.0;
+					dum[(MAX(0,src->x[is]-idx))*nz+MIN(nz-1,src->z[is]+idz)] = 1.0;
+					dum[(MIN(nx-1,src->x[is]+idx))*nz+MIN(nz-1,src->z[is]+idz)] = 1.0;
+					dum[(MIN(nx-1,src->x[is]+idx))*nz+MAX(0,src->z[is]-idz)] = 1.0;
+				}
+			}
+			fprintf(fp, "%f %f\n", src->z[is]*dz+sub_z0, src->x[is]*dx+sub_x0);
+		}
+		fclose(fp);
+	}
+	/* source positions for single shot sources with plane waves */
+	else if (src->plane) {
+    	is0 = -1*floor((src->n-1)/2);
+		sprintf(tmpname,"SrcPositions%d.txt",shot->n);
+		fp = fopen(tmpname, "w+");
+		for (ish=0; ish<shot->n; ish++) {
+			for (is=0; is<src->n; is++) {
+				ix = shot->x[ish] + 1 + is0 + is;
+				iz = shot->z[ish] + 1;
+				dum[ix*nz+iz] = 1.0;
+				dum[(MAX(0,ix-1))*nz+iz] = 1.0;
+				dum[(MIN(nx-1,ix+1))*nz+iz] = 1.0;
+				dum[ix*nz+MAX(0,iz-1)] = 1.0;
+				dum[ix*nz+MIN(nz-1,iz+1)] = 1.0;
+				fprintf(fp, "(%f, %f)\n", ix*dx+sub_x0, iz*dz+sub_z0);
+			}
+		}
+		fclose(fp);
+	}
+	else if (src->multiwav) {
+	/* source positions for single shot sources with multiple wavelets */
+		sprintf(tmpname,"SrcPositions%d.txt",shot->n);
+		fp = fopen(tmpname, "w+");
+		for (ish=0; ish<shot->n; ish++) {
+			for (is=0; is<src->n; is++) {
+				ix = src->x[is];
+				iz = src->z[is];
+				dum[ix*nz+iz] = 1.0;
+				dum[(MAX(0,ix-1))*nz+iz] = 1.0;
+				dum[(MIN(nx-1,ix+1))*nz+iz] = 1.0;
+				dum[ix*nz+MAX(0,iz-1)] = 1.0;
+				dum[ix*nz+MIN(nz-1,iz+1)] = 1.0;
+				fprintf(fp, "(%f, %f)\n", ix*dx+sub_x0, iz*dz+sub_z0);
+			}
+		}
+		fclose(fp);
+	}
+	else {
+		sprintf(tmpname,"SrcPositions%d.txt",shot->n);
+		fp = fopen(tmpname, "w+");
+		for (is=0; is<shot->n; is++) {
+			for (idx=0; idx<=ndot; idx++) {
+				for (idz=0; idz<=ndot; idz++) {
+					dum[(MAX(0,shot->x[is]-idx))*nz+MAX(0,shot->z[is]-idz)] = 1.0;
+					dum[(MAX(0,shot->x[is]-idx))*nz+MIN(nz-1,shot->z[is]+idz)] = 1.0;
+					dum[(MIN(nx-1,shot->x[is]+idx))*nz+MIN(nz-1,shot->z[is]+idz)] = 1.0;
+					dum[(MIN(nx-1,shot->x[is]+idx))*nz+MAX(0,shot->z[is]-idz)] = 1.0;
+				}
+			}
+			fprintf(fp, "%f %f\n", shot->z[is]*dz+sub_z0, shot->x[is]*dx+sub_x0);
+		}
+		fclose(fp);
+	}
+
+	/* receiver positions */
+	sprintf(tmpname,"RcvPositions%d.txt",rec->n);
+	fp = fopen(tmpname, "w+");
+	for (is=0; is<rec->n; is++) {
+		dum[rec->x[is]*nz+rec->z[is]] = -1.0;
+		dum[(MAX(0,rec->x[is]-1))*nz+rec->z[is]] = -1.0;
+		dum[(MIN(nx-1,rec->x[is]+1))*nz+rec->z[is]] = -1.0;
+		dum[rec->x[is]*nz+MAX(0,rec->z[is]-1)] = -1.0;
+		dum[rec->x[is]*nz+MIN(nz-1,rec->z[is]+1)] = -1.0;
+
+//		vmess("receiver position %d at grid[ix=%d, iz=%d] = (x=%f z=%f)", ir, ix+ioPx, rec.z[ir]+ioPz, rec.xr[ir]+mod.x0, rec.zr[ir]+mod.z0);
+		fprintf(fp, "(%f, %f)\n", rec->x[is]*dx+sub_x0, rec->z[is]*dz+sub_z0);
+	}
+	fclose(fp);
+	writesufile("SrcRecPositions.su", dum, nz, nx, sub_z0, sub_x0, dz, dx);
+	free(dum);
+
+	return 0;
+}
diff --git a/raytime3d/writesufile.c b/raytime3d/writesufile.c
new file mode 100644
index 0000000000000000000000000000000000000000..6eac57d300aaa653e621b99fe2731c9ed3ddb60a
--- /dev/null
+++ b/raytime3d/writesufile.c
@@ -0,0 +1,169 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include <string.h>
+#include "par.h"
+#include "raytime.h"
+#include "SUsegy.h"
+#include "segy.h"
+
+/**
+*  Writes an 2D array to a SU file
+*
+*   AUTHOR:
+*           Jan Thorbecke (janth@xs4all.nl)
+*           The Netherlands 
+**/
+
+#define TRCBYTES 240
+
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#define ISODD(n) ((n) & 01)
+#define NINT(x) ((int)((x)>0.0?(x)+0.5:(x)-0.5))
+
+int writesufile(char *filename, float *data, int n1, int n2, float f1, float f2, float d1, float d2)
+{
+	FILE    *file_out;
+	size_t  nwrite, itrace;
+	int     ns;
+	segy    *hdr;
+//	char    *ptr;
+
+/* Read in parameters */
+
+//    ptr = strstr(filename, " ");
+//    *ptr = '\0';
+
+	
+	if (n1 > USHRT_MAX) {
+		vwarn("Output file %s: number of samples is truncated from %d to USHRT_MAX.", filename, n1);
+	}
+	ns = MIN(n1,USHRT_MAX);
+
+	file_out = fopen( filename, "w+" );
+	assert( file_out );
+
+	hdr = (segy *)calloc(1,TRCBYTES);
+	hdr->ns = ns;
+	hdr->dt = NINT(1000000*(d1));
+	hdr->d1 = d1;
+	hdr->d2 = d2;
+	hdr->f1 = f1;
+	hdr->f2 = f2;
+	hdr->fldr = 1;
+	hdr->trwf = n2;
+
+	for (itrace=0; itrace<n2; itrace++) {
+		hdr->tracl = itrace+1;
+		nwrite = fwrite( hdr, 1, TRCBYTES, file_out );
+		assert (nwrite == TRCBYTES);
+		nwrite = fwrite( &data[itrace*n1], sizeof(float), ns, file_out );
+		assert (nwrite == ns);
+	} 
+	fclose(file_out);
+	free(hdr);
+
+	return 0;
+}
+
+/**
+*  Writes an 2D array to a SU file
+*  special routine for src_nwav array which has a different number of samples for each shot 
+*
+**/
+
+int writesufilesrcnwav(char *filename, float **src_nwav, wavPar wav, int n1, int n2, float f1, float f2, float d1, float d2)
+{
+	FILE    *file_out;
+	size_t  nwrite, itrace;
+	float   *trace;
+	int     ns;
+	segy    *hdr;
+//	char    *ptr;
+
+/* Read in parameters */
+
+//    ptr = strstr(filename, " ");
+//    *ptr = '\0';
+
+	if (n1 > USHRT_MAX) {
+		vwarn("Output file %s: number of samples is truncated from %d to USHRT_MAX.", filename, n1);
+	}
+	ns = MIN(n1,USHRT_MAX);
+
+	file_out = fopen( filename, "w+" );
+	assert( file_out );
+
+	trace = (float *)malloc(n1*sizeof(float));
+	hdr = (segy *)calloc(1,TRCBYTES);
+	hdr->ns = ns;
+	hdr->dt = NINT(1000000*(d1));
+	hdr->d1 = d1;
+	hdr->d2 = d2;
+	hdr->f1 = f1;
+	hdr->f2 = f2;
+	hdr->fldr = 1;
+	hdr->trwf = n2;
+
+	for (itrace=0; itrace<n2; itrace++) {
+		hdr->tracl = itrace+1;
+		nwrite = fwrite( hdr, 1, TRCBYTES, file_out );
+		assert (nwrite == TRCBYTES);
+		memset(trace, 0, n1*sizeof(float));
+		memcpy(trace, &src_nwav[itrace][0], wav.nsamp[itrace]*sizeof(float));
+		nwrite = fwrite( &trace[0], sizeof(float), ns, file_out );
+		assert (nwrite == ns);
+	} 
+	fclose(file_out);
+	free(hdr);
+	free(trace);
+
+	return 0;
+}
+
+/**
+*  Writes an 2D array to a SU file
+*  special routine which used segyhdrs which have ns defined as integer (32 bit)
+*  to handle more than 2^16 samples per trace.
+*
+**/
+
+int writeSUfile(char *filename, float *data, int n1, int n2, float f1, float f2, float d1, float d2)
+{
+	FILE    *file_out;
+	size_t  nwrite, itrace;
+	SUsegy  *SUhdr;
+	char    *ptr;
+
+/* Read in parameters */
+
+    ptr = strstr(filename, " ");
+    *ptr = '\0';
+
+	file_out = fopen( filename, "w+" );
+	assert( file_out );
+
+	SUhdr = (SUsegy *)calloc(1,TRCBYTES);
+	SUhdr->ns = n1;
+	SUhdr->dt = NINT(1000000*(d1));
+	SUhdr->d1 = d1;
+	SUhdr->d2 = d2;
+	SUhdr->f1 = f1;
+	SUhdr->f2 = f2;
+	SUhdr->fldr = 1;
+	SUhdr->trwf = n2;
+
+	for (itrace=0; itrace<n2; itrace++) {
+		SUhdr->tracl = itrace+1;
+		nwrite = fwrite( SUhdr, 1, TRCBYTES, file_out );
+		assert (nwrite == TRCBYTES);
+		nwrite = fwrite( &data[itrace*n1], sizeof(float), n1, file_out );
+		assert (nwrite == n1);
+	} 
+	fclose(file_out);
+	free(SUhdr);
+
+	return 0;
+}
+