	subroutine QP_3d
c	s/r to find the values of X and the partial derivatives PXPR,
c	PXPTH and PXPHI to be used by the Jones program, given a gridded
c	array of the parameters required to erect a QP profile.
c	The array is set up by the program IONMOD_QP  --  see the listing
c	to see what the grid is, and how the array of parameters is set up.
c
c	first call reads in the array P
c
c	written by leo mcnamara 6-apr-89 (from DUD_3D)
c-----	last modified 10-aug-90
c
c	uses QP_XPXPR, XPXPR_QPAR, QLFNH
c
	real m3000
	logical lcond
	character*8 modx,id
	real*8 x,freq,hh,pxpr,pxpth,pxpph,pxpt,hmax,r,w0,w,ffiray
c
	common / xx / modx(2),x,pxpr,pxpth,pxpph,pxpt,hmax
	common r(6) / ww / id(10),w0,w(400)
	dimension p(50,5,20),colat(50),elon(50),xc(4),yc(4),kk(4,2),
     a            xs(4),pr(4),hm(4)
	data ipass / 0 /
c
c---------------------------------
	ENTRY ELECTX
c---------------------------------
c
	pi = 3.141592654
	radeg = 180. / pi
	degrad = pi / 180.
c
c	read in the array P on the first call
	if(ipass.eq.1) go to 50
	open (unit=3,file='ionmod_qp.dat',status='old')
c	skip first 5 lines
	do 20 i = 1,5
20	read(3,300) trash
300	format(a1)
	read(3,301) nop
301	format(i3)
	type*,' # of profiles ',nop
	read(3,301) iray
	firay = float(iray)
	ffiray = dble (firay)
	if(dabs(ffiray-dabs(w(1))).le.1.d-5) go to 1112
	type*,' INCONSISTENT MODEL GRID AND W(1) ',iray,w(1)
	stop
1112	read(3,301) ispec
	do 333 i = 1,nop
	do 333 j = 1,5
333	read(3,334) (p(i,j,k),k=1,20)
334	format(5e16.6)
c
c	arrange to use geographic or geomagnetic coords
	ir = 1
	if(iray.eq.1) ir = 3
	jr = 2
	if(iray.eq.1) jr = 4
c
c	the colatitudes and longitudes of the points along the circuit
c	(including the TX and RX)
c	For E-W propagation, row 3 is a line of latitude, NOT the
c	great circle
	jray = 2 * iray
	do 30 i = 1,nop
	colat(i) = p(i,3,jray+1)
	elon(i) = p(i,3,jray+2)
	if(elon(i).lt.0.) elon(i) = elon(i) + 360.
	type*,'i,colat,elon',i, colat(i),elon(i)
30	continue
c
	ipass = 1
	return
50	continue
c
	freq = w(6)
	hh = r(1) - w(2)
c	coords of point - r,theta,phi - work in degrees
	rr = sngl (r(1))
	th = sngl (r(2)) * radeg
	ph = sngl (r(3)) * radeg
	if(ph.lt.0.) ph = ph + 360.
c
c	print out locations when ray hits the ground
	tz = 90. - th 
	pz = ph 
	if(dabs(r(1)-w(2)).le.0.01) type*,' r,theta,phi ',rr,tz,pz
	if(dabs(r(1)-w(2)).le.0.01.and.abs(w(1)).eq.1.d0)
     a            call ggm (1,pz,tz,ph,90.-th)
	if(dabs(r(1)-w(2)).le.0.01.and.abs(w(1)).eq.1.d0)
     a            type*,' r,theta,phi ',rr,tz,pz
c
	nop1 = nop - 1
	if(ispec.lt.0) go to 59
c
	if(ispec.eq.0.or.ispec.eq.180) go to 230
c	E-W or W-E propagation. jj is along the circuit; ii is across
	do 200 i = 1,nop1
	jj = i
	if(ph.ge.elon(i).and.ph.le.elon(i+1)) go to 210
	if(ph.ge.elon(i+1).and.ph.le.elon(i)) go to 210
200	continue
	type*,' Phi out of bounds s/n 200', ph,elon(1),elon(nop)
	go to 6666
210	continue
c	find the latitudes above and below the point (latitudes at all
c	""jj" are in fact the same
	do 211 i = 1,4
	ii = i
	if(th.ge.p(jj,i,ir).and.th.le.p(jj,i+1,ir)) go to 215
	if(th.ge.p(jj,i+1,ir).and.th.le.p(jj,i,ir)) go to 215
211	continue
	type*,' theta out of range s/n 211', th,p(jj,1,ir),p(jj,5,ir)
	go to 6666
215	continue
c
c	the 4 corners of the box surrounding the point P (for interpolation)
c	The latitudes all correspond to those at the end of the circuit, but 
c	we will leave the coding general
	xc(1) = p(jj,ii+1,ir)
	yc(1) = elon(jj)
	xc(2) = p(jj+1,ii+1,ir)
	yc(2) = elon(jj+1)
	xc(3) = p(jj+1,ii,ir)
	yc(3) = elon(jj+1)
	xc(4) = p(jj,ii,ir)
	yc(4) = elon(jj)
c	the points at which the QP parameters are required
	kk(1,1) = jj
	kk(1,2) = ii + 1
	kk(2,1) = jj + 1
	kk(2,2) = ii + 1
	kk(3,1) = jj + 1
	kk(3,2) = ii 
	kk(4,1) = jj
	kk(4,2) = ii 
ccc	type*,' 4 corners ',(xc(i),yc(i),i=1,4)
ccc	do 9000 i = 1,4
ccc9000	type*,' the array kk ',(kk(i,j),j=1,2)
	go to 87
c
c	N-S or S-N propagation. ii is along the circuit, jj is across
230	continue
	do 400 i = 1,4
	jj = i
	if(ph.ge.p(nop,i,jr).and.ph.le.p(nop,i+1,jr)) go to 410
	if(ph.ge.p(nop,i+1,jr).and.ph.le.p(nop,i,jr)) go to 410
400	continue
	type*,' Phi out of bounds s/n 400', ph,p(nop,1,jr),p(nop,5,jr)
	go to 6666
410	continue
c	find the latitudes above and below the point
	do 411 i = 1,nop1
	ii = i
	if(th.ge.colat(i).and.th.le.colat(i+1)) go to 415
	if(th.ge.colat(i+1).and.th.le.colat(i)) go to 415
411	continue
	type*,' theta out of range s/n 411', th,colat(1),colat(nop)
	go to 6666
415	continue
c
c	the 4 corners of the box surrounding the point P (for interpolation)
c	The longitudes all correspond to those at the end of the circuit, but 
c	we will leave the coding general
	xc(1) = colat(ii+1)
	yc(1) = p(ii+1,jj,jr)
	xc(2) = colat(ii+1)
	yc(2) = p(ii+1,jj+1,jr)
	xc(3) = colat(ii)
	yc(3) = p(ii,jj+1,jr)
	xc(4) = colat(ii)
	yc(4) = p(ii,jj,jr)
c	the points at which the QP parameters are required
	kk(1,1) = ii + 1
	kk(1,2) = jj
	kk(2,1) = ii + 1
	kk(2,2) = jj + 1
	kk(3,1) = ii
	kk(3,2) = jj + 1
	kk(4,1) = ii 
	kk(4,2) = jj
ccc	type*,' 4 corners ',(xc(i),yc(i),i=1,4)
ccc	do 9000 i = 1,4
ccc9000	type*,' the array kk ',(kk(i,j),j=1,2)
	go to 87
c
c	GENERAL CASE  - find coords of box surrounding the given point P
59	do 60 i = 1,nop1
	ii = i
	if(th.ge.colat(i).and.th.le.colat(i+1)) go to 65
	if(th.ge.colat(i+1).and.th.le.colat(i)) go to 65
60	continue
	type*,' theta out of bounds -- theta,colat(1),colat(nop)',
     a          th,colat(1),colat(nop)
	go to 6666
65	do 70 i = 1,nop1
	jj = i
	if(ph.ge.elon(i).and.ph.le.elon(i+1)) go to 75
	if(ph.ge.elon(i+1).and.ph.le.elon(i)) go to 75
70	continue
	type*,' phi out of bounds -- phi,elon(1),elon(nop)',
     a          ph,elon(1),elon(nop)
	go to 6666
75	continue
ccc	type*,' II & JJ  ',ii,jj
c
c	the 4 corners of the box (clockwise, from top left)
	xc(1) = colat(ii+1)
	yc(1) = elon(jj)
	xc(2) = colat(ii+1)
	yc(2) = elon(jj+1)
	xc(3) = colat(ii)
	yc(3) = elon(jj+1)
	xc(4) = colat(ii)
	yc(4) = elon(jj)
ccc	type*,' 4 corners ',(xc(i),yc(i),i=1,4)
c
c	the points along the rows of the grid at which the QP parameters
c	are required.  kk(l,m) is used for P(kk(l,1),kk(l,2),n)  --  3 cases
c	case 1    ii = jj
	print*,' ii & jj ', ii,jj
	if(ii.ne.jj) go to 80
	kk(1,1) = ii + 1
	kk(1,2) = 2
	kk(2,1) = ii+1
	kk(2,2) = 3
	kk(3,1) = ii
	kk(3,2) = 4
	kk(4,1) = ii
	kk(4,2) = 3
	go to 90
c
80	if(ii.ne.jj-1) go to 85
c	case 2   ii = jj - 1
	kk(1,1) = ii+1
	kk(1,2) = 3
	kk(2,1) = ii + 1
	kk(2,2) = 4
	kk(3,1) = ii
	kk(3,2) = 5
	kk(4,1) = ii
	kk(4,2) = 4
	go to 90
c
c	case 3    ii = jj + 1
85	if(ii.ne.jj+1) type*,'ii,jj+1,  theta,phi ',ii,jj+1,th,ph
	if(ii.ne.jj+1) go to 6666
	kk(1,1) = ii + 1
	kk(1,2) = 1
	kk(2,1) = ii + 1
	kk(2,2) = 2
	kk(3,1) = ii
	kk(3,2) = 3
	kk(4,1) = ii
	kk(4,2) = 2
c
90	continue
ccc	do 900 i = 1,4
ccc900	type*,' the array kk ',(kk(i,j),j=1,2)
c
c	set up the QP parameters for each corner, and find the values
c	of X and PXPR at the height HH
87	do 100 kc = 1,4
	k1 = kk(kc,1)
	k2 = kk(kc,2)
	foe =	p(k1,k2,5)
	yme =	p(k1,k2,6)
	hme=	p(k1,k2,7)
	fof1 =	p(k1,k2,8)
	ymf1 =	p(k1,k2,9)
	hmf1 =	p(k1,k2,10)
	fof2 =	p(k1,k2,11)
	ymf2 =	p(k1,k2,12)
	hmf2 =	p(k1,k2,13)
	hsf =	p(k1,k2,14)
	hsf2 =	p(k1,k2,15)
	fnmax=	p(k1,k2,16)
	ymax =	p(k1,k2,17)
	himax =	p(k1,k2,18)
	invqp =	p(k1,k2,19)
	call qp_xpxpr
     a  (foe,yme,hme,fof1,ymf1,hmf1,fof2,ymf2,hmf2,hsf,hsf2,
     a   fnmax,ymax,himax,invqp)
c	x, pxpr and hmf2 are in labelled common XX
	xs(kc) = x
	pr(kc) = pxpr
	hm(kc) = hmf2
100	continue
ccc	type*,' X',(xs(i),i=1,4)
ccc	type*,' PXPR',(pr(i),i=1,4)
ccc	type*,' hmF2',(hm(i),i=1,4)
c
c	interpolate at the point P to get X, HMAX & PXPR (2-D interpolation)
	xa = xc(1)
	xd = xc(4)
	ya = yc(1)
	yb = yc(2)
	if(xa.eq.xd) type*,'theta,phi ',th,ph
	if(ya.eq.yb) type*,'theta,phi ',th,ph
	if(xa.eq.xd) type*,' xa & xd are equal --- ',xa
	if(ya.eq.yb) type*, 'ya & yb are equal --- ',ya
	if(xa.eq.xd) type*,' xc', (xc(i),i=1,4)
	if(xa.eq.xd) type*,' yc', (yc(i),i=1,4)
	if(ya.eq.yb) type*,' xc ',(xc(i),i=1,4)
	if(ya.eq.yb) type*,' yc ',(yc(i),i=1,4)
	xp = th
	yp = ph
	za = xs(1)
	zb = xs(2)
	zc = xs(3)
	zd = xs(4)
	fac1 = (yp - ya) / (yb - ya)
	fac2 = (xp - xa) / (xd - xa)
	zp = za + fac1*(zb-za) + fac2*(zd-za+fac1*(za-zb+zc-zd))
	x = dble (zp)
c	calculate the product mu * r for Bouger's rule
	aamu = sqrt(1. - zp)
	h = sngl (hh)
	aar = h + 6370.
	bouger = aamu * aar
cccc	type*,' Bouger -- h, mu, mu * r ', h, aamu, bouger
	za = hm(1)
	zb = hm(2)
	zc = hm(3)
	zd = hm(4)
	zp = za + fac1*(zb-za) + fac2*(zd-za+fac1*(za-zb+zc-zd))
	hmax = dble (zp)
	za = pr(1)
	zb = pr(2)
	zc = pr(3)
	zd = pr(4)
	zp = za + fac1*(zb-za) + fac2*(zd-za+fac1*(za-zb+zc-zd))
	pxpr = dble (zp)
c
c	the partial derivatives wrt theta and phi -- the second derivatives
c	are assumed constant over the box
	pp1 = (xs(1) - xs(4)) / (xc(1) - xc(4))
	pp2 = (xs(2) - xs(3)) / (xc(2) - xc(3))
	pp12 = pp1 + (pp2-pp1) * (yc(1) - ph) / (yc(1) - yc(2))
	pxpth = dble (pp12 * radeg)
ccc	type*,' pp1,pp2,pp12 ',pp1,pp2,pp12
	pt1 = (xs(2) - xs(1)) / (yc(2) - yc(1))
	pt2 = (xs(3) - xs(4)) / (yc(3) - yc(4))
	pt12 = pt1 + (pt2-pt1) * (xc(1) - th) / (xc(1) - xc(4))
ccc	type*,' pt1  pt2  pt12 ',pt1,pt2,pt12
	pxpph = dble (pt12 * radeg)
ccc	print*,' pxpth & pxpph ', pxpth,pxpph
c
	return
6666	call ggm (1,zlon,zlat,ph,90.-th)
	write(2,6667) zlat,zlon,90.-th,ph
	write(6,6667) zlat,zlon,90.-th,ph
6667	format(//3x,'The ray has gone out of the grid provided',
     a	 /'    at GEOGRAPHIC  coords ',2f8.2,
     a   /'    &  GEOMAGNETIC coords ',2f8.2)
	stop '  TRY it again, Sam .....'
	end


