def compute_jones (Jones,sources,stations=None,inspectors=[],**kw): """Creates the Z Jones for ionospheric phase, given TECs (per source, per station)."""; stations = stations or Context.array.stations; ns = Jones.Subscope(); piercings = iono_geometry.compute_piercings(ns,sources,stations); za_cos = iono_geometry.compute_za_cosines(ns,sources,stations); tecs = iono_model(ns,piercings,za_cos,sources,stations); # make inspector for TECs inspectors.append( Jones.scope.inspector('TEC') << StdTrees.define_inspector(tecs,sources,stations, label='tec',freqavg=False) ); if diff_mode: absJones = Jones('abs'); iono_geometry.compute_zeta_jones_from_tecs(absJones,tecs,sources,stations); for src in sources: for p in stations: Jones(src,p) << absJones(src,p)/absJones(sources[0],p); else: iono_geometry.compute_zeta_jones_from_tecs(Jones,tecs,sources,stations); # make inspector for ionospheric phases Zphase = ns.Zphase; for src in sources: for p in stations: Zphase(src,p) << Meq.Arg(Jones(src,p)); inspectors += [ Jones.scope.inspector('iono_phase') << \ StdTrees.define_inspector(Zphase,sources,stations,label='z'), Jones.scope.inspector('iono_piercings') << \ StdTrees.define_inspector(ns.dxy,sources,stations,label='dxy'), ] return Jones;
def compute_jones(Jones, sources, stations=None, inspectors=[], **kw): """Creates the Z Jones for ionospheric phase, given TECs (per source, per station).""" stations = stations or Context.array.stations ns = Jones.Subscope() piercings = iono_geometry.compute_piercings(ns, sources, stations) za_cos = iono_geometry.compute_za_cosines(ns, sources, stations) tecs = iono_model(ns, piercings, za_cos, sources, stations) # make inspector for TECs inspectors.append( Jones.scope.inspector('TEC') << StdTrees.define_inspector( tecs, sources, stations, label='tec', freqavg=False)) if diff_mode: absJones = Jones('abs') iono_geometry.compute_zeta_jones_from_tecs(absJones, tecs, sources, stations) for src in sources: for p in stations: Jones(src, p) << absJones(src, p) / absJones(sources[0], p) else: iono_geometry.compute_zeta_jones_from_tecs(Jones, tecs, sources, stations) # make inspector for ionospheric phases Zphase = ns.Zphase for src in sources: for p in stations: Zphase(src, p) << Meq.Arg(Jones(src, p)) inspectors += [ Jones.scope.inspector('iono_phase') << \ StdTrees.define_inspector(Zphase,sources,stations,label='z'), Jones.scope.inspector('iono_piercings') << \ StdTrees.define_inspector(ns.dxy,sources,stations,label='dxy'), ] return Jones
def compute_jones (Jones,sources,stations=None,pointing_offsets=None,inspectors=[],label='E',**kw): stations = stations or Context.array.stations; ns = Jones.Subscope(); # make the gridded beam pattern node beam = ns.beam; make_beam_nodes(beam); # declare an inspector node for the Jons matrix -- will be defined below insp = Jones.scope.inspector(label); inspectors += [ insp ]; # if sky rotation is in effect, make rotation matrices if sky_rotation: for p in stations: pa = ns.pa(p) << Meq.ParAngle(radec=Context.observation.radec0(),xyz=Context.array.xyz(p)); ca = ns.cos_pa(p) << Meq.Cos(pa); sa = ns.sin_pa(p) << Meq.Sin(pa); ns.parot(p) << Meq.Matrix22(ca,-sa,sa,ca); # loop over sources for src in sources: # If sky rotation and/or pointing offsets are in effect, we have a per-station beam. # Otherwise the beam is the same for all stations. if sky_rotation or pointing_offsets: for p in stations: lm = src.direction.lm(); # apply rotation to put sources into the antenna frame if sky_rotation: lm = ns.lmrot(src,p) << Meq.MatrixMultiply(ns.parot(p),src.direction.lm()); # apply offset (so pointing offsets are interpreted in the azel frame, if rotating) if pointing_offsets: lm = ns.lmoff(src,p) << lm + pointing_offsets(p); # now make the resampler/compounder combo. dep_mask=0xFF is a little cache-defeating magic # (becaise I'm too lazy to fiure out the proper symdep to put in) res = Jones("res",src,p) << Meq.Resampler(ns.beam,dep_mask=0xFF); Jones(src,p) << Meq.Compounder(lm,res,common_axes=[hiid('l'),hiid('m')]); else: # compute E for a given source. Use Resampler (though this is not really adequate!) res = Jones("res",src) << Meq.Resampler(ns.beam,dep_mask=0xFF); Jones(src) << Meq.Compounder(src.direction.lm(),res,common_axes=[hiid('l'),hiid('m')]); for p in stations: Jones(src,p) << Meq.Identity(Jones(src)) # add a bookmark for the beam pattern Meow.Bookmarks.Page("%s-Jones beam pattern"%label).add(beam,viewer="Result Plotter"); # define an inspector if sky_rotation or pointing_offsets: # Jones inspector is per-source, per-station insp << StdTrees.define_inspector(Jones,sources,stations,label=label); else: # Jones inspector is per-source insp << StdTrees.define_inspector(Jones,sources,label=label); return Jones;
def compute_jones(Jones, sources, stations=None, pointing_offsets=None, inspectors=[], label='E', **kw): stations = stations or Context.array.stations ns = Jones.Subscope() # declare an inspector node for the Jones matrix -- will be defined below insp = Jones.scope.inspector(label) inspectors += [insp] radec0 = Context.observation.phase_centre.radec( ) if interpol_coord is COORD_THETAPHI else None # loop over sources for src in sources: xy = src.direction.radec( ) if interpol_coord is COORD_THETAPHI else src.direction.lm() # If sky rotation and/or horizon masking and/or pointing offsets are in effect, we have a per-station beam. # Otherwise the beam is the same for all stations. if sky_rotation or pointing_offsets or horizon_masking: for p in stations: azel = src.direction.azel( Context.array.xyz(p)) if horizon_masking else None pa = Context.observation.phase_centre.pa( Context.array.xyz(p)) if sky_rotation else None # apply offset in the node (so pointing offsets are interpreted in the azel frame, if rotating) make_beam_node(Jones(src, p), filename_pattern, xy, radec0=radec0, dlm=pointing_offsets and pointing_offsets(p), azel=azel, pa=pa) else: make_beam_node(Jones(src), filename_pattern, xy, radec0=radec0) for p in stations: Jones(src, p) << Meq.Identity(Jones(src)) # define an inspector if sky_rotation or pointing_offsets or horizon_masking: # Jones inspector is per-source, per-station insp << StdTrees.define_inspector( Jones, sources, stations, label=label) else: # Jones inspector is per-source insp << StdTrees.define_inspector(Jones, sources, label=label) return Jones
def compute_jones(Jones, sources, stations=None, pointing_offsets=None, inspectors=[], label='E', **kw): stations = stations or Context.array.stations ns = Jones.Subscope() # declare an inspector node for the Jones matrix -- will be defined below insp = Jones.scope.inspector(label) inspectors += [insp] # loop over sources for src in sources: # If sky rotation and/or pointing offsets are in effect, we have a per-station beam. # Otherwise the beam is the same for all stations. if sky_rotation or pointing_offsets: for p in stations: lm = src.direction.lm() # apply rotation to put sources into the antenna frame if sky_rotation: xyz = Context.array.xyz(p) pa_rot = Context.observation.phase_centre.pa_rot(xyz) lm = ns.lmrot(src, p) << Meq.MatrixMultiply( pa_rot, src.direction.lm()) # apply offset in the node (so pointing offsets are interpreted in the azel frame, if rotating) make_beam_node(Jones(src, p), filename_pattern, lm, pointing_offsets and pointing_offsets(p)) else: make_beam_node(Jones(src), filename_pattern, src.direction.lm()) for p in stations: Jones(src, p) << Meq.Identity(Jones(src)) # define an inspector if sky_rotation or pointing_offsets: # Jones inspector is per-source, per-station insp << StdTrees.define_inspector( Jones, sources, stations, label=label) else: # Jones inspector is per-source insp << StdTrees.define_inspector(Jones, sources, label=label) return Jones
def compute_jones (Jones,sources,stations=None,pointing_offsets=None,inspectors=[],label='E',**kw): stations = stations or Context.array.stations; ns = Jones.Subscope(); # declare an inspector node for the Jones matrix -- will be defined below insp = Jones.scope.inspector(label); inspectors += [ insp ]; # loop over sources for src in sources: # If sky rotation and/or pointing offsets are in effect, we have a per-station beam. # Otherwise the beam is the same for all stations. if sky_rotation or pointing_offsets: for p in stations: lm = src.direction.lm(); # apply rotation to put sources into the antenna frame if sky_rotation: xyz = Context.array.xyz(p); pa_rot = Context.observation.phase_centre.pa_rot(xyz); lm = ns.lmrot(src,p) << Meq.MatrixMultiply(pa_rot,src.direction.lm()); # apply offset in the node (so pointing offsets are interpreted in the azel frame, if rotating) make_beam_node(Jones(src,p),filename_pattern,lm,pointing_offsets and pointing_offsets(p)); else: make_beam_node(Jones(src),filename_pattern,src.direction.lm()); for p in stations: Jones(src,p) << Meq.Identity(Jones(src)); # define an inspector if sky_rotation or pointing_offsets: # Jones inspector is per-source, per-station insp << StdTrees.define_inspector(Jones,sources,stations,label=label); else: # Jones inspector is per-source insp << StdTrees.define_inspector(Jones,sources,label=label); return Jones;
def compute_jones (Jones,sources,stations=None,pointing_offsets=None,inspectors=[],label='E',**kw): stations = stations or Context.array.stations; ns = Jones.Subscope(); # declare an inspector node for the Jones matrix -- will be defined below insp = Jones.scope.inspector(label); inspectors += [ insp ]; radec0 = Context.observation.phase_centre.radec() if interpol_coord is COORD_THETAPHI else None; # loop over sources for src in sources: xy = src.direction.radec() if interpol_coord is COORD_THETAPHI else src.direction.lm(); # If sky rotation and/or horizon masking and/or pointing offsets are in effect, we have a per-station beam. # Otherwise the beam is the same for all stations. if sky_rotation or pointing_offsets or horizon_masking: for p in stations: azel = src.direction.azel(Context.array.xyz(p)) if horizon_masking else None; pa = Context.observation.phase_centre.pa(Context.array.xyz(p)) if sky_rotation else None; # apply offset in the node (so pointing offsets are interpreted in the azel frame, if rotating) make_beam_node(Jones(src,p),filename_pattern,xy,radec0=radec0, dlm=pointing_offsets and pointing_offsets(p),azel=azel,pa=pa); else: make_beam_node(Jones(src),filename_pattern,xy,radec0=radec0); for p in stations: Jones(src,p) << Meq.Identity(Jones(src)); # define an inspector if sky_rotation or pointing_offsets or horizon_masking: # Jones inspector is per-source, per-station insp << StdTrees.define_inspector(Jones,sources,stations,label=label); else: # Jones inspector is per-source insp << StdTrees.define_inspector(Jones,sources,label=label); return Jones;
def compute_jones (Jones,sources,stations=None,inspectors=[],label='L',**kw): """Creates the dipole projection matrix."""; stations = stations or Context.array.stations; ns = Jones.Subscope(); insp = Jones.scope.inspector(label); for src in sources: for p in stations: Jones(src,p) << proj_matrix(src,Context.array.xyz(p)); insp << StdTrees.define_inspector(Jones,sources,stations,label=label); # add inspectors StdTrees.inspector(Jones.scope.inspector(label,'AzEl') ,[src.direction.azel() for src in sources],bookmark=False); inspectors += [ insp,Jones.scope.inspector(label,'AzEl') ]; return Jones;
def compute_jones (self,Jones,sources,stations=None,inspectors=[],**kw): """Computes beam gain for a list of sources. The output node, will be qualified with either a source only, or a source/station pair """; stations = stations or Context.array.stations(); ns = Jones.Subscope(); # init solvables etc. self.init_parameters(ns,sources,stations,inspectors); # this dict will hold LM tuples (or nodes) for each source. lmsrc = {}; # see if sources have a "beam_lm" attribute, use that for beam offsets for src in sources: lm = src.get_attr("beam_lm",None) or src.get_attr("_lm_ncp",None); if lm: src.set_attr(self.label+'r',math.sqrt(lm[0]**2+lm[1]**2)/math.pi*(180*60)); lmsrc[src.name] = ns.lm(src) << Meq.Constant(value=Timba.array.array(lm)); # else try to use static lm coordinates else: # else try to use static lm coordinates lmnst = src.direction.lmn_static(); if lmnst: lm = lmnst[0:2]; src.set_attr(self.label+'r',math.sqrt(lm[0]**2+lm[1]**2)/math.pi*(180*60)); lmsrc[src.name] = ns.lm(src) << Meq.Constant(value=Timba.array.array(lm)); # else use lmn node else: lmsrc[src.name] = src.direction.lm(); if self.per_station: for src in sources: for p in stations: self.make_beam_nodes(Jones(src,p),self.beamshape(p),lmsrc[src.name],self.ell(p),self.dlm(p)); else: p0 = stations[0]; for src in sources: self.make_beam_nodes(Jones(src,p0),self.beamshape(p0),lmsrc[src.name],self.ell(p0),self.dlm(p0)); for p in stations[1:]: Jones(src,p) << Meq.Identity(Jones(src,p0)); # make inspectors inspectors.append(ns.inspector << StdTrees.define_inspector( Jones,sources,stations,label=self.label)); return Jones;
def compute_jones(Jones, sources, stations=None, inspectors=[], meqmaker=None, label='R', **kw): """Creates the Z Jones for ionospheric phase, given TECs (per source, per station).""" stations = stations or Context.array.stations ns = Jones.Subscope() parmdef = Meq.Parm(0, tags="pos_offset") parms = [] uvw = Context.array.uvw() # now loop over sources for isrc, src in enumerate(sources): parms += [ns.dl(src) << parmdef, ns.dm(src) << parmdef] dlmn = ns.dlmn(src) << Meq.Composer(ns.dl(src), ns.dm(src), 0) for p in stations: Jones(src, p) << Meq.VisPhaseShift(lmn=dlmn, uvw=uvw(p)) # make bookmarks srcnames = [src.name for src in sources] meqmaker.make_bookmark_set(Jones, [(src, p) for src in srcnames for p in stations], "%s: inspector plot" % label, "%s: by source-station" % label, freqmean=True) inspectors.append(ns.inspector(label,'dlmn') << \ StdTrees.define_inspector(ns.dlmn,srcnames,label=label)) # make parmgroups and solvejobs global pg pg = ParmGroup.ParmGroup(label, parms, table_name="%s.fmep" % label, bookmark=False) # make solvejobs ParmGroup.SolveJob("cal_" + label, "Calibrate %s (position shifts)" % label, pg) return Jones
def compute_jones(Jones, sources, stations=None, pointing_offsets=None, inspectors=[], label='E', **kw): stations = stations or Context.array.stations ns = Jones.Subscope() JE = Jones("elem") per_station = sky_rotation or pointing_offsets # read offsets file if read_offsets_file: offsets = list(map(float, open(offsets_file).read().split())) if len(offsets) < (beam_number + 1) * 2: raise ValueError("beam number %d not found in offsets file" % beam_number) l_offset, m_offset = offsets[beam_number * 2:(beam_number + 1) * 2] if invert_l: l_offset = -l_offset else: l_offset, m_offset = 0, 0 # loop over sources to create per-element beamgains for src in sources: # If sky rotation and/or pointing offsets are in effect, we have a per-station beam. # Otherwise the beam is the same for all stations. if per_station: for p in stations: lm = src.direction.lm() # apply rotation to put sources into the antenna frame if sky_rotation: xyz = Context.array.xyz(p) pa_rot = Context.observation.phase_centre.pa_rot(xyz) lm = ns.lmrot(src, p) << Meq.MatrixMultiply( pa_rot, src.direction.lm()) # apply offset (so pointing offsets are interpreted in the azel frame, if rotating) if pointing_offsets: lm = ns.lmoff(src, p) << lm + pointing_offsets(p) # now make the beam node make_beam_node(JE(src, p), filename_pattern, l_offset, m_offset, lm) else: make_beam_node(JE(src), filename_pattern, l_offset, m_offset, src.direction.lm()) # now load weights wx = pickle.load(open(weight_filename_x, "rb")) wy = pickle.load(open(weight_filename_y, "rb")) if wx.shape[1] != num_elements or wy.shape[1] != num_elements: raise ValueError( """weights files contain weights for %d (X) and %d (Y) complex elements, %d expected""" % (wx.shape[1], wy.shape[1], num_elements)) if beam_number > wx.shape[0] or beam_number > wy.shape[0]: raise ValueError("beam number %d not found in weights files" % beam_number) # w0:x and w0:y are the nominal weight vectors ns.w0('x') << Meq.Constant(value=wx[beam_number, :]) ns.w0('y') << Meq.Constant(value=wy[beam_number, :]) if sim_element_errors: # create perturbed weights a0 = 10**(min_ampl_var / 20) - 1 a1 = 10**(max_ampl_var / 20) - 1 for p in stations: for xy in 'x', 'y': werr = ns.werr(xy, p) # amplitude and phase period and offset for ap in 'ampl', 'phase': p0 = werr("period", ap) << Meq.Constant(value=[ random.uniform(min_period_var * 3600, max_period_var * 3600) / (2 * math.pi) for i in range(num_elements) ]) if start_phased_up: werr("sin", ap) << Meq.Sin(Meq.Time() / p0) else: t0 = werr("offset", ap) << Meq.Constant(value=[ random.uniform(0, 2 * math.pi) for i in range(num_elements) ]) werr("sin", ap) << Meq.Sin((Meq.Time() / p0) + t0) # amplitude excursion e0 = werr("maxampl") << Meq.Constant(value=[ random.uniform(a0, a1) for i in range(num_elements) ]) ep = werr("maxphase") << Meq.Constant(value=[ random.uniform(min_phase_var * DEG, max_phase_var * DEG) for i in range(num_elements) ]) # weight errors werr << Meq.Polar(1 + e0 * werr("sin", "ampl"), ep * werr("sin", "phase")) ns.weight(xy, p) << ns.w0(xy) * werr # compute matrix norms based on nominal matrices if per_station: quallist = [[src, p] for src in sources for p in stations] else: quallist = [[src] for src in sources] for qq in quallist: ex0 = Jones(*(qq + ["x0"])) << Meq.MatrixMultiply(JE(*qq), ns.w0("x")) ey0 = Jones(*(qq + ["y0"])) << Meq.MatrixMultiply(JE(*qq), ns.w0("y")) J0 = Jones(*(qq + ["nominal"])) << Meq.Composer(ex0, ey0, dims=[2, 2]) if do_normalize or (qq[0] is sources[0] and do_correct): make_norm(J0, Jones(*(qq + ["norm"]))) if do_normalize: # norm towards source is average per-station norm if per_station: for src in sources: Jones(src, "norm") << Meq.Add( *[Jones(src, p, "norm") for p in stations]) / len(stations) #average must be float elif do_correct: if per_station: for src in sources: Jones(sources[0], "norm") << Meq.Add( *[Jones(sources[0], p, "norm") for p in stations]) / len(stations) #average must be float for src in sources[1:]: Jones(src, "norm") << Meq.Identity(Jones(sources[0], "norm")) else: for src in sources: Jones(src, "norm") << 1 # put these together into Jones matrices for src in sources: # jesrc/JJ will eventually point to the unqualified element beam node # of the unqualified jones node. Depending on whether we're per-station or # not, this is qualified with src,p or just src. jesrc = JE(src) jnorm = Jones(src, "norm") JJ = Jones(src) if sim_element_errors: for p in stations: if per_station: jesrc = JE(src, p) JJ = JJ(p) # jesrc returns a (2,N) matrix of element gains towards this source. # Multiply this by the weights to get the "x" and "y" beams ex = Jones(src, p, "x") << Meq.MatrixMultiply( jesrc, ns.weight("x", p)) ey = Jones(src, p, "y") << Meq.MatrixMultiply( jesrc, ns.weight("y", p)) if do_correct: J0 = Jones( src, p, "ref") << Meq.Composer(ex, ey, dims=[2, 2]) / jnorm if src is sources[0]: Jones(src, p) << Meq.Constant(value=[1, 0, 0, 1], dims=[2, 2]) Jones(src, p, "inv") << Meq.MatrixInvert22(J0) else: Jones(src, p) << Meq.MatrixMultiply( Jones(sources[0], p, "inv"), J0) else: Jones(src, p) << Meq.Composer(ex, ey, dims=[2, 2]) / jnorm # no element errors, use nominal beam else: if per_station: for p in stations: if do_correct: J0 = Jones(src, p, "ref") << Jones(src, p, "nominal") / jnorm if src is sources[0]: Jones(src, p) << Meq.Constant(value=[1, 0, 0, 1], dims=[2, 2]) Jones(src, p, "inv") << Meq.MatrixInvert22(J0) else: Jones(src, p) << Meq.MatrixMultiply( Jones(sources[0], p, "inv"), J0) else: Jones(src, p) << Jones(src, p, "nominal") / jnorm else: if do_correct: J0 = Jones(src, "ref") << Jones(src, "nominal") / jnorm if src is sources[0]: Jones(src) << Meq.Constant(value=[1, 0, 0, 1], dims=[2, 2]) Jones(src, "inv") << Meq.MatrixInvert22(J0) else: Jones(src) << Meq.MatrixMultiply( Jones(sources[0], "inv"), J0) else: Jones(src) << Jones(src, "nominal") / jnorm for p in stations: Jones(src, p) << Meq.Identity(Jones(src)) # declare an inspector node for the Jones matrix -- will be defined below insp = Jones.scope.inspector(label) # define inspectors insp << StdTrees.define_inspector(Jones, sources, stations, label=label) inspectors += [insp] if sim_element_errors: insp1 = insp("werr") << StdTrees.define_inspector( ns.werr, ("x", "y"), stations, label="%s weight drifts" % label) insp2 = insp("weights") << StdTrees.define_inspector( ns.weight, ("x", "y"), stations, label="%s weights" % label) inspectors += [insp1, insp2] return Jones
def compute_jones (Jones,sources,stations=None,inspectors=[],meqmaker=None,label='R',**kw): """Creates the Z Jones for ionospheric phase, given TECs (per source, per station)."""; stations = stations or Context.array.stations; ns = Jones.Subscope(); # get reference source if ref_source: # treat as index first dir0 = None; try: dir0 = sources[int(ref_source)].direction; except: pass; # else treat as name, find in list if not dir0: for src0 in sources: if src0.name == ref_source: dir0 = src0.direction; break; # else treat as direction string if not dir0: ff = list(ref_source.split()); if len(ff) < 2 or len(ff) > 3: raise RuntimeError,"invalid reference dir '%s' specified for %s-Jones"%(ref_source,label); global dm; if not dm: raise RuntimeError,"pyrap measures module not available, cannot use direction strings for %s-Jones"%label; if len(ff) == 2: ff = [ 'J2000' ] +ff; # treat as direction measure try: dmdir = dm.direction(*ff); except: raise RuntimeError,"invalid reference dir '%s' specified for %s-Jones"%(ref_source,label); # convert to J2000 and make direction object dmdir = dm.measure(dmdir,'J2000'); ra,dec = dm.getvalue(dmdir)[0].get_value(),dm.getvalue(dmdir)[1].get_value(); dir0 = Meow.Direction(ns,"refdir",ra,dec,static=True); else: dir0 = Context.observation.phase_centre; # make refraction scale node scale = ns.scale(0) << Meq.Parm(0,tags="refraction"); xyz0 = Context.array.xyz0(); if coord_approx: # get PA, and assume it's the same over the whole field pa = ns.pa0 << Meq.ParAngle(dir0.radec(),xyz0); # second column of the Rot(-PA) matrix. Multiply this by del to get a rotation of (0,del) into the lm plane. # The third component (0) is for convenience, as it immediately gives us dl,dm,dn, since we assume dn~0 rot_pa = ns.rotpa0 << Meq.Composer(Meq.Sin(pa),Meq.Cos(pa),0); # el0: elevation of field centre el0 = dir0.el(); if do_extinction: ns.inv_ext0 << Meq.Sin(el0); # inverse of extinction towards el0 # station UVWs uvw = Context.array.uvw(); # now loop over sources for isrc,src in enumerate(sources): # reference direction: no refraction at all if src.direction is dir0: for p in stations: Jones(src,p) << 1; continue; # dEl is source elevation minus el0 # ddEl = scale*dEl: amount by which source refracts (negative means field is compressed) el = src.direction.el() ns.dEl(src) << el - el0; ddel = ns.ddEl(src) << ns.dEl(src)*scale; # get el1: refracted elevation angle if not coord_approx or do_extinction: el1 = ns.el1(src) << el + ddel; # compute extinction component if do_extinction: # compute inverse of extinction towards the refracted direction el1 iext = ns.inv_ext(src) << Meq.Sin(el1); # # and differential extinction is then ext1/ext0 ext = ns.dext(src) << ns.inv_ext0/iext; # Compute dlmn offset in lm plane. if coord_approx: # Approximate mode: ddel is added to elevation, so to get the lm offset, we need # to apply Rot(PA) to the column vector (0,ddel), and then take the sine of the result. dlmn = ns.dlmn(src) << Meq.Sin(ddel*rot_pa); else: ns.azel1(src) << Meq.Composer(src.direction.az(),el1); ns.radec1(src) << Meq.RADec(ns.azel1(src),xyz0); ns.lmn1(src) << Meq.LMN(Context.observation.radec0(),ns.radec1(src)); dlmn = ns.dlmn(src) << ns.lmn1(src) - src.lmn(); # get per-station phases for p in stations: if do_extinction: Jones(src,p) << ext*(ns.phase(src,p) << Meq.VisPhaseShift(lmn=dlmn,uvw=uvw(p))); else: Jones(src,p) << Meq.VisPhaseShift(lmn=dlmn,uvw=uvw(p)); # make bookmarks srcnames = [ src.name for src in sources ]; meqmaker.make_bookmark_set(Jones,[ (src,p) for src in srcnames for p in stations ], "%s: inspector plot"%label,"%s: by source-station"%label,freqmean=True); inspectors.append(ns.inspector(label,'scale') << \ StdTrees.define_inspector(ns.scale,[0],label=label)); inspectors.append(ns.inspector(label,'delta-el') << \ StdTrees.define_inspector(ns.ddEl,srcnames,label=label)); inspectors.append(ns.inspector(label,'delta-el') << \ StdTrees.define_inspector(ns.ddEl,srcnames,label=label)); inspectors.append(ns.inspector(label,'dlmn') << \ StdTrees.define_inspector(ns.dlmn,srcnames,label=label)); if do_extinction: inspectors.append(ns.inspector(label,'inv-ext') << \ StdTrees.define_inspector(ns.inv_ext,srcnames,label=label)); inspectors.append(ns.inspector(label,'diff-ext') << \ StdTrees.define_inspector(ns.dext,srcnames,label=label)); # make parmgroups and solvejobs global pg; pg = ParmGroup.ParmGroup(label,[scale],table_name="%s.fmep"%label,bookmark=False); # make solvejobs ParmGroup.SolveJob("cal_"+label,"Calibrate %s (differential refraction)"%label,pg); return Jones;
def compute_jones (Jones,sources,stations=None,pointing_offsets=None,inspectors=[],label='E',**kw): stations = stations or Context.array.stations; ns = Jones.Subscope(); JE = Jones("elem"); per_station = sky_rotation or pointing_offsets; # read offsets file if read_offsets_file: offsets = map(float,open(offsets_file).read().split()); if len(offsets) < (beam_number+1)*2: raise ValueError,"beam number %d not found in offsets file"%beam_number; l_offset,m_offset = offsets[beam_number*2:(beam_number+1)*2]; if invert_l: l_offset = -l_offset; else: l_offset,m_offset = 0,0; # loop over sources to create per-element beamgains for src in sources: # If sky rotation and/or pointing offsets are in effect, we have a per-station beam. # Otherwise the beam is the same for all stations. if per_station: for p in stations: lm = src.direction.lm(); # apply rotation to put sources into the antenna frame if sky_rotation: xyz = Context.array.xyz(p); pa_rot = Context.observation.phase_centre.pa_rot(xyz); lm = ns.lmrot(src,p) << Meq.MatrixMultiply(pa_rot,src.direction.lm()); # apply offset (so pointing offsets are interpreted in the azel frame, if rotating) if pointing_offsets: lm = ns.lmoff(src,p) << lm + pointing_offsets(p); # now make the beam node make_beam_node(JE(src,p),filename_pattern,l_offset,m_offset,lm); else: make_beam_node(JE(src),filename_pattern,l_offset,m_offset,src.direction.lm()); # now load weights wx = cPickle.load(open(weight_filename_x)); wy = cPickle.load(open(weight_filename_y)); if wx.shape[1] != num_elements or wy.shape[1] != num_elements: raise ValueError,"""weights files contain weights for %d (X) and %d (Y) complex elements, %d expected"""%(wx.shape[1],wy.shape[1],num_elements); if beam_number > wx.shape[0] or beam_number > wy.shape[0]: raise ValueError,"beam number %d not found in weights files"%beam_number; # w0:x and w0:y are the nominal weight vectors ns.w0('x') << Meq.Constant(value=wx[beam_number,:]); ns.w0('y') << Meq.Constant(value=wy[beam_number,:]); if sim_element_errors: # create perturbed weights a0 = 10**(min_ampl_var/20)-1; a1 = 10**(max_ampl_var/20)-1; for p in stations: for xy in 'x','y': werr = ns.werr(xy,p); # amplitude and phase period and offset for ap in 'ampl','phase': p0 = werr("period",ap) << Meq.Constant(value=[random.uniform(min_period_var*3600,max_period_var*3600)/(2*math.pi) for i in range(num_elements)]); if start_phased_up: werr("sin",ap) << Meq.Sin(Meq.Time()/p0); else: t0 = werr("offset",ap) << Meq.Constant(value=[random.uniform(0,2*math.pi) for i in range(num_elements)]); werr("sin",ap) << Meq.Sin((Meq.Time()/p0)+t0); # amplitude excursion e0 = werr("maxampl") << Meq.Constant(value=[random.uniform(a0,a1) for i in range(num_elements)]); ep = werr("maxphase") << Meq.Constant(value=[random.uniform(min_phase_var*DEG,max_phase_var*DEG) for i in range(num_elements)]); # weight errors werr << Meq.Polar(1+e0*werr("sin","ampl"),ep*werr("sin","phase")); ns.weight(xy,p) << ns.w0(xy)*werr; # compute matrix norms based on nominal matrices if per_station: quallist = [ [src,p] for src in sources for p in stations ]; else: quallist = [ [src] for src in sources ]; for qq in quallist: ex0 = Jones(*(qq+["x0"])) << Meq.MatrixMultiply(JE(*qq),ns.w0("x")); ey0 = Jones(*(qq+["y0"])) << Meq.MatrixMultiply(JE(*qq),ns.w0("y")); J0 = Jones(*(qq+["nominal"])) << Meq.Composer(ex0,ey0,dims=[2,2]); if do_normalize or (qq[0] is sources[0] and do_correct): make_norm(J0,Jones(*(qq+["norm"]))); if do_normalize: # norm towards source is average per-station norm if per_station: for src in sources: Jones(src,"norm") << Meq.Add(*[Jones(src,p,"norm") for p in stations])/len(stations); elif do_correct: if per_station: for src in sources: Jones(sources[0],"norm") << Meq.Add(*[Jones(sources[0],p,"norm") for p in stations])/len(stations); for src in sources[1:]: Jones(src,"norm") << Meq.Identity(Jones(sources[0],"norm")); else: for src in sources: Jones(src,"norm") << 1; # put these together into Jones matrices for src in sources: # jesrc/JJ will eventually point to the unqualified element beam node # of the unqualified jones node. Depending on whether we're per-station or # not, this is qualified with src,p or just src. jesrc = JE(src); jnorm = Jones(src,"norm"); JJ = Jones(src); if sim_element_errors: for p in stations: if per_station: jesrc = JE(src,p); JJ = JJ(p); # jesrc returns a (2,N) matrix of element gains towards this source. # Multiply this by the weights to get the "x" and "y" beams ex = Jones(src,p,"x") << Meq.MatrixMultiply(jesrc,ns.weight("x",p)); ey = Jones(src,p,"y") << Meq.MatrixMultiply(jesrc,ns.weight("y",p)); if do_correct: J0 = Jones(src,p,"ref") << Meq.Composer(ex,ey,dims=[2,2])/jnorm; if src is sources[0]: Jones(src,p) << Meq.Constant(value=[1,0,0,1],dims=[2,2]); Jones(src,p,"inv") << Meq.MatrixInvert22(J0); else: Jones(src,p) << Meq.MatrixMultiply(Jones(sources[0],p,"inv"),J0); else: Jones(src,p) << Meq.Composer(ex,ey,dims=[2,2])/jnorm; # no element errors, use nominal beam else: if per_station: for p in stations: if do_correct: J0 = Jones(src,p,"ref") << Jones(src,p,"nominal")/jnorm; if src is sources[0]: Jones(src,p) << Meq.Constant(value=[1,0,0,1],dims=[2,2]); Jones(src,p,"inv") << Meq.MatrixInvert22(J0); else: Jones(src,p) << Meq.MatrixMultiply(Jones(sources[0],p,"inv"),J0); else: Jones(src,p) << Jones(src,p,"nominal")/jnorm; else: if do_correct: J0 = Jones(src,"ref") << Jones(src,"nominal")/jnorm; if src is sources[0]: Jones(src) << Meq.Constant(value=[1,0,0,1],dims=[2,2]); Jones(src,"inv") << Meq.MatrixInvert22(J0); else: Jones(src) << Meq.MatrixMultiply(Jones(sources[0],"inv"),J0); else: Jones(src) << Jones(src,"nominal")/jnorm; for p in stations: Jones(src,p) << Meq.Identity(Jones(src)); # declare an inspector node for the Jones matrix -- will be defined below insp = Jones.scope.inspector(label); # define inspectors insp << StdTrees.define_inspector(Jones,sources,stations,label=label); inspectors += [ insp ]; if sim_element_errors: insp1 = insp("werr") << StdTrees.define_inspector(ns.werr,("x","y"),stations,label="%s weight drifts"%label); insp2 = insp("weights") << StdTrees.define_inspector(ns.weight,("x","y"),stations,label="%s weights"%label); inspectors += [ insp1,insp2 ]; return Jones;
def compute_jones(Jones, sources, stations=None, inspectors=[], meqmaker=None, label='R', **kw): """Creates the Z Jones for ionospheric phase, given TECs (per source, per station).""" stations = stations or Context.array.stations ns = Jones.Subscope() # get reference source if ref_source: # treat as index first dir0 = None try: dir0 = sources[int(ref_source)].direction except: pass # else treat as name, find in list if not dir0: for src0 in sources: if src0.name == ref_source: dir0 = src0.direction break # else treat as direction string if not dir0: ff = list(ref_source.split()) if len(ff) < 2 or len(ff) > 3: raise RuntimeError( "invalid reference dir '%s' specified for %s-Jones" % (ref_source, label)) global dm if not dm: raise RuntimeError( "pyrap measures module not available, cannot use direction strings for %s-Jones" % label) if len(ff) == 2: ff = ['J2000'] + ff # treat as direction measure try: dmdir = dm.direction(*ff) except: raise RuntimeError( "invalid reference dir '%s' specified for %s-Jones" % (ref_source, label)) # convert to J2000 and make direction object dmdir = dm.measure(dmdir, 'J2000') ra, dec = dm.getvalue(dmdir)[0].get_value(), dm.getvalue( dmdir)[1].get_value() dir0 = Meow.Direction(ns, "refdir", ra, dec, static=True) else: dir0 = Context.observation.phase_centre # make refraction scale node scale = ns.scale(0) << Meq.Parm(0, tags="refraction") xyz0 = Context.array.xyz0() if coord_approx: # get PA, and assume it's the same over the whole field pa = ns.pa0 << Meq.ParAngle(dir0.radec(), xyz0) # second column of the Rot(-PA) matrix. Multiply this by del to get a rotation of (0,del) into the lm plane. # The third component (0) is for convenience, as it immediately gives us dl,dm,dn, since we assume dn~0 rot_pa = ns.rotpa0 << Meq.Composer(Meq.Sin(pa), Meq.Cos(pa), 0) # el0: elevation of field centre el0 = dir0.el() if do_extinction: ns.inv_ext0 << Meq.Sin(el0) # inverse of extinction towards el0 # station UVWs uvw = Context.array.uvw() # now loop over sources for isrc, src in enumerate(sources): # reference direction: no refraction at all if src.direction is dir0: for p in stations: Jones(src, p) << 1 continue # dEl is source elevation minus el0 # ddEl = scale*dEl: amount by which source refracts (negative means field is compressed) el = src.direction.el() ns.dEl(src) << el - el0 ddel = ns.ddEl(src) << ns.dEl(src) * scale # get el1: refracted elevation angle if not coord_approx or do_extinction: el1 = ns.el1(src) << el + ddel # compute extinction component if do_extinction: # compute inverse of extinction towards the refracted direction el1 iext = ns.inv_ext(src) << Meq.Sin(el1) # # and differential extinction is then ext1/ext0 ext = ns.dext(src) << ns.inv_ext0 / iext # Compute dlmn offset in lm plane. if coord_approx: # Approximate mode: ddel is added to elevation, so to get the lm offset, we need # to apply Rot(PA) to the column vector (0,ddel), and then take the sine of the result. dlmn = ns.dlmn(src) << Meq.Sin(ddel * rot_pa) else: ns.azel1(src) << Meq.Composer(src.direction.az(), el1) ns.radec1(src) << Meq.RADec(ns.azel1(src), xyz0) ns.lmn1(src) << Meq.LMN(Context.observation.radec0(), ns.radec1(src)) dlmn = ns.dlmn(src) << ns.lmn1(src) - src.lmn() # get per-station phases for p in stations: if do_extinction: Jones(src, p) << ext * (ns.phase(src, p) << Meq.VisPhaseShift( lmn=dlmn, uvw=uvw(p))) else: Jones(src, p) << Meq.VisPhaseShift(lmn=dlmn, uvw=uvw(p)) # make bookmarks srcnames = [src.name for src in sources] meqmaker.make_bookmark_set(Jones, [(src, p) for src in srcnames for p in stations], "%s: inspector plot" % label, "%s: by source-station" % label, freqmean=True) inspectors.append(ns.inspector(label,'scale') << \ StdTrees.define_inspector(ns.scale,[0],label=label)) inspectors.append(ns.inspector(label,'delta-el') << \ StdTrees.define_inspector(ns.ddEl,srcnames,label=label)) inspectors.append(ns.inspector(label,'delta-el') << \ StdTrees.define_inspector(ns.ddEl,srcnames,label=label)) inspectors.append(ns.inspector(label,'dlmn') << \ StdTrees.define_inspector(ns.dlmn,srcnames,label=label)) if do_extinction: inspectors.append(ns.inspector(label,'inv-ext') << \ StdTrees.define_inspector(ns.inv_ext,srcnames,label=label)) inspectors.append(ns.inspector(label,'diff-ext') << \ StdTrees.define_inspector(ns.dext,srcnames,label=label)) # make parmgroups and solvejobs global pg pg = ParmGroup.ParmGroup(label, [scale], table_name="%s.fmep" % label, bookmark=False) # make solvejobs ParmGroup.SolveJob("cal_" + label, "Calibrate %s (differential refraction)" % label, pg) return Jones
def init_parameters (self,ns,sources,stations,inspectors=[]): if self.beamshape is not None: return; # create solvables if enabled parms = []; parmgroups = []; parmdef_scale = Meq.Parm(self.bf*1e-9,tags="beam solvable"); parmdef_ell = Meq.Parm(self.ellipticity,tags="beam solvable"); self.per_station = False; # solvable beam scale if self.solve_scale is PER_STATION: self.beamshape = ns.beamshape; for p in stations: parms.append(beamshape(p) << parmdef_scale); inspectors.append(ns.inspector("scale") << StdTrees.define_inspector(ns.beamshape,stations,label=self.label)); self.per_station = True; elif self.solve_scale is PER_ARRAY: parms.append(ns.beamshape << parmdef_scale); self.beamshape = lambda p:ns.beamshape; else: ns.beamshape ** (self.bf*1e-9); self.beamshape = lambda p:ns.beamshape; # solvable ellipticities if self.solve_ell is PER_STATION: self.ell = ns.ell; for p in stations: ell_xy = ns.ell_xy(p) << parmdef_ell; parms.append(ell_xy); self.ell(p) << Meq.Composer(ell_xy,-ell_xy); inspectors.append(ns.inspector("ellipticity") << StdTrees.define_inspector(ns.ell_xy,stations,label=self.label)); self.per_station = True; elif self.solve_ell is PER_ARRAY: ell_xy = ns.ell_xy << parmdef_ell; parms.append(ell_xy); ns.ell << Meq.Composer(ell_xy,-ell_xy); self.ell = lambda p:ns.ell; elif self.ellipticity != 0: ns.ell ** Meq.Constant([self.ellipticity,-self.ellipticity]); self.ell = lambda p:ns.ell; else: self.ell = lambda p:None; # make parm group, if any solvables have been created if parms: parmgroups.append(ParmGroup.Subgroup("beam shape",list(parms))); # solvable pointings if self.solve_pointings: self.dlm = ns.dlm; parmdef_0 = Meq.Parm(0,tags="beam solvable"); pparms = []; for p in stations: dl = ns.dl(p) << parmdef_0; dm = ns.dm(p) << parmdef_0; ns.dlm(p) << Meq.Composer(dl,dm); pparms += [dl,dm]; parmgroups.append(ParmGroup.Subgroup("pointing offsets",pparms)); parms += pparms; inspectors.append(ns.inspector('dlm') << StdTrees.define_inspector(ns.dlm,stations,label=self.label)); self.per_station = True; else: ns.dlm_null ** Meq.Constant([0,0]); self.dlm = lambda p:ns.dlm_null; # add solve jobs self.solvable = bool(parms); if self.solvable: self.pg_beam = ParmGroup.ParmGroup(self.label,parms,subgroups=parmgroups,table_name="%s.fmep"%self.label,bookmark=True); ParmGroup.SolveJob("cal_"+self.label,"Calibrate beam parameters",self.pg_beam);