"""A module defining functions to produce antenna positions algorithmically.Each function here defined may take arbitrary parameters, but must returna single array of shape (Nant, 3) with units of meters, corresponding to (x,y,z) positionsof antennae centred at zero."""from__future__importannotationsimportnumpyasnpfromastropyimportunitsasunfromtypingimportSequencefrom.importunitsastpfrom.importyaml
[docs]@yaml.yaml_func()defhera(hex_num:int,separation:tp.Length=14*un.m,split_core:bool=False,outriggers:bool=False,row_separation:tp.Length|None=None,)->tp.Meters:""" Produce a simple regular hexagonal array. Note that the returned order of the core array antennas matches the antenna numbering used by the HERA team. Parameters ---------- hex_num Number of antennas per side of the hexagon separation The distance between antennas along a side. May have units of distance or time, the latter interpreted as a distance travelled by light. split_core Whether to split the hex into three offset segments. outriggers Whether to add outrigger antennas. Returns ------- antpos A 2D array of antenna positions, shape ``(Nants, 3)``. """ifhex_num<=1:raiseValueError("hex_num must be greater than 1")sep=separation.to_value("m")ifrow_separationisNone:row_sep=sep*np.sqrt(3)/2else:row_sep=row_separation.to_value("m")# construct the main hexagonpositions=[]forrowinrange(-hex_num+split_core+1,hex_num):# adding split_core deletes a row if it's trueforcolinrange(2*hex_num-abs(row)-1):x_pos=sep*((2-(2*hex_num-abs(row)))/2+col)y_pos=row*row_seppositions.append([x_pos,y_pos,0])# basis vectors (normalized to sep)up_right=sep*np.asarray([0.5,row_sep/sep,0])up_left=sep*np.asarray([-0.5,row_sep/sep,0])# split the core if desiredifsplit_core:new_pos=[]forposinpositions:# find out which sector the antenna is intheta=np.arctan2(pos[1],pos[0])ifpos[0]==0andpos[1]==0:new_pos.append(pos)elif-np.pi/3<theta<np.pi/3:new_pos.append(np.asarray(pos)+(up_right+up_left)/3)elifnp.pi/3<=theta<np.pi:new_pos.append(np.asarray(pos)+up_left-(up_right+up_left)/3)else:new_pos.append(pos)# update the positionspositions=new_pos# add outriggers if desiredifoutriggers:# The specific displacements of the outrigger sectors are# designed specifically for redundant calibratability and# "complete" uv-coverage, but also to avoid specific# obstacles on the HERA site (e.g. a road to a MeerKAT antenna)exterior_hex_num=outriggers+2forrowinrange(exterior_hex_num-1,-exterior_hex_num,-1):forcolinrange(2*exterior_hex_num-abs(row)-1):x_pos=(((2-(2*exterior_hex_num-abs(row)))/2+col)*sep*(hex_num-1))y_pos=row*(hex_num-1)*row_septheta=np.arctan2(y_pos,x_pos)ifnp.sqrt(x_pos**2+y_pos**2)>sep*(hex_num+1):if0<theta<=2*np.pi/3+0.01:positions.append(np.asarray([x_pos,y_pos,0])-4*(up_right+up_left)/3)elif0>=theta>-2*np.pi/3:positions.append(np.asarray([x_pos,y_pos,0])-2*(up_right+up_left)/3)else:positions.append(np.asarray([x_pos,y_pos,0])-3*(up_right+up_left)/3)returnnp.array(positions)*un.m