示例#1
0
    def sqrt_abs_det(self, frame=None):
        r"""
        Square root of the absolute value of the determinant of the metric 
        components in the specified frame.
        
        INPUT:
        
        - ``frame`` -- (default: None) vector frame with 
          respect to which the components `g_{ij}` of ``self`` are defined; 
          if None, the domain's default frame is used. If a chart is 
          provided, the associated coordinate frame is used
          
        OUTPUT:
        
        -  `\sqrt{|\det (g_{ij})|}`, as an instance of :class:`ScalarField`
        
        EXAMPLES:
        
        Standard metric in the Euclidean space `\RR^3` with spherical 
        coordinates::
        
            sage: m = Manifold(3, 'M', start_index=1)
            sage: c_spher.<r,th,ph> = m.chart(r'r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi')
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2
            sage: g.view()
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: g.sqrt_abs_det().expr()
            r^2*sin(th)
            
        Metric determinant on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M', start_index=1)
            sage: X.<x,y> = M.chart('x y')
            sage: g = Metric(M, 'g')
            sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
            sage: g[:]
            [ x + 1    x*y]
            [   x*y -y + 1]
            sage: s = g.sqrt_abs_det() ; s
            scalar field on the 2-dimensional manifold 'M'
            sage: s.expr()
            sqrt(-x^2*y^2 - (x + 1)*y + x + 1)

        Determinant in a frame different from the default's one::
            
            sage: Y.<u,v> = M.chart('u v')
            sage: ch_X_Y = CoordChange(X, Y, x+y, x-y)   
            sage: ch_X_Y.inverse()
            coordinate change from chart (M, (u, v)) to chart (M, (x, y))                    
            sage: g.comp(Y.frame)[:, Y]
            [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2                            1/4*u]
            [                           1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
            sage: g.sqrt_abs_det(Y.frame).expr()
            1/2*sqrt(-x^2*y^2 - (x + 1)*y + x + 1)
            sage: g.sqrt_abs_det(Y.frame).expr(Y)
            1/8*sqrt(-u^4 - v^4 + 2*(u^2 + 2)*v^2 - 4*u^2 + 16*v + 16)

        A chart can be passed instead of a frame::
        
            sage: g.sqrt_abs_det(Y) is g.sqrt_abs_det(Y.frame)
            True

        The metric determinant depends on the frame::
        
            sage: g.sqrt_abs_det(X.frame) == g.sqrt_abs_det(Y.frame) 
            False

        """
        from sage.functions.other import sqrt
        from scalarfield import ScalarField
        from utilities import simplify_chain
        manif = self.manifold
        dom = self.domain
        if frame is None:
            frame = dom.def_frame
        if frame in dom.atlas:   
            # frame is actually a chart and is changed to the associated 
            # coordinate frame:
            frame = frame.frame
        if frame not in self._sqrt_abs_dets:
            # a new computation is necessary
            detg = self.determinant(frame)
            resu = ScalarField(dom)
            for chart in detg.express:
                x = self._indic_signat * detg.express[chart].express # |g|
                x = simplify_chain(sqrt(x))
                resu.add_expr(x, chart=chart)
            self._sqrt_abs_dets[frame] = resu
        return self._sqrt_abs_dets[frame]
示例#2
0
    def pullback(self, tensor):
        r""" 
        Pullback operator associated with the differentiable mapping. 
        
        INPUT:
        
        - ``tensor`` -- instance of :class:`TensorField` representing a fully 
          covariant tensor field `T` on the *arrival* domain, i.e. a tensor 
          field of type (0,p), with p a positive or zero integer. The case p=0 
          corresponds to a scalar field.
          
        OUTPUT:
        
        - instance of :class:`TensorField` representing a fully 
          covariant tensor field on the *start* domain that is the 
          pullback of `T` given by ``self``. 
          
        EXAMPLES:
        
        Pullback on `S^2` of a scalar field defined on `R^3`::
        
            sage: m = Manifold(2, 'S^2', start_index=1)
            sage: c_spher.<th,ph> = m.chart(r'th:(0,pi):\theta ph:(0,2*pi):\phi') # spherical coord. on S^2
            sage: n = Manifold(3, 'R^3', r'\RR^3', start_index=1)
            sage: c_cart.<x,y,z> = n.chart('x y z') # Cartesian coord. on R^3
            sage: Phi = DiffMapping(m, n, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)), name='Phi', latex_name=r'\Phi')
            sage: f = ScalarField(n, x*y*z, name='f') ; f
            scalar field 'f' on the 3-dimensional manifold 'R^3'
            sage: f.view()
            f: (x, y, z) |--> x*y*z
            sage: pf = Phi.pullback(f) ; pf
            scalar field 'Phi_*(f)' on the 2-dimensional manifold 'S^2'
            sage: pf.view()
            Phi_*(f): (th, ph) |--> cos(ph)*cos(th)*sin(ph)*sin(th)^2
            
        Pullback on `S^2` of the standard Euclidean metric on `R^3`::
                
            sage: g = SymBilinFormField(n, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
            sage: g.view()
            g = dx*dx + dy*dy + dz*dz
            sage: pg = Phi.pullback(g) ; pg
            field of symmetric bilinear forms 'Phi_*(g)' on the 2-dimensional manifold 'S^2'
            sage: pg.view()
            Phi_*(g) = dth*dth + sin(th)^2 dph*dph

        Pullback on `S^2` of a 3-form on `R^3`::
                
            sage: a = DiffForm(n, 3, 'A')
            sage: a[1,2,3] = f 
            sage: a.view()
            A = x*y*z dx/\dy/\dz
            sage: pa = Phi.pullback(a) ; pa
            3-form 'Phi_*(A)' on the 2-dimensional manifold 'S^2'
            sage: pa.view() # should be zero (as any 3-form on a 2-dimensional manifold)
            Phi_*(A) = 0

        """
        from scalarfield import ScalarField
        from vectorframe import CoordFrame
        from rank2field import SymBilinFormField
        from diffform import DiffForm, OneForm

        if not isinstance(tensor, TensorField):
            raise TypeError("The argument 'tensor' must be a tensor field.")
        dom1 = self.domain1
        dom2 = self.domain2
        if not tensor.domain.is_subdomain(dom2):
            raise TypeError("The tensor field is not defined on the mapping " +
                            "arrival domain.")
        (ncon, ncov) = tensor.tensor_type
        if ncon != 0:
            raise TypeError("The pullback cannot be taken on a tensor " + 
                            "with some contravariant part.")
        resu_name = None ; resu_latex_name = None
        if self.name is not None and tensor.name is not None:
            resu_name = self.name + '_*(' + tensor.name + ')'
        if self.latex_name is not None and tensor.latex_name is not None:
            resu_latex_name = self.latex_name + '_*' + tensor.latex_name                
        if ncov == 0:
            # Case of a scalar field
            # ----------------------
            resu = ScalarField(dom1, name=resu_name, 
                               latex_name=resu_latex_name)
            for chart2 in tensor.express:
                for chart1 in dom1.atlas:
                    if (chart1, chart2) in self.coord_expression:
                        phi = self.coord_expression[(chart1, chart2)]
                        coord1 = chart1.xx
                        ff = tensor.express[chart2]
                        resu.add_expr( ff(*(phi(*coord1))), chart1)
            return resu
        else:
            # Case of tensor field of rank >= 1
            # ---------------------------------
            if isinstance(tensor, OneForm):
                resu = OneForm(dom1, name=resu_name, 
                               latex_name=resu_latex_name)
            elif isinstance(tensor, DiffForm):
                resu = DiffForm(dom1, ncov, name=resu_name, 
                                latex_name=resu_latex_name)
            elif isinstance(tensor, SymBilinFormField):
                resu = SymBilinFormField(dom1, name=resu_name, 
                                         latex_name=resu_latex_name)                
            else:
                resu = TensorField(dom1, 0, ncov, name=resu_name, 
                                   latex_name=resu_latex_name, sym=tensor.sym,
                                   antisym=tensor.antisym)
            for frame2 in tensor.components:
                if isinstance(frame2, CoordFrame):
                    chart2 = frame2.chart
                    for chart1 in dom1.atlas:
                        if (chart1, chart2) in self.coord_expression:
                            # Computation at the component level:
                            frame1 = chart1.frame
                            tcomp = tensor.components[frame2]
                            if isinstance(tcomp, CompFullySym):
                                ptcomp = CompFullySym(frame1, ncov)
                            elif isinstance(tcomp, CompFullyAntiSym):
                                ptcomp = CompFullyAntiSym(frame1, ncov)
                            elif isinstance(tcomp, CompWithSym):
                                ptcomp = CompWithSym(frame1, ncov, sym=tcomp.sym, 
                                                     antisym=tcomp.antisym)
                            else:
                                ptcomp = Components(frame1, ncov)
                            phi = self.coord_expression[(chart1, chart2)]
                            jacob = phi.jacobian()
                            # X2 coordinates expressed in terms of X1 ones via the mapping:
                            coord2_1 = phi(*(chart1.xx)) 
                            si1 = dom1.manifold.sindex
                            si2 = dom2.manifold.sindex
                            for ind_new in ptcomp.non_redundant_index_generator(): 
                                res = 0 
                                for ind_old in dom2.manifold.index_generator(ncov): 
                                    ff = tcomp[[ind_old]].function_chart(chart2)
                                    t = FunctionChart(chart1, ff(*coord2_1))
                                    for i in range(ncov):
                                        t *= jacob[ind_old[i]-si2][ind_new[i]-si1]
                                    res += t
                                ptcomp[ind_new] = res
                            resu.components[frame1] = ptcomp
            return resu
示例#3
0
    def determinant(self, frame=None):
        r"""
        Determinant of the metric components in the specified frame.
        
        INPUT:
        
        - ``frame`` -- (default: None) vector frame with 
          respect to which the components `g_{ij}` of ``self`` are defined; 
          if None, the domain's default frame is used. If a chart is 
          provided, the associated coordinate frame is used
          
        OUTPUT:
        
        - the determinant `\det (g_{ij})`, as an instance of :class:`ScalarField`
        
        EXAMPLES:
        
        Metric determinant on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M', start_index=1)
            sage: X.<x,y> = M.chart('x y')
            sage: g = Metric(M, 'g')
            sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
            sage: g[:]
            [ x + 1    x*y]
            [   x*y -y + 1]
            sage: s = g.determinant()  # determinant in M's default frame
            sage: s.expr()
            -x^2*y^2 - (x + 1)*y + x + 1

        Determinant in a frame different from the default's one::
            
            sage: Y.<u,v> = M.chart('u v')
            sage: ch_X_Y = CoordChange(X, Y, x+y, x-y)   
            sage: ch_X_Y.inverse()
            coordinate change from chart (M, (u, v)) to chart (M, (x, y))                 
            sage: g.comp(Y.frame)[:, Y]
            [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2                            1/4*u]
            [                           1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
            sage: g.determinant(Y.frame).expr()
            -1/4*x^2*y^2 - 1/4*(x + 1)*y + 1/4*x + 1/4
            sage: g.determinant(Y.frame).expr(Y)
            -1/64*u^4 - 1/64*v^4 + 1/32*(u^2 + 2)*v^2 - 1/16*u^2 + 1/4*v + 1/4

        A chart can be passed instead of a frame::
        
            sage: g.determinant(X) is g.determinant(X.frame)
            True
            sage: g.determinant(Y) is g.determinant(Y.frame)
            True

        The metric determinant depends on the frame::
        
            sage: g.determinant(X.frame) == g.determinant(Y.frame)
            False
        
        """
        from sage.matrix.constructor import matrix
        from scalarfield import ScalarField
        from utilities import simple_determinant, simplify_chain
        manif = self.manifold
        dom = self.domain
        if frame is None:
            frame = dom.def_frame
        if frame in dom.atlas:   
            # frame is actually a chart and is changed to the associated 
            # coordinate frame:
            frame = frame.frame
        if frame not in self._determinants:
            # a new computation is necessary
            resu = ScalarField(dom)
            gg = self.comp(frame)
            i1 = manif.sindex
            for chart in gg[[i1, i1]].express:
                gm = matrix( [[ gg[i, j, chart].express 
                            for j in manif.irange()] for i in manif.irange()] )
                detgm = simplify_chain(simple_determinant(gm))
                resu.add_expr(detgm, chart=chart)
            self._determinants[frame] = resu
        return self._determinants[frame]
示例#4
0
    def sqrt_abs_det(self, frame_name=None):
        r"""
        Square root of the absolute value of the determinant of the metric 
        components in the specified frame.
        
        INPUT:
        
        - ``frame_name`` -- (default: None) name of the vector frame with 
          respect to which the components `g_{ij}` of ``self`` are defined; 
          if None, the manifold's default frame is used. If a chart name is 
          provided, the associated coordinate basis is used
          
        OUTPUT:
        
        -  `\sqrt{|\det (g_{ij})|}`, as an instance of :class:`ScalarField`
        
        EXAMPLES:
        
        Standard metric in the Euclidean space `\RR^3` with spherical 
        coordinates::
        
            sage: m = Manifold(3, 'M', start_index=1)
            sage: c_spher = Chart(m, r'r:positive th:positive:\theta ph:\phi', 'spher')
            sage: assume(th>=0); assume(th<=pi)
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2
            sage: g.show()
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: g.sqrt_abs_det().expr()
            r^2*sin(th)
            
        Metric determinant on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M', start_index=1)
            sage: X = Chart(M, 'x y', 'xy')
            sage: g = Metric(M, 'g')
            sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
            sage: g[:]
            [ x + 1    x*y]
            [   x*y -y + 1]
            sage: s = g.sqrt_abs_det() ; s
            scalar field on the 2-dimensional manifold 'M'
            sage: s.expr()
            sqrt(-x^2*y^2 - (x + 1)*y + x + 1)

        Determinant in a frame different from the default's one::
            
            sage: Y = Chart(M, 'u v', 'uv')
            sage: ch_X_Y = CoordChange(X, Y, x+y, x-y)   
            sage: ch_X_Y.inverse()                    
            coordinate change from chart 'uv' (u, v) to chart 'xy' (x, y)
            sage: g.comp('uv_b')[:, 'uv']
            [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2                            1/4*u]
            [                           1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
            sage: g.sqrt_abs_det('uv_b').expr()
            1/2*sqrt(-x^2*y^2 - (x + 1)*y + x + 1)
            sage: g.sqrt_abs_det('uv_b').expr('uv')
            1/8*sqrt(-u^4 - 4*u^2 - v^4 + 2*(u^2 + 2)*v^2 + 16*v + 16)

        The name of a chart can be passed instead of the name of a frame::
        
            sage: g.sqrt_abs_det('uv') is g.sqrt_abs_det('uv_b')
            True

        The metric determinant depends on the frame::
        
            sage: g.sqrt_abs_det('xy_b') == g.sqrt_abs_det('uv_b') 
            False

        """
        from sage.functions.other import sqrt
        from scalarfield import ScalarField
        from utilities import simplify_chain
        manif = self.manifold
        if frame_name is None:
            frame_name = manif.def_frame.name
        if frame_name in manif.atlas:
            # frame_name is actually the name of a chart and is changed to the
            # name of the associated coordinate basis:
            frame_name = manif.atlas[frame_name].frame.name
        if frame_name not in self._sqrt_abs_dets:
            # a new computation is necessary
            detg = self.determinant(frame_name)
            resu = ScalarField(manif)
            for chart_name in detg.express:
                x = self._indic_signat * detg.express[chart_name].express  # |g|
                x = simplify_chain(sqrt(x))
                resu.set_expr(x, chart_name=chart_name, delete_others=False)
            self._sqrt_abs_dets[frame_name] = resu
        return self._sqrt_abs_dets[frame_name]
示例#5
0
    def determinant(self, frame_name=None):
        r"""
        Determinant of the metric components in the specified frame.
        
        INPUT:
        
        - ``frame_name`` -- (default: None) name of the vector frame with 
          respect to which the components `g_{ij}` of ``self`` are defined; 
          if None, the manifold's default frame is used. If a chart name is 
          provided, the associated coordinate basis is used
          
        OUTPUT:
        
        - the determinant `\det (g_{ij})`, as an instance of :class:`ScalarField`
        
        EXAMPLES:
        
        Metric determinant on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M', start_index=1)
            sage: X = Chart(M, 'x y', 'xy')
            sage: g = Metric(M, 'g')
            sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
            sage: g[:]
            [ x + 1    x*y]
            [   x*y -y + 1]
            sage: s = g.determinant()  # determinant in M's default frame
            sage: s.expr()
            -x^2*y^2 - (x + 1)*y + x + 1

        Determinant in a frame different from the default's one::
            
            sage: Y = Chart(M, 'u v', 'uv')
            sage: ch_X_Y = CoordChange(X, Y, x+y, x-y)   
            sage: ch_X_Y.inverse()                    
            coordinate change from chart 'uv' (u, v) to chart 'xy' (x, y)
            sage: g.comp('uv_b')[:, 'uv']
            [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2                            1/4*u]
            [                           1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
            sage: g.determinant('uv_b').expr()
            -1/4*x^2*y^2 - 1/4*(x + 1)*y + 1/4*x + 1/4
            sage: g.determinant('uv_b').expr('uv')
            -1/64*u^4 - 1/16*u^2 - 1/64*v^4 + 1/32*(u^2 + 2)*v^2 + 1/4*v + 1/4

        The name of a chart can be passed instead of the name of a frame::
        
            sage: g.determinant('xy') is g.determinant('xy_b')
            True
            sage: g.determinant('uv') is g.determinant('uv_b')
            True

        The metric determinant depends on the frame::
        
            sage: g.determinant('xy_b') == g.determinant('uv_b')
            False
        
        """
        from sage.matrix.constructor import matrix
        from scalarfield import ScalarField
        from utilities import simple_determinant, simplify_chain
        manif = self.manifold
        if frame_name is None:
            frame_name = manif.def_frame.name
        if frame_name in manif.atlas:
            # frame_name is actually the name of a chart and is changed to the
            # name of the associated coordinate basis:
            frame_name = manif.atlas[frame_name].frame.name
        if frame_name not in self._determinants:
            # a new computation is necessary
            resu = ScalarField(manif)
            gg = self.comp(frame_name)
            i1 = manif.sindex
            for chart_name in gg[[i1, i1]].express:
                gm = matrix(
                    [[gg[i, j, chart_name].express for j in manif.irange()]
                     for i in manif.irange()])
                detgm = simplify_chain(simple_determinant(gm))
                resu.set_expr(detgm,
                              chart_name=chart_name,
                              delete_others=False)
            self._determinants[frame_name] = resu
        return self._determinants[frame_name]
示例#6
0
    def pullback(self, tensor):
        r""" 
        Pullback operator associated with the differentiable mapping. 
        
        INPUT:
        
        - ``tensor`` -- instance of :class:`TensorField` representing a fully 
          covariant tensor field `T` on the *arrival* manifold, i.e. a tensor 
          field of type (0,p), with p a positive or zero integer. The case p=0 
          corresponds to a scalar field.
          
        OUTPUT:
        
        - instance of :class:`TensorField` representing a fully 
          covariant tensor field on the *start* manifold that is the 
          pullback of `T` given by ``self``. 
          
        EXAMPLES:
        
        Pullback on `S^2` of a scalar field defined on `R^3`::
        
            sage: m = Manifold(2, 'S^2', start_index=1)
            sage: c_spher = Chart(m, r'th:[0,pi]:\theta ph:[0,2*pi):\phi', 'spher') # spherical coord. on S^2
            sage: n = Manifold(3, 'R^3', r'\RR^3', start_index=1)
            sage: c_cart = Chart(n, 'x y z', 'cart') # Cartesian coord. on R^3
            sage: Phi = DiffMapping(m, n, (sin(th)*cos(ph), sin(th)*sin(ph), cos(th)), name='Phi', latex_name=r'\Phi')
            sage: f = ScalarField(n, x*y*z, name='f') ; f
            scalar field 'f' on the 3-dimensional manifold 'R^3'
            sage: f.show()
            f: (x, y, z) |--> x*y*z
            sage: pf = Phi.pullback(f) ; pf
            scalar field 'Phi_*(f)' on the 2-dimensional manifold 'S^2'
            sage: pf.show()
            Phi_*(f): (th, ph) |--> cos(ph)*cos(th)*sin(ph)*sin(th)^2
            
        Pullback on `S^2` of the standard Euclidean metric on `R^3`::
                
            sage: g = SymBilinFormField(n, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, 1, 1
            sage: g.show()
            g = dx*dx + dy*dy + dz*dz
            sage: pg = Phi.pullback(g) ; pg
            field of symmetric bilinear forms 'Phi_*(g)' on the 2-dimensional manifold 'S^2'
            sage: pg.show()
            Phi_*(g) = dth*dth + sin(th)^2 dph*dph

        Pullback on `S^2` of a 3-form on `R^3`::
                
            sage: a = DiffForm(n, 3, 'A')
            sage: a[1,2,3] = f 
            sage: a.show()
            A = x*y*z dx/\dy/\dz
            sage: pa = Phi.pullback(a) ; pa
            3-form 'Phi_*(A)' on the 2-dimensional manifold 'S^2'
            sage: pa.show() # should be zero (as any 3-form on a 2-dimensional manifold)
            Phi_*(A) = 0

        """
        from scalarfield import ScalarField
        if not isinstance(tensor, TensorField):
            raise TypeError("The argument 'tensor' must be a tensor field.")
        manif1 = self.manifold1
        manif2 = self.manifold2
        if tensor.manifold != manif2:
            raise TypeError("The tensor field is not defined on the mapping " +
                            "arrival manifold.")
        (ncon, ncov) = tensor.tensor_type
        if ncon != 0:
            raise TypeError("The pullback cannot be taken on a tensor " +
                            "with some contravariant part.")
        resu_name = None
        resu_latex_name = None
        if self.name is not None and tensor.name is not None:
            resu_name = self.name + '_*(' + tensor.name + ')'
        if self.latex_name is not None and tensor.latex_name is not None:
            resu_latex_name = self.latex_name + '_*' + tensor.latex_name
        chart1_name = None
        chart2_name = None
        def_chart1 = manif1.def_chart
        def_chart1_name = def_chart1.name
        def_chart2 = manif2.def_chart
        def_chart2_name = def_chart2.name
        if ncov == 0:
            # Case of a scalar field
            # ----------------------
            # A pair of chart (chart1_name, chart2_name) where the computation
            # is feasable is searched, privileging the default chart of the
            # start manifold for chart1_name
            if def_chart2_name in tensor.express and \
                   (def_chart1_name, def_chart2_name) in self.coord_expression:
                chart1_name = def_chart1_name
                chart2_name = def_chart2_name
            else:
                for (chart1n, chart2n) in self.coord_expression:
                    if chart1n == def_chart1_name and chart2n in tensor.express:
                        chart1_name = def_chart1_name
                        chart2_name = chart2n
                        break
            if chart1_name is None:
                # It is not possible to have def_chart1 as chart for
                # expressing the result; any other chart is then looked for:
                for (chart1n, chart2n) in self.coord_expression:
                    if chart2n in tensor.express:
                        chart1_name = chart1n
                        chart2_name = chart2n
                        break
            if chart1_name is None:
                raise ValueError("No common chart could be find to compute " +
                                 "the pullback of the scalar field.")
            phi = self.coord_expression[(chart1_name, chart2_name)]
            coord1 = manif1.atlas[chart1_name].xx
            ff = tensor.express[chart2_name]
            return ScalarField(manif1, ff(*(phi(*coord1))), chart1_name,
                               resu_name, resu_latex_name)
        else:
            # Case of tensor field of rank >= 1
            # ---------------------------------
            # A pair of chart (chart1_name, chart2_name) where the computation
            # is feasable is searched, privileging the default chart of the
            # start manifold for chart1_name
            if def_chart2.frame.name in tensor.components and \
                   (def_chart1_name, def_chart2_name) in self.coord_expression:
                chart1_name = def_chart1_name
                chart2_name = def_chart2_name
            else:
                for (chart1n, chart2n) in self.coord_expression:
                    if chart1n == def_chart1_name and \
                         manif2.atlas[chart2n].frame.name in tensor.components:
                        chart1_name = def_chart1_name
                        chart2_name = chart2n
                        break
            if chart1_name is None:
                # It is not possible to have def_chart1 as chart for
                # expressing the result; any other chart is then looked for:
                for (chart1n, chart2n) in self.coord_expression:
                    if manif2.atlas[chart2n].frame.name in tensor.components:
                        chart1_name = chart1n
                        chart2_name = chart2n
                        break
            if chart1_name is None:
                raise ValueError("No common chart could be find to compute " +
                                 "the pullback of the tensor field.")
            chart1 = manif1.atlas[chart1_name]
            chart2 = manif2.atlas[chart2_name]
            frame1_name = chart1.frame.name
            frame2_name = chart2.frame.name
            # Computation at the component level:
            tcomp = tensor.components[frame2_name]
            if isinstance(tcomp, CompFullySym):
                ptcomp = CompFullySym(manif1, ncov, frame1_name)
            elif isinstance(tcomp, CompFullyAntiSym):
                ptcomp = CompFullyAntiSym(manif1, ncov, frame1_name)
            elif isinstance(tcomp, CompWithSym):
                ptcomp = CompWithSym(manif1,
                                     ncov,
                                     frame1_name,
                                     sym=tcomp.sym,
                                     antisym=tcomp.antisym)
            else:
                ptcomp = Components(manif1, ncov, frame1_name)
            phi = self.coord_expression[(chart1_name, chart2_name)]
            jacob = phi.jacobian()
            # X2 coordinates expressed in terms of X1 ones via the mapping:
            coord2_1 = phi(*(chart1.xx))
            si1 = manif1.sindex
            si2 = manif2.sindex
            for ind_new in ptcomp.non_redundant_index_generator():
                res = 0
                for ind_old in manif2.index_generator(ncov):
                    ff = tcomp[[ind_old]].function_chart(chart2_name)
                    t = FunctionChart(chart1, ff(*coord2_1))
                    for i in range(ncov):
                        t *= jacob[ind_old[i] - si2][ind_new[i] - si1]
                    res += t
                ptcomp[ind_new] = res
            resu = tensor_field_from_comp(ptcomp, (0, ncov))
            resu.set_name(resu_name, resu_latex_name)
            return resu
示例#7
0
    def sqrt_abs_det(self, frame=None):
        r"""
        Square root of the absolute value of the determinant of the metric 
        components in the specified frame.
        
        INPUT:
        
        - ``frame`` -- (default: None) vector frame with 
          respect to which the components `g_{ij}` of ``self`` are defined; 
          if None, the domain's default frame is used. If a chart is 
          provided, the associated coordinate frame is used
          
        OUTPUT:
        
        -  `\sqrt{|\det (g_{ij})|}`, as an instance of :class:`ScalarField`
        
        EXAMPLES:
        
        Standard metric in the Euclidean space `\RR^3` with spherical 
        coordinates::
        
            sage: m = Manifold(3, 'M', start_index=1)
            sage: c_spher.<r,th,ph> = m.chart(r'r:[0,+oo) th:[0,pi]:\theta ph:[0,2*pi):\phi')
            sage: g = Metric(m, 'g')
            sage: g[1,1], g[2,2], g[3,3] = 1, r^2, (r*sin(th))^2
            sage: g.view()
            g = dr*dr + r^2 dth*dth + r^2*sin(th)^2 dph*dph
            sage: g.sqrt_abs_det().expr()
            r^2*sin(th)
            
        Metric determinant on a 2-dimensional manifold::
        
            sage: M = Manifold(2, 'M', start_index=1)
            sage: X.<x,y> = M.chart('x y')
            sage: g = Metric(M, 'g')
            sage: g[1,1], g[1, 2], g[2, 2] = 1+x, x*y , 1-y
            sage: g[:]
            [ x + 1    x*y]
            [   x*y -y + 1]
            sage: s = g.sqrt_abs_det() ; s
            scalar field on the 2-dimensional manifold 'M'
            sage: s.expr()
            sqrt(-x^2*y^2 - (x + 1)*y + x + 1)

        Determinant in a frame different from the default's one::
            
            sage: Y.<u,v> = M.chart('u v')
            sage: ch_X_Y = CoordChange(X, Y, x+y, x-y)   
            sage: ch_X_Y.inverse()
            coordinate change from chart (M, (u, v)) to chart (M, (x, y))                    
            sage: g.comp(Y.frame)[:, Y]
            [ 1/8*u^2 - 1/8*v^2 + 1/4*v + 1/2                            1/4*u]
            [                           1/4*u -1/8*u^2 + 1/8*v^2 + 1/4*v + 1/2]
            sage: g.sqrt_abs_det(Y.frame).expr()
            1/2*sqrt(-x^2*y^2 - (x + 1)*y + x + 1)
            sage: g.sqrt_abs_det(Y.frame).expr(Y)
            1/8*sqrt(-u^4 - v^4 + 2*(u^2 + 2)*v^2 - 4*u^2 + 16*v + 16)

        A chart can be passed instead of a frame::
        
            sage: g.sqrt_abs_det(Y) is g.sqrt_abs_det(Y.frame)
            True

        The metric determinant depends on the frame::
        
            sage: g.sqrt_abs_det(X.frame) == g.sqrt_abs_det(Y.frame) 
            False

        """
        from sage.functions.other import sqrt
        from scalarfield import ScalarField
        from utilities import simplify_chain
        manif = self.manifold
        dom = self.domain
        if frame is None:
            frame = dom.def_frame
        if frame in dom.atlas:
            # frame is actually a chart and is changed to the associated
            # coordinate frame:
            frame = frame.frame
        if frame not in self._sqrt_abs_dets:
            # a new computation is necessary
            detg = self.determinant(frame)
            resu = ScalarField(dom)
            for chart in detg.express:
                x = self._indic_signat * detg.express[chart].express  # |g|
                x = simplify_chain(sqrt(x))
                resu.add_expr(x, chart=chart)
            self._sqrt_abs_dets[frame] = resu
        return self._sqrt_abs_dets[frame]