Пример #1
0
 def _eval_derivative_array(self, arg):
     from sympy import derive_by_array
     from sympy import Tuple
     from sympy.matrices.common import MatrixCommon
     if isinstance(arg, (Iterable, Tuple, MatrixCommon, NDimArray)):
         return derive_by_array(self, arg)
     else:
         return self.applyfunc(lambda x: x.diff(arg))
Пример #2
0
 def add_derivative(self, name, fname, wrt, flatten_wrt=False):
     # Test if we have only one wrt item
     if isinstance(wrt, (str, sympy.NDimArray)):
         wrt = (wrt,)
     
     out = self.default_function_output(fname)
     for wrt_array in wrt:
         if utils.isstr(wrt_array):
             wrt_array = self.variables[wrt_array]
         if flatten_wrt:
             wrt_array = sympy.flatten(wrt_array)
         out = sympy.derive_by_array(out, wrt_array)
     
     args = self.function_codegen_arguments(fname)
     deriv = function.SymbolicSubsFunction(args, out)
     setattr(self, name, deriv)
Пример #3
0
 def _visit_eval_derivative_array(self, base):
     # Types are (base: array/matrix, self: array)
     from sympy import derive_by_array
     return derive_by_array(base, self)
Пример #4
0
def generate_random_crater_sympy_expr(
    center,
    radiuses,
    depth=None,
    height=None,
    locations=None,
    standard_deviations=None,
    multiplier=None,
):
    """generate_random_crater_sympy_expr
    Parameters
    ----------
    center :

    radiuses :

    depth : float
        The depth of the crater
    height : float
        The height of the crater
    locations : np.array
        The locations of all the Gaussian random bumps
    standard_deviations : np.array
        The standard deviations for the different Gaussian random bumps
    multiplier : float
        The multiplier used to balance the main and the random parts of the energy function
    Returns
    -------
    """
    assert locations.shape[1] == center.size
    assert standard_deviations.shape == (locations.shape[0], )
    n_dim = center.size
    n_bumps = locations.shape[0]
    location = sympy.Array(sympy.symbols('x:{}'.format(n_dim)), (n_dim, ))
    center = sympy.Array(center, center.shape)
    r_squared = sympy_array_squared_norm(location - center)
    C = (3 * radiuses[1]**2 *
         sympy.cbrt(depth * height * (depth + sympy.sqrt(depth *
                                                         (depth + height)))))
    Delta0 = -9 * depth * height * radiuses[1]**4
    b_squared = -(1 /
                  (3 * depth)) * (-3 * depth * radiuses[1]**2 + C + Delta0 / C)
    a = depth / (3 * b_squared * radiuses[1]**4 - radiuses[1]**6)
    crater_expr = (a * (2 * r_squared**3 - 3 *
                        (b_squared + radiuses[1]**2) * r_squared**2 +
                        6 * b_squared * radiuses[1]**2 * r_squared) - depth)
    mollifier_expr = sympy.functions.exp(
        -radiuses[1] /
        (radiuses[1] -
         sympy_array_squared_norm(location - center)**10)) / np.exp(-1)
    random_components = [
        sympy.functions.exp(
            -sympy_array_squared_norm(location -
                                      sympy.Array(locations[ii], (n_dim, ))) /
            (2 * standard_deviations[ii]**2)) for ii in range(n_bumps)
    ]
    random_expr = 0
    for ii in range(n_bumps):
        random_expr += random_components[ii]

    sympy_expr = crater_expr + multiplier * mollifier_expr * random_expr
    gradient_expr = sympy.derive_by_array(sympy_expr, location)
    return location, gradient_expr
Пример #5
0
 def _visit_eval_derivative_array(self, base):
     # Types are (base: array/matrix, self: array)
     from sympy import derive_by_array
     return derive_by_array(base, self)
    def Thermoneutral_Voltage(self):
        """ Function for calculating the thermoneutral cell voltage
            Ref. K. Onda et al., Journal of Power Sources, 132 (2004), pp.64-70.
        """

        # Coefficients for specfic heat of water, hydrogen and oxygen [a, b, c, e]
        Coefficients = np.array(([72.39, 9.38, 0,
                                  0], [26.57, 3.77, 1.17,
                                       0], [34.35, 1.92, -18.45, 4.06]))
        # Enthalpy calculation according to temperature with coefficients
        ΔH = np.array(
            ([(self.T - self.T0)
              ], [0.5 * 10**(-3) * ((self.T**2) - (self.T0**2))
                  ], [-(10**5) * ((1 / self.T) - (1 / self.T0))],
             [-0.5 * (10**8) * ((1 / (self.T**2)) - (1 / (self.T0**2)))]))

        # Enthalpy of water splitting (Temperature change)
        Enthalpy_T = -285830 - (Coefficients.dot(ΔH)[1, 0] +
                                0.5 * Coefficients.dot(ΔH)[2, 0] -
                                Coefficients.dot(ΔH)[0, 0])

        # Define the symbol of temperature (T)
        T = sp.symbols('T', real=True)

        # Coefficients for virial constant of hydrogen and oxygen [b1, b2, c1, c2]
        Coefficient_B = np.array(([20.5, -1857], [42.6, -17400]))
        Coefficient_C = np.array(([-351, 12760], [-2604, 61457]))

        # Virial constants
        B = np.array(([1], [1 / T]))
        C = np.array(([1], [1 / (T**0.5)]))

        # ∂B/∂T and ∂C/∂T
        Derivative_B = sp.derive_by_array(Coefficient_B.dot(B), T)
        Derivative_C = sp.derive_by_array(Coefficient_C.dot(C), T)

        # Enthalpy of water splitting (Pressure change)
        Enthalpy_P = 0.101325 * (
            ((Coefficient_B.dot(B)[0, 0].subs(T, self.T) -
              self.T * Derivative_B[0, 0].subs(T, self.T)) * self.P +
             (self.P**2) *
             (Coefficient_C.dot(C)[0, 0].subs(T, self.T) -
              Coefficient_B.dot(B)[0, 0].subs(T, self.T) *
              Coefficient_B.dot(B)[0, 0].subs(T, self.T) - 0.5 * self.T *
              (Derivative_C[0, 0].subs(T, self.T) - 2 * Coefficient_B.dot(B)
               [0, 0].subs(T, self.T) * Derivative_B[0, 0].subs(T, self.T))) /
             (self.R * self.T)) + 0.5 *
            ((Coefficient_B.dot(B)[1, 0].subs(T, self.T) -
              self.T * Derivative_B[1, 0].subs(T, self.T)) * self.P +
             (self.P**2) *
             (Coefficient_C.dot(C)[1, 0].subs(T, self.T) -
              Coefficient_B.dot(B)[1, 0].subs(T, self.T) *
              Coefficient_B.dot(B)[1, 0].subs(T, self.T) - 0.5 * self.T *
              (Derivative_C[1, 0].subs(T, self.T) - 2 * Coefficient_B.dot(B)
               [1, 0].subs(T, self.T) * Derivative_B[1, 0].subs(T, self.T))) /
             (self.R * self.T)))

        # Enthalpy of water splitting according to temperature and pressure
        Enthalpy_T_P = Enthalpy_T - Enthalpy_P

        # Thermoneutral cell voltage
        ThermoVoltage = (-Enthalpy_T_P) / (2 * self.F)

        return ThermoVoltage
Пример #7
0
def diff(target, coords, new_index):
    new_vals = sympy.derive_by_array(target.vals, coords)
    new_inds = target.indices[:] + [new_index]
    return objects.Tensor(new_inds, new_vals)
    def num_poisson_bracket(self,
                            bivector,
                            function_1,
                            function_2,
                            mesh,
                            tf_output=False,
                            pt_output=False,
                            dict_output=False):
        """
            Calculates the evaluation of Poisson bracket {f,g} = π(df,dg) = ⟨dg,π#(df)⟩ of two functions f and g in
            a Poisson manifold (M,P) in all point from given a mesh. Where d is the exterior derivatives and
            P#: T*M -> TM is the vector bundle morphism defined by P#(alpha) := i_(alpha)P, with i the interior
            product of alpha and P.

        Parameters
        ==========
        :bivector:
            Is a Poisson bivector in a dictionary format with tuple type 'keys' and string type 'values'.
        :function_1/function_2:
            Is a function scalar f: M --> R that is a string type.
        :mesh:
            Is a numpy array where each value is a list of float values that representa a point in R^{dim}.
        :pt_output/tf_output:
            Is a boolean flag to indicates if the result is given in a tensor from PyTorch/TensorFlow, its
            default value is False.

        Returns
        =======
            The default result is a NumPy array that contains all the evaluations of Poisson bracket.
            This value can be converted to Tensor PyTorch or TensorFlow by setting their respective flag as True
            in the params.

        Example
        ========
            >>> import numpy as np
            >>> from poisson import NumPoissonGeometry
            >>> # Instance the class to dimension 3
            >>> npg3 = NumPoissonGeometry(3)
            >>> # For bivector x3*Dx1^Dx2 - x2*Dx1^Dx3 + x1*Dx2^Dx3
            >>> bivector = {(1, 2): 'x3', (1, 3): '-x2', (2, 3): 'x1'}
            >>> # For f(x1,x2,x3) = x1 + x2 + x3.
            >>> function_1 = 'x1 + x2 + x3'
            >>> # For g(x1,x2,x3) = '2*x1 + 3*x2 + 4*x3'.
            >>> function_2 = '2*x1 + 3*x2 + 4*x3'
            >>> # Creates a mesh
            >>> mesh = np.array([[5., 10., 0.]])
            >>> # Evaluates the mesh into {f,g}
            >>> npg3.num_poisson_bracket(bivector, function_1, function_2, mesh)
            >>> [-15.]
            >>> npg3.num_poisson_bracket(bivector, function_1, function_2, mesh, pt_output=True)
            >>> tensor([-15.], dtype=torch.float64)
            >>> npg3.num_poisson_bracket(bivector, mesh, function_1, function_2, tf_output=True)
            >>> tf.Tensor([-15.], shape=(1,), dtype=float64)
        """

        # Convert from string to sympy value the function_2
        gg = sym.sympify(function_2)
        # Calculates the differential matrix of function_2
        d_gg = sym.Matrix(sym.derive_by_array(gg, self.coords))
        # Evaluates the differential matrix of function_2 in each point from a mesh and converts to Numpy array
        dgg_num_vec = np.array(tuple(list_mesh_eval(d_gg, mesh, self.coords)))
        # Evaluates the Hamiltonian vector field with function_1 in each point from a mesh and converts to Numpy
        ham_ff_num_vec = np.array(
            tuple(self.num_hamiltonian_vf(bivector, function_1, mesh)))
        # Calculate the product from differential matrix of function_2 with Hamiltonian vector field with function_1
        # to each point from mesh and save the result in Numpy array
        raw_result = map(lambda e1, e2: np.dot(e1.T, e2)[0][0], dgg_num_vec,
                         ham_ff_num_vec)
        np_result = np.array(list(raw_result))
        # return the result in a PyTorch tensor if the flag is True
        if pt_output:
            return torch.from_numpy(np_result)
        # return the result in a TensorFlow tensor if the flag is True
        if tf_output:
            # TODO apply lambdify method to tensorflow
            return tf.convert_to_tensor(np_result)
        # TODO add dict_output flag
        # return the result in Numpy array
        return np_result
    def num_one_form_bracket(self,
                             bivector,
                             one_form_1,
                             one_form_2,
                             mesh,
                             tf_output=False,
                             pt_output=False,
                             dict_output=False):
        """
            Evaluates the Lie bracket of two differential 1-forms induced by a given Poisson bivector field in all
            points given of a mesh.

            The calculus is as {alpha,beta}_P := i_P#(alpha)(d_beta) - i_P#(beta)(d_alpha) + d_P(alpha,beta)
            for 1-forms alpha and beta, where d_alpha and d_beta are the exterior derivative of alpha and beta,
            respectively, i_ the interior product of vector fields on differential forms, P#: T*M -> TM the vector
            bundle morphism defined by P#(alpha) := i_(alpha)P, with i the interior product of alpha and P. Note that,
            by definition {df,dg}_P = d_{f,g}_P, for ant functions f,g on M.

        Parameters
        ==========
        :bivector:
            Is a Poisson bivector in a dictionary format with tuple type 'keys' and string type 'values'.
        one_form_1/one_form_2:
            Is a 1-form differential in a dictionary format with tuple type 'keys' and string type 'values'.
        :mesh:
            Is a numpy array where each value is a list of float values that representa a point in R^{dim}.
        :pt_output/tf_output:
            Is a boolean flag to indicates if the result is given in a tensor from PyTorch/TensorFlow, its
            default value is False.

        Returns
        =======
            The default result is a NumPy array that contains all the evaluations of {one_form_1, one_form_2}_π
            This value can be converted to Tensor PyTorch, TensorFlow or dictionary for by setting their respective
            flag as True in the params.

        Example
        ========
            >>> import numpy as np
            >>> from poisson import NumPoissonGeometry
            >>> # Instance the class to dimension 3
            >>> npg3 = NumPoissonGeometry(3)
            >>> # For bivector x3*Dx1^Dx2 - x2*Dx1^Dx3 + x1*Dx2^Dx3
            >>> bivector = {(1, 2): 'x3', (1, 3): '-x2', (2, 3): 'x1'}
            >>> # For one form alpha
            >>> one_form_1 = {(1,): '2', (2,): '1', (3,): '2'}
            >>> # For one form beta
            >>> one_form_2 = {(1,): '1', (2,): '1', (3,): '1'}
            >>> # Defines a simple mesh
            >>> mesh = np.array([[1., 1., 1.]])
            >>> # Evaluates the mesh into {one_form_1, one_form_2}_π
            >>> npg3.num_one_form_bracket(bivector, one_form_1, one_form_2, mesh,)
            >>> [[[-1.]
                  [ 0.]
                  [ 1.]]]
            >>> npg3.num_one_form_bracket(bivector, one_form_1, one_form_2, mesh, pt_output=True)
            >>> tensor([[[-1.],
                         [ 0.],
                         [ 1.]]], dtype=torch.float64)
            >>> npg3.num_one_form_bracket(bivector, one_form_1, one_form_2, mesh, tf_output=True)
            >>> tf.Tensor(
                [[[-1.]
                  [ 0.]
                  [ 1.]]], shape=(1, 3, 1), dtype=float64)
        """
        """ This block calculates i_P#(alpha)(d_beta) """
        # Converts to one-form from dict format into matrix format
        beta_vect = vector_of(one_form_2, self.dim)
        # Calculates the differential matrix of one_form_2 parameter
        D_beta = sym.Matrix(
            [sym.derive_by_array(e, self.coords) for e in beta_vect])
        # lambdify the differential matrix of one_form_2 parameter
        lamb_D_beta = sym.lambdify(self.coords, D_beta)
        # Evaluates the differential matrix of one_form_2 parameter in each point from a mesh
        D_beta_eval = [lamb_D_beta(*e) for e in mesh]
        # Evaluate the sharp morphism from bivector and one_form_1 parameters in each point from a mesh
        sharp_alpha_eval = self.num_sharp_morphism(bivector, one_form_1, mesh)
        # Result to i_P#(alpha)(d_beta)
        ii_sharp_alpha_D_beta_eval = map(lambda e1, e2: np.dot(e1 - e1.T, e2),
                                         D_beta_eval, sharp_alpha_eval)
        """ This block calculates i_P#(beta)(d_alpha) """
        # Converts to one-form from dict format into matrix format
        alpha_vect = vector_of(one_form_1, self.dim)
        # Calculates the differential matrix of one_form_1 parameter
        D_alpha = sym.Matrix(
            [sym.derive_by_array(e, self.coords) for e in alpha_vect])
        # lambdify the differential matrix of one_form_1 parameter
        lamb_D_alpha = sym.lambdify(self.coords, D_alpha)
        # Evaluates the differential matrix of one_form_1 parameter in each point from a mesh
        D_alpha_eval = [lamb_D_alpha(*e) for e in mesh]
        # Evaluate the sharp morphism from bivector and one_form_1 parameters in each point from a mesh
        sharp_beta_eval = self.num_sharp_morphism(bivector, one_form_2, mesh)
        # Result to i_P#(beta)(d_alpha)
        ii_sharp_beta_D_alpha_eval = map(lambda e1, e2: np.dot(e1 - e1.T, e2),
                                         D_alpha_eval, sharp_beta_eval)
        """ This block calculate d_P(alpha,beta) that is the same to d(<beta,P#(alpha)>) """
        sharp_alpha_vect = vector_of(
            self.pg.sharp_morphism(bivector, one_form_1), self.dim)
        pairing_sharp_alpha_beta = (sym.transpose(sharp_alpha_vect) *
                                    beta_vect)[0]
        grad_pairing = sym.Matrix(
            sym.derive_by_array(pairing_sharp_alpha_beta, self.coords))
        # lambdify the grad_pairing variable
        lamb_grad_pairing = sym.lambdify(self.coords, grad_pairing)
        lamb_grad_pairing_eval = [lamb_grad_pairing(*e) for e in mesh]

        # Calculate {alpha, beta}_π to each point from mesh and save the result in Numpy array
        raw_result = map(lambda e1, e2, e3: e1 - e2 + e3,
                         ii_sharp_alpha_D_beta_eval,
                         ii_sharp_beta_D_alpha_eval,
                         lamb_grad_pairing_eval)  # noqa
        np_result = np.array(list(raw_result))
        # return the result in a PyTorch tensor if the flag is True
        if pt_output:
            return torch.from_numpy(np_result)
        # return the result in a TensorFlow tensor if the flag is True
        if tf_output:
            # TODO apply lambdify method to tensorflow
            return tf.convert_to_tensor(np_result)
        # return the result in Numpy array
        # TODO add dict_output flag
        return np_result
    def num_hamiltonian_vf(self,
                           bivector,
                           ham_function,
                           mesh,
                           tf_output=False,
                           pt_output=False,
                           dict_output=False):
        """
            Evaluates the Hamiltonian vector field of a function relative to a Poisson bivector field in
            the points from a mesh given. The Hamiltonian vector field is calculated as follows: X_h = P#(dh),
            where d is the exterior derivative of h and P#: T*M -> TM is the vector bundle morphism defined
            by P#(alpha) := i_(alpha)P, with i is the interior product of alpha and P.

        Parameters
        ==========
        :bivector:
            Is a Poisson bivector in a dictionary format with tuple type 'keys' and string type 'values'.
        :ham_function:
            Is a function scalar h: M --> R that is a string type.
        :mesh:
            Is a numpy array where each value is a list of float values that representa a point in R^{dim}.
        :pt_output/tf_output:
            Is a boolean flag to indicates if the result is given in a tensor from PyTorch/TensorFlow, its
            default value is False.

        Returns
        =======
            The default result is a NumPy array that contains all the evaluations of a Hamiltonian vector field.
            This value can be converted to Tensor PyTorch or TensorFlow by setting their respective flag as True
            in the params

        Example
        ========
            >>> import numpy as np
            >>> from poisson import NumPoissonGeometry
            >>> # Instance the class to dimension 3
            >>> npg3 = NumPoissonGeometry(3)
            >>> # For bivector x3*Dx1^Dx2 - x2*Dx1^Dx3 + x1*Dx2^Dx3
            >>> bivector = {(1, 2): 'x3', (1, 3): '-x2', (2, 3): 'x1'}
            >>> # For hamiltonian_function h(x1,x2,x3) = x1 + x2 + x3.
            >>> ham_function = '1/(x1 - x2) + 1/(x1 - x3) + 1/(x2 - x3)'
            >>> # Creates a mesh
            >>> mesh = np.array([[1., 2., 3.]])
            >>> # Evaluates the mesh into bivector
            >>> npg3.num_hamiltonian_vf(bivector, ham_function, mesh)
            >>> [[[ 2.5]
                  [-5. ]
                  [ 2.5]]]
            >>> npg3.num_hamiltonian_vf(bivector, ham_function, mesh, pt_output=True)
            >>> tensor([[[ 2.5000],
                         [-5.0000],
                         [ 2.5000]]], dtype=torch.float64)
            >>> npg3.num_hamiltonian_vf(bivector, mesh, ham_function, tf_output=True)
            >>> tf.Tensor(
                [[[ 2.5]
                  [-5. ]
                  [ 2.5]]], shape=(1, 3, 1), dtype=float64)
        """
        # Converts the hamiltonian_function from type string to symbolic expression
        ff = sym.sympify(ham_function)
        # Calculates the differential matrix of Hamiltonian function
        d_ff = sym.Matrix(sym.derive_by_array(ff, self.coords))
        # Evaluates the differential matrix of Hamiltonian function in each point from a mesh
        dff_num_vec = list_mesh_eval(d_ff, mesh, self.coords)
        # Evaluates all points from the mesh in the bivector matrix
        bivector_num_mat = self.num_bivector_to_matrix(bivector, mesh)
        # Calculate the product from bivector with the differential of Hamiltonian function to
        # each point from mesh and save the result in Numpy array
        raw_result = map(lambda e1, e2: (-1) * np.dot(e1, e2),
                         bivector_num_mat, dff_num_vec)
        np_result = np.array(list(raw_result))
        # return the result in a PyTorch tensor if the flag is True
        if pt_output:
            return torch.from_numpy(np_result)
        # return the result in a TensorFlow tensor if the flag is True
        if tf_output:
            # TODO apply lambdify method to tensorflow
            return tf.convert_to_tensor(np_result)
        # TODO add dict_output flag
        # return the result in Numpy array
        return np_result
def row_wise_div(tensor):
    return sym.Matrix(
        tensorcontraction(derive_by_array(tensor, [x, y]), (0, 2)))
Пример #12
0

# Velocity induced by a segment
def Vind_segment(R, cf, g):
    BiotTerm = cf * g * R / linfunc.scalar_product(R, R)
    Qind = linfunc.matrix_product(Kskew2D, BiotTerm)
    return linfunc.simplify(Qind)


# Joukovski force of secment C from segment 01
Fjouk = -gammaC * linfunc.matrix_product(Kskew2D, Vind_segment(
    R01, CF, gamma01))
Fjouk = linfunc.simplify(Fjouk)

### Derivative
Der = sm.derive_by_array(Fjouk, ZetaAllList).transpose()  # 2x6
#Der=linfunc.simplify(Der)

### Verification
BiotTerm_vortex = +CF * gamma01 * R01 / linfunc.scalar_product(R01, R01)
derBiotTerm = sm.derive_by_array(BiotTerm_vortex, ZetaAllList).transpose()
derQind = linfunc.matrix_product(Kskew2D, derBiotTerm)
Der2 = -gammaC * linfunc.matrix_product(Kskew2D, derQind)

check = linfunc.simplify(Der - Der2)
assert linfunc.scalar_product(check,
                              check) == 0, 'Derivatives are not the same'

################ we use Der2 as it has a shorter form ##########################
Der = Der2
Пример #13
0
def diff(a, b):
    D = derive_by_array(a, b)
    dims = tuple([x + len(b.shape) for x in range(0, len(a.shape))]) + \
           tuple(range(0, len(b.shape)))
    return permutedims(D, dims)
Пример #14
0
Area=sm.sqrt(linfunc.scalar_product(Dzeta,Dzeta))
Dzeta_unit=Dzeta/Area

# Normal
Norm=linfunc.matrix_product(Kskew2D,Dzeta_unit)
Norm=linfunc.simplify(Norm)

### check norm
assert linfunc.scalar_product(Norm,Dzeta).simplify()==0, 'Norm is wrong'
assert linfunc.scalar_product(Norm,Dzeta_unit).simplify()==0, 'Norm is wrong'
assert linfunc.scalar_product(Norm,Norm).simplify()==1, 'Normal is not unit length'


# Normal by Area derivative
NA=Area*Norm
derNA=sm.derive_by_array(NA,ZetaAllList).transpose()
derNA=linfunc.simplify(derNA)

# Verify Normal by Area derivative
derDzeta=sm.derive_by_array(Dzeta,ZetaAllList).transpose()
derDzeta=linfunc.simplify(derDzeta)

derNA2=linfunc.matrix_product(Kskew2D,derDzeta)
derNA2=linfunc.simplify(derNA2)

check=linfunc.simplify(derNA-derNA2)
assert linfunc.scalar_product(check,check)==0,\
                                   'Normal by Aera derivatives are not the same'


embed()