def width_at_overlap(self, overlap): """ return the half widths of the ellipse in major axis and minor axis direction given a overlap level. the relationship between one sigma and the full width maximal can be found in this link https://en.wikipedia.org/wiki/Full_width_at_half_maximum 2.*np.sqrt(2.*np.log(2)) = 2.3548200450309493 """ sigmaH = self.axisH * (2. / 2.3548200450309493) sigmaV = self.axisV * (2. / 2.3548200450309493) widthH = normInverse(overlap, 0, sigmaH) widthV = normInverse(overlap, 0, sigmaV) return widthH, widthV
def calculateBeamOverlaps(ellipseCenters, radius, majorAxis, minorAxis, rotation, overlap, mode): def RotatedGaussian2DPDF(x, y, xMean, yMean, xSigma, ySigma, angle): angle = -(angle - np.pi) a = np.power(np.cos(angle), 2) / (2 * xSigma**2) + np.power( np.sin(angle), 2) / (2 * ySigma**2) b = -np.sin(2 * angle) / (4 * xSigma**2) + np.sin( 2 * angle) / (4 * ySigma**2) c = np.power(np.sin(angle), 2) / (2 * xSigma**2) + np.power( np.cos(angle), 2) / (2 * ySigma**2) return np.exp(-(a * np.power(x - xMean, 2) + 2 * b * (x - xMean) * (y - yMean) + c * np.power(y - yMean, 2))) def isInsideEllips(center, majorAxis, minorAxis, rotation, testPointX, testPointY): xOffset = testPointX - center[0] yOffset = testPointY - center[1] cosa = np.cos(rotation) sina = np.sin(rotation) # majorSquare = np.power(majorAxis,2) # minorSquare = np.power(minorAxis,2) result = np.power((cosa*xOffset + sina*yOffset)/majorAxis,2) +\ np.power((sina*xOffset - cosa*yOffset)/minorAxis,2) # result = 1/majorAxis**2 * ((testPointX - center[0])*np.cos(rotation) +\ # (testPointY - center[1])*np.sin(rotation))**2 +\ # 1/minorAxis**2 * ((testPointX - center[0])*np.sin(rotation) -\ # (testPointY - center[1])*np.cos(rotation))**2 return result if mode == "counter": mode = 1 elif mode == "heater": mode = 2 elif mode == "both": mode = 3 rotation = np.deg2rad(rotation) # rotated = 0/(3600*24.) * 2 * np.pi # rotation += rotated longAxis = majorAxis if majorAxis > minorAxis else minorAxis gridNum = 1000 # print 0.3*radius, longAxis # halfSidelength = 0.15 * radius halfSidelength = longAxis * 3. offsetCenter = [radius, radius] # np.savetxt('tmp/oldcenter', ellipseCenters) ellipseCenters = ellipseCenters + offsetCenter # np.savetxt('tmp/newcenter', ellipseCenters) innerEllipses = [] for ellipseCenter in ellipseCenters: if (ellipseCenter[0] > (offsetCenter[0]-halfSidelength) and\ ellipseCenter[0] < (offsetCenter[0]+halfSidelength)) and\ (ellipseCenter[1] > (offsetCenter[1]-halfSidelength) and\ ellipseCenter[1] < (offsetCenter[1]+halfSidelength)): innerEllipses.append(ellipseCenter) paddingRatio = 2 * longAxis / halfSidelength halfSidelength *= 1 + paddingRatio # np.savetxt('tmp/innercenter', innerEllipses) # step = 2*halfSidelength/gridNum width = longAxis * 2 squareEdgeX = [ offsetCenter[0] - halfSidelength, offsetCenter[0] + halfSidelength ] squareEdgeY = [ offsetCenter[1] - halfSidelength, offsetCenter[1] + halfSidelength ] # print squareEdgeX, squareEdgeY # grids = np.mgrid[squareEdgeY[0]:squareEdgeY[1]:step, squareEdgeX[0]:squareEdgeX[1]:step] grids = np.meshgrid(np.linspace(squareEdgeX[0], squareEdgeX[1], gridNum), np.linspace(squareEdgeX[1], squareEdgeX[0], gridNum)) # nopoint = [] # gridLength = grids.shape[1] gridLength = gridNum overlapCounter = np.zeros((gridLength, gridLength)) overlapHeater = np.zeros((gridLength, gridLength)) # overlapCounter = np.full((gridLength, gridLength), np.inf) sigmaH, sigmaV = majorAxis * (2. / 2.3556), minorAxis * (2. / 2.3556) widthH = normInverse(overlap, 0, sigmaH) widthV = normInverse(overlap, 0, sigmaV) for ellipseCenter in innerEllipses: horizontalBoarder = [ ellipseCenter[0] - width, ellipseCenter[0] + width ] verticalBoarder = [ellipseCenter[1] - width, ellipseCenter[1] + width] horizontalIndex = np.round([(horizontalBoarder[0] - squareEdgeX[0]) / (2.0 * halfSidelength) * gridNum, (horizontalBoarder[1] - squareEdgeX[0]) / (2.0 * halfSidelength) * gridNum ]).astype(int) verticalIndex = gridNum - np.round( [(verticalBoarder[0] - squareEdgeY[0]) / (2.0 * halfSidelength) * gridNum, (verticalBoarder[1] - squareEdgeY[0]) / (2.0 * halfSidelength) * gridNum]).astype(int) # print verticalIndex, horizontalIndex insideThisBorder = np.s_[verticalIndex[1]:verticalIndex[0], horizontalIndex[0]:horizontalIndex[1]] gridX = grids[0][insideThisBorder] gridY = grids[1][insideThisBorder] #heat if mode == 2 or mode == 3: probability = RotatedGaussian2DPDF(gridX, gridY, ellipseCenter[0], ellipseCenter[1], sigmaH, sigmaV, rotation) probabilityMask = (overlapHeater[insideThisBorder] < probability) overlapHeater[insideThisBorder][probabilityMask] = probability[ probabilityMask] #counter if mode == 1 or mode == 3: counts = isInsideEllips(ellipseCenter, widthH, widthV, rotation, gridX, gridY) countMask = counts < 1 counts[countMask] = 1 counts[~countMask] = 0 overlapCounter[insideThisBorder] += counts # print ellipseCenter, majorAxis, minorAxis, rotation # np.save('tmp/grid', [gridX, gridY]) # np.savetxt('tmp/pointm', result) # exit(0) # if np.amin(result) > 1.: # np.savetxt('tmp/grid', [gridX,gridY]) # print ellipseCenter # exit() # print len(gridX) # print result[result<1] # print len(gridY), np.amin(result), result[result<1] # np.savetxt('tmp/nopoint', nopoint) trimmedGridLength = int(np.round(gridLength / (1 + 2 * paddingRatio))) halfPaddingCount = int(np.round((gridLength - trimmedGridLength) / 2.)) overlapCounter = overlapCounter[halfPaddingCount:-halfPaddingCount, halfPaddingCount:-halfPaddingCount] overlapHeater = overlapHeater[halfPaddingCount:-halfPaddingCount, halfPaddingCount:-halfPaddingCount] # print np.count_nonzero(overlapCounter > 1), np.count_nonzero(overlapCounter == 1), np.count_nonzero(overlapCounter == 0) # unique, counts = np.unique(overlapCounter, return_counts=True) # print dict(zip(unique, counts)) if mode == 1: return overlapCounter elif mode == 2: return overlapHeater elif mode == 3: return overlapCounter, overlapHeater
values = np.exp(-(a * xMinusxMean**2 + 2 * b * (xMinusxMean) * (yMinusyMean) + c * yMinusyMean**2)) return values yData = image dataShape = yData.shape X, Y = np.meshgrid(np.linspace(0, dataShape[0] - 1, dataShape[0]), np.linspace(0, dataShape[1] - 1, dataShape[1])) X = X[yData != 0] Y = Y[yData != 0] yData = yData[yData != 0] initial_guess = (dataShape[1] / 2, dataShape[0] / 2, 160, 160, 0) # paras_bounds = ([300, 300, 10, 10, -2*np.inf], [500, 500, dataShape[0], dataShape[0], 2*np.inf]) paras_bounds = ([360, 360, 10, 10, -2 * np.inf], [440, 440, dataShape[0], dataShape[0], 2 * np.inf]) popt, pcov = curve_fit(RotatedGaussian2DPDF, (X, Y), yData, p0=initial_guess, bounds=paras_bounds) centerX, centerY, sigmaH, sigmaV, angle = popt widthH = normInverse(0.5, 0, sigmaH) widthV = normInverse(0.5, 0, sigmaV) return widthH, widthV, angle
def createContour(self, antennas, fileName=None, minAlt=0): self.array = coord.Array("main", antennas, self.arrayReferece) self.baselines = self.array.getBaselines() self.boresight = coord.Boresight("main", self.boresightCoord, self.observeTime, self.arrayReferece, self.boresightFrame) self.projectedBaselines = self.array.getRotatedProjectedBaselines(self.boresight) rotatedProjectedBaselines = self.projectedBaselines beamMajorAxisScale, beamMinorAxisScale = self.calculateBeamScaleFromBaselines( self.projectedBaselines, self.waveLength) # print self.waveLength, beamMinorAxisScale baselineMax = 1.22*self.waveLength/(beamMinorAxisScale*2) baselineNum = len(self.baselines) density = self.imageDensity gridNum = self.gridNumOfDFT imageLength = gridNum * self.resolution sidelength = density * self.beamSizeFactor windowLength = self.resolution * sidelength if baselineNum > 2 and self.autoZoom == True: axisRatio = beamMajorAxisScale/beamMinorAxisScale newBeamSizeFactor = axisRatio * beamMajorAxisScale*2*1.3 / (self.resolution * density) # print newBeamSizeFactor, if baselineMax > 2e3: logger.debug('larger') # print 'larger' newBeamSizeFactor = 6 if newBeamSizeFactor < 6 else int(round(newBeamSizeFactor)) else: # print 'smaller', newBeamSizeFactor logger.debug('smaller') if newBeamSizeFactor > 6: newBeamSizeFactor = 6 elif newBeamSizeFactor > 1.: newBeamSizeFactor = int(round(newBeamSizeFactor)) else: newBeamSizeFactor = 1 # if newBeamSizeFactor < 3: # newBeamSizeFactor = 3 if baselineMax < 1e3 else 6 # elif newBeamSizeFactor > 12: # newBeamSizeFactor = 10 if baselineMax < 1e3 else 20 # else: # newBeamSizeFactor = int(round(newBeamSizeFactor)) # print newBeamSizeFactor, # print newBeamSizeFactor self.setBeamSizeFactor(newBeamSizeFactor) sidelength = density * self.beamSizeFactor windowLength = self.resolution * sidelength imageLength = gridNum * self.resolution image = self.partialDFT(self.partialDFTGrid, rotatedProjectedBaselines, self.waveLength, imageLength, density, gridNum) #if fileName != None: # plotBeamContour(image, (0,0), windowLength, # interpolation = self.interpolating, fileName='contourTest.png') sizeInfo = calculateBeamSize(image, density, windowLength, np.rad2deg(beamMajorAxisScale)) # self.beamAxis = [sizeInfo[0], sizeInfo[1], sizeInfo[2]] # print sizeInfo[3] if sizeInfo[3] != 0: sigmaTest = normSigma(windowLength/2., 0, sizeInfo[3]) majorAxis = normInverse(0.4, 0, sigmaTest) # majorAxis = beamMajorAxisScale / (sizeInfo[3]/0.5) else: majorAxis, minorAxis, angle = sizeInfo[0], sizeInfo[1], sizeInfo[2] # print np.deg2rad(majorAxis), beamMajorAxisScale newBeamSizeFactor = 2*majorAxis*1.7 / (self.resolution * density) # print newBeamSizeFactor overstep = sizeInfo[3] if overstep != 0: newBeamSizeFactor += 3.5 # print newBeamSizeFactor # print majorAxis, minorAxis, angle if newBeamSizeFactor < 1.: sidelength = density * newBeamSizeFactor windowLength = self.resolution * sidelength if windowLength / (2.*majorAxis*1.4) < 1.1: newBeamSizeFactor = 2 else: newBeamSizeFactor = 1 else: newBeamSizeFactor = int(round(newBeamSizeFactor)) self.setBeamSizeFactor(newBeamSizeFactor) # imageLength = self.calculateImageLength(rotatedProjectedBaselines, # self.waveLength, self.beamSizeFactor, density, gridNum, fixRange=width) image = self.partialDFT(self.partialDFTGrid, rotatedProjectedBaselines, self.waveLength, imageLength, density, gridNum) else: image = self.partialDFT(self.partialDFTGrid, rotatedProjectedBaselines, self.waveLength, imageLength, density, gridNum) # image_height, image_width = image.shape # image_grid = np.mgrid(-image_height/2., image_height/2., 1) # pixel_coordinates = np.stack((image_grid[0], vert_grid), axis= -1) # print pixel_coordinates.shape sidelength = density * self.beamSizeFactor windowLength = self.resolution * sidelength self.imageLength = windowLength upper_left_pixel = [-windowLength/2., windowLength/2.] # x,y bottom_right_pixel = [windowLength/2., -windowLength/2.] # x,y coordinates_equatorial = coord.convert_pixel_coordinate_to_equatorial( [upper_left_pixel, bottom_right_pixel], self.boresight.equatorial) equatorial_range = [coordinates_equatorial[0][0], coordinates_equatorial[1][0], # left, right coordinates_equatorial[0][1], coordinates_equatorial[1][1]] # up, bottom self.beamAxis = [None, None, None, equatorial_range] self.constructFitsHeader(density, self.resolution*self.beamSizeFactor, self.boresight.equatorial) self.psf = PointSpreadFunction(image, self.boresight, windowLength, self.WCS, equatorial_range) if fileName is not None: plotBeamContour(image, self.boresight.equatorial, equatorial_range, interpolation = self.interpolating, fileName = fileName) # if baselineNum > 2: # resolution = windowLength/density # sizeInfo = calculateBeamSize(image, density, windowLength, beamMajorAxisScale, fit=True) # if sizeInfo[3] != 0: # elevation = np.rad2deg(self.boresight.horizontal[1]) # if abs(elevation) < 20.: # logger.warning("Elevation is low %f" % elevation) # logger.warning("Beam shape probably is not correct.") # self.beamAxis[0:3] = [sizeInfo[0], sizeInfo[1], sizeInfo[2]] self.imageData = image logger.info("beamshape simulation imputs, freq: {:.5g}, source: {}, " "time: {}, subarray: {}".format(299792458./self.waveLength, self.boresightInput, self.observeTime, [ant.name for ant in antennas])) return image