;+ ;FUNCTION: mvn_swe_getpad ;PURPOSE: ; Constructs PAD data structure from raw data. ; ;USAGE: ; pad = mvn_swe_getpad(time) ; ;INPUTS: ; time: An array of times for extracting one or more PAD data structure(s) ; from survey data (APID A2). Can be in any format accepted by ; time_double. ; ;KEYWORDS: ; ARCHIVE: Get PAD data from archive instead (APID A3). ; ; ALL: Get all PAD spectra bounded by the earliest and latest times in ; the input time array. ; ; SUM: If set, then sum all PAD's selected. ; ; UNITS: Convert data to these units. (See mvn_swe_convert_units) ; ; $LastChangedBy: dmitchell $ ; $LastChangedDate: 2014-11-17 16:49:19 -0800 (Mon, 17 Nov 2014) $ ; $LastChangedRevision: 16206 $ ; $URL: svn+ssh://thmsvn@ambrosia.ssl.berkeley.edu/repos/spdsoft/trunk/projects/maven/swea/mvn_swe_getpad.pro $ ; ;CREATED BY: David L. Mitchell 03-29-14 ;FILE: mvn_swe_getpad.pro ;- function mvn_swe_getpad, time, archive=archive, all=all, sum=sum, units=units @mvn_swe_com if (size(time,/type) eq 0) then begin print,"You must specify a time." return, 0 endif time = time_double(time) if keyword_set(archive) then begin if (size(a3,/type) ne 8) then begin print,"No PAD archive data." return, 0 endif if keyword_set(all) then begin tmin = min(time, max=tmax, /nan) indx = where((a3.time ge tmin) and (a3.time le tmax), npts) if (npts eq 0L) then begin print,"No PAD archive data at specified time(s)." return, 0 endif time = a3[indx].time endif npts = n_elements(time) pad = replicate(swe_pad_struct, npts) pad.data_name = "SWEA PAD Archive" pad.apid = 'A3'XB aflg = 1 endif else begin if (size(a2,/type) ne 8) then begin print,"No PAD survey data." return, 0 endif if keyword_set(all) then begin tmin = min(time, max=tmax, /nan) indx = where((a2.time ge tmin) and (a2.time le tmax), npts) if (npts eq 0L) then begin print,"No PAD survey data at specified time(s)." return, 0 endif time = a2[indx].time endif npts = n_elements(time) pad = replicate(swe_pad_struct, npts) pad.data_name = "SWEA PAD Survey" pad.apid = 'A2'XB aflg = 0 endelse if (size(swe_mag1,/type) eq 8) then addmag = 1 else addmag = 0 if (size(swe_sc_pot,/type) eq 8) then addpot = 1 else addpot = 0 ; Locate the PAD data closest to the desired time for n=0L,(npts-1L) do begin if (aflg) then begin tgap = min(abs(a3.time - time[n]), i) pkt = a3[i] thsk = min(abs(swe_hsk.time - a3[i].time), j) if (swe_active_chksum ne swe_chksum[j]) then mvn_swe_calib, chksum=swe_chksum[j] endif else begin tgap = min(abs(a2.time - time[n]), i) pkt = a2[i] thsk = min(abs(swe_hsk.time - a2[i].time), j) if (swe_active_chksum ne swe_chksum[j]) then mvn_swe_calib, chksum=swe_chksum[j] endelse pad[n].chksum = swe_active_chksum dt = 1.95D ; measurement span pad[n].time = pkt.time + (dt/2D) ; center time (unix) pad[n].met = pkt.met + (dt/2D) ; center time (met) pad[n].end_time = pkt.time + dt ; end time (unix) pad[n].delta_t = swe_dt[pkt.period] ; cadence ; Integration time per energy/angle bin prior to summing bins ; There are 7 deflection bins for each of 64 energy bins spanning ; 1.95 sec. The first deflection bin is for settling and is ; discarded. pad[n].integ_t = swe_integ_t ; There are 16 anodes (az) X 6 deflections (el). PAD data use the magnetic ; field to calculate the optimal deflection bin for each of the 16 anode ; bins in order to provide the best pitch angle coverage. There is no ; summing of angle bins, even at the highest deflections (as in the 3D's). ; So for each energy bin, there is a 16x1 (az, el) array. The final array ; dimensions are then 64 energies X 16 anodes X 1 deflector bin per anode, ; or 64x16, for short. pad[n].dt_arr = 2.^(pkt.group) ; energy bin summing only ; Pitch angle map pam = mvn_swe_padmap(pkt) pad[n].pa = transpose(pam.pa) pad[n].dpa = transpose(pam.dpa) pad[n].pa_min = transpose(pam.pa_min) pad[n].pa_max = transpose(pam.pa_max) ; Energy bins are summed according to the group parameter. ; Energy resolution in the standard PAD structure allows for the possibility of ; variation with elevation angle. SWEA calibrations show that this variation ; is modest (< 1% from +55 to -30 deg, increasing to ~4% at -45 deg). For ; now, I will not include elevation variation. pad[n].group = pkt.group energy = swe_swp[*,0] # replicate(1.,16) pad[n].energy = energy pad[n].denergy[0,*] = abs(energy[0,*] - energy[1,*]) for i=1,62 do pad[n].denergy[i,*] = abs(energy[i-1,*] - energy[i+1,*])/2. pad[n].denergy[63,*] = abs(energy[62,*] - energy[63,*]) ; Geometric factor. When using V0, the geometric factor is a function of ; energy. There is also variation in azimuth and elevation. pad[n].gf = swe_gf[*,pam.iaz,pkt.group] * swe_dgf[*,pam.jel,pkt.group] ; Relative MCP efficiency. pad[n].eff = swe_mcp_eff[*,pam.iaz,pkt.group] ; Fill in the elevation array (units = deg) pad[n].theta = transpose(swe_el[pam.jel,*,pkt.group]) pad[n].dtheta = transpose(swe_del[pam.jel,*,pkt.group]) ; Fill in the azimuth array - no energy dependance (units = deg) pad[n].phi = replicate(1.,64) # swe_az[pam.iaz] pad[n].dphi = replicate(1.,64) # swe_daz[pam.iaz] ; Calculate solid angles from elevation and azimuth pad[n].domega = (2.*!dtor)*pad[n].dphi * $ cos(pad[n].theta*!dtor) * $ sin(pad[n].dtheta*!dtor/2.) ; Fill in the data array, duplicating values as needed (I have to swap the ; first two dimensions of pkt.data.) counts = transpose(pkt.data[*,indgen(64)/(2^pkt.group)]) var = transpose(pkt.var[*,indgen(64)/(2^pkt.group)]) ; Calculate the deadtime correction, since the units are conveniently COUNTS. ; This makes it possible to convert back and forth between RATE, COUNTS and ; other units. rate = counts/(swe_integ_t*pad[n].dt_arr) ; raw count rate dtc = 1. - rate*swe_dead indx = where(dtc lt swe_min_dtc, count) ; maximum deadtime correction if (count gt 0L) then dtc[indx] = !values.f_nan pad[n].dtc = dtc ; corrected count rate = rate/dtc ; Fill in the magnetic field direction pad[n].Baz = pam.Baz pad[n].Bel = pam.Bel ; Fill in bin numbers (useful for comparing PAD and 3D data) pad[n].iaz = pam.iaz pad[n].jel = pam.jel pad[n].k3d = pam.k3d ; Insert MAG1 data, if available. This is distinct from the MAG angles ; included in the PAD packets (A2, A3), which are calculated by flight ; software using a basic calibration. if (addmag) then begin dt = min(abs(pad[n].time - swe_mag1.time),i) if (dt lt 1D) then pad[n].magf = swe_mag1[i].magf endif ; Insert spacecraft potential, if available if (addpot) then begin dt = min(abs(pad[n].time - swe_sc_pot.time),i) if (dt lt pad[n].delta_t) then pad[n].sc_pot = swe_sc_pot[i].potential $ else pad[n].sc_pot = !values.f_nan endif ; Electron rest mass [eV/(km/s)^2] pad[n].mass = mass_e ; And last, but not least, the data pad[n].data = counts ; raw counts pad[n].var = var ; variance ; Validate the data if (tgap gt 1.1D*pad[n].delta_t) then begin msg = strtrim(string(round(tgap)),2) print,"data gap: ",msg," sec" endif pad[n].valid = 1B ; Yep, it's valid. endfor ; Adjust MCP efficiency for bias increases indx = where(pad.time gt t_mcp[0], count) if (count gt 0L) then pad[indx].eff = pad[indx].eff * 1.5 ; Sum the data. This is done by summing raw counts corrected by deadtime ; and then setting dtc to unity. Also, note that summed PAD's can be ; "blurred" by a changing magnetic field direction, so summing only makes ; sense for short intervals. The theta, phi, and omega tags can be ; hopelessly confused if the MAG direction changes much. if (keyword_set(sum) and (npts gt 1)) then begin padsum = pad[0] padsum.met = mean(pad.met) padsum.time = mean(pad.time) padsum.end_time = max(pad.end_time) tmin = min(pad.time, max=tmax) padsum.delta_t = (tmax - tmin) > pad[0].delta_t padsum.dt_arr = total(pad.dt_arr,3) ; normalization for the sum pa = total(pad.pa,3)/float(npts) ; pitch angles can be blurred dpa = total(pad.dpa,3)/float(npts) sc_pot = mean(pad.sc_pot) Baz = mean(pad.Baz) Bel = mean(pad.Bel) padsum.magf = total(pad.magf,2)/float(npts) padsum.v_flow = total(pad.v_flow,2)/float(npts) padsum.bkg = mean(pad.bkg) padsum.data = total(pad.data/pad.dtc,3) ; corrected counts padsum.var = total(pad.var/pad.dtc,3) ; variance padsum.dtc = 1. ; summing corrected counts is not reversible pad = padsum endif if (size(units,/type) eq 7) then mvn_swe_convert_units, pad, units return, pad end