Skip to content
Snippets Groups Projects
Select Git revision
  • f90e33d2f4e0ff3e625c93c25d84b6300aecad3c
  • master default protected
  • muons
  • v1.0.0
  • v0.1.0
5 results

event.f

Blame
  • user avatar
    Garth Huber authored
    Garth Huber
    Nov 24, 2015
    5b1bb80e
    History
    event.f 53.55 KiB
    	subroutine limits_update(main,vertex,orig,recon,doing_deuterium,
         >		doing_pion,doing_kaon,doing_delta,doing_rho,contrib,slop)
    
    	implicit none
    
    	include 'structures.inc'
    	include 'radc.inc'
    	type(event_main):: main
    	type(event):: vertex, orig, recon
    	type(contribtype):: contrib
    	type(sloptype):: slop
    	integer i
    	logical	doing_deuterium, doing_pion, doing_kaon, doing_delta, doing_rho
    
    ! Update the "contribution limits" records
    
    ! ... GENERATION values
    	call update_range(vertex%e%delta, contrib%gen%e%delta)
    	call update_range(vertex%e%yptar, contrib%gen%e%yptar)
    	call update_range(vertex%e%xptar, contrib%gen%e%xptar)
    	call update_range(vertex%p%delta, contrib%gen%p%delta)
    	call update_range(vertex%p%yptar, contrib%gen%p%yptar)
    	call update_range(vertex%p%xptar, contrib%gen%p%xptar)
    	call update_range(main%Trec, contrib%gen%Trec)
    
    ! ........ another tricky shift
    	if (doing_deuterium .or. doing_pion .or. doing_kaon .or. doing_delta .or. doing_rho) then
    	  call update_range(vertex%e%E-main%Ein_shift,contrib%gen%sumEgen)
    	else
    	  call update_range(vertex%e%E+vertex%p%E-main%Ein_shift,contrib%gen%sumEgen)
    	endif
    
    ! ... TRUE values
    ! ........ tricky shift here, remember this'll get compared with edge.e.E,
    ! ........ compensate for main.target.Coulomb to
    ! ........ copy the shift made to the edge in generate
    	call update_range(orig%e%E-main%Ee_shift, contrib%tru%e%E)
    	call update_range(orig%e%xptar, contrib%tru%e%xptar)
    	call update_range(orig%e%yptar, contrib%tru%e%yptar)
    	call update_range(orig%e%xptar, contrib%tru%e%xptar)
    	call update_range(orig%p%E, contrib%tru%p%E)
    	call update_range(orig%p%yptar, contrib%tru%p%yptar)
    	call update_range(orig%p%xptar, contrib%tru%p%xptar)
    
    ! ........ another tricky shift
    	call update_range(orig%Em-main%Ein_shift+main%Ee_shift,contrib%tru%Em)
    	call update_range(orig%Pm, contrib%tru%Pm)
    	call update_range(orig%Trec, contrib%tru%Trec)
    
    ! ... SPECTROMETER values
    	call update_range(main%SP%e%delta, contrib%SP%e%delta)
    	call update_range(main%SP%e%yptar, contrib%SP%e%yptar)
    	call update_range(main%SP%e%xptar, contrib%SP%e%xptar)
    	call update_range(main%SP%p%delta, contrib%SP%p%delta)
    	call update_range(main%SP%p%yptar, contrib%SP%p%yptar)
    	call update_range(main%SP%p%xptar, contrib%SP%p%xptar)
    
    ! ... VERTEX values
    	call update_range(vertex%Trec, contrib%vertex%Trec)
    	call update_range(vertex%Em, contrib%vertex%Em)
    	call update_range(vertex%Pm, contrib%vertex%Pm)
    
    ! ... RADIATION stuff
    ! ??? should be looking at Egamma2+3 cause we do use limits on that, indirectly
    
    	do i = 1, 3
    	  call update_range(Egamma_used(i), contrib%rad%Egamma(i))
    	enddo
    	call update_range(Egamma_used(1)+Egamma_used(2)+Egamma_used(3),
         >		contrib%rad%Egamma_total)
    
    ! Update the "slop limits" records
    ! ... MC slops
    	call update_range(main%RECON%e%delta-main%SP%e%delta,slop%MC%e%delta)
    	call update_range(main%RECON%e%yptar-main%SP%e%yptar,slop%MC%e%yptar)
    	call update_range(main%RECON%e%xptar-main%SP%e%xptar,slop%MC%e%xptar)
    	call update_range(main%RECON%p%delta-main%SP%p%delta,slop%MC%p%delta)
    	call update_range(main%RECON%p%yptar-main%SP%p%yptar,slop%MC%p%yptar)
    	call update_range(main%RECON%p%xptar-main%SP%p%xptar,slop%MC%p%xptar)
    
    ! %.. total slops
    ! ........ that tricky shift again, slops accounted for by the shift not
    ! ........ included in slop.total.Em.
    	call update_range(recon%Em-(orig%Em-main%Ein_shift+main%Ee_shift),
         >		slop%total%Em)
    	call update_range(abs(recon%Pm)-abs(orig%Pm), slop%total%Pm)
    
    	return
    	end
    
    !-------------------------------------------------------------------
    
    	subroutine update_range(val,range)
    
    	include 'structures.inc'
    	type(rangetype):: range
    	real*8	val
    
    	range%lo = min(range%lo, val)
    	range%hi = max(range%hi, val)
    
    	return
    	end
    
    !----------------------------------------------------------------------
    ! THE routine to GENERATE the (max of 7) random quantities we need to get
    ! a full description of our event.
    
    	subroutine generate(main,vertex,orig,success)
    
    	implicit none
    	include 'simulate.inc'
    
    	integer i, ii
    	real*8 Emin, Emax
    	real*8 ranprob,ranth1,ranth,ranph,t3,t4,t5,t6
    	real*8 pferlo,pferhi
    	real*8 m_spec		!spectator (A-1) mass based on missing energy
    	real*8 gauss1
    	logical success
    	real*8 grnd		!random # generator.
    	type(event_main):: main
    	type(event):: vertex, orig
    
    	real*8 nsig_max
    	parameter(nsig_max=3.0e0)      !max #/sigma for gaussian ran #s.
    
    
    ! Randomize the position of the interaction inside the available region.
    ! gen.xwid and gen.ywid are the intrinsic beam widths (one sigma value).
    ! Use a gaussian beam distribution with +/- 3.0 sigma (add raster afterwards).
    
    C DJG As best I can figger, main.target.y is positive when the beam is high in the lab
    C DJG and main.target.x is positive when the beam is right when looking downstream.
    C DJG Don't ask me why, but it seems to be this way.
    C DJG Note that this means that +fry points down. I will make frx point left. 
    
    	main%target%x = gauss1(nsig_max)*gen%xwid+targ%xoffset
    	main%target%y = gauss1(nsig_max)*gen%ywid+targ%yoffset
    
    ! fr_pattern=1 - old bedpost raster rectangle - targ.fr1/fr2 are the x/y raster half-widths.
    ! fr_pattern=2 - circle - targ.fr1/fr2 are the inner and outer radii.
    ! fr_pattern=3 - new flat raster rectangle - targ.fr1/fr2 are the x/y raster half-widths.
    
    	if (targ%fr_pattern .eq. 1) then		!old bedpost, square raster
    	  t3=grnd()*pi
    	  t4=grnd()*pi
    	  t5=cos(t3)*targ%fr1
    	  t6=cos(t4)*targ%fr2
    	elseif (targ%fr_pattern .eq. 2) then		!circular raster
    	  t3=grnd()*2.*pi
    	  t4=sqrt(grnd())*(targ%fr2-targ%fr1)+targ%fr1
    	  t5=cos(t3)*t4
    	  t6=sin(t3)*t4
    	elseif (targ%fr_pattern .eq. 3) then		!new, flat square raster
    	  t3=2.*grnd()-1.0
    	  t4=2.*grnd()-1.0
    	  t5=targ%fr1*t3
    	  t6=targ%fr2*t4
    	else						!no raster
    	  t5=0.0
    	  t6=0.0
    	endif
    
    	main%target%x = main%target%x+t5
    	main%target%y = main%target%y+t6
    	main%target%z = (0.5-grnd())*targ%length+targ%zoffset
    	main%target%rastery = t6	!'raster' contribution to vert. pos.
    	main%target%rasterx = t5	! points right as you look downstream  - need to flip sign later.
    
    ! Take fluctuations of the beam energy into account, and remember to correct
    ! for ionization loss in the target and Coulomb acceleration of incoming
    ! electron.  Remove targ.zoffset from the z position of the scattering
    ! in order to get the position relative to the center of the target.
    
    	call trip_thru_target (1, main%target%z-targ%zoffset, Ebeam, 0.0e0,
         >		main%target%Eloss(1), main%target%teff(1),Me,1)
    	if (.not.using_Eloss) main%target%Eloss(1) = 0.0
    	if (using_Coulomb) then
    c	  main%target%Coulomb=targ%Coulomb_constant*(3.-(grnd())**(2./3.))
    C modified 5/15/06 for poinct
    	  main%target%Coulomb=targ%Coulomb_constant
    	else
    	  main%target%Coulomb=0.0
    	endif
    	vertex%Ein = Ebeam + (grnd()-0.5)*dEbeam +
         >		main%target%Coulomb - main%target%Eloss(1)
    
    ! ... deterimine known variation in Ein from Ebeam_vertex_ave and in
    ! ... Ee due to Coulomb energy to compare limits to generated event by event.
    ! ... (USED TO SHIFT 'LIMIT' VALUES IN UPDATE_RANGE CALLS.  ARE THEY NEEDED???)
    
            main%Ein_shift = vertex%Ein - Ebeam_vertex_ave
            main%Ee_shift = main%target%Coulomb - targ%Coulomb%ave
    
    ! Initialize success code and fractional weight due to radiation and
    ! generation tricks
    
    5	success = .false.
    	main%gen_weight = 1.0
    
    ! Generated quantities: (phase_space NOT YET IMPLEMENTED).
    !
    ! phase_space: Generate electron E,yptar,xptar and hadron yptar,xptar??
    ! doing_hyd_elast: Generate electron angles. Solve for everything else.
    ! doing_deuterium: Generate electron energy and angles, proton angles.
    !	Solve for proton momentum, p_fermi.
    ! doing_eep, A>2: generate electron and hadron energy, angles. Solve for Em,Pm.
    ! doing_pion: generate electron energy and angles, hadron angles, p_fermi, Em.
    !	Solve for hadron momentum.
    ! doing_kaon: as doing_pion.
    ! doing_delta: as doing_pion.
    ! doing_rho: as doing_pion.
    ! doing_semi: Generate electron E,yptar,xptar and hadron E, yptar,xptar
    !
    ! The above is summarized in the following table:
    !
    !                    ELECTRON                  HADRON
    !               ------------------      ------------------
    !               E       yptar   xptar   E       yptar   xptar   p_fermi	Em
    !
    !H(e,e'p)		X	X
    !D(e,e'p)	X	X	X		X	X
    !A(e,e'p)	X	X	X	X	X	X
    !----------------------------------------------------------------------
    !H(e,e'pi)	X	X	X		X	X
    !A(e,e'pi)	X	X	X		X	X	X	X
    !H(e,e'K)	X	X	X		X	X
    !A(e,e'K)	X	X	X		X	X	X	X
    !H(e,e'p)pi	X	X	X		X	X
    !A(e,e'p)pi	X	X	X		X	X	X	X
    !----------------------------------------------------------------------
    !phase_space	X	X	X	?	X	X
    !
    ! So our procedure is the following:
    ! 1) Always generate electron yptar and xptar
    ! 2) generate hadron yptar and xptar for all cases except H(e,e'p).
    ! 3) Generate hadron E for A(e,e'p)
    ! 4) generate electron E for all but hydrogen elastic.
    ! 5) generate p_fermi, Em for A(e,e'pi) and A(e,e'K).
    !
    ! After we generate xptar/yptar/energy, we calculate physics angles (theta/phi),
    !  momenta, unit vectors, etc... here and/or in complete_ev.
    !
    ! Note that there are also jacobians associated with some and/or all of
    ! the above.
    ! 1: We generate uniformly in xptar/yptar, not theta/phi.  We define the
    ! phase space volume (genvol contribution) as the product of the xptar/yptar
    ! range, and have a jacobian for each event taking into account the mapping
    ! between the solid angle on the unit sphere, and the dxptar/dyptar volume
    ! (the jacobian is 1/cos**3(dtheta), where dtheta is the angle between the
    ! event and the central spectrometer vector
    ! 2: For the D(e,e'p), we take Em as fixed in order to calculate the proton
    ! energy.  There is a jacobian ( |dEp'/dEm| ).  It comes from integrating
    ! over the energy conservation delta function: delta(E_D - E_p - E_n - Em).
    
    ! Generate Electron Angles (all cases):
    	vertex%e%yptar=gen%e%yptar%min+grnd()*(gen%e%yptar%max-gen%e%yptar%min)
    	vertex%e%xptar=gen%e%xptar%min+grnd()*(gen%e%xptar%max-gen%e%xptar%min)
    
    ! Generate Hadron Angles (all but H(e,e'p)):
    	if (doing_deuterium.or.doing_heavy.or.doing_pion.or.doing_kaon
         >         .or.doing_delta.or.doing_semi) then
    	  vertex%p%yptar=gen%p%yptar%min+grnd()*
         >  	(gen%p%yptar%max-gen%p%yptar%min)
    	  vertex%p%xptar=gen%p%xptar%min+grnd()*
         >          (gen%p%xptar%max-gen%p%xptar%min)
    	endif
    
    ! Generate Hadron Momentum (A(e,e'p) or semi-inclusive production).
    	if (doing_heavy .or. doing_semi) then
    	  Emin = max(gen%p%E%min, gen%sumEgen%min - gen%e%E%max)
    	  Emax = min(gen%p%E%max, gen%sumEgen%max - gen%e%E%min)
    	  if (Emin.gt.Emax) goto 100
    	  main%gen_weight=main%gen_weight*(Emax-Emin)/(gen%p%E%max-gen%p%E%min)
    	  vertex%p%E = Emin + grnd()*(Emax-Emin)
    	  vertex%p%P = sqrt(vertex%p%E**2 - Mh2)
    	  vertex%p%delta = 100.*(vertex%p%P-spec%p%P)/spec%p%P
    	endif
    
    ! Generate Electron Energy (all but hydrogen elastic)
    	if (doing_deuterium.or.doing_heavy.or.doing_pion.or.doing_kaon
         >       .or.doing_delta.or.doing_rho.or.doing_semi) then
    	  Emin=gen%e%E%min
    	  Emax=gen%e%E%max
    	  if (doing_deuterium .or. doing_pion .or. doing_kaon .or. doing_delta .or. doing_rho) then
    	    Emin = max(Emin,gen%sumEgen%min)
    	    Emax = min(Emax,gen%sumEgen%max)
    	  else if (doing_heavy) then		! A(e,e'p)
    	    Emin = max(Emin, gen%sumEgen%min - vertex%p%E)
    	    Emax = min(Emax, gen%sumEgen%max - vertex%p%E)
    	  endif
    	  if (Emin.gt.Emax) goto 100
    	  main%gen_weight=main%gen_weight*(Emax-Emin)/(gen%e%E%max-gen%e%E%min)
    	  vertex%e%E = Emin + grnd()*(Emax-Emin)
    	  vertex%e%P = vertex%e%E
    	  vertex%e%delta = 100.*(vertex%e%P-spec%e%P)/spec%e%P
    	endif	!not (doing_hyd_elast)
    
    
    ! Calculate the electron and proton PHYSICS angles from the spectrometer angles.
    ! Note that the proton angles are not yet know for hydrogen elastic.
    ! NOTE: this needs to be done again for the exclusive rho stuff (just on the hadron side).
    
    	call physics_angles(spec%e%theta,spec%e%phi,
         &		vertex%e%xptar,vertex%e%yptar,vertex%e%theta,vertex%e%phi)
    	call physics_angles(spec%p%theta,spec%p%phi,
         &		vertex%p%xptar,vertex%p%yptar,vertex%p%theta,vertex%p%phi)
    
    
    ! Generate Fermi Momentum and Em for A(e,e'pi) and A(e,e'K). 
    	pfer=0.0
    	pferx=0.0
    	pfery=0.0
    	pferz=0.0
    	vertex%Em=0.0
    	efer=targ%Mtar_struck		!used for pion/kaon xsec calcs.
    	if(doing_deutpi.or.doing_hepi.or.doing_deutkaon.or.doing_hekaon.or.
         >      doing_deutdelta.or.doing_hedelta.or.doing_deutrho.or.doing_herho
         >      .or.doing_deutsemi)then
    	  ranprob=grnd()
    	  ii=1
    	  do while (ranprob.gt.mprob(ii) .and. ii.lt.nump)
    	    ii=ii+1
    	  enddo
    	  if (ii.eq.1) then
    	    pferlo=0
    	  else
    	    pferlo=(pval(ii-1)+pval(ii))/2
    	  endif
    	  if (ii.eq.nump) then
    	    pferhi=pval(nump)
    	  else
    	    pferhi=(pval(ii)+pval(ii+1))/2
    	  endif
    	  pfer=pferlo+(pferhi-pferlo)*grnd()
    	  ranth1=grnd()*2.-1.0
    	  ranth=acos(ranth1)
    	  ranph=grnd()*2.*pi
    	  pferx=sin(ranth)*cos(ranph)
    	  pfery=sin(ranth)*sin(ranph)
    	  pferz=cos(ranth)
    
    	  if (doing_deutpi.or.doing_deutkaon.or.doing_deutdelta
         >        .or.doing_deutrho .or.doing_deutsemi) then !Em = binding energy
    	    vertex%Em = Mp + Mn - targ%M
    	    m_spec = targ%M - targ%Mtar_struck + vertex%Em != Mn(Mp) for pi+(-)
    	    efer = targ%M - sqrt(m_spec**2+pfer**2)
    	  endif
    	  if (doing_hepi .or. doing_hekaon .or. doing_hedelta .or. doing_herho) then
    	    call generate_em(pfer,vertex%Em)		!Generate Em
    	    m_spec = targ%M - targ%Mtar_struck + vertex%Em != M^*_{A-1}
    	    efer = targ%M - sqrt(m_spec**2+pfer**2)
    	  endif
    	endif
    
    ! Compute all non-generated quantities
    
    	if (debug(5)) write(6,*)'gen: calling comp_ev with false, main, vertex'
    	if (debug(3)) write(6,*)'gen: calling comp_ev with false, main, vertex'
    	if (debug(3)) write(6,*)'gen: Ein, E =',vertex%Ein,vertex%e%E
    
    	call complete_ev(main,vertex,success)
    
    
    	main%sigcc = 1.0
    
    	if (debug(2)) write(6,*)'gen: initial success =',success
    	if (.not.success) goto 100
    
    ! ........ temporary storage of Trec for generated event
    
    	main%Trec = vertex%Trec
    
    ! Radiate the event, if requested. If we get an event weight of zero (i.e.
    ! if we CAN'T radiate our event into the acceptance) then success is
    ! false.  generate_rad also set orig kinematics, and cuts on Em/Pm.
    ! If not using_rad, must do these here.
    
    	if (using_rad) then
    	  call generate_rad(main,vertex,orig,success)
    	  if (debug(2)) write(6,*)'gen: after gen_rad, success =',success
    	else
    	  success = .true.
    	  if (doing_heavy) success = 
         >		(vertex%Em .ge. VERTEXedge%Em%min .and.
         >		 vertex%Em .le. VERTEXedge%Em%max .and.
         >		 vertex%Pm .ge. VERTEXedge%Pm%min .and. 
         >		 vertex%Pm .le. VERTEXedge%Pm%max)
    	  if (success) then
    c	    do i = 1, neventfields
    c	      orig.all(i) = vertex.all(i)
    c	    enddo
    	     orig = vertex
    	  endif
    	endif
    
    
    C DJG need to decay the rho here before we begin transporting through the
    C DJG spectrometer
    
    	if(doing_rho) then
    	   call rho_decay(orig,spec%p%P,main%epsilon,success)
    	endif
    
    	
    100	if (debug(2)) write(6,*)'gen: final success =',success
    	if (debug(2)) write(6,*)'gen: ending'
    	return
    	end
    
    !---------------------------------------------------------------------
    
    	subroutine complete_ev(main,vertex,success)
    
    	implicit none
    	include 'simulate.inc'
    
    	real*8 a, b, c, r, t, QA, QB, QC, radical
    	real*8 p_new_x,p_new_y,new_x_x,new_x_y,new_x_z
    	real*8 targ_new_x,targ_new_y
    	real*8 new_y_x,new_y_y,new_y_z,dummy
    	real*8 targx,targy,targz
    	real*8 px,py,pz,qx,qy,qz
    	real*8 oop_x,oop_y
    	real*8 krel,krelx,krely,krelz
    	real*8 MM
    
    	real*8 Ehad2,E_rec
    	real*8 W2
    	real*8 grnd		!random # generator.
    
    	logical success
    	type(event_main):: main
    	type(event)::	vertex
    
    !-----------------------------------------------------------------------
    ! Calculate everything left in the /event/ structure, given all necessary
    !  GENERATION values (some set of xptar,yptar,delta for both arms and p_fermi,
    !  and p_fermi, depending on the scattering process: see table in generate.f 
    !
    ! The SINGLE element of /event/ NOT computed here is sigcc.
    !
    ! Another small anomaly is that main.jacobian IS computed here.
    ! This is because all the necessary terms have to be
    ! computed here anyway to calculate /event/ qties.
    !
    !-----------------------------------------------------------------------
    
    ! Initialize
    
    	success = .false.
    	main%jacobian = 1.0
    
    ! ... unit vector components of outgoing e,p
    ! ... z is DOWNSTREAM, x is DOWN and y is LEFT looking downstream.
    
    	if (debug(4)) write(6,*)'comp_ev: at 1'
    	vertex%ue%x = sin(vertex%e%theta)*cos(vertex%e%phi)
    	vertex%ue%y = sin(vertex%e%theta)*sin(vertex%e%phi)
    	vertex%ue%z = cos(vertex%e%theta)
    	if ((.not.doing_hyd_elast).and.(.not.doing_rho)) then
    	  vertex%up%x = sin(vertex%p%theta)*cos(vertex%p%phi)
    	  vertex%up%y = sin(vertex%p%theta)*sin(vertex%p%phi)
    	  vertex%up%z = cos(vertex%p%theta)
    	endif
    	if (debug(4)) write(6,*)'comp_ev: at 2'
    
    ! First finish off the e side
    ! Calculate scattered electron energy for hydrogen/deuterium (e,e'p)
    
    	if (doing_hyd_elast) then
    	  vertex%e%E = vertex%Ein*Mh/(Mh+vertex%Ein*(1.-vertex%ue%z))
    
    	  if (vertex%e%E.gt.vertex%Ein) return
    	  vertex%e%P = vertex%e%E
    	  vertex%e%delta = (vertex%e%P - spec%e%P)*100./spec%e%P
    	  if (debug(4)) write(6,*)'comp_ev: at 3'
    	endif
    
    ! The q vector
    
    	if (debug(5)) write(6,*)'comp_ev: Ein,E,uez=',vertex%Ein,vertex%e%E,vertex%ue%z
    
    	vertex%nu = vertex%Ein - vertex%e%E
    	vertex%Q2 = 2*vertex%Ein*vertex%e%E*(1.-vertex%ue%z)
    	vertex%q = sqrt(vertex%Q2 + vertex%nu**2)
    	vertex%xbj = vertex%Q2/2./Mp/vertex%nu
    
    	vertex%uq%x = - vertex%e%P*vertex%ue%x / vertex%q
    	vertex%uq%y = - vertex%e%P*vertex%ue%y / vertex%q
    	vertex%uq%z =(vertex%Ein - vertex%e%P*vertex%ue%z)/ vertex%q
    	if (abs(vertex%uq%x**2+vertex%uq%y**2+vertex%uq%z**2-1).gt.0.01)
         >		stop 'Error in q vector normalization'
    	if (debug(4)) write(6,*)'comp_ev: at 5'
    
    ! Now complete the p side, along with vertex.Em, vertex.Pm, vertex.Mrec.
    ! NOTE: Coherent pion/kaon production (bound final state) is treated as
    ! hydrogen, but with targ.Mtar_struck=targ.M, targ.Mtar_rec=bound final state.
    
    	if (doing_hyd_elast) then	!p = q
    	  vertex%Em = 0.0
    	  vertex%Pm = 0.0
    	  vertex%Mrec = 0.0
    	  vertex%up%x = vertex%uq%x
    	  vertex%up%y = vertex%uq%y
    	  vertex%up%z = vertex%uq%z
    	  vertex%p%P = vertex%q
    	  vertex%p%theta = acos(vertex%up%z)
    	  if (abs(vertex%up%x/sin(vertex%p%theta)).gt.1)
         >	    write(6,*) 'cos(phi)=',vertex%up%x/sin(vertex%p%theta)
    	  vertex%p%phi = atan2(vertex%up%y,vertex%up%x)
    	  if (vertex%p%phi.lt.0.) vertex%p%phi=vertex%p%phi+2.*pi
    	  call spectrometer_angles(spec%p%theta,spec%p%phi,
         &		vertex%p%xptar,vertex%p%yptar,vertex%p%theta,vertex%p%phi)
    	  vertex%p%E = sqrt(vertex%p%P**2+Mh2)
    	  vertex%p%delta = (vertex%p%P - spec%p%P)*100./spec%p%P
    	  if (debug(4)) write(6,*)'comp_ev: at 6'
    
    	elseif (doing_deuterium) then	!need Ep, and a jacobian.
    
    	  vertex%Em = targ%Mtar_struck + targ%Mrec - targ%M	!=2.2249 MeV
    	  vertex%Mrec = targ%M - targ%Mtar_struck + vertex%Em	!=targ.Mrec
    
    	  a = -1.*vertex%q*(vertex%uq%x*vertex%up%x+vertex%uq%y*vertex%up%y+vertex%uq%z*vertex%up%z)
    	  b = vertex%q**2
    	  c = vertex%nu + targ%M
    	  t = c**2 - b + Mh2 - vertex%Mrec**2
    	  QA = 4.*(a**2 - c**2)
    	  QB = 4.*c*t
    	  QC = -4.*a**2*Mh2 - t**2
    	  radical = QB**2 - 4.*QA*QC
    	  if (radical.lt.0) return
    	  vertex%p%E = (-QB - sqrt(radical))/2./QA
    
    ! Check for two solutions
    !	  if ( (-QB + sqrt(radical))/2./QA .gt. Mh ) then
    !	    write(6,*) 'There are two valid solutions for the hadron momentum'
    !	    write(6,*) 'We always pick one, so this may be a problem, and needs to be checked'
    !	    write(6,*) 'solns=',(-QB - sqrt(radical))/2./QA,(-QB + sqrt(radical))/2./QA
    !	  endif
    
    ! Check for two solutions, but only print warning if both are within
    ! event generation limits.
    	  Ehad2 = (-QB + sqrt(radical))/2./QA
    	  if (Ehad2.gt.edge%p%E%min .and. Ehad2.lt.edge%p%E%max .and. ntried.le.5000) then
    	    write(6,*) 'The low-momentum solution to E_hadron is within the spectrometer generation'
    	    write(6,*) 'limits.  If it is in the acceptance, Its the end of the world as we know it!!!'
    	    write(6,*) 'E_hadron solns=',vertex%p%E,Ehad2
    	  endif
    
    
    	  if (vertex%p%E.le.Mh) return
    	  vertex%p%P = sqrt(vertex%p%E**2 - Mh2)
    	  vertex%p%delta = (vertex%p%P - spec%p%P)*100./spec%p%P
    
    ! ........ the Jacobian here is |dEp'/dEm|
    	  main%jacobian = (t*(c-vertex%p%E) + 2*c*vertex%p%E*(vertex%p%E-c)) /
         > 		(2*(a**2-c**2)*vertex%p%E + c*t)
    	  main%jacobian = abs(main%jacobian)
    
    
    	elseif (doing_pion .or. doing_kaon .or. doing_delta) then
    	   
    c	  if (doing_rho) then 
    c	     Mh = Mrho
    ! DJG give the rho mass some width (non-relativistic Breit-Wigner)
    c	     Mh = Mh + 0.5*150.2*tan((2.*grnd()-1.)*atan(2.*500./150.2))
    c	     Mh2 = Mh*Mh
    c	     ntup.rhomass=Mh
    c            write(6,*) 'rho mass is', Mh
    c	  endif
    	      
    
    
    	  vertex%Pm = pfer	!vertex%Em generated at beginning.
    	  vertex%Mrec = targ%M - targ%Mtar_struck + vertex%Em
    	  a = -1.*vertex%q*(vertex%uq%x*vertex%up%x+vertex%uq%y*vertex%up%y+vertex%uq%z*vertex%up%z)
    	  b = vertex%q**2
    	  c = vertex%nu + targ%M
    
    ! For nuclei, correct for fermi motion and missing energy.  Also, check
    ! second solution to quadratic equation - there are often two valid
    ! solutions, and we always pick the larger one (which is the forward going
    ! one in the center of mass) and HOPE that the smaller one is never in the
    ! acceptance.  If the low momentum solution IS within the acceptance, we
    ! have big problems.
    	  if (doing_deutpi.or.doing_hepi.or.doing_deutkaon.or.doing_hekaon.or.
         >        doing_deutdelta.or.doing_hedelta) then
    	    a = a - abs(pfer)*(pferx*vertex%up%x+pfery*vertex%up%y+pferz*vertex%up%z)
    	    b = b + pfer**2 + 2*vertex%q*abs(pfer)*
         >  	 (pferx*vertex%uq%x+pfery*vertex%uq%y+pferz*vertex%uq%z)
    ***	    c = c - sqrt(vertex.Mrec**2+pfer**2)
    	    c = vertex%nu + efer !same as above, but this way if we redefine
    				    !'efer', it's the same everywhere.
    	  endif
    	  t = c**2 - b + Mh2 - targ%Mrec_struck**2
    	  QA = 4.*(a**2 - c**2)
    	  QB = 4.*c*t
    	  QC = -4.*a**2*Mh2 - t**2
    
    !	write(6,*) '    '
    !	write(6,*) '    '
    !	write(6,*) 'E0=',vertex.Ein
    !	write(6,*) 'P_elec,P_prot=',vertex.e.P/1000.,vertex.p.P/1000.
    !	write(6,*) 'thetae,phie=',vertex.e.theta*180./pi,vertex.e.phi*180./pi
    !	write(6,*) 'thetap,phip=',vertex.p.theta*180./pi,vertex.p.phi*180./pi
    !	write(6,*) 'q,nu,costhetapq=',vertex.q,vertex.nu,(vertex.uq.x*vertex.up.x+vertex.uq.y*vertex.up.y+vertex.uq.z*vertex.up.z)
    !	write(6,*) 'a,b,c=',a/1000.,b/1000000.,c/1000.
    !	write(6,*) 't=',t/1000000.
    !	write(6,*) 'A,B,C=',QA/1.d6,QB/1.d9,QC/1.d12
    !	write(6,*) 'rad=',QB**2 - 4.*QA*QC
    !	write(6,*) 'e1,e2=',(-QB-sqrt(radical))/2000./QA,(-QB+sqrt(radical))/2000./QA
    !	write(6,*) 'E_pi1,2=',vertex.nu+targ.M-(-QB-sqrt(radical))/2./QA,
    !     >				vertex.nu+targ.M-(-QB+sqrt(radical))/2./QA
    
    
    	  radical = QB**2 - 4.*QA*QC
    	  if (radical.lt.0) return
    	  vertex%p%E = (-QB - sqrt(radical))/2./QA
    	  Ehad2 = (-QB + sqrt(radical))/2./QA
    
    	  if (doing_delta) then		!choose one of the two solutions.
    !	    write(6,*) ' e1, e2=',vertex%p%E,Ehad2
    	    if (grnd().gt.0.5) vertex%p%E = Ehad2
    	  else				!verify that 'backwards' soln. is no good.
    	    if (Ehad2.gt.edge%p%E%min .and. Ehad2.lt.edge%p%E%max .and. ntried.le.5000) then
    	      write(6,*) 'The low-momentum solution to E_hadron is within the spectrometer generation'
    	      write(6,*) 'limits.  If it is in the acceptance, Its the end of the world as we know it!!!'
    	      write(6,*) 'E_hadron solns=',vertex%p%E,Ehad2
    	    endif
    	  endif
    
    	  E_rec=c-vertex%p%E	!energy of recoil system
    	  if (E_rec.le.targ%Mrec_struck) return	!non-physical solution
    
    	  if (vertex%p%E.le.Mh) return
    	  vertex%p%P = sqrt(vertex%p%E**2 - Mh2)
    	  vertex%p%delta = (vertex%p%P - spec%p%P)*100./spec%p%P
    !	write(6,*) 'p,e=',vertex%p%P,vertex%p%E
    
    	elseif (doing_rho) then
    	   call generate_rho(vertex,success)  !generate rho in 4pi in CM
    	   if(.not.success) then
    	      return
    	   else  ! we have a success, but set back to false for rest of complete_ev
    	      success=.false.
    	   endif
    
    	elseif (doing_phsp) then
    
    	  vertex%p%P = spec%p%P		!????? single arm phsp??
    	  vertex%p%E= sqrt(Mh2+vertex%p%P**2)
    	  vertex%p%delta = (vertex%p%P - spec%p%P)*100./spec%p%P
    	  if (debug(4)) write(6,*)'comp_ev: at 7.5',Mh2,vertex%p%E
    
    	endif
    
    	if (debug(4)) write(6,*)'comp_ev: at 7'
    
    ! Compute some pion and kaon stuff.  Some of these should be OK for proton too.
    
    
    	if (doing_pion .or. doing_kaon .or. doing_delta .or. doing_rho .or. doing_semi) then
    	  W2 = targ%Mtar_struck**2 + 2.*targ%Mtar_struck*vertex%nu - vertex%Q2
    	  main%W = sqrt(abs(W2)) * W2/abs(W2) 
    	  main%epsilon=1./(1. + 2.*(1+vertex%nu**2/vertex%Q2)*tan(vertex%e%theta/2.)**2)
    	  main%theta_pq=acos(vertex%up%x*vertex%uq%x+vertex%up%y*vertex%uq%y+vertex%up%z*vertex%uq%z)
    	  main%t = vertex%Q2 - Mh2 + 2*vertex%nu*vertex%p%E -
         >		2*vertex%p%P*vertex%q*cos(main%theta_pq)
    	  main%tmin = vertex%Q2 - Mh2 + 2*vertex%p%E*vertex%nu -
         >		2*vertex%p%P*vertex%q
    	  main%q2 = vertex%Q2
    
    ! CALCULATE ANGLE PHI BETWEEN SCATTERING PLANE AND REACTION PLANE.
    ! Therefore, define a new system with the z axis parallel to q, and
    ! the x axis inside the q-z-plane: z' = q, y' = q X z, x' = y' X q
    ! this gives phi the way it is usually defined, i.e. phi=0 for in-plane
    ! particles closer to the downstream beamline than q.
    ! phi=90 is above the horizontal plane when q points to the right, and
    ! below the horizontal plane when q points to the left.
    ! Also take into account the different definitions of x, y and z in
    ! replay and SIMC:
    ! As seen looking downstream:  		replay	SIMC	(old_simc)
    !				x	right	down	(left)
    !				y	down	left	(up)
    !				z	all have z pointing downstream
    !
    ! SO: x_replay=-y_simc, y_replay=x_simc, z_replay= z_simc
    
    	  qx = -vertex%uq%y		!convert to 'replay' coord. system
    	  qy =  vertex%uq%x
    	  qz =  vertex%uq%z
    	  px = -vertex%up%y
    	  py =  vertex%up%x
    	  pz =  vertex%up%z
    
    	  dummy=sqrt((qx**2+qy**2)*(qx**2+qy**2+qz**2))
    	  new_x_x = -qx*qz/dummy
    	  new_x_y = -qy*qz/dummy
    	  new_x_z = (qx**2 + qy**2)/dummy
    
    	  dummy   = sqrt(qx**2 + qy**2)
    	  new_y_x =  qy/dummy
    	  new_y_y = -qx/dummy
    	  new_y_z =  0.0
    
    	  p_new_x = px*new_x_x + py*new_x_y + pz*new_x_z
    	  p_new_y = px*new_y_x + py*new_y_y + pz*new_y_z
    
    	  main%phi_pq = atan2(p_new_y,p_new_x)		!atan2(y,x)=atan(y/x)
    	  if (main%phi_pq.lt.0.e0) main%phi_pq=main%phi_pq+2.*pi
    !	  if (p_new_y.lt.0.) then
    !	    main.phi_pq = 2*pi - main.phi_pq
    !	  endif
    
    !	  if ((p_new_x**2+p_new_y**2).eq.0.) then
    !	    main.phi_pq = 0.0
    !	  else
    !	    main.phi_pq = acos(p_new_x/sqrt(p_new_x**2+p_new_y**2))
    !	  endif
    !	  if (p_new_y.lt.0.) then
    !	    main.phi_pq = 2*pi - main.phi_pq
    !	  endif
    
    	  if (debug(2)) then
    	    write(6,*)'comp_ev: nu =',vertex%nu
    	    write(6,*)'comp_ev: Q2 =',vertex%Q2
    	    write(6,*)'comp_ev: theta_e =',vertex%e%theta
    	    write(6,*)'comp_ev: epsilon =',main%epsilon
    	    write(6,*)'comp_ev: theta_pq =',main%theta_pq
    	    write(6,*)'comp_ev: phi_pq =',main%phi_pq
    	    write(6,*)'comp_ev: E_hadron =',vertex%p%E
    	  endif
    
    
    	  if(using_tgt_field) then   !calculate some azimuthal angles that only make
    	                             !sense for polarized target
    ! CALCULATE ANGLE PHI BETWEEN SCATTERING PLANE AND TARGET POLARIZATION.
    ! As seen looking downstream:  		replay	SIMC	(old_simc)
    !				x	right	down	(left)
    !				y	down	left	(up)
    !				z	all have z pointing downstream
    !
    ! SO: x_replay=-y_simc, y_replay=x_simc, z_replay= z_simc
    
    	     qx = -vertex%uq%y	!convert to 'replay' coord. system
    	     qy =  vertex%uq%x
    	     qz =  vertex%uq%z
    
    c Target in-plane, so targy=0
    	     targx = -targ_pol*sin(abs(targ_Bangle)) ! replay coordinates
    	     targy = 0.0
    	     targz = targ_pol*cos(abs(targ_Bangle)) 
    
    c Target out of plane, so targx=0
    c       targx = 0.0      ! replay coordinates
    c       targy = -targ_pol*sin(abs(targ_Bangle))
    c       targz = targ_pol*cos(abs(targ_Bangle)) 
    	     
    	     dummy=sqrt((qx**2+qy**2)*(qx**2+qy**2+qz**2))
    	     new_x_x = -qx*qz/dummy
    	     new_x_y = -qy*qz/dummy
    	     new_x_z = (qx**2 + qy**2)/dummy
    	     
    	     dummy   = sqrt(qx**2 + qy**2)
    	     new_y_x =  qy/dummy
    	     new_y_y = -qx/dummy
    	     new_y_z =  0.0
    
    	     p_new_x = targx*new_x_x + targy*new_x_y + targz*new_x_z
    	     p_new_y = targx*new_y_x + targy*new_y_y + targz*new_y_z
    
    	     main%phi_targ = atan2(p_new_y,p_new_x) !atan2(y,x)=atan(y/x)
    	     if(main%phi_targ.lt.0.) main%phi_targ = 2.*pi+main%phi_targ
    
    
    ! CALCULATE ANGLE BETA BETWEEN REACTION PLANE AND TRANSVERSE TARGET 
    ! POLARIZATION.
    ! As seen looking downstream:		replay	SIMC	(old_simc)
    !				x	right	down	(left)
    !				y	down	left	(up)
    !				z	all have z pointing downstream
    !
    ! SO: x_replay=-y_simc, y_replay=x_simc, z_replay= z_simc
    
    	     qx = -vertex%uq%y	!convert to 'replay' coord% system
    	     qy =  vertex%uq%x
    	     qz =  vertex%uq%z
    
    C Taret in plane
    	     targx = -targ_pol*sin(abs(targ_Bangle)) ! 'replay' coordinates
    	     targy = 0.0
    	     targz = targ_pol*cos(abs(targ_Bangle)) 
    
    C Target out of plane
    
    c	targx = 0.0		! 'replay' coordinates
    c	targy = -targ_pol*sin(abs(targ_Bangle))
    c	targz = targ_pol*cos(abs(targ_Bangle)) 
    
    	     px = -vertex%up%y
    	     py =  vertex%up%x
    	     pz =  vertex%up%z
    	     
    	     dummy   = sqrt((qy*pz-qz*py)**2 + (qz*px-qx*pz)**2 + (qx*py-qy*px)**2)
    	     new_y_x =  (qy*pz-qz*py)/dummy
    	     new_y_y =  (qz*px-qx*pz)/dummy
    	     new_y_z =  (qx*py-qy*px)/dummy
    	     
    	     dummy   = sqrt((new_y_y*qz-new_y_z*qy)**2 + (new_y_z*qx-new_y_x*qz)**2
         >  	  + (new_y_x*qy-new_y_y*qx)**2)
    
    	     new_x_x = (new_y_y*qz - new_y_z*qy)/dummy
    	     new_x_y = (new_y_z*qx - new_y_x*qz)/dummy
    	     new_x_z = (new_y_x*qy - new_y_y*qx)/dummy
    	     
    
    	     targ_new_x = targx*new_x_x + targy*new_x_y + targz*new_x_z
    	     targ_new_y = targx*new_y_x + targy*new_y_y + targz*new_y_z
    
    	     main%beta = atan2(targ_new_y,targ_new_x)
    	     if(main%beta .lt. 0.) main%beta = 2*pi+main%beta
    
    
    CDJG Calculate the "Collins" (phi_pq+phi_targ) and "Sivers"(phi_pq-phi_targ) angles
    	     vertex%phi_s = main%phi_pq-main%phi_targ
    	     if(vertex%phi_s .lt. 0.) vertex%phi_s = 2*pi+vertex%phi_s
    
    	     vertex%phi_c = main%phi_pq+main%phi_targ
    	     if(vertex%phi_c .gt. 2.*pi) vertex%phi_c = vertex%phi_c-2*pi
    	     if(vertex%phi_c .lt. 0.0) vertex%phi_c = 2*pi+vertex%phi_c
    
    	     
    	     dummy = sqrt((qx**2+qy**2+qz**2))*sqrt((targx**2+targy**2+targz**2))
    	     main%theta_tarq = acos((qx*targx+qy*targy+qz*targz)/dummy)
    
    	  endif !polarized-target specific azimuthal angles
    
    
    	endif		!end of pion/kaon specific stuff.
    
    	if (debug(4)) write(6,*)'comp_ev: at 8'
    
    ! Compute the Pm vector in in SIMC LAB system, with x down, and y to the left.
    ! Computer Parallel, Perpendicular, and Out of Plane componenants.
    ! Parallel is component along q_hat.  Out/plane is component along
    ! (e_hat) x (q_hat)  (oop_x,oop_y are components of out/plane unit vector)
    ! Perp. component is what's left: along (q_hat) x (oop_hat).
    ! So looking along q, out of plane is down, perp. is left.
    
    	vertex%Pmx = vertex%p%P*vertex%up%x - vertex%q*vertex%uq%x
    	vertex%Pmy = vertex%p%P*vertex%up%y - vertex%q*vertex%uq%y
    	vertex%Pmz = vertex%p%P*vertex%up%z - vertex%q*vertex%uq%z
    	vertex%Pmiss = sqrt(vertex%Pmx**2+vertex%Pmy**2+vertex%Pmz**2)
    	vertex%Emiss = vertex%nu + targ%M - vertex%p%E
    
    !STILL NEED SIGN FOR PmPer!!!!!!
    
    	oop_x = -vertex%uq%y	! oop_x = q_y *(z_hat x y_hat) = q_y *-(x_hat)
    	oop_y =  vertex%uq%x	! oop_y = q_x *(z_hat x x_hat) = q_x * (y_hat)
    	vertex%PmPar = (vertex%Pmx*vertex%uq%x + vertex%Pmy*vertex%uq%y + vertex%Pmz*vertex%uq%z)
    	vertex%PmOop = (vertex%Pmx*oop_x + vertex%Pmy*oop_y) / sqrt(oop_x**2+oop_y**2)
    	vertex%PmPer = sqrt( max(0.e0, vertex%Pm**2 - vertex%PmPar**2 - vertex%PmOop**2 ) )
    
    	if (debug(4)) write(6,*)'comp_ev: at 9',vertex%Pmx,vertex%Pmy,vertex%Pmz
    
    ! Calculate Em, Pm, Mrec, Trec for all cases not already done.
    ! For doing_heavy, get Mrec from nu+M=Ep+Erec, and Erec**2=Mrec**2+Pm**2
    ! For (e,e'pi/K), could go back and determine momentum of recoil struck
    ! particle, and get Mrec and Trec seperately for struck nucleon(hyperon)
    ! and A-1 system.  For now, just take Trec for the A-1 system, and ignore
    ! the recoiling struck nucleon (hyperon), so Trec=0 for hydrogen target.
    
    	if (doing_hyd_elast) then
    	  vertex%Trec = 0.0
    	else if (doing_deuterium) then
    	  vertex%Pm = vertex%Pmiss
    	  vertex%Trec = sqrt(vertex%Mrec**2 + vertex%Pm**2) - vertex%Mrec
    	else if (doing_heavy) then
    	  vertex%Pm = vertex%Pmiss
    	  vertex%Mrec = sqrt(vertex%Emiss**2-vertex%Pmiss**2)
    	  vertex%Em = targ%Mtar_struck + vertex%Mrec - targ%M
    	  vertex%Trec = sqrt(vertex%Mrec**2 + vertex%Pm**2) - vertex%Mrec
    	else if (doing_hydpi .or. doing_hydkaon .or. doing_hyddelta .or. doing_hydrho) then
    	  vertex%Trec = 0.0
    	else if (doing_deutpi.or.doing_hepi.or.doing_deutkaon.or.doing_hekaon
         >       .or.doing_deutdelta.or.doing_hedelta.or.doing_deutrho.or.doing_herho) then
    	  vertex%Trec = sqrt(vertex%Mrec**2 + vertex%Pm**2) - vertex%Mrec
    	else if (doing_semi) then
    	   vertex%Pm = vertex%Pmiss
    	   vertex%Em = vertex%Emiss
    	endif
    
    	if (debug(5)) write(6,*) 'vertex%Pm,vertex%Trec,vertex%Em',vertex%Pm,vertex%Trec,vertex%Em
    	if (debug(4)) write(6,*)'comp_ev: at 10'
    
    
    ! calculate krel for deuteron/heavy pion(kaon).  Deuteron is straightforward.
    ! A>2 case is some approximation for 3He (DJG).
    
    	if (doing_deutpi .or. doing_deutkaon .or. doing_deutdelta .or. doing_deutrho) then
    	  if ((vertex%Emiss**2-vertex%Pmiss**2).lt.0) write(6,*) 'BAD MM!!!!! Emiss,Pmiss=',vertex%Emiss, vertex%Pmiss
    	  MM = sqrt(max(0.e0,vertex%Emiss**2-vertex%Pmiss**2))
    	  krel = sqrt( max(0.e0,MM**2-4.*targ%Mrec_struck**2) )
    	else if (doing_hepi .or. doing_hekaon .or. doing_hedelta .or. doing_herho) then
    	  if ((vertex%Emiss**2-vertex%Pmiss**2).lt.0) write(6,*) 'BAD MM!!!!! Emiss,Pmiss=',vertex%Emiss, vertex%Pmiss
    	  MM = sqrt(max(0.e0,vertex%Emiss**2-vertex%Pmiss**2))
    	  krelx = vertex%Pmx + 1.5*pferx*pfer
    	  krely = vertex%Pmy + 1.5*pfery*pfer
    	  krelz = vertex%Pmz + 1.5*pferz*pfer
    	  krel = sqrt(krelx**2+krely**2+krelz**2)
    	  if(vertex%Em.lt.6.0) krel = -krel		!bound state test???
    	endif
    	ntup%krel = krel
    
    	if(doing_semi) then
    CDJG	   if ((vertex%Emiss**2-vertex%Pmiss**2).lt.0) then
    CDJG I should be testing that the missing mass is above two pion
    CDJG threshold! Otherwise, it's just exclusive
    c	   if ((vertex%Emiss**2-vertex%Pmiss**2).lt.(Mp+Mpi0)**2) then
    	   if (((targ%Mtar_struck+vertex%nu-vertex%p%E)**2-vertex%Pmiss**2).lt.(Mp+Mpi0)**2) then
    	      success=.false.
    	      return
    	   endif
    	endif
    
    	if(doing_semi) then
    	   vertex%zhad = vertex%p%E/vertex%nu
    	   vertex%pt2 = vertex%p%P**2*(1.0-cos(main%theta_pq)**2)
    	   if(vertex%zhad.gt.1.0) then
    	      success=.false.
    	      return
    	   endif
    	endif
    
    
    ! Determine PHYSICS scattering angles theta/phi for the two spectrometer
    ! vectors, and the Jacobian which we must include in our xsec computation
    ! to take into account the fact that we're not generating in the physics
    ! solid angle d(omega) but in 'spectrometer angles' yptar,xptar.
    ! NOTE: the conversion from spectrometer to physics angles was done when
    ! the angles were first generated (except for the proton angle for hydrogen
    ! elastic, where it was done earlier in complete_ev).
    !
    !	call physics_angles(spec.e.theta,spec.e.phi,
    !     &		vertex.e.xptar,vertex.e.yptar,vertex.e.theta,vertex.e.phi)
    !	call physics_angles(spec.p.theta,spec.p.phi,
    !     &		vertex.p.xptar,vertex.p.yptar,vertex.p.theta,vertex.p.phi)
    
    	r = sqrt(1.+vertex%e%yptar**2+vertex%e%xptar**2) !r=cos(theta-theta0)
    	main%jacobian = main%jacobian / r**3		 !1/cos**3(theta-theta0)
    
    C DJG Since we generate rho's in 4pi (in spherical angles) we don't need no
    C DJG stinkin' Jacobian!
    
    	if (doing_heavy .or. doing_pion .or. doing_kaon .or. 
         >      doing_delta .or. doing_semi) then
    	  r = sqrt(1.+vertex%p%yptar**2+vertex%p%xptar**2)
    	  main%jacobian = main%jacobian / r**3		 !1/cos**3(theta-theta0)
    	endif
    
    	if (debug(4)) write(6,*)'comp_ev: at 11'
    
    ! The effective target thickness that the scattered particles see, and the
    ! resulting energy losses
    
    
    	call trip_thru_target (2, main%target%z-targ%zoffset, vertex%e%E,
         >		vertex%e%theta, main%target%Eloss(2), main%target%teff(2),Me,1)
    
    	call trip_thru_target (3, main%target%z-targ%zoffset, vertex%p%E,
         >		vertex%p%theta, main%target%Eloss(3), main%target%teff(3),Mh,1)
    
    	if (.not.using_Eloss) then
    	  main%target%Eloss(2) = 0.0
    	  main%target%Eloss(3) = 0.0
    	endif
    	if (debug(4)) write(6,*)'comp_ev: at 12'
    
    ! Initialize parameters necessary for radiative corrections
    
    	call radc_init_ev(main,vertex)
    
    ! Success code
    
    	success = .true.
    	if(debug(2)) write(6,*)'comp_ev: at end...'
    	return
    	end
    
    !---------------------------------------------------------------------
    
    	subroutine complete_recon_ev(recon,success)
    
    	implicit none
    	include 'simulate.inc'
    
    	real*8 p_new_x,p_new_y,new_x_x,new_x_y,new_x_z
    	real*8 new_y_x,new_y_y,new_y_z,dummy
    	real*8 targ_new_x,targ_new_y
    	real*8 px,py,pz,qx,qy,qz
    	real*8 targx,targy,targz
    	real*8 W2
    	real*8 oop_x,oop_y
    	real*8 mm,mmA,mm2,mmA2,t
    
    	logical success
    	type(event)::	recon
    
    !-----------------------------------------------------------------------
    ! Calculate everything left in the /event/ structure, given
    !	recon.Ein, and the following for both recon.e AND recon.p:
    ! delta,xptar,yptar, z,P,E,theta,phi (with E,P corrected for eloss, if desired).
    !
    ! The SINGLE element of /event/ NOT computed here is sigcc (for (e,e'p)).
    !
    !-----------------------------------------------------------------------
    
    ! Initialize
    
    	success = .false.
    
    	recon%Ein = Ebeam_vertex_ave	!lowered by most probable eloss (init.f)
    
    ! ... unit vector components of outgoing e,p
    ! ... z is DOWNSTREAM, x is DOWN and y is LEFT looking downstream.
    
    C Ebeam_vertex_ave has been shifted to account for Coulomb effects
    C In general, the Hall C analyzer does not correct for this
    C If you do NOT apply an energy shift in the ENGINE to account
    C for Coulomb corrections, make sure the line below is NOT commented out.
    	recon%Ein = Ebeam_vertex_ave - targ%Coulomb%ave
    
    	if (debug(4)) write(6,*)'comp_rec_ev: at 1'
    	recon%ue%x = sin(recon%e%theta)*cos(recon%e%phi)
    	recon%ue%y = sin(recon%e%theta)*sin(recon%e%phi)
    	recon%ue%z = cos(recon%e%theta)
    	recon%up%x = sin(recon%p%theta)*cos(recon%p%phi)
    	recon%up%y = sin(recon%p%theta)*sin(recon%p%phi)
    	recon%up%z = cos(recon%p%theta)
    	if (debug(4)) write(6,*)'comp_rec_ev: at 2'
    
    ! The q vector
    
    	if (debug(5)) write(6,*)'comp_rec_ev: Ein,E,uez=',recon%Ein,recon%e%E,recon%ue%z
    	recon%nu = recon%Ein - recon%e%E
    	recon%Q2 = 2*recon%Ein*recon%e%E*(1-recon%ue%z)
    	recon%q	= sqrt(recon%Q2 + recon%nu**2)
    	recon%uq%x = - recon%e%P*recon%ue%x / recon%q
    	recon%uq%y = - recon%e%P*recon%ue%y / recon%q
    	recon%uq%z =(recon%Ein - recon%e%P*recon%ue%z)/ recon%q
    
    c	if (doing_pion .or. doing_kaon .or. doing_delta .or. doing_rho .or. doing_semi) then
    c	   W2 = targ%mtar_struck**2 + 2.*targ%mtar_struck*recon%nu - recon%Q2
    c	else
    c	   W2 = targ%M**2 + 2.*targ%M*recon%nu - recon%Q2
    c	endif
    
    c Everyone else in the world calculates W using the proton mass.
    	W2 = mp**2 + 2.*mp*recon%nu - recon%Q2
    
    	recon%W = sqrt(abs(W2)) * W2/abs(W2) 
    	recon%xbj = recon%Q2/2./Mp/recon%nu
    	if (debug(4)) write(6,*)'comp_rec_ev: at 5'
    
    ! Now complete the p side
    
    	if(doing_phsp)then
    	  recon%p%P=spec%p%P
    	  recon%p%E=sqrt(Mh2+recon%p%P**2)
    	  if (debug(4)) write(6,*)'comp_rec_ev: at 7.5',Mh2,recon%p%E
    	endif
    
    ! Compute some pion/kaon stuff.
    
    	recon%epsilon=1./(1. + 2.*(1+recon%nu**2/recon%Q2)*tan(recon%e%theta/2.)**2)
    	recon%theta_pq=acos(min(1.0,recon%up%x*recon%uq%x+recon%up%y*recon%uq%y+recon%up%z*recon%uq%z))
    
    ! CALCULATE ANGLE PHI BETWEEN SCATTERING PLANE AND REACTION PLANE.
    ! Therefore, define a new system with the z axis parallel to q, and
    ! the x axis inside the q-z-plane: z' = q, y' = q X z, x' = y' X q
    ! this gives phi the way it is usually defined, i.e. phi=0 for in-plane
    ! particles closer to the downstream beamline than q.
    ! phi=90 is above the horizontal plane when q points to the right, and
    ! below the horizontal plane when q points to the left.
    ! Also take into account the different definitions of x, y and z in
    ! replay and SIMC:
    ! As seen looking downstream:		replay	SIMC	(old_simc)
    !				x	right	down	(left)
    !				y	down	left	(up)
    !				z	all have z pointing downstream
    !
    ! SO: x_replay=-y_simc, y_replay=x_simc, z_replay= z_simc
    
    	qx = -recon%uq%y		!convert to 'replay' coord. system
    	qy =  recon%uq%x
    	qz =  recon%uq%z
    	px = -recon%up%y
    	py =  recon%up%x
    	pz =  recon%up%z
    
    	dummy=sqrt((qx**2+qy**2)*(qx**2+qy**2+qz**2))
    	new_x_x = -qx*qz/dummy
    	new_x_y = -qy*qz/dummy
    	new_x_z = (qx**2 + qy**2)/dummy
    
    	dummy   = sqrt(qx**2 + qy**2)
    	new_y_x =  qy/dummy
    	new_y_y = -qx/dummy
    	new_y_z =  0.0
    
    	p_new_x = px*new_x_x + py*new_x_y + pz*new_x_z
    	p_new_y = px*new_y_x + py*new_y_y + pz*new_y_z
    
    	if ((p_new_x**2+p_new_y**2).eq.0.) then
    	  recon%phi_pq = 0.0
    	else
    	  recon%phi_pq = acos(p_new_x/sqrt(p_new_x**2+p_new_y**2))
    	endif
    	if (p_new_y.lt.0.) then
    	  recon%phi_pq = 2*pi - recon%phi_pq
    	endif
    
    
    	if(using_tgt_field) then !calculate polarized-target specific azimuthal angles
    
    ! CALCULATE ANGLE PHI BETWEEN SCATTERING PLANE AND TARGET POL.
    ! Take into account the different definitions of x, y and z in
    ! replay and SIMC:
    ! As seen looking downstream:		replay	SIMC	(old_simc)
    !				x	right	down	(left)
    !				y	down	left	(up)
    !				z	all have z pointing downstream
    !
    ! SO: x_replay=-y_simc, y_replay=x_simc, z_replay= z_simc
    
    	   qx = -recon%uq%y	!convert to 'replay' coord. system
    	   qy =  recon%uq%x
    	   qz =  recon%uq%z
    
    C In-plane target
    	   targx = -targ_pol*sin(abs(targ_Bangle)) ! 'replay' coordinates
    	   targy = 0.0
    	   targz = targ_pol*cos(abs(targ_Bangle)) 
    
    C out of plane target
    c	targx = 0.0       ! 'replay' coordinates
    c	targy = -targ_pol*sin(abs(targ_Bangle)) 
    c	targz = targ_pol*cos(abs(targ_Bangle)) 
    
    	   dummy=sqrt((qx**2+qy**2)*(qx**2+qy**2+qz**2))
    	   new_x_x = -qx*qz/dummy
    	   new_x_y = -qy*qz/dummy
    	   new_x_z = (qx**2 + qy**2)/dummy
    
    	   dummy   = sqrt(qx**2 + qy**2)
    	   new_y_x =  qy/dummy
    	   new_y_y = -qx/dummy
    	   new_y_z =  0.0
    
    	   p_new_x = targx*new_x_x + targy*new_x_y + targz*new_x_z
    	   p_new_y = targx*new_y_x + targy*new_y_y + targz*new_y_z
    	   
    
    	   recon%phi_targ = atan2(p_new_y,p_new_x)
    	   if(recon%phi_targ.lt.0.) recon%phi_targ = 2.*pi + recon%phi_targ
    
    
    ! CALCULATE ANGLE BETA BETWEEN REACTION PLANE AND (TRANSVERSE) TARGET 
    ! POLARIZATION.
    ! Also take into account the different definitions of x, y and z in
    ! replay and SIMC:
    ! As seen looking downstream:		replay	SIMC	(old_simc)
    !				x	right	down	(left)
    !				y	down	left	(up)
    !				z	all have z pointing downstream
    !
    ! SO: x_replay=-y_simc, y_replay=x_simc, z_replay= z_simc
    
    	   qx = -recon%uq%y	!convert to 'replay' coord. system
    	   qy =  recon%uq%x
    	   qz =  recon%uq%z
    
    	   targx = -targ_pol*sin(abs(targ_Bangle)) ! 'replay' coordinates
    	   targy = 0.0
    	   targz = targ_pol*cos(abs(targ_Bangle)) 
    
    c	targx = 0.0              ! 'replay' coordinates
    c	targy = -targ_pol*sin(abs(targ_Bangle))
    c	targz = targ_pol*cos(abs(targ_Bangle)) 
    
    
    	   px = -recon%up%y
    	   py =  recon%up%x
    	   pz =  recon%up%z
    
    	   dummy   = sqrt((qy*pz-qz*py)**2 + (qz*px-qx*pz)**2 + (qx*py-qy*px)**2)
    	   new_y_x =  (qy*pz-qz*py)/dummy
    	   new_y_y =  (qz*px-qx*pz)/dummy
    	   new_y_z =  (qx*py-qy*px)/dummy
    
    	   dummy   = sqrt((new_y_y*qz-new_y_z*qy)**2 + (new_y_z*qx-new_y_x*qz)**2
         >  	+ (new_y_x*qy-new_y_y*qx)**2)
    
    	   new_x_x = (new_y_y*qz - new_y_z*qy)/dummy
    	   new_x_y = (new_y_z*qx - new_y_x*qz)/dummy
    	   new_x_z = (new_y_x*qy - new_y_y*qx)/dummy
    
    
    	   targ_new_x = targx*new_x_x + targy*new_x_y + targz*new_x_z
    	   targ_new_y = targx*new_y_x + targy*new_y_y + targz*new_y_z
    
    	   recon%beta = atan2(targ_new_y,targ_new_x)
    	   if(recon%beta.lt.0.) recon%beta = 2.*pi + recon%beta
    
    CDJG Calculate the "Collins" (phi_pq+phi_targ) and "Sivers"(phi_pq-phi_targ) angles
    	   recon%phi_s = recon%phi_pq-recon%phi_targ
    	   if(recon%phi_s .lt. 0.) recon%phi_s = 2*pi+recon%phi_s
    
    	   recon%phi_c = recon%phi_pq+recon%phi_targ
    	   if(recon%phi_c .gt. 2.*pi) recon%phi_c = recon%phi_c-2*pi
    	   if(recon%phi_c .lt. 0.) recon%phi_c = 2*pi+recon%phi_c
    
    	   dummy = sqrt((qx**2+qy**2+qz**2))*sqrt((targx**2+targy**2+targz**2))
    	   recon%theta_tarq = acos((qx*targx+qy*targy+qz*targz)/dummy)
    	endif !polarized-target specific stuff
    
    	if (debug(2)) then
    	  write(6,*)'comp_rec_ev: nu =',recon%nu
    	  write(6,*)'comp_rec_ev: Q2 =',recon%Q2
    	  write(6,*)'comp_rec_ev: theta_e =',recon%e%theta
    	  write(6,*)'comp_rec_ev: epsilon =',recon%epsilon
    	  write(6,*)'comp_rec_ev: theta_pq =',recon%theta_pq
    	  write(6,*)'comp_rec_ev: phi_pq =',recon%phi_pq
    	endif
    
    	if (debug(4)) write(6,*)'comp_rec_ev: at 8'
    
    ! Compute the Pm vector in in SIMC LAB system, with x down, and y to the left.
    ! Computer Parallel, Perpendicular, and Out of Plane componenants.
    ! Parallel is component along q_hat.  Out/plane is component along
    ! (e_hat) x (q_hat)  (oop_x,oop_y are components of out/plane unit vector)
    ! Perp. component is what's left: along (q_hat) x (oop_hat).
    ! So looking along q, out of plane is down, perp. is left.
    
    	recon%Pmx = recon%p%P*recon%up%x - recon%q*recon%uq%x
    	recon%Pmy = recon%p%P*recon%up%y - recon%q*recon%uq%y
    	recon%Pmz = recon%p%P*recon%up%z - recon%q*recon%uq%z
    	recon%Pm = sqrt(recon%Pmx**2+recon%Pmy**2+recon%Pmz**2)
    
    !STILL NEED SIGN FOR PmPer!!!!!!
    
    	oop_x = -recon%uq%y	! oop_x = q_y *(z_hat x y_hat) = q_y *-(x_hat)
    	oop_y =  recon%uq%x	! oop_y = q_x *(z_hat x x_hat) = q_x * (y_hat)
    	recon%PmPar = (recon%Pmx*recon%uq%x + recon%Pmy*recon%uq%y + recon%Pmz*recon%uq%z)
    	recon%PmOop = (recon%Pmx*oop_x + recon%Pmy*oop_y) / sqrt(oop_x**2+oop_y**2)
    	recon%PmPer = sqrt( max(0.e0, recon%Pm**2 - recon%PmPar**2 - recon%PmOop**2 ) )
    
    	if (doing_pion .or. doing_kaon .or. doing_delta .or. doing_rho .or. doing_semi) then
    	  recon%Em = recon%nu + targ%Mtar_struck - recon%p%E
              mm2 = recon%Em**2 - recon%Pm**2
              mm  = sqrt(abs(mm2)) * abs(mm2)/mm2
              mmA2= (recon%nu + targ%M - recon%p%E)**2 - recon%Pm**2
              mmA = sqrt(abs(mmA2)) * abs(mmA2)/mmA2
              t = recon%Q2 - Mh2
         >      + 2*(recon%nu*recon%p%E - recon%p%P*recon%q*cos(recon%theta_pq))
    	  ntup%mm = mm
    	  ntup%mmA = mmA
    	  ntup%t = t
    	endif
    
    	if(doing_semi.or.doing_rho) then
    	   recon%zhad = recon%p%E/recon%nu
    	   recon%pt2 = recon%p%P**2*(1.0-cos(recon%theta_pq)**2)
    	endif
    
    ! Calculate Trec, Em. Trec for (A-1) system (eep), or for struck nucleon (pi/K)
    ! Note that there are other ways to calculate 'Em' for the pion/kaon case.
    ! This Em for pi/kaon gives roughly E_m + E_rec + T_{A-1}  (I think)
    	if (doing_hyd_elast) then
    	  recon%Trec = 0.0
    	  recon%Em = recon%nu + targ%M - recon%p%E - recon%Trec
    	else if (doing_deuterium .or. doing_heavy) then
    	  recon%Trec = sqrt(recon%Pm**2+targ%Mrec**2) - targ%Mrec
    	  recon%Em = recon%nu + targ%Mtar_struck - recon%p%E - recon%Trec
    	else if (doing_pion .or. doing_kaon .or. doing_delta .or. doing_rho) then
    	  recon%Em = recon%nu + targ%Mtar_struck - recon%p%E
    	endif
    
    	if (debug(5)) write(6,*) 'recon%Pm,recon%Trec,recon%Em',recon%Pm,recon%Trec,recon%Em
    	if (debug(4)) write(6,*)'comp_rec_ev: at 10'
    
    	success=.true.
    	return
    	end
    
    !------------------------------------------------------------------------
    
    	subroutine complete_main(force_sigcc,main,vertex,vertex0,recon,success)
    
    	implicit none
    	include 'simulate.inc'
    
    	integer		i, iPm1
    	real*8		a, b, r, frac, peepi, peeK, peedelta, peerho, peepiX
    	real*8		survivalprob, semi_dilution
    	real*8		weight, width, sigep, deForest, tgtweight
    	logical		force_sigcc, success
    	type(event_main):: main
    	type(event)::	vertex, vertex0, recon
    
    !-----------------------------------------------------------------------
    ! Calculate everything left in the /main/ structure that hasn't been
    ! required up til now. This routine is called ONLY after we
    ! know an event IS going to contribute, don't want to be doing these
    ! calculations if they're not needed!
    !
    ! A small anomaly is that sigcc from the /event/ structure is computed
    ! here since it's not needed til now, and was not calculated by
    ! COMPLETE_ev.
    !-----------------------------------------------------------------------
    
    
    ! Initialize success code
    
    	if (debug(2)) write(6,*)'comp_main:  entering...'
    	success = .false.
    
    ! The spectral function weighting
    
    	if (doing_hyd_elast.or.doing_pion.or.doing_kaon.or.doing_delta.or.doing_phsp.or.doing_rho.or.doing_semi) then !no SF.
    	  main%SF_weight=1.0
    	else if (use_benhar_sf.and.doing_heavy) then ! Doing Spectral Functions
    	   call sf_lookup_diff(vertex%Em, vertex%Pm, weight)
    	   main%SF_weight = targ%Z*transparency*weight
     	else if (doing_deuterium .or. (doing_heavy.and.(.not.use_benhar_sf))) then
    	  main%SF_weight = 0.0
    	  do i=1,nrhoPm
    	    weight = 0.0
    
    ! ... use linear interpolation to determine rho(pm)
    
    	    r = (vertex%Pm-Pm_theory(i)%min)/Pm_theory(i)%bin
    	    if (r.ge.0 .and. r.le.Pm_theory(i)%n) then
    	      iPm1 = nint(r)
    	      if (iPm1.eq.0) iPm1 = 1
    	      if (iPm1.eq.Pm_theory(i)%n) iPm1 = Pm_theory(i)%n-1
    	      frac = r+0.5-float(iPm1)
    	      b = theory(i,iPm1)
    	      a = theory(i,iPm1+1)-b
    	      weight = a*frac + b
    	    endif
    
    	    if (doing_heavy) then
    
    	      width=Emsig_theory(i)/2.0
    	      if (vertex%Em.lt.E_Fermi) weight = 0.0
    	      weight=weight/pi/Em_int_theory(i) * width/
         >				((vertex%Em-Em_theory(i))**2+width**2)
    	    endif
    	    main%SF_weight = main%SF_weight+weight*nprot_theory(i)
    	  enddo ! <i=1,nrhoPm>
    	endif
    
    ! ... if we have come up with weight<=, quit now (avoid weight<0 in ntuple)
    ! ... unless FORCE_SIGCC is on (to get central sigcc).
    
    	if (debug(5))write(6,*)'comp_main: calculating cross section'
    	if (main%SF_weight.le.0 .and. .not.force_sigcc) return
    
    ! ... Cross section, for BOTH vertex and recon (where possible)
    ! ... Note that all of these are cross section per nucleon.  For A(e,e'p)
    ! ... this becomes cross section per nucleus because of the weighting of
    ! ... the spectral function.  For pion/kaon production, we explicitly
    ! ... apply a weight for the number of nucleons involved (protons for pi+ or Y0,
    ! ... neutrons for pi- or Y-) (Y=hyperon)
    
    	tgtweight = 1.0
    
    	if (doing_phsp) then
    	  main%sigcc = 1.0
    	  main%sigcc_recon = 1.0
    
    	elseif (doing_hyd_elast) then
    	  main%sigcc = sigep(vertex)
    	  main%sigcc_recon = sigep(recon)
    
    	elseif (doing_deuterium.or.doing_heavy) then
    	  main%sigcc = deForest(vertex)		
    	  main%sigcc_recon = deForest(recon)
    
    	elseif (doing_pion) then
    	  main%sigcc = peepi(vertex,main)
    	  main%sigcc_recon = 1.0
    	  if (which_pion.eq.1 .or. which_pion.eq.11) then  !OK for coherent???
    	    tgtweight = targ%N
    	  else
    	    tgtweight = targ%Z
    	  endif
    
    	elseif (doing_kaon) then
    	  main%sigcc = peeK(vertex,main,survivalprob)
    	  main%sigcc_recon = 1.0
    	  if (which_kaon.eq.2 .or. which_kaon.eq.12) then  !OK for coherent???
    	    tgtweight = targ%N
    	  else
    	    tgtweight = targ%Z
    	  endif
    
    	elseif (doing_delta) then
    	  main%sigcc = peedelta(vertex,main)	!Need new xsec model.
    	  main%sigcc_recon = 1.0
    
    	elseif (doing_rho) then
    	  main%sigcc = peerho(vertex,main)
    	  main%sigcc_recon = 1.0
    
    	elseif (doing_semi) then
    	  main%sigcc = peepiX(vertex,vertex0,main,survivalprob,.FALSE.)
    	  main%sigcc_recon = 1.0
    	  main%sigcent = peepiX(vertex,vertex0,main,survivalprob,.TRUE.)
    	  ntup%dilu = semi_dilution(vertex,main) 
    
    	else
    	  main%sigcc = 1.0
    	  main%sigcc_recon = 1.0
    	endif
    
    C If using Coulomb cirrections, include focusing factor
    	if(using_Coulomb) then
    	   main%sigcc = main%sigcc*(1.0+targ%Coulomb%ave/Ebeam)**2
    	endif
    
    	if (debug(3)) then
    	  write(6,*)'======================================'
    	  write(6,*)'complete_main:'
    	  write(6,*)'theta_e =',vertex%e%theta
    	  write(6,*)'q mag =',vertex%q
    	  write(6,*)'nu =',vertex%nu
    	  write(6,*)'Q2 =',vertex%Q2/1000000.
    	  write(6,*)'Ein =',vertex%Ein
    	  write(6,*)'hadron mom =',vertex%p%P
    	  write(6,*)'e mom =',vertex%e%P
    	  write(6,*)'mass =',Mh
    	  write(6,*)'epsilon =',main%epsilon
    	  write(6,*)'phi_pq =',main%phi_pq
    	  write(6,*)'theta_pq =',main%theta_pq
    	  write(6,*)'======================================'
    	endif
    
    ! The total contributing weight from this event -- this weight is
    ! proportional to # experimental counts represented by the event.
    ! Apply survival probability to kaons if we're not modeling decay.
    
    	main%weight = main%SF_weight*main%jacobian*main%gen_weight*main%sigcc
    	main%weight = main%weight * tgtweight	!correct for #/nucleons involved
    	if ((doing_kaon.or.doing_semika) .and. .not.doing_decay) 
         >		main%weight = main%weight*survivalprob
    	if (debug(5))write(6,*) 'gen_weight = ',main%gen_weight,
         >		main%jacobian,main%sigcc
    
    	success = .true.
    
    	if (debug(2)) write(6,*)'comp_main: ending, success =',success
    	return
    	end
    
    
    	subroutine physics_angles(theta0,phi0,dx,dy,theta,phi)
    
    !Generate physics angles in lab frame.  Theta is angle from beamline.
    !phi is projection on x-y plane (so phi=0 is down, sos=pi/2, hms=3*pi/2.
    !
    !theta=acos( (cos(theta0)-dy*sin(theta0)*sin(phi0))/ sqrt(1+dx**2+dy**2) )
    !phi=atan( (dy*cos(theta0)+sin(theta0)*sin(phi0)) / (sin(theta0)*cos(phi0)+dx) )
    !
    ! Note that these formulae assume phi0=pi/2 or 3*pi/2 (thus the sin(phi0)
    ! gives a -/+ sign for the HMS/SOS).  Thus, we set the cos(phi0) term to zero.
    
    	real*8 dx,dy		!dx/dy (xptar/yptar) for event.
    	real*8 theta0,phi0	!central physics angles of spectrometer.
    	real*8 theta,phi	!physics angles for event.
    	real*8 r,sinth,costh,sinph,cosph	!intermediate variables.
    	real*8 tmp
    
    	include 'constants.inc'
    
    	costh = cos(theta0)
    	sinth = sin(theta0)
    	sinph = sin(phi0)
    	cosph = cos(phi0)
    	r = sqrt( 1. + dx**2 + dy**2 )
    
    	if (abs(cosph).gt.0.0001) then	!phi not at +/- pi/2
    	  write(6,*) 'theta,phi will be incorrect if phi0 <> pi/2 or 3*pi/2'
    	  write(6,*) 'phi0=',phi0,'=',phi0*180/pi,'degrees'
    	endif
    
    	tmp=(costh - dy*sinth*sinph) / r
    	if (abs(tmp).gt.1) write(6,*) 'tmp=',tmp
    	theta = acos( (costh - dy*sinth*sinph) / r )
    	if (dx.ne.0.0) then
    	  phi = atan( (dy*costh + sinth*sinph) / dx )	!gives -90 to 90 deg.
    	  if (phi.le.0) phi=phi+pi			!make 0 to 180 deg.
    	  if (sinph.lt.0.) phi=phi+pi		!add pi to phi for HMS
    	else
    	  phi = phi0
    	endif
    
    	return
    	end
    
    
    
    	subroutine spectrometer_angles(theta0,phi0,dx,dy,theta,phi)
    
    !Generate spectrometer angles from physics angles in lab frame.
    !Theta is angle from beamline.
    !phi is projection on x-y plane (so phi=0 is down, sos=pi/2, hms=3*pi/2.
    
    	real*8 dx,dy		!dx/dy (xptar/yptar) for event.
    	real*8 theta0,phi0	!central physics angles of spectrometer.
    	real*8 theta,phi	!physics angles for event.
    	real*8 x,y,z				!intermediate variables.
    	real*8 x0,y0,z0				!intermediate variables.
    	real*8 cos_dtheta,y_event
    
    	include 'constants.inc'
    
    	x = sin(theta)*cos(phi)
    	y = sin(theta)*sin(phi)
    	z = cos(theta)
    	x0 = sin(theta0)*cos(phi0)
    	y0 = sin(theta0)*sin(phi0)
    	z0 = cos(theta0)
    
    	cos_dtheta = x*x0 + y*y0 + z*z0
    	dx = x / cos_dtheta
    	dy = sqrt(1/cos_dtheta**2-1.-dx**2)
    
    	y_event = y/cos_dtheta	!projected to plane perp. to spectrometer.
    	if (y_event .lt. y0) dy = -dy
    
    	return
    	end