def residual_fn_BoundMin_default(s, p, tmesh): # uses L2 norm of error (1-D only) s.modelArgs[s.parTypeStr][s.freeParNames[0]] = p s.testModel.compute(**s.modelArgs) vec = s.goalTraj(tmesh, s.depVarNames) - s.testModel( s.trajname, tmesh, s.depVarNames) return math.sqrt(reduce(float.__add__, power(vec.toarray(), 2)))
def residual_fn_BoundMin_default(s, p, tmesh): # uses L2 norm of error (1-D only) s.modelArgs[s.parTypeStr][s.freeParNames[0]] = p s.testModel.compute(**s.modelArgs) vec = s.goalTraj(tmesh,s.depVarNames) - s.testModel(s.trajname, tmesh, s.depVarNames) return math.sqrt(reduce(float.__add__, power(vec.toarray(),2)))
def __call__(self, x): if (type(x) == type(1) or type(x) == type(1.)): return self.value(x) elif (type(x) == type([])): my_list = [] for xx in x: my_list.append(self.value(xx)) return my_list elif (type(x) == numarray.NumArray): return (numarray.exp(-numarray.power((x-self.mean)/self.sigma, 2)/2.) /numarray.sqrt(2.*numarray.pi)/self.sigma)
def __call__(self, x): if (type(x) == type(1) or type(x) == type(1.)): return self.value(x) elif (type(x) == type([])): my_list = [] for xx in x: my_list.append(self.value(xx)) return my_list elif (type(x) == numarray.NumArray): return (numarray.exp(-numarray.power( (x - self.mean) / self.sigma, 2) / 2.) / numarray.sqrt(2. * numarray.pi) / self.sigma)
def calcMatrixHelper(builder, traits1, traits2, sc, strainThreshold, verbose): # intelligently figure out strain count step0 = time.time() #localSC = max(findLargestStrain(traits1, sc), # findLargestStrain(traits2, sc)) commonStrains = findCommonStrains(traits1, traits2) buildStart = time.time() matrix1, test1 = builder(traits1, commonStrains) matrix2, test2 = builder(traits2, commonStrains) buildTime = time.time() - buildStart step1 = time.time() ns = numarray.innerproduct(test1, test2) # mask all ns less than strainThreshold so the correlation values # end up masked # ns is now a MaskedArray and so all ops involving ns will be # MaskedArrays ns = MA.masked_less(ns, strainThreshold, copy=0) # divide-by-zero errors are automatically masked #ns = -1.0/ns step2 = time.time() # see comment above to find out where this ridiculously cool # matrix algebra comes from xs = numarray.innerproduct(matrix1, test2) ys = numarray.innerproduct(test1, matrix2) xys = numarray.innerproduct(matrix1, matrix2) # use in-place operations to try to speed things up numarray.power(matrix1, 2, matrix1) numarray.power(matrix2, 2, matrix2) x2s = numarray.innerproduct(matrix1, test2) y2s = numarray.innerproduct(test1, matrix2) step3 = time.time() # parens below are very important # the instant we touch ns, arrays become masked and # computation is much, much slower top = ns*xys - (xs*ys) bottom1 = ns*x2s - (xs*xs) bottom2 = ns*y2s - (ys*ys) bottom = MA.sqrt(bottom1*bottom2) # mask catches floating point divide-by-zero problems here corrs = top / bottom step4 = time.time() # we define undefined correlations as zero even though there # is a mathematical distinction returnValue = MA.filled(corrs, 0.0) step5 = time.time() #print ("calcMatrixHelper: %.2f s, %.2f s, %.2f s, %.2f s, %.2f s, %.2f s, total: %.2f s" # %(buildTime, # buildStart - step0, # step2 - step1, # step3 - step2, # step4 - step3, # step5 - step4, # step5 - step0)) if verbose: print "Matrix 1:", matrix1 print "Matrix 2:", matrix2 print "Ns:", ns print "Xs", xs print "Ys", ys print "XYs:", xys print "Top:", top print "Bottom 1:", bottom1 print "Bottom 2:", bottom2 print "Bottom:", bottom print "Corrs:", corrsa return returnValue
def matchum(file1, file2, tol=10, perr=4, aerr=1.0, nmax=40, im_masks1=[], im_masks2=[], debug=0, domags=0, xrange=None, yrange=None, sigma=4, aoffset=0): '''Take the output of two sextractor runs and match up the objects with each other (find out which objects in the first file match up with objects in the second file. The routine considers a 'match' to be any two objects that are closer than tol pixels (after applying the shift). Returns a 6-tuple: (x1,y1,x2,y2,o1,o2). o1 and o2 are the ojbects numbers such that o1[i] in file 1 corresponds to o2[i] in file 2.''' NA = num.NewAxis sexdata1 = readsex(file1) sexdata2 = readsex(file2) # Use the readsex data to get arrays of the (x,y) positions x1 = num.asarray(sexdata1[0]['X_IMAGE']) y1 = num.asarray(sexdata1[0]['Y_IMAGE']) x2 = num.asarray(sexdata2[0]['X_IMAGE']) y2 = num.asarray(sexdata2[0]['Y_IMAGE']) m1 = num.asarray(sexdata1[0]['MAG_BEST']) m2 = num.asarray(sexdata2[0]['MAG_BEST']) o1 = num.asarray(sexdata1[0]['NUMBER']) o2 = num.asarray(sexdata2[0]['NUMBER']) f1 = num.asarray(sexdata1[0]['FLAGS']) f2 = num.asarray(sexdata2[0]['FLAGS']) # First, make a cut on the flags: gids = num.where(f1 < 4) x1 = x1[gids] y1 = y1[gids] m1 = m1[gids] o1 = o1[gids] gids = num.where(f2 < 4) x2 = x2[gids] y2 = y2[gids] m2 = m2[gids] o2 = o2[gids] # next, if there is a range to use: if xrange is not None and yrange is not None: cond = num.greater(x1, xrange[0])*num.less(x1,xrange[1])*\ num.greater(y1, yrange[0])*num.less(y1,yrange[1]) gids = num.where(cond) x1 = x1[gids] y1 = y1[gids] m1 = m1[gids] o1 = o1[gids] cond = num.greater(x2, xrange[0])*num.less(x2,xrange[1])*\ num.greater(y2, yrange[0])*num.less(y2,yrange[1]) gids = num.where(cond) x2 = x2[gids] y2 = y2[gids] m2 = m2[gids] o2 = o2[gids] # Use the user masks for m in im_masks1: print "applying mask (%d,%d,%d,%d)" % tuple(m) condx = num.less(x1, m[0]) + num.greater(x1, m[1]) condy = num.less(y1, m[2]) + num.greater(y1, m[3]) gids = num.where(condx + condy) x1 = x1[gids] y1 = y1[gids] m1 = m1[gids] o1 = o1[gids] for m in im_masks2: print "applying mask (%d,%d,%d,%d)" % tuple(m) condx = num.less(x2, m[0]) + num.greater(x2, m[1]) condy = num.less(y2, m[2]) + num.greater(y2, m[3]) gids = num.where(condx + condy) x2 = x2[gids] y2 = y2[gids] m2 = m2[gids] o2 = o2[gids] if nmax: if len(x1) > nmax: ids = num.argsort(m1)[0:nmax] x1 = x1[ids] y1 = y1[ids] m1 = m1[ids] o1 = o1[ids] if len(x2) > nmax: ids = num.argsort(m2)[0:nmax] x2 = x2[ids] y2 = y2[ids] m2 = m2[ids] o2 = o2[ids] if debug: print "objects in frame 1:" print o1 print "objects in frame 2:" print o2 mp = pygplot.MPlot(2, 1, device='/XWIN') p = pygplot.Plot() p.point(x1, y1) [p.label(x1[i], y1[i], "%d" % o1[i]) for i in range(len(x1))] mp.add(p) p = pygplot.Plot() p.point(x2, y2) [p.label(x2[i], y2[i], "%d" % o2[i]) for i in range(len(x2))] mp.add(p) mp.plot() mp.close() # Now, we make 2-D arrays of all the differences in x and y between each pair # of objects. e.g., dx1[n,m] is the delta-x between object n and m in file 1 and # dy2[n,m] is the y-distance between object n and m in file 2. dx1 = x1[NA, :] - x1[:, NA] dx2 = x2[NA, :] - x2[:, NA] dy1 = y1[NA, :] - y1[:, NA] dy2 = y2[NA, :] - y2[:, NA] # Same, but with angles da1 = num.arctan2(dy1, dx1) * 180 / num.pi da2 = num.arctan2(dy2, dx2) * 180 / num.pi # Same, but with absolute distances ds1 = num.sqrt(num.power(dx1, 2) + num.power(dy1, 2)) ds2 = num.sqrt(num.power(dx2, 2) + num.power(dy2, 2)) # Here's the real magic: this is a matrix of matrices (4-D). Consider 4 objects: # objects i and j in file 1 and objects m and n in file 2. dx[i,j,m,n] is the # difference between delta-xs for objects i,j in file 1 and m,n in file 2. If object # i corresponds to object m and object j corresponds to object n, this should be a small # number, irregardless of an overall shift in coordinate systems between file 1 and 2. dx = dx1[::, ::, NA, NA] - dx2[NA, NA, ::, ::] dy = dy1[::, ::, NA, NA] - dy2[NA, NA, ::, ::] da = da1[::, ::, NA, NA] - da2[NA, NA, ::, ::] + aoffset ds = ds1[::, ::, NA, NA] - ds2[NA, NA, ::, ::] # pick out close pairs. #use = num.less(dy,perr)*num.less(dx,perr)*num.less(num.abs(da),aerr) use = num.less(ds, perr) * num.less(num.abs(da), aerr) use = use.astype(num.Int32) #use = num.less(num.abs(da),perr) suse = num.add.reduce(num.add.reduce(use, 3), 1) print suse[0] guse = num.greater(suse, suse.flat.max() / 2) i = [j for j in range(x1.shape[0]) if num.sum(guse[j])] m = [num.argmax(guse[j]) for j in range(x1.shape[0]) if num.sum(guse[j])] xx0, yy0, oo0, mm0 = num.take([x1, y1, o1, m1], i, 1) xx1, yy1, oo1, mm1 = num.take([x2, y2, o2, m2], m, 1) if debug: mp = pygplot.MPlot(2, 1, device='/XWIN') p = pygplot.Plot() p.point(xx0, yy0) [p.label(xx0[i], yy0[i], "%d" % oo0[i]) for i in range(len(xx0))] mp.add(p) p = pygplot.Plot() p.point(xx1, yy1) [p.label(xx1[i], yy1[i], "%d" % oo1[i]) for i in range(len(xx1))] mp.add(p) mp.plot() mp.close() xshift, xscat = stats.bwt(xx0 - xx1) xscat = max([1.0, xscat]) yshift, yscat = stats.bwt(yy0 - yy1) yscat = max([1.0, yscat]) mshift, mscat = stats.bwt(mm0 - mm1) print "xscat = ", xscat print "yscat = ", yscat print "xshift = ", xshift print "yshift = ", yshift print "mshift = ", mshift print "mscat = ", mscat keep = num.less(num.abs(xx0-xx1-xshift),sigma*xscat)*\ num.less(num.abs(yy0-yy1-yshift),sigma*yscat) # This is a list of x,y,object# in each file. xx0, yy0, oo0, xx1, yy1, oo1 = num.compress(keep, [xx0, yy0, oo0, xx1, yy1, oo1], 1) if debug: print file1, oo0 print file2, oo1 mp = pygplot.MPlot(2, 1, device='temp.ps/CPS') p1 = pygplot.Plot() p1.point(xx0, yy0, symbol=25, color='red') for i in range(len(xx0)): p1.label(xx0[i], yy0[i], " %d" % oo0[i], color='red') mp.add(p1) p2 = pygplot.Plot() p2.point(xx1, yy1, symbol=25, color='green') for i in range(len(xx1)): p2.label(xx1[i], yy1[i], " %d" % oo1[i], color='green') mp.add(p2) mp.plot() mp.close() if domags: return (xx0, yy0, mm0, xx1, yy1, mm1, mshift, mscat, oo0, oo1) else: return (xx0, yy0, xx1, yy1, oo0, oo1)
def combine_images(images, output, reference=None, method='average', zscale=1, fitgeometry='general', function='polynomial', xxorder=3, yyorder=3, xyorder=3, yxorder=3, objects=None, trim=0, interactive=1, maxiter=5, reject=3, sigma=None, xrange=None, yrange=None, rectify=1, thresh=2.0, scale=0.125, fwhm=4.0, debug=0, aoffset=0, creject=None): '''This Routine will take a list of images and use rectify_image to rectify each with respect to referece. It will then use imcombine to combine the images into one and output to "output". Default method is 'average', but you can use any available to imcombine. The rest of the arguments are sent to rectify_images. If zscale=1, all the images are scaled to a common zmag (30). Also, if a file with _sigma.fits is found for all input files, we combine them too. If you specify a sigma, that file will hold the standard deviations from the files.''' names = get_files(images) if reference is None: reference = names[0] names = names[1:] pclip = -0.5 lsigma = 3. hsigma = 3. nkeep = -2 if creject: creject = "pclip" else: creject = "none" # Check to see if we have _sigma files for each input file if os.path.isfile(reference.replace('.fits', '_sigma.fits')): do_sigmas = 1 else: do_sigmas = 0 sigmas = [] for name in names: if os.path.isfile(name.replace('.fits', '_sigma.fits')): sigmas.append(name.replace('.fits', '_sigma.fits')) else: do_sigmas = 0 break # Put the reference image first, to ensure that all positional header keywords are # valid. if do_sigmas: ref_sig = reference.replace('.fits', '_sigma.fits') update = 0 if zscale: zmag = get_header(reference, "ZMAG", float) if zmag is not None and zmag != 26: update = 1 zmagfac = num.power(10, (zmag - 30) / 2.5) if zmagfac != 1: print 'zmagfac = ', zmagfac iraf.imarith(reference, '/', zmagfac, reference) iraf.hedit(reference, "ZMAG", 30.0, add=1, verify=0) if do_sigmas: iraf.imarith(ref_sig, '/', zmagfac, ref_sig) iraf.hedit(ref_sig, "ZMAG", 30.0, add=1, verify=0) print "Using %s as reference" % (reference) if rectify: nuke(reference.replace('.fits', '_rec.fits')) iraf.imcopy(reference, reference.replace('.fits', '_rec.fits')) if do_sigmas: nuke(reference.replace('.fits', '_rec_sigma.fits')) iraf.imcopy(reference.replace('.fits', '_sigma.fits'), reference.replace('.fits', '_rec_sigma.fits')) temps = [reference.replace('.fits', '_rec.fits')] if do_sigmas: sig_temps = [reference.replace('.fits', '_rec_sigma.fits')] else: temps = [reference] if do_sigmas: sig_temps = [ref_sig] i = 0 for name in names: print name if rectify: temp = name.replace('.fits', '_rec.fits') nuke(temp) if do_sigmas: (x0, x1, y0, y1) = rectify_image(name, reference, output=temp, fitgeometry=fitgeometry, function=function, xxorder=xxorder, yyorder=yyorder, xyorder=xyorder, yxorder=yxorder, objects=objects, interactive=interactive, maxiter=maxiter, reject=reject, xrange=xrange, yrange=yrange, thresh=thresh, scale=scale, fwhm=fwhm, image_sigma=sigmas[i], reference_sigma=ref_sig, debug=debug, aoffset=aoffset) else: (x0, x1, y0, y1) = rectify_image(name, reference, output=temp, fitgeometry=fitgeometry, function=function, xxorder=xxorder, yyorder=yyorder, xyorder=xyorder, yxorder=yxorder, objects=objects, interactive=interactive, maxiter=maxiter, reject=reject, xrange=xrange, yrange=yrange, thresh=thresh, scale=scale, fwhm=fwhm, debug=debug, aoffset=aoffset) else: temp = name bpm = get_header(name, 'BPM', str) if bpm and rectify: bpm_fits = bpm.replace('.pl', '.fits') temp_bpm = bpm.replace('.pl', '_rec.fits') temp_bpm_pl = bpm.replace('.pl', '_rec.pl') nuke(bpm_fits) nuke(temp_bpm) nuke(temp_bpm_pl) iraf.imcopy(bpm, bpm_fits) iraf.imarith(bpm_fits, "*", 10.0, bpm_fits) if objects is None: sigmaobjects = 'geomap.objects' iraf.geotran(input=bpm_fits, output=temp_bpm, database='geomap.db', transforms=sigmaobjects, geometry='geometric', interpolant="linear") iraf.imreplace(temp_bpm, lower=0.02, upper="INDEF", value=1.) iraf.imcopy(temp_bpm, temp_bpm_pl) iraf.hedit(temp, 'BPM', temp_bpm_pl, update=1, verify=0) if do_sigmas: if rectify: temp_sig = sigmas[i].replace('_sigma.fits', '_rec_sigma.fits') nuke(temp_sig) if objects is None: sigmaobjects = 'geomap.objects' else: sigmaobjects = objects iraf.geotran(input=sigmas[i], output=temp_sig, database='geomap.db', transforms=sigmaobjects, geometry='geometric', interpolant="linear") else: temp_sig = sigmas[i] if rectify: if i == 0: xmin = x0 ymin = y0 xmax = x1 ymax = y1 else: xmin = max(xmin, x0) ymin = max(ymin, y0) xmax = min(xmax, x1) ymax = min(ymax, y1) if zscale: zmag = get_header(name, "ZMAG", float) if zmag is not None and zmag != 26: zmagfac = num.power(10, (zmag - 30) / 2.5) if zmagfac != 1: print 'zmagfac = ', zmagfac iraf.imarith(temp, '/', zmagfac, temp) iraf.hedit(temp, 'ZMAG', 30.0, add=1, verify=0) if do_sigmas: iraf.imarith(temp_sig, '/', zmagfac, temp_sig) iraf.hedit(temp_sig, 'ZMAG', 30.0, add=1, verify=0) temps.append(temp) if do_sigmas: sig_temps.append(temp_sig) i = i + 1 Nimages = len(temps) temps = string.join(temps, ',') print "Combining ", temps nuke(output) if sigma is not None: iraf.imcombine(temps, output, combine=method, sigma=sigma, masktyp='badvalue', maskval=1., reject=creject, lsigma=lsigma, hsigma=hsigma, nkeep=nkeep) else: iraf.imcombine(temps, output, combine=method, masktyp='badvalue', maskval=1., reject=creject, lsigma=lsigma, hsigma=hsigma, nkeep=nkeep) if do_sigmas: Ns = [] for this in sig_temps: N = this.replace('.fits', '_N.fits') nuke(N) iraf.imcopy(this, N) iraf.imreplace(N, lower=0.01, upper="INDEF", value=1) Ns.append(N) sig_temps = string.join(sig_temps, ',') Ns = string.join(Ns, ',') iraf.imfunction(sig_temps, sig_temps, 'square') file = output.replace('.fits', '_sigma.fits') nuke(file) iraf.imcombine(sig_temps, file, combine='sum') if method == 'average': nuke("N.fits") iraf.imcombine(Ns, 'N.fits', combine='sum') iraf.imfunction('N.fits', 'N.fits', 'square') iraf.imarith(file, '/', 'N.fits', file) iraf.imfunction(file, file, 'sqrt') iraf.imfunction(sig_temps, sig_temps, 'sqrt') if update: iraf.hedit(output, "ZMAG", 30.0, verify=0, add=1) #nuke('temp?.fits') # Now, let's clean up the gain and rdnoise headers, as they don't seem to # be handled in the PANIC pipeline. NOTE: we really need a noise map, but # for now, we'll deal with just global values. gain = get_header(output, "gain", float) rdnoise = get_header(output, "rdnoise", float) if gain is None: # have to compute it from scratch egain = get_header(output, "egain", float) enoise = get_header(output, "enoise", float) nloop = get_header(output, "nloops", int) i = 1 key = "" # This seems to be the only safe way to compute this. Can't trust # NDITHERS while key is not None: key = get_header(output, "imcmb%03d" % (i), str) i = i + 1 ndither = i - 1 print "N, ndither, nloop, egain, enoise = ", Nimages, ndither, nloop, egain, enoise gain = egain * Nimages * nloop * ndither rdnoise = enoise * num.sqrt(Nimages * nloop * ndither) else: gain = gain * Nimages rdnoise = rdnoise * num.sqrt(Nimages) iraf.hedit(output, "gain", gain, verify=0, add=1) iraf.hedit(output, "rdnoise", rdnoise, verify=0, add=1) # If requested, trim to the common regions of the combined images if rectify and trim and Nimages > 1: iraf.imcopy(output + "[%d:%d,%d:%d]" % (xmin, xmax, ymin, ymax), output.replace('.fits', '_trim.fits'))
def recenter(self): """ Reset the reference position values to correspond to the center of the reference frame. Algorithm used here developed by Colin Cox - 27-Jan-2004. """ if self.ctype1.find('TAN') < 0 or self.ctype2.find('TAN') < 0: print 'WCS.recenter() only supported for TAN projections.' raise TypeError # Check to see if WCS is already centered... if self.crpix1 == self.naxis1 / 2. and self.crpix2 == self.naxis2 / 2.: # No recentering necessary... return without changing WCS. return # This offset aligns the WCS to the center of the pixel, in accordance # with the 'align=center' option used by 'drizzle'. #_drz_off = -0.5 _drz_off = 0. _cen = (self.naxis1 / 2. + _drz_off, self.naxis2 / 2. + _drz_off) # Compute the RA and Dec for center pixel _cenrd = self.xy2rd(_cen) _cd = N.array([[self.cd11, self.cd12], [self.cd21, self.cd22]], type=N.Float64) _ra0 = DEGTORAD(self.crval1) _dec0 = DEGTORAD(self.crval2) _ra = DEGTORAD(_cenrd[0]) _dec = DEGTORAD(_cenrd[1]) # Set up some terms for use in the final result _dx = self.naxis1 / 2. - self.crpix1 _dy = self.naxis2 / 2. - self.crpix2 _dE, _dN = DEGTORAD(N.dot(_cd, (_dx, _dy))) _dE_dN = 1 + N.power(_dE, 2) + N.power(_dN, 2) _cosdec = N.cos(_dec) _sindec = N.sin(_dec) _cosdec0 = N.cos(_dec0) _sindec0 = N.sin(_dec0) _n1 = N.power(_cosdec, 2) + _dE * _dE + _dN * _dN * N.power(_sindec, 2) _dra_dE = (_cosdec0 - _dN * _sindec0) / _n1 _dra_dN = _dE * _sindec0 / _n1 _ddec_dE = -_dE * N.tan(_dec) / _dE_dN _ddec_dN = (1 / _cosdec) * ((_cosdec0 / N.sqrt(_dE_dN)) - (_dN * N.sin(_dec) / _dE_dN)) # Compute new CD matrix values now... _cd11n = _cosdec * (self.cd11 * _dra_dE + self.cd21 * _dra_dN) _cd12n = _cosdec * (self.cd12 * _dra_dE + self.cd22 * _dra_dN) _cd21n = self.cd11 * _ddec_dE + self.cd21 * _ddec_dN _cd22n = self.cd12 * _ddec_dE + self.cd22 * _ddec_dN _new_orient = RADTODEG(N.arctan2(_cd12n, _cd22n)) # Update the values now... self.crpix1 = _cen[0] self.crpix2 = _cen[1] self.crval1 = RADTODEG(_ra) self.crval2 = RADTODEG(_dec) # Keep the same plate scale, only change the orientation self.rotateCD(_new_orient) # These would update the CD matrix with the new rotation # ALONG with the new plate scale which we do not want. self.cd11 = _cd11n self.cd12 = _cd12n self.cd21 = _cd21n self.cd22 = _cd22n
def recenter(self): """ Reset the reference position values to correspond to the center of the reference frame. Algorithm used here developed by Colin Cox - 27-Jan-2004. """ if self.ctype1.find('TAN') < 0 or self.ctype2.find('TAN') < 0: print 'WCS.recenter() only supported for TAN projections.' raise TypeError # Check to see if WCS is already centered... if self.crpix1 == self.naxis1/2. and self.crpix2 == self.naxis2/2.: # No recentering necessary... return without changing WCS. return # This offset aligns the WCS to the center of the pixel, in accordance # with the 'align=center' option used by 'drizzle'. #_drz_off = -0.5 _drz_off = 0. _cen = (self.naxis1/2.+ _drz_off,self.naxis2/2. + _drz_off) # Compute the RA and Dec for center pixel _cenrd = self.xy2rd(_cen) _cd = N.array([[self.cd11,self.cd12],[self.cd21,self.cd22]],type=N.Float64) _ra0 = DEGTORAD(self.crval1) _dec0 = DEGTORAD(self.crval2) _ra = DEGTORAD(_cenrd[0]) _dec = DEGTORAD(_cenrd[1]) # Set up some terms for use in the final result _dx = self.naxis1/2. - self.crpix1 _dy = self.naxis2/2. - self.crpix2 _dE,_dN = DEGTORAD(N.dot(_cd,(_dx,_dy))) _dE_dN = 1 + N.power(_dE,2) + N.power(_dN,2) _cosdec = N.cos(_dec) _sindec = N.sin(_dec) _cosdec0 = N.cos(_dec0) _sindec0 = N.sin(_dec0) _n1 = N.power(_cosdec,2) + _dE*_dE + _dN*_dN*N.power(_sindec,2) _dra_dE = (_cosdec0 - _dN*_sindec0)/_n1 _dra_dN = _dE*_sindec0 /_n1 _ddec_dE = -_dE*N.tan(_dec) / _dE_dN _ddec_dN = (1/_cosdec) * ((_cosdec0 / N.sqrt(_dE_dN)) - (_dN*N.sin(_dec) / _dE_dN)) # Compute new CD matrix values now... _cd11n = _cosdec * (self.cd11*_dra_dE + self.cd21 * _dra_dN) _cd12n = _cosdec * (self.cd12*_dra_dE + self.cd22 * _dra_dN) _cd21n = self.cd11 * _ddec_dE + self.cd21 * _ddec_dN _cd22n = self.cd12 * _ddec_dE + self.cd22 * _ddec_dN _new_orient = RADTODEG(N.arctan2(_cd12n,_cd22n)) # Update the values now... self.crpix1 = _cen[0] self.crpix2 = _cen[1] self.crval1 = RADTODEG(_ra) self.crval2 = RADTODEG(_dec) # Keep the same plate scale, only change the orientation self.rotateCD(_new_orient) # These would update the CD matrix with the new rotation # ALONG with the new plate scale which we do not want. self.cd11 = _cd11n self.cd12 = _cd12n self.cd21 = _cd21n self.cd22 = _cd22n