def normalize_metric(self): if self.de is None: return renorm = [] # Generate mapping for renormalizing reciprocal basis vectors for ib in self.n_range: # e^{ib} --> e^{ib}/|e_{ib}| renorm.append((self.r_symbols[ib], self.r_symbols[ib] / self.e_norm[ib])) # Normalize derivatives of basis vectors for x_i in self.n_range: for jb in self.n_range: self.de[x_i][jb] = Simp.apply((((self.de[x_i][jb].subs(renorm) - diff(self.e_norm[jb], self.coords[x_i]) * self.basis[jb]) / self.e_norm[jb]))) if self.debug: for x_i in self.n_range: for jb in self.n_range: print '\partial_{' + str(self.coords[x_i]) + '}\hat{e}_{' + str(self.coords[jb]) + '} =', self.de[x_i][jb] # Normalize metric tensor for ib in self.n_range: for jb in self.n_range: self.g[ib, jb] = Simp.apply(self.g[ib, jb] / (self.e_norm[ib] * self.e_norm[jb])) if self.debug: printer.oprint('e^{i}->e^{i}/|e_{i}|', renorm) printer.oprint('renorm(g)', self.g) return
def derivatives_of_basis( self): # Derivatives of basis vectors from Christ-Awful symbols dg = [] # dg[i][j][k] = \partial_{x_{k}}g_{ij} for i in self.n_range: dg_row = [] for j in self.n_range: dg_row.append( [diff(self.g[i, j], coord) for coord in self.coords]) dg.append(dg_row) # See if metric is flat self.connect_flg = False for i in self.n_range: for j in self.n_range: for k in self.n_range: if dg[i][j][k] != 0: self.connect_flg = True break if not self.connect_flg: self.de = None return n_range = range(len(self.basis)) de = [] # de[i][j] = \partial_{x_{i}}e^{x_{j}} # Christoffel symbols of the first kind, \Gamma_{ijk} for i in n_range: de_row = [] for j in n_range: Gamma = [] for k in n_range: gamma = half * (dg[j][k][i] + dg[i][k][j] - dg[i][j][k]) Gamma.append(Simp.apply(gamma)) de_row.append( sum([ gamma * base for (gamma, base) in zip(Gamma, self.r_symbols) ])) de.append(de_row) if self.debug: printer.oprint('D_{i}e^{j}', de) self.de = de return
def derivatives_of_basis(self): # Derivatives of basis vectors from Christ-Awful symbols dg = [] # dg[i][j][k] = \partial_{x_{k}}g_{ij} for i in self.n_range: dg_row = [] for j in self.n_range: dg_row.append([diff(self.g[i, j], coord) for coord in self.coords]) dg.append(dg_row) # See if metric is flat self.connect_flg = False for i in self.n_range: for j in self.n_range: for k in self.n_range: if dg[i][j][k] != 0: self.connect_flg = True break if not self.connect_flg: self.de = None return n_range = range(len(self.basis)) de = [] # de[i][j] = \partial_{x_{i}}e^{x_{j}} # Christoffel symbols of the first kind, \Gamma_{ijk} for i in n_range: de_row = [] for j in n_range: Gamma = [] for k in n_range: gamma = half * (dg[j][k][i] + dg[i][k][j] - dg[i][j][k]) Gamma.append(Simp.apply(gamma)) de_row.append(sum([gamma * base for (gamma, base) in zip(Gamma, self.r_symbols)])) de.append(de_row) if self.debug: printer.oprint('D_{i}e^{j}', de) self.de = de return
def main(): enhance_print() coords = symbols('x y z') (ex,ey,ez,grad) = MV.setup('ex ey ez',metric='[1,1,1]',coords=coords) mfvar = (u,v) = symbols('u v') eu = ex+ey ev = ex-ey (eu_r,ev_r) = ReciprocalFrame([eu,ev]) oprint('Frame',(eu,ev),'Reciprocal Frame',(eu_r,ev_r)) print 'eu.eu_r =',eu|eu_r print 'eu.ev_r =',eu|ev_r print 'ev.eu_r =',ev|eu_r print 'ev.ev_r =',ev|ev_r eu = ex+ey+ez ev = ex-ey (eu_r,ev_r) = ReciprocalFrame([eu,ev]) oprint('Frame',(eu,ev),'Reciprocal Frame',(eu_r,ev_r)) print 'eu.eu_r =',eu|eu_r print 'eu.ev_r =',eu|ev_r print 'ev.eu_r =',ev|eu_r print 'ev.ev_r =',ev|ev_r print 'eu =',eu print 'ev =',ev def_prec(locals()) print GAeval('eu^ev|ex',True) print GAeval('eu^ev|ex*eu',True) return
def main(): enhance_print() coords = symbols('x y z') (ex, ey, ez, grad) = MV.setup('ex ey ez', metric='[1,1,1]', coords=coords) mfvar = (u, v) = symbols('u v') eu = ex + ey ev = ex - ey (eu_r, ev_r) = ReciprocalFrame([eu, ev]) oprint('Frame', (eu, ev), 'Reciprocal Frame', (eu_r, ev_r)) print('eu.eu_r =', eu | eu_r) print('eu.ev_r =', eu | ev_r) print('ev.eu_r =', ev | eu_r) print('ev.ev_r =', ev | ev_r) eu = ex + ey + ez ev = ex - ey (eu_r, ev_r) = ReciprocalFrame([eu, ev]) oprint('Frame', (eu, ev), 'Reciprocal Frame', (eu_r, ev_r)) print('eu.eu_r =', eu | eu_r) print('eu.ev_r =', eu | ev_r) print('ev.eu_r =', ev | eu_r) print('ev.ev_r =', ev | ev_r) print('eu =', eu) print('ev =', ev) def_prec(locals()) print(GAeval('eu^ev|ex', True)) print(GAeval('eu^ev|ex*eu', True)) return
def main(): Eprint() coords = symbols('x y z') (o3d,ex,ey,ez) = Ga.build('ex ey ez',g=[1,1,1],coords=coords) mfvar = (u,v) = symbols('u v') eu = ex+ey ev = ex-ey (eu_r,ev_r) = o3d.ReciprocalFrame([eu,ev]) oprint('Frame',(eu,ev),'Reciprocal Frame',(eu_r,ev_r)) print 'eu.eu_r =',eu|eu_r print 'eu.ev_r =',eu|ev_r print 'ev.eu_r =',ev|eu_r print 'ev.ev_r =',ev|ev_r eu = ex+ey+ez ev = ex-ey (eu_r,ev_r) = o3d.ReciprocalFrame([eu,ev]) oprint('Frame',(eu,ev),'Reciprocal Frame',(eu_r,ev_r)) print 'eu.eu_r =',eu|eu_r print 'eu.ev_r =',eu|ev_r print 'ev.eu_r =',ev|eu_r print 'ev.ev_r =',ev|ev_r print 'eu =',eu print 'ev =',ev def_prec(locals()) print GAeval('eu^ev|ex',True) print GAeval('eu^ev|ex*eu',True) return
def __init__(self, basis, **kwargs): kwargs = test_init_slots(Metric.init_slots, **kwargs) self.name = 'GA' + str(Metric.count) Metric.count += 1 if not isinstance(basis, basestring): raise TypeError('"' + str(basis) + '" must be string') X = kwargs['X'] # Vector manifold g = kwargs['g'] # Explicit metric or base metric for vector manifold debug = kwargs['debug'] coords = kwargs['coords'] # Manifold coordinates (sympy symbols) norm = kwargs['norm'] # Normalize basis vectors self.sig = kwargs['sig'] # Hint for metric signature """ String for symbolic metric determinant. If self.gsym = 'g' then det(g) is sympy scalar function of coordinates with name 'det(g)'. Useful for complex non-orthogonal coordinate systems or for calculations with general metric. """ self.gsym = kwargs['gsym'] self.debug = debug self.is_ortho = False # Is basis othogonal self.coords = coords # Manifold coordinates if self.coords is None: self.connect_flg = False else: self.connect_flg = True # Connection needed for postion dependent metric self.norm = norm # True to normalize basis vectors self.detg = None # Determinant of g self.g_adj = None # Adjugate of g self.g_inv = None # Inverse of g # Generate list of basis vectors and reciprocal basis vectors # as non-commutative symbols if ' ' in basis or ',' in basis or '*' in basis: # bases defined by substrings separated by spaces or commas self.basis = symbols_list(basis) self.r_symbols = symbols_list(basis, sub=False) else: if coords is not None: # basis defined by root string with symbol list as indices self.basis = symbols_list(basis, coords) self.r_symbols = symbols_list(basis, coords, sub=False) self.coords = coords if self.debug: printer.oprint('x^{i}', self.coords) else: raise ValueError('for basis "' + basis + '" coords must be entered') if self.debug: printer.oprint('e_{i}', self.basis, 'e^{i}', self.r_symbols) self.n = len(self.basis) self.n_range = range(self.n) # Generate metric as list of lists of symbols, rationals, or functions of coordinates if g is None: if X is None: # default metric from dot product of basis as symbols self.g = self.metric_symbols_list() else: # Vector manifold if coords is None: raise ValueError('For metric derived from vector field ' + ' coordinates must be defined.') else: # Vector manifold defined by vector field dX = [] for coord in coords: # Get basis vectors by differentiating vector field dX.append([diff(x, coord) for x in X]) g_tmp = [] for dx1 in dX: g_row = [] for dx2 in dX: dx1_dot_dx2 = trigsimp(Metric.dot_orthogonal(dx1, dx2, g)) g_row.append(dx1_dot_dx2) g_tmp.append(g_row) self.g = Matrix(g_tmp) if self.debug: printer.oprint('X_{i}', X, 'D_{i}X_{j}', dX) else: # metric is symbolic or list of lists of functions of coordinates if isinstance(g, basestring): # metric elements are symbols or constants if g == 'g': # general symbolic metric tensor (g_ij functions of position) g_lst = [] g_inv_lst = [] for coord1 in self.coords: i1 = str(coord2) tmp = [] tmp_inv = [] for coord2 in self.coords: i2 = str(coord2) tmp.append(Function('g_'+i1+'_'+i2)(*self.coords)) tmp_inv.append(Function('g__'+i1+'__'+i2)(*self.coords)) g_lst.append(tmp) g_inv_lst.append(tmp_inv) self.g = Matrix(g_lst) self.g_inv = Matrix(g_inv_lst) else: # specific symbolic metric tensor (g_ij are symbolic or numerical constants) self.g = self.metric_symbols_list(g) # construct symbolic metric from string and basis else: # metric is given as list of function or list of lists of function or matrix of functions if isinstance(g, Matrix): self.g = g else: if isinstance(g[0], list): self.g = Matrix(g) else: m = eye(len(g)) for i in range(len(g)): m[i, i] = g[i] self.g = m self.g_raw = copy.deepcopy(self.g) # save original metric tensor for use with submanifolds if self.debug: printer.oprint('g', self.g) # Determine if metric is orthogonal self.is_ortho = True for i in self.n_range: for j in self.n_range: if i < j: if self.g[i, j] != 0: self.is_ortho = False break self.g_is_numeric = True for i in self.n_range: for j in self.n_range: if i < j: if not self.g[i, j].is_number: self.g_is_numeric = False break if self.coords is not None: self.derivatives_of_basis() # calculate derivatives of basis if self.norm: # normalize basis, metric, and derivatives of normalized basis self.e_norm = [] for i in self.n_range: self.e_norm.append(square_root_of_expr(self.g[i, i])) if debug: printer.oprint('|e_{i}|', self.e_norm) else: self.e_norm = None if self.norm: if self.is_ortho: self.normalize_metric() else: raise ValueError('!!!!Basis normalization only implemented for orthogonal basis!!!!') if not self.g_is_numeric: self.signature() # Sign of square of pseudo scalar self.e_sq_sgn = '+' if ((self.n*(self.n-1))/2+self.sig[1])%2 == 1: self.e_sq_sgn = '-' if self.debug: print 'signature =', self.sig
def Christoffel_symbols(self,mode=1): """ mode = 1 Christoffel symbols of the first kind mode = 2 Christoffel symbols of the second kind """ if mode == 1: dg = [] # dg[i][j][k] = \partial_{x_{k}}g_{ij} for i in self.n_range: dg_row = [] for j in self.n_range: dg_row.append([diff(self.g[i, j], coord) for coord in self.coords]) dg.append(dg_row) # See if connection is zero self.connect_flg = False for i in self.n_range: for j in self.n_range: for k in self.n_range: if dg[i][j][k] != 0: self.connect_flg = True break if not self.connect_flg: self.de = None return n_range = range(len(self.basis)) dG = [] # dG[i][j][k] = half * (dg[j][k][i] + dg[i][k][j] - dg[i][j][k]) # Christoffel symbols of the first kind, \Gamma_{ijk} # \partial_{x^{i}}e_{j} = \Gamma_{ijk}e^{k} for i in n_range: dG_j = [] for j in n_range: dG_k = [] for k in n_range: gamma = half * (dg[j][k][i] + dg[i][k][j] - dg[i][j][k]) dG_k.append(Simp.apply(gamma)) dG_j.append(dG_k) dG.append(dG_j) if self.debug: printer.oprint('Gamma_{ijk}', dG) return dG elif mode == 2: Gamma1 = self.Christoffel_symbols(mode=1) if self.connect_flg: # Connection is not zero self.inverse_metric() # Christoffel symbols of the second kind, \Gamma_{ij}^{k} = \Gamma_{ijl}g^{lk} # \partial_{x^{i}}e_{j} = \Gamma_{ij}^{k}e_{k} Gamma = [] for Gi in Gamma1: Gamma_i = [] for Gij in Gi: Gamma_ij = [] Gamma_ijk = S(0) l = 0 for Gijl in Gij: Gamma_ijk += Gijl * g(l,) else: return else: raise ValueError('In Christoffle_symobols mode = ' +str(mode) +' is not allowed\n')
def __init__(self, basis, **kwargs): kwargs = test_init_slots(Metric.init_slots, **kwargs) self.name = 'GA' + str(Metric.count) Metric.count += 1 if not isinstance(basis, basestring): raise TypeError('"' + str(basis) + '" must be string') X = kwargs['X'] # Vector manifold g = kwargs['g'] # Explicit metric or base metric for vector manifold debug = kwargs['debug'] coords = kwargs['coords'] # Manifold coordinates (sympy symbols) norm = kwargs['norm'] # Normalize basis vectors self.sig = kwargs['sig'] # Hint for metric signature """ String for symbolic metric determinant. If self.gsym = 'g' then det(g) is sympy scalar function of coordinates with name 'det(g)'. Useful for complex non-orthogonal coordinate systems or for calculations with general metric. """ self.gsym = kwargs['gsym'] self.debug = debug self.is_ortho = False # Is basis othogonal self.coords = coords # Manifold coordinates if self.coords is None: self.connect_flg = False else: self.connect_flg = True # Connection needed for postion dependent metric self.norm = norm # True to normalize basis vectors self.detg = None # Determinant of g self.g_adj = None # Adjugate of g self.g_inv = None # Inverse of g # Generate list of basis vectors and reciprocal basis vectors # as non-commutative symbols if ' ' in basis or ',' in basis or '*' in basis: # bases defined by substrings separated by spaces or commas self.basis = symbols_list(basis) self.r_symbols = symbols_list(basis, sub=False) else: if coords is not None: # basis defined by root string with symbol list as indices self.basis = symbols_list(basis, coords) self.r_symbols = symbols_list(basis, coords, sub=False) self.coords = coords if self.debug: printer.oprint('x^{i}', self.coords) else: raise ValueError('for basis "' + basis + '" coords must be entered') if self.debug: printer.oprint('e_{i}', self.basis, 'e^{i}', self.r_symbols) self.n = len(self.basis) self.n_range = range(self.n) # Generate metric as list of lists of symbols, rationals, or functions of coordinates if g is None: if X is None: # default metric from dot product of basis as symbols self.g = self.metric_symbols_list() else: # Vector manifold if coords is None: raise ValueError('For metric derived from vector field ' + ' coordinates must be defined.') else: # Vector manifold defined by vector field dX = [] for coord in coords: # Get basis vectors by differentiating vector field dX.append([diff(x, coord) for x in X]) g_tmp = [] for dx1 in dX: g_row = [] for dx2 in dX: dx1_dot_dx2 = trigsimp(Metric.dot_orthogonal(dx1, dx2, g)) g_row.append(dx1_dot_dx2) g_tmp.append(g_row) self.g = Matrix(g_tmp) if self.debug: printer.oprint('X_{i}', X, 'D_{i}X_{j}', dX) else: # metric is symbolic or list of lists of functions of coordinates if isinstance(g, basestring): # metric elements are symbols or constants if g == 'g': # general symbolic metric tensor (g_ij functions of position) g_lst = [] g_inv_lst = [] for coord1 in self.coords: i1 = str(coord2) tmp = [] tmp_inv = [] for coord2 in self.coords: i2 = str(coord2) tmp.append(Function('g_'+i1+'_'+i2)(*self.coords)) tmp_inv.append(Function('g__'+i1+'__'+i2)(*self.coords)) g_lst.append(tmp) g_inv_lst.append(tmp_inv) self.g = Matrix(g_lst) self.g_inv = Matrix(g_inv_lst) else: # specific symbolic metric tensor (g_ij are symbolic or numerical constants) self.g = self.metric_symbols_list(g) # construct symbolic metric from string and basis else: # metric is given as list of function or list of lists of function or matrix of functions if isinstance(g, Matrix): self.g = g else: if isinstance(g[0], list): self.g = Matrix(g) else: m = eye(len(g)) for i in range(len(g)): m[i, i] = g[i] self.g = m self.g_raw = copy.deepcopy(self.g) # save original metric tensor for use with submanifolds if self.debug: printer.oprint('g', self.g) # Determine if metric is orthogonal self.is_ortho = True for i in self.n_range: for j in self.n_range: if i < j: if self.g[i, j] != 0: self.is_ortho = False break if self.coords is not None: self.derivatives_of_basis() # calculate derivatives of basis if self.norm: # normalize basis, metric, and derivatives of normalized basis self.e_norm = [] for i in self.n_range: self.e_norm.append(square_root_of_expr(self.g[i, i])) if debug: printer.oprint('|e_{i}|', self.e_norm) else: self.e_norm = None if self.norm: if self.is_ortho: self.normalize_metric() else: raise ValueError('!!!!Basis normalization only implemented for orthogonal basis!!!!') self.signature() # Sign of square of pseudo scalar self.e_sq_sgn = '+' if ((self.n*(self.n-1))/2+self.sig[1])%2 == 1: self.e_sq_sgn = '-' if self.debug: print 'signature =', self.sig