;************************************************************************ pro for_intlos,rbite,thbite,phbite,alfabite,losoffbite,LosPramsStruct,ObsPramsStruct,$ GridPramsStruct,r3D,theta3D,phi3D,r2,cmer2,x2,tau2,dlos,doprint,verbose=verbose ;+ ; Name: FOR_INTLOS ; ; Purpose: DETERMINE spherical coords along LOS in viewer's coordinate system, also determine line of sight vector and differential line of sight dlos ; ; INPUTS ; ; rbite,thbite,phbite - reduced POS array ; (rbite is radial position at the intersection of the LOS and the X=0 plane) ; (remember thbite goes 0 to 360 counterclockwise) ; alfabite - limb ; LosPramsStruct,ObsPramsStruct,GridPramsStruct ; doprint = whether to print verbose stuff ; losoffbite -- GridPramsStruct.LOSoffset -- if an array, put into bite size ; for_get_grid will store one of four things here: ; 1) if USER and POS set and LOSOFFSET not inputted as keyword, will be the distance of the user points ; (inputted in spherical geometry r3D,theta3D,phi3D) ; along the LOS from the intersection of the LOS with either X=0 or TS (XLOS, or TLOS/TAU) ; 2) if USER and POS set and LOSOFFSET inputted by user, will be the sum of that input ; and the LOS distance as in 1 ; 3) if USER and POS not set, all LOSOFFSET information will be ignored ; because integration will be centered on X=0 (XLOS) or TS (TLOS, TAU) ; *note -- I had thought to center integrals on the USER point, but that way madness lies ; the integral should be over infinite LOS, and if not, optimized to includes most emission/brightness ; -- which is why we center on X=0 or TS ; however, we will need to be careful to zero out LOSOFFSET and to deal with above solar disk ; as we would for nonuser Grids ; 4) if USER not set, and POS set, and LOSOFFSET inputted ; will be the user input value ; 5) if USER not set, and POS not set, and LOSOFFSET inputted ; will be ignored (should in fact be forced to 0) ; ; KEYWORD INPUT ; verbose ; ; OUTPUTS ; ; r3D,theta3D,phi3D - spherical coords along LOS, in viewer's system of dimension [nlos,nactualbite] ; (note nlos can be reduced from original input if OBSLOSLIMIT is set to a maximum radius) ; r2- pos position of LOS intersection but put in [nlos,nactualbite] matrix ; cmer2 - central meridian in [nlos,nactualbite] matrix ; tau2 LOS angle along line of sight, dimension [nlos,nactualbite] ; x2 - line of sight position vector, dimension [nlos,nactualbite] ; for both XLOS and TLOS - XLOS forces parallel lines of sight ; dlos - differential line of sight, dimension [nlos,nactualbite] ; this is dx -- even if we use TAU it is converted ; used in for_euvsxrcalc and for_radiocalc although no longer explicitly ; used in for_integrate (int_tabulated function doesn't need as such - implicit in array) ; ; Called by: FOR_INTENSINT ; ; History: Written by Sarah Gibson 2015 ;- ; Feb 5 2016: changed definition of Tau so ; mimics XLOS in that it is always negative ; behind POS independent of limb -- see ; comments below ; Feb 2018: added Elongation capability ; for lines of sight not close to sun ; applications e.g. to heliospheric imaging ; July 2018: added test for POS before elongation problem ; April 2020: BUG FIX -- inconsistency between tau2 and dlos ; Nov 2020: BUG FIX -- asymmetric integrations in tau were being thwarted ; by recalculation associated with obsloslimit ; Jan 2021: edited VERBOSE stuff ; Sep 2021: fix(round so that nlos didn't end up long ; Oct 2021: added fix for USER LOS=tau integration ; LOSoffset needs to be taken into account in determiing POS intersection ; of line of sight ; Dec 2021 - Jan 2022: passed through distobs, defined tau2 for xlos case ; added comments ; March 2022 -- fixed bug where dlos didn't have LOS dimension ; added TLOS capability ; also introduced RBITEUSE so that RBITE not changed ; also changed xoffset --> losoffset ; removed unnecessary rloslimit change of nlos for tau -- after all ; those points removed later for all choices LOSUSE ; and dealt with in for_intensint by reducing to *rmoduse* etc ; April 2022 -- added keyword nostretch ; July 2022 - fixed problem with USER losoffset ; Sept 2022 -- added back revised conditional for POS ne 0 TLOS ; (search on shouldnt) ; was printing unnecessary error ; Oct 2022 -- changed array ( to [ (with help from Vema Panditi) ; added some clarifying comments about how LOSOFFSET used ; fixed bug where stretch was multiplying by < 1 everywhere ; updated integrals to ignore losoff unless POS set ; and fixed bug where TLOS was not centering on POS shifted by LOSOFFSET ; and simplified TLOS vs TAU formulation and overal structure of code ; Nov 2022 -- moved all points below r3d=1 to 1000 to ignore ; Apr 2023 -- commented out NEVIII blocking disk ; May 2022 -- gave same capability for other UV specpol lines ; (OVI, LYA-- be careful esp. for LYA ; -- just for tests because ; generally chromo not treated in FORWARD) ; ; useful variables pid2= !dpi/2.d0 nactualbite=n_elements(rbite) ; ; distance from observer ; usually 1 AU 215 Rsun ; but e.g. Probe, Orbiter will change this ; so in future this can be a parameter ; note if one goes too close in, the Thomson Sphere shrinks to be partly inside the Sun. distobs=GridPramsStruct.DistObs ; ; check elongation -- ; if rbite greater than about 5, print warning ; better to step constant angle ; elongbite=atan(rbite/distobs) if max(elongbite) gt 0.02 and strupcase(LosPramsStruct.LosUse) eq 'XLOS' and ObsPramsStruct.Pos eq 0 then begin print,'WARNING: max elongation=',max(elongbite) print,'Consider switching LOSUSE to TAU or TLOS for nonparallel lines of sight.' endif ; ; figure out starting point on LOS (losmin) ; and number of points along LOS (nlos) losmin=LosPramsStruct.LosMin nlos=LosPramsStruct.NLos losint=LosPramsStruct.LosInt ; ; scale by elongation if LOSUSE=TLOS ; UNLESS keyword "nostretch" is set ; note this will give LOSMIN, LOSINT dimension of rbite (POS) ; if tag_exist(LosPramsStruct,'NoStretch') then begin if is_number(LosPramsStruct.NoStretch) then nostretch=LosPramsStruct.NoStretch $ else nostretch=0 endif else nostretch=0 if strupcase(LosPramsStruct.LosUse) eq 'TLOS' and nostretch eq 0 then begin if verbose eq 1 then begin print,'losmin orig',minmax(losmin) print,'losint orig',minmax(losint) endif if ObsPramsStruct.Pos eq 0 then begin losmaxorig=losmin+losint*(nlos-1) ; this was a bug ; losmin=losmin*distobs*sin(elongbite) ; losmaxnew=losmaxorig*distobs*sin(elongbite) losmin=losmin/cos(elongbite) losmaxnew=losmaxorig/cos(elongbite) losint=(losmaxnew-losmin)/(nlos-1) endif endif ; POS dimension matrix bitenorm = replicate(1.,(nactualbite)) ; LOS dimension matrix losnorm = replicate(1.,nlos) losintbite= losint*bitenorm cmer2=losnorm#phbite r2 = losnorm#rbite th2=losnorm#thbite elong2=losnorm#elongbite alfa2=losnorm#alfabite losoff2=losnorm#losoffbite tau2=r2*0.d0 ; IF INTEGRATING OVER TAU -- LOS ANGLE ; or TLOS -- constant distance along (not parallel) LOS if strupcase(LosPramsStruct.LosUse) eq 'TAU' $ or strupcase(LosPramsStruct.LosUse) eq 'TLOS' then begin if ObsPramsStruct.Pos ne 0 then begin if strupcase(LosPramsStruct.LosUse) eq 'TAU' then print,'for_intlos,losuse=tau,pos=',ObsPramsStruct.Pos,': shouldnt happen' if strupcase(LosPramsStruct.LosUse) eq 'TLOS' and ObsPramsStruct.Pos ne 2 $ then print,'for_intlos, losuse=tlos, pos=',ObsPramsStruct.Pos,': shouldnt happen' endif ; ; calculate spherical coords along lines of sight ; ; commented out below -- the old way assuming zero elongation ; (new version should reduce to this for elong=0) ; ; dlos = losint*r2/cos(tau2)/cos(tau2) ; r3D=(1/cos(tau2))*r2 ; ; theta3D = acos(cos(tau2)*cos(th2)) ; ; changed below to abs(sin(th2))) ; (remember th2 is 0 to 360) ; so that now tau negative is always behind plane of sky ; so integration along LOS occurs in same order as for XLOS ; matters for lyman absorption, or integration asymmetric about POS ; ; (alfa identifies which limb we are looking at) ; ; phi2=atan(tan(tau2)*(1/abs(sin(th2)))) ; phi3D = alfa2*(pid2 - phi2) ; ; ; now recalculate more generally ; ; it's helpful to first calculate ; 3D coordinates of point along (no longer necessarily parallel) lines of sight ; the loci of intersections of LOS with its closest appoach to sun ; make up the Thomson sphere ; ; note r2 and th2 are still plane of sky (X=0 plane) intersecting radius and polar angle ; can convert these to spherical coordinates of point of intersection of LOS with Thomson Sphere ; rp2, thp2, php2 ; ; essentially we are making our LOS spacing cluster at the TS. This makes sense for white light ; but not other observables -- but, only WL will be out so far as for this to matter ; and it is not wrong, just perhaps not optimal LOS spacing for other wavelengths, anyway ; (it is optimal for WL, which is the point) rp2=r2*cos(elong2) rpbite=rbite*cos(elongbite) ; don't actually use these next, but useful for reference ; ; thp2=acos(cos(elong2)*cos(th2)) ; ; elong between 0 and pi/2, so cos(elong) always positive ; ; cos(th2),cos(thp2) positive in north, negative in south as they should be ; thp2 has lost information about east west, but that is ok, it is retained in alfa ; ; php2 = asin(sin(elong2)/sin(thp2)) ; which is equivalent to ; php2 = atan(tan(elong2)*(1/abs(sin(th2)))) ; now make sure tau is within -pi/2 to pi/2 limits ; and if elong significant make sure in front of the observer ; so maximum positive angle is pi/2-elong ; ; note if we put a value for taumin close to -1.57 we can get into the ; situation of all bite points needing to be changed because elongbite is > 0 ; ; in this case we will keep the number of points and change the resolution ; because this is a hard cutoff and we need to apply it for all ; cases (including CoMP, etc. which has problems with matrices where NLOS varies from point to point) ; low=-1.57d0 highbite=1.57d0-elongbite ; ; ALSO we need to check if there is a LOS offset ; either because of user keyword input LOSOFFSET and POS slice ; or because doing gridtype='USER' and POS slice (both of which will only happen for TLOS and POS=2), ; and we need to adjust our center for POS integral accordingly if strupcase(LosPramsStruct.LosUse) eq 'TLOS' then begin if ObsPramsStruct.Pos eq 2 then begin ; this is the angle from the TS, just for reference ; gamma2 = atan(losoffbite,rpbite) ; and this is the radial distance to it ; but this is also for reference because we are going to measure ; tau from the TS still, since that is where teh right angle is ; rpbitep=sqrt(rpbite*rpbite + losoffbite*losoffbite) losoffbiteuse=losoffbite endif else begin losoffbiteuse=0. endelse ; this next includes losoffbiteuse explicitly and is in radians tauminbite=atan(losmin+losoffbiteuse,rpbite)>low ; note this next does not include losoffbiteuse explicitly (although an adjustment ; has been made to aovid going below -pid2 that takes it into account) ; and it is in distance units losminbite=tan(tauminbite)*rpbite-losoffbiteuse ; this nextdoes include losoffbiteuse explicitly losmaxbite=losminbite+losoffbiteuse+losintbite*(nlos-1) ; as does this taumaxbite=atan(losmaxbite,rpbite) losmaxbitenew=tan(taumaxbitelow taumaxbite=tauminbite+losintbite*(nlos-1) losintbitenew=(taumaxbite1000 ; as defined above; these individual points along the LOS will ; be ignored in for_intlos, but the entire LOS does not need to be ; thrown away since the foreground points are good. ; ; be careful though because sometimes r3d=1.0 exactly will trigger ; the NaN -- might be better to just throw all of them to r3D>1000 ; -- trying that now test = where(r3D lt 1.0,p) ;if p gt 0 and strupcase(ObsPramsStruct.Instrument) ne 'RADIO' and $ ; strupcase(GridPramsStruct.GridType) ne 'USER' $ ; then r3D[test]=sqrt(-1) ;if p gt 0 and $ ; strupcase(GridPramsStruct.GridType) eq 'USER' $ ; then r3D[test]=1000.d0 if p gt 0 then $ r3D[test]=1000.d0 end