def trunc_tuple(t, tolerance): """ Apply the purify (trunc) function to a tuple or array. """ return array(tuple([trunc(c, tolerance) for c in t]), Complex)
def test_basic_matrix(self): """This test is rather monolithic, but at least it implements a concrete example that we can compare with our earlier computations. It also tests the mutual-inverse character of the equi-to-diag and diag-to-equi transformations.""" tolerance = 5.0e-15 eig = self.diag.compute_eigen_system(self.h_2, tolerance) self.diag.compute_diagonal_change() eq_type = eig.get_equilibrium_type() self.assertEquals(eq_type, self.eq_type) eigs = [pair.val for pair in eig.get_raw_eigen_value_vector_pairs()] for actual, expected in zip(eigs, self.eig_vals): self.assert_(abs(actual-expected) < tolerance, (actual, expected)) mat = self.diag.get_matrix_diag_to_equi() assert self.diag.matrix_is_symplectic(mat) sub_diag_into_equi = self.diag.matrix_as_vector_of_row_polynomials(mat) mat_inv = LinearAlgebra.inverse(MLab.array(mat)) sub_equi_into_diag = self.diag.matrix_as_vector_of_row_polynomials(mat_inv) h_diag_2 = self.h_2.substitute(sub_diag_into_equi) h_2_inv = h_diag_2.substitute(sub_equi_into_diag) self.assert_(h_2_inv) #non-zero self.assert_(not h_2_inv.is_constant()) self.assert_(self.lie.is_isograde(h_2_inv, 2)) self.assert_((self.h_2-h_2_inv).l1_norm() < 1.0e-14) comp = Complexifier(self.diag.get_lie_algebra(), eq_type) sub_complex_into_real = comp.calc_sub_complex_into_real() h_comp_2 = h_diag_2.substitute(sub_complex_into_real) h_comp_2 = h_comp_2.with_small_coeffs_removed(tolerance) self.assert_(self.lie.is_diagonal_polynomial(h_comp_2))
def arrow(x0,y0,x1,y1,color=0,ang=45.0,height=6,width=1.5,lc=None): """Draw an arrow. Description: Draw an arrow from (x0,y0) to (x1,y1) in the current coordinate system. Inputs: x0, y0 -- The beginning point. x1, y1 -- Then ending point. color -- The color of the arrowhead. Number represents an index in the current palette or a negative number or a spelled out basic color. lc -- The color of the line (same as color by default). ang -- The angle of the arrowhead. height -- The height of the arrowhead in points. width -- The width of the arrow line in points. """ if lc is None: lc = color if type(lc) is types.StringType: lc = _colornum[lc] if type(color) is types.StringType: color = _colornum[color] vp = gist.viewport() plotlims = gist.limits() gist.limits(plotlims) conv_factorx = (vp[1]-vp[0]) / (plotlims[1]-plotlims[0]) conv_factory = (vp[3]-vp[2]) / (plotlims[3]-plotlims[2]) ang = ang*pi/180 height = height*points hypot = height / cos(ang) difx = (x1 - x0) * conv_factorx dify = (y1 - y0) * conv_factory theta = arctan2(dify,difx) + pi tha = theta + ang thb = theta - ang x1a = x1 + hypot*cos(tha) / conv_factorx x1b = x1 + hypot*cos(thb) / conv_factorx y1a = y1 + hypot*sin(tha) / conv_factory y1b = y1 + hypot*sin(thb) / conv_factory gist.pldj([x0],[y0],[x1],[y1],color=lc,width=width) gist.plfp(array([color],'B'),[y1,y1a,y1b],[x1,x1a,x1b],[3]) return
def test_basic_matrix(self): """This test is rather monolithic, but at least it implements a concrete example that we can compare with our earlier computations. It also tests the mutual-inverse character of the equi-to-diag and diag-to-equi transformations.""" tolerance = 5.0e-15 eig = self.diag.compute_eigen_system(self.h_2, tolerance) self.diag.compute_diagonal_change() eq_type = eig.get_equilibrium_type() self.assertEquals(eq_type, self.eq_type) eigs = [pair.val for pair in eig.get_raw_eigen_value_vector_pairs()] for actual, expected in zip(eigs, self.eig_vals): self.assert_( abs(actual - expected) < tolerance, (actual, expected)) mat = self.diag.get_matrix_diag_to_equi() assert self.diag.matrix_is_symplectic(mat) sub_diag_into_equi = self.diag.matrix_as_vector_of_row_polynomials(mat) mat_inv = LinearAlgebra.inverse(MLab.array(mat)) sub_equi_into_diag = self.diag.matrix_as_vector_of_row_polynomials( mat_inv) h_diag_2 = self.h_2.substitute(sub_diag_into_equi) h_2_inv = h_diag_2.substitute(sub_equi_into_diag) self.assert_(h_2_inv) #non-zero self.assert_(not h_2_inv.is_constant()) self.assert_(self.lie.is_isograde(h_2_inv, 2)) self.assert_((self.h_2 - h_2_inv).l1_norm() < 1.0e-14) comp = Complexifier(self.diag.get_lie_algebra(), eq_type) sub_complex_into_real = comp.calc_sub_complex_into_real() h_comp_2 = h_diag_2.substitute(sub_complex_into_real) h_comp_2 = h_comp_2.with_small_coeffs_removed(tolerance) self.assert_(self.lie.is_diagonal_polynomial(h_comp_2))
def compare_matrix(dia, mat1, mat2, comment): print dia.matrix_norm(array(mat1, Float) - array(mat2, Float)), comment
def compare_normal_form(dir_name1, dir_name2, grade=4): def compare_matrix(dia, mat1, mat2, comment): print dia.matrix_norm(array(mat1, Float) - array(mat2, Float)), comment print "Comparing data in Normal form files upto grade %d" % (grade) print print "Reading python data" first = NormalFormData(dir_name1, is_xxpp_format=True, degree=grade) ring = PolynomialRing(first.equi_to_tham.n_vars()) print print "Comparing python data with cpp files upto grade %d" % (grade) print "l_infinity_norm \t l1_norm \t\t polynomials" ringIO = PolynomialRingIO(ring) file_istr = open("hill_l1_18--norm_to_diag.vpol", 'r') pv_norm_to_diag = ringIO.read_sexp_vector_of_polynomials(file_istr) compare_poly_vec(first.norm_to_diag, pv_norm_to_diag, "norm_to_diag", grade=grade - 1) file_istr = open("hill_l1_18--diag_to_norm.vpol", 'r') pv_diag_to_norm = ringIO.read_sexp_vector_of_polynomials(file_istr) compare_poly_vec(first.diag_to_norm, pv_diag_to_norm, "diag_to_norm", grade=grade - 1) print print "Reading mathematica data" n_ints = len(first.ints_to_freq) # get the frequencies to find the order of the planes order_f = [poly((0.0, ) * n_ints) for poly in first.ints_to_freq] second = NormalFormData(dir_name2, order_f=order_f, is_xxpp_format=True, degree=grade) from Diagonal import Diagonalizer lie = LieAlgebra(n_ints) dia = Diagonalizer(lie) grade_ints = grade / 2 dia.matrix_is_symplectic(array(first.diag_to_equi, Float)) dia.matrix_is_symplectic(array(second.diag_to_equi, Float)) dia.matrix_is_symplectic(array(first.equi_to_diag, Float)) dia.matrix_is_symplectic(array(second.equi_to_diag, Float)) # For the case develloped, Hill, there is a 45deg rotation between the # diagonalised coordinates in each of the centre planes. Thus: # These matrices are different #compare_matrix(dia, first.diag_to_equi, second.diag_to_equi, "diag_to_equi") #compare_matrix(dia, first.equi_to_diag, second.equi_to_diag, "equi_to_diag") # We neeed to convert between the diagonal planes and back to # compare the nonlinear normalisation plolynomials # second.diag_to_first.diag = first.diag_in_terms_of_second.diag = fd_in_sd = dia.matrix_as_vector_of_row_polynomials( matrixmultiply(array(first.equi_to_diag, Float), array(second.diag_to_equi, Float))) sd_in_fd = dia.matrix_as_vector_of_row_polynomials( matrixmultiply(array(second.equi_to_diag, Float), array(first.diag_to_equi, Float))) print print "Comparing mathematica data with cpp files upto grade %d" % (grade - 1) compare_poly_vec(pv_norm_to_diag, poly_vec_substitute( fd_in_sd, poly_vec_substitute( poly_vec_isograde(second.norm_to_diag, grade - 1), sd_in_fd)), "norm_to_diag", grade=grade - 1) print "Comparing mathematica data with cpp files upto grade %d" % (grade - 1) compare_poly_vec(pv_diag_to_norm, poly_vec_substitute( fd_in_sd, poly_vec_substitute( poly_vec_isograde(second.diag_to_norm, grade - 1), sd_in_fd)), "diag_to_norm", grade=grade - 1) print print "Comparing mathematica data with python upto grade %d" % (grade) compare_poly(first.equi_to_tham, second.equi_to_tham, "equi_to_tham", grade=grade) compare_poly_vec(first.ints_to_freq, second.ints_to_freq, "ints_to_freq", grade=grade_ints - 1) ring_ints = PolynomialRing(second.ints_to_tham.n_vars()) poly_2 = ring_ints.isograde(second.ints_to_tham, 0, up_to=grade_ints + 1) compare_poly(first.ints_to_tham, poly_2, "ints_to_tham") compare_poly_vec(first.norm_to_ints, second.norm_to_ints, "norm_to_ints", grade=grade) second.diag_to_norm = poly_vec_isograde(second.diag_to_norm, grade) second.norm_to_diag = poly_vec_isograde(second.norm_to_diag, grade) compare_poly_vec(first.norm_to_diag, poly_vec_substitute( fd_in_sd, poly_vec_substitute(second.norm_to_diag, sd_in_fd)), "norm_to_diag", grade=grade - 1) compare_poly_vec(first.diag_to_norm, poly_vec_substitute( fd_in_sd, poly_vec_substitute(second.diag_to_norm, sd_in_fd)), "diag_to_norm", grade=grade - 1) compare_poly_vec(first.diag_to_norm, second.diag_to_norm, "diag_to_norm", grade=grade - 1) compare_poly_vec(first.diag_to_norm, poly_vec_substitute( fd_in_sd, poly_vec_substitute(second.diag_to_norm, sd_in_fd)), "diag_to_norm", grade=grade) compare_poly_vec(first.equi_to_tvec, second.equi_to_tvec, "equi_to_tvec", grade=grade - 1)
def compare_matrix(dia, mat1, mat2, comment): print dia.matrix_norm(array(mat1, Float)-array(mat2, Float)), comment
def compare_normal_form(dir_name1, dir_name2, grade=4): def compare_matrix(dia, mat1, mat2, comment): print dia.matrix_norm(array(mat1, Float)-array(mat2, Float)), comment print "Comparing data in Normal form files upto grade %d" %(grade) print print "Reading python data" first = NormalFormData(dir_name1, is_xxpp_format=True, degree=grade) ring = PolynomialRing(first.equi_to_tham.n_vars()) print print "Comparing python data with cpp files upto grade %d" %(grade) print "l_infinity_norm \t l1_norm \t\t polynomials" ringIO = PolynomialRingIO(ring) file_istr = open("hill_l1_18--norm_to_diag.vpol", 'r') pv_norm_to_diag = ringIO.read_sexp_vector_of_polynomials(file_istr) compare_poly_vec(first.norm_to_diag, pv_norm_to_diag, "norm_to_diag", grade=grade-1) file_istr = open("hill_l1_18--diag_to_norm.vpol", 'r') pv_diag_to_norm = ringIO.read_sexp_vector_of_polynomials(file_istr) compare_poly_vec(first.diag_to_norm, pv_diag_to_norm, "diag_to_norm", grade=grade-1) print print "Reading mathematica data" n_ints = len(first.ints_to_freq) # get the frequencies to find the order of the planes order_f=[poly((0.0,)*n_ints) for poly in first.ints_to_freq] second = NormalFormData(dir_name2, order_f=order_f, is_xxpp_format=True, degree=grade) from Diagonal import Diagonalizer lie = LieAlgebra(n_ints) dia = Diagonalizer(lie) grade_ints = grade / 2 dia.matrix_is_symplectic(array(first.diag_to_equi, Float)) dia.matrix_is_symplectic(array(second.diag_to_equi, Float)) dia.matrix_is_symplectic(array(first.equi_to_diag, Float)) dia.matrix_is_symplectic(array(second.equi_to_diag, Float)) # For the case develloped, Hill, there is a 45deg rotation between the # diagonalised coordinates in each of the centre planes. Thus: # These matrices are different #compare_matrix(dia, first.diag_to_equi, second.diag_to_equi, "diag_to_equi") #compare_matrix(dia, first.equi_to_diag, second.equi_to_diag, "equi_to_diag") # We neeed to convert between the diagonal planes and back to # compare the nonlinear normalisation plolynomials # second.diag_to_first.diag = first.diag_in_terms_of_second.diag = fd_in_sd = dia.matrix_as_vector_of_row_polynomials(matrixmultiply( array(first.equi_to_diag, Float),array(second.diag_to_equi, Float))) sd_in_fd = dia.matrix_as_vector_of_row_polynomials(matrixmultiply( array(second.equi_to_diag, Float),array(first.diag_to_equi, Float))) print print "Comparing mathematica data with cpp files upto grade %d" %(grade-1) compare_poly_vec(pv_norm_to_diag, poly_vec_substitute(fd_in_sd, poly_vec_substitute( poly_vec_isograde(second.norm_to_diag, grade-1), sd_in_fd)), "norm_to_diag", grade=grade-1) print "Comparing mathematica data with cpp files upto grade %d" %(grade-1) compare_poly_vec(pv_diag_to_norm, poly_vec_substitute(fd_in_sd, poly_vec_substitute( poly_vec_isograde(second.diag_to_norm, grade-1), sd_in_fd)), "diag_to_norm", grade=grade-1) print print "Comparing mathematica data with python upto grade %d" %(grade) compare_poly(first.equi_to_tham, second.equi_to_tham, "equi_to_tham", grade=grade) compare_poly_vec(first.ints_to_freq , second.ints_to_freq , "ints_to_freq", grade=grade_ints-1) ring_ints = PolynomialRing(second.ints_to_tham.n_vars()) poly_2 = ring_ints.isograde(second.ints_to_tham, 0, up_to=grade_ints+1) compare_poly(first.ints_to_tham , poly_2 , "ints_to_tham") compare_poly_vec(first.norm_to_ints , second.norm_to_ints , "norm_to_ints", grade=grade) second.diag_to_norm = poly_vec_isograde(second.diag_to_norm, grade) second.norm_to_diag = poly_vec_isograde(second.norm_to_diag, grade) compare_poly_vec(first.norm_to_diag, poly_vec_substitute(fd_in_sd, poly_vec_substitute( second.norm_to_diag, sd_in_fd)), "norm_to_diag", grade=grade-1) compare_poly_vec(first.diag_to_norm, poly_vec_substitute(fd_in_sd, poly_vec_substitute( second.diag_to_norm, sd_in_fd)), "diag_to_norm", grade=grade-1) compare_poly_vec(first.diag_to_norm, second.diag_to_norm,"diag_to_norm", grade=grade-1) compare_poly_vec(first.diag_to_norm, poly_vec_substitute(fd_in_sd, poly_vec_substitute( second.diag_to_norm, sd_in_fd)), "diag_to_norm", grade=grade) compare_poly_vec(first.equi_to_tvec, second.equi_to_tvec,"equi_to_tvec", grade=grade-1)
def imag_part_of_vector(vec): """Extract pure imaginary part of complex vector.""" return array(tuple([imag_part_of_scalar(elt) for elt in vec]), Float)
def real_part_of_vector(vec): """Extract real vector part of complex vector.""" return array(tuple([real_part_of_scalar(elt) for elt in vec]), Float)
def _compute_symplectic_matrix_diag_to_equi(self): """ Construct the change of coordinates between the equilibrium and real-diagonal coordinates. Using the (generally complex) eigenvectors, corresponding to the quadratic part of the Hamiltonian, we build a real symplectic linear coordinate transformation on the phase space (expressed as a matrix), under which the quadratic part is transformed into real normal form. It is important to note that any non-zero multiple of an eigenvector is also an eigenvector. Therefore, although certain eigenvalues (those corresponding to centres) will come in pure imaginary complex conjugate pairs, the assocaited eigenvectors need not be complex conjugate pairs --- although, we could express them as such by multiplication by suitable complex scale factors --- instead, we may have any complex (including pure-imaginary) multiple of the complex conjugate eigenvector. Care must therefore be taken in the choice of the eigenvectors for the symplectic matrix, especially in the case where the original system already contains subsystems that are in real normal form. To cope with the above, we use the following scheme: 1. In the case of a saddle (pure real +/- eigenvalues, $(+e, -e)$) we simply use whatever eigenvectors, $(v_0, v_1)$, we are given and scale (via a real scale factor) these suitably to give a real symplectic subsystem. 2. In the case of a centre (pure imaginary complex conjugate pair of eigenvalues), we denote the given eigenvectors by $v_0,v_1$. We then use $v_0':=\re(v_0)$ and $v_1':=\im(v_0)$, i.e., we only use one of the complex eigenvectors, taking its real and imaginary parts. Again, this choice of real vectors will be suitably scaled so as to give a symplectic subsystem. It can be confirmed that the action of the linearised version of Hamilton's equations on the above choice of real vectors spans the same two-dimensional subspace as on the original complex ones. The chosen vectors form the columns of a matrix $M$. Given a vector in the real diagonal coordinate system, $x_{dr}$, one can then compute the equilibrium coordinate system vector from $Mx_{dr}=x_{er}$. So the matrix is the transformation from DIAG to EQUI. todo: In the case of pairs of zero eigenvalues, perhaps we should emit an error, insisting that the user first projects (via a momentum-independent projector) to a subspace of the non-null space? """ logger.info('Constructing symplectic change:') pm_val_vec_pairs = self._eig.plus_minus_pairs rearranged_pairs = [] columns = [] for i in xrange(0, self.dof()): i0 = 2 * i i1 = i0 + 1 plus, minus = pm_val_vec_pairs[i] if self._eig.equilibrium_type[i] == 's': logger.info('Saddle-type eigenvalues') a = real_part_of_vector(plus.vec) #real anyway b = real_part_of_vector(minus.vec) #real anyway else: if self._eig.equilibrium_type[i] == 'c': logger.info('Centre-type eigenvalues') a = real_part_of_vector(plus.vec) b = imag_part_of_vector(plus.vec) #N.B. *same* vector! else: logger.info('Zero-type eigenvalues') assert (self._eig.equilibrium_type[i] == '0') #todo: assert imag part is close to zero #todo: assert plus close to minus assert 0, 'do something clever to original hamiltonian, please' #logger.info('Original eigenvectors:') #logger.info(plus.vec) #logger.info(minus.vec) #logger.info('Choice of real vectors spanning real subspace:') #logger.info(a) #logger.info(b) c = 0.0 for k in xrange(0, self.dof()): k0 = 2 * k k1 = k0 + 1 c += (a[k0] * b[k1] - a[k1] * b[k0]) if (abs(c) < 1.0e-12): assert (self._eig.equilibrium_type[i] == '0') assert 0, 'do something clever to original hamiltonian, please' else: if c < 0.0: if self._eig.equilibrium_type[i] == 's': a_final = a b_final = -b c_final = -c #ADB! logger.info('Negative Multiplier in saddle: %s', c_final) logger.info('Negating second vector') else: #Swapping pairs to make symplectic matrix: rearranged_pairs.append((minus, plus)) a_final = b b_final = a c_final = -c #ADB! logger.info('Negative Multiplier in centre: %s', c_final) logger.info('NEGATIVE EIGENVALUE, Swap two vectors') else: rearranged_pairs.append((plus, minus)) a_final = a b_final = b c_final = +c #ADB! logger.info('Multiplier present in eigenvector matrix: %s', c_final) scale = +pow(1.0 / c_final, 0.5) #+/- #ADB! logger.info('Scale factor to produce symplectic matrix: %s', scale) columns.append(scale * a_final) columns.append(scale * b_final) self.final_pairs = rearranged_pairs #we must transpose the result, since arrays are created row-wise: mat = transpose(array(columns, Float)) #logger.info('Candidate symplectic matrix') #logger.info(mat) assert self.matrix_is_symplectic(mat) self.matrix_diag_to_equi = mat
def subplot(Numy,Numx,win=0,pw=None,ph=None,hsep=100,vsep=100,color='black',frame=0,fontsize=8,font=None,ticks=1,land=0): # Use gist.plsys to change coordinate systems # all inputs (except fontsize) given as pixels, gist wants # things in normalized device # coordinate. Window is brought up with center of window at # center of 8.5 x 11 inch page: in landscape mode (5.25, 4.25) # or at position (4.25,6.75) for portrait mode msg = 1 if pw is None: pw = Numx*300 msg = 0 if ph is None: ph = Numy*300 msg = 0 if land: maxwidth=min(_maxwidth,11*_dpi) maxheight=min(_maxheight,8.5*_dpi) else: maxwidth=min(_maxwidth,8.5*_dpi) maxheight=min(_maxheight,11*_dpi) printit = 0 if ph > maxheight: ph = maxheight printit = 1 if pw > maxwidth: pw = maxwidth printit = 1 if _dpi != 100: fontsize = 12 conv = inches *1.0 / _dpi # multiply by this factor to convert pixels to # NDC if printit and msg: message = "Warning: Requested height and width too large.\n" message +="Changing to %d x %d" % (pw,ph) print message # Now we've got a suitable height and width if land: cntr = array([5.5,4.25])*_dpi # landscape else: if sys.platform == 'win32': cntr = array([4.25,6.75])*_dpi # portrait else: cntr = array([4.25,5.5])*_dpi Yspace = ph/float(Numy)*conv Xspace = pw/float(Numx)*conv hsep = hsep * conv vsep = vsep * conv ytop = (cntr[1]+ph/2.0)*conv xleft = (cntr[0]-pw/2.0)*conv if type(color) is types.StringType: color = _colornum[color] systems=[] ind = -1 for nY in range(Numy): ystart = ytop - (nY+1)*Yspace for nX in range(Numx): xstart = xleft + nX*Xspace systems.append({}) systems[-1]['viewport'] = [xstart+hsep/2.0,xstart+Xspace-hsep/2.0,ystart+vsep/2.0,ystart+Yspace-vsep/2.0] if font is not None or fontsize is not None: _chng_font(systems[-1],font,fontsize) if color != -3 or frame != 0: _add_color(systems[-1],color,frame=frame) if ticks != 1: _remove_ticks(systems[-1]) _current_style=os.path.join(_user_path,"subplot%s.gs" % win) fid = open(_current_style,'w') fid.write(write_style.style2string(systems,landscape=land)) fid.close() gist.winkill(win) gist.window(win,style=_current_style,width=int(pw),height=int(ph))
def twoplane(DATA,slice1,slice2,dx=[1,1,1],cmin=None,cmax=None,xb=None,xe=None, xlab="",ylab="",zlab="",clab="",titl="", totalheight=0.5,space=0.02, medfilt=5, font='helvetica',fontsize=16,color='black',lcolor='white', fcolor='black', cb=1, line=1, palette=None): """ Visualize a 3d volume as a two connected slices. The slices are given in the 2-tuple slice1 and slice2. These give the dimension and corresponding slice numbers to plot. The unchosen slice is the common dimension in the images. twoplane(img3d,(0,12),(2,60)) plots two images with a common "x"-axis as the first dimension. The lower plot is img3d[12,:,:] with a line through row 60 corresponding to the slice transpose(img3d[:,:,60]) plotted above this first plot. """ if xb is None: xb = [0,0,0] if xe is None: xe = DATA.shape # get two image slices # make special style file so that pixels are square getdx = array([1,1,1]) imgsl1 = [slice(None,None),slice(None,None),slice(None,None)] imgsl1[slice1[0]] = slice1[1] img1 = DATA[imgsl1] getdx1 = getdx.__copy__() getdx1[slice1[0]] = 0 dx1 = compress(getdx1,dx,axis=-1) xb1 = compress(getdx1,xb,axis=-1) xe1 = compress(getdx1,xe,axis=-1) imgsl2 = [slice(None,None),slice(None,None),slice(None,None)] imgsl2[slice2[0]] = slice2[1] img2 = DATA[imgsl2] getdx2 = getdx.__copy__() getdx2[slice2[0]] = 0 dx2 = compress(getdx2,dx,axis=-1) xb2 = compress(getdx2,xb,axis=-1) xe2 = compress(getdx2,xe,axis=-1) if (slice1[0] == slice2[0]): raise ValueError, "Same slice dimension.." for k in range(3): if k not in [slice1[0],slice2[0]]: samedim = k break if samedim == 2: pass elif samedim == 1: if samedim > slice1[0]: img1 = transpose(img1) dx1 = dx1[::-1] xb1 = xb1[::-1] xe1 = xe1[::-1] if samedim > slice2[0]: img2 = transpose(img2) dx2 = dx2[::-1] xb2 = xb2[::-1] xe2 = xe2[::-1] else: img1 = transpose(img1) dx1 = dx1[::-1] xb1 = xb1[::-1] xe1 = xe1[::-1] img2 = transpose(img2) dx2 = dx2[::-1] xb2 = xb2[::-1] xe2 = xe2[::-1] assert(img1.shape[1] == img2.shape[1]) units = totalheight - space totaldist = img1.shape[0]*dx1[0] + img2.shape[0]*dx2[0] convfactor = units / float(totaldist) height1 = img1.shape[0]*dx1[0] * convfactor xwidth = img1.shape[1]*dx1[1]*convfactor if xwidth > 0.6: rescale = 0.6 / xwidth xwidth = rescale * xwidth height1 = rescale * height1 totalheight = totalheight * rescale print xwidth, height1 else: print xwidth ystart = 0.5 - totalheight / 2 ypos1 = [ystart, ystart+height1] ypos2 = [ystart+height1+space,ystart+totalheight] xpos = [0.395-xwidth/2.0, 0.395+xwidth/2.0] systems = [] system = write_style.getsys(hticpos='', vticpos='left') system['viewport'] = [xpos[0],xpos[1],ypos2[0],ypos2[1]] if fcolor not in ['black',None]: _add_color(system, _colornum[color]) systems.append(system) system = write_style.getsys(hticpos='below', vticpos='left') system['viewport'] = [xpos[0],xpos[1],ypos1[0],ypos1[1]] if fcolor not in ['black',None]: _add_color(system, _colornum[color]) systems.append(system) the_style = os.path.join(_user_path,"two-plane.gs") write_style.writestyle(the_style,systems) gist.window(style=the_style) _current_style = the_style change_palette(palette) gist.plsys(1) if medfilt > 1: img1 = signal.medfilt(img1,[medfilt,medfilt]) img2 = signal.medfilt(img2,[medfilt,medfilt]) if cmax is None: cmax = max(max(ravel(img1)),max(ravel(img2))) if cmin is None: cmin = min(min(ravel(img1)),min(ravel(img2))) cmax = float(cmax) cmin = float(cmin) byteimage = gist.bytscl(img2,cmin=cmin,cmax=cmax) gist.pli(byteimage,xb2[1],xb2[0],xe2[1],xe2[0]) ylabel(zlab,color=color) if titl != "": title(titl,color=color) if line: xstart = xb2[1] xstop = xe2[1] yval = slice1[1]*(xe2[0] - xb2[0])/(img2.shape[0]) + xb2[0] gist.pldj([xstart],[yval],[xstop],[yval],type='dash',width=2,color='white') gist.plsys(2) ylabel(ylab,color=color) xlabel(xlab,color=color) byteimage = gist.bytscl(img1,cmin=cmin,cmax=cmax) gist.pli(byteimage,xb1[1],xb1[0],xe1[1],xe1[0]) if line: xstart = xb1[1] xstop = xe1[1] yval = slice2[1]*(xe1[0] - xb1[0])/(img1.shape[0]) + xb1[0] gist.pldj([xstart],[yval],[xstop],[yval],type='dash',width=2,color='white') if cb: colorbar.color_bar(cmin,cmax,ncol=240,zlabel=clab,font=font,fontsize=fontsize,color=color,ymin=ystart,ymax=ystart+totalheight,xmin0=xpos[1]+0.02,xmax0=xpos[1]+0.04)
def _compute_symplectic_matrix_diag_to_equi(self): """ Construct the change of coordinates between the equilibrium and real-diagonal coordinates. Using the (generally complex) eigenvectors, corresponding to the quadratic part of the Hamiltonian, we build a real symplectic linear coordinate transformation on the phase space (expressed as a matrix), under which the quadratic part is transformed into real normal form. It is important to note that any non-zero multiple of an eigenvector is also an eigenvector. Therefore, although certain eigenvalues (those corresponding to centres) will come in pure imaginary complex conjugate pairs, the assocaited eigenvectors need not be complex conjugate pairs --- although, we could express them as such by multiplication by suitable complex scale factors --- instead, we may have any complex (including pure-imaginary) multiple of the complex conjugate eigenvector. Care must therefore be taken in the choice of the eigenvectors for the symplectic matrix, especially in the case where the original system already contains subsystems that are in real normal form. To cope with the above, we use the following scheme: 1. In the case of a saddle (pure real +/- eigenvalues, $(+e, -e)$) we simply use whatever eigenvectors, $(v_0, v_1)$, we are given and scale (via a real scale factor) these suitably to give a real symplectic subsystem. 2. In the case of a centre (pure imaginary complex conjugate pair of eigenvalues), we denote the given eigenvectors by $v_0,v_1$. We then use $v_0':=\re(v_0)$ and $v_1':=\im(v_0)$, i.e., we only use one of the complex eigenvectors, taking its real and imaginary parts. Again, this choice of real vectors will be suitably scaled so as to give a symplectic subsystem. It can be confirmed that the action of the linearised version of Hamilton's equations on the above choice of real vectors spans the same two-dimensional subspace as on the original complex ones. The chosen vectors form the columns of a matrix $M$. Given a vector in the real diagonal coordinate system, $x_{dr}$, one can then compute the equilibrium coordinate system vector from $Mx_{dr}=x_{er}$. So the matrix is the transformation from DIAG to EQUI. todo: In the case of pairs of zero eigenvalues, perhaps we should emit an error, insisting that the user first projects (via a momentum-independent projector) to a subspace of the non-null space? """ logger.info('Constructing symplectic change:') pm_val_vec_pairs = self._eig.plus_minus_pairs rearranged_pairs = [] columns = [] for i in xrange(0, self.dof()): i0 = 2*i i1 = i0+1 plus, minus = pm_val_vec_pairs[i] if self._eig.equilibrium_type[i] == 's': logger.info('Saddle-type eigenvalues') a = real_part_of_vector(plus.vec) #real anyway b = real_part_of_vector(minus.vec) #real anyway else: if self._eig.equilibrium_type[i] == 'c': logger.info('Centre-type eigenvalues') a = real_part_of_vector(plus.vec) b = imag_part_of_vector(plus.vec) #N.B. *same* vector! else: logger.info('Zero-type eigenvalues') assert (self._eig.equilibrium_type[i] == '0') #todo: assert imag part is close to zero #todo: assert plus close to minus assert 0, 'do something clever to original hamiltonian, please' #logger.info('Original eigenvectors:') #logger.info(plus.vec) #logger.info(minus.vec) #logger.info('Choice of real vectors spanning real subspace:') #logger.info(a) #logger.info(b) c = 0.0 for k in xrange(0, self.dof()): k0 = 2*k k1 = k0+1 c += (a[k0]*b[k1] - a[k1]*b[k0]) if (abs(c) < 1.0e-12): assert (self._eig.equilibrium_type[i] == '0') assert 0, 'do something clever to original hamiltonian, please' else: if c < 0.0: if self._eig.equilibrium_type[i] == 's': a_final = a b_final = -b c_final = -c #ADB! logger.info('Negative Multiplier in saddle: %s', c_final) logger.info('Negating second vector') else: #Swapping pairs to make symplectic matrix: rearranged_pairs.append((minus, plus)) a_final = b b_final = a c_final = -c #ADB! logger.info('Negative Multiplier in centre: %s', c_final) logger.info('NEGATIVE EIGENVALUE, Swap two vectors') else: rearranged_pairs.append((plus, minus)) a_final = a b_final = b c_final = +c #ADB! logger.info('Multiplier present in eigenvector matrix: %s', c_final) scale = +pow(1.0/c_final, 0.5) #+/- #ADB! logger.info('Scale factor to produce symplectic matrix: %s', scale) columns.append(scale*a_final) columns.append(scale*b_final) self.final_pairs = rearranged_pairs #we must transpose the result, since arrays are created row-wise: mat = transpose(array(columns, Float)) #logger.info('Candidate symplectic matrix') #logger.info(mat) assert self.matrix_is_symplectic(mat) self.matrix_diag_to_equi = mat