def test_coordinate_vars(): """ Tests the coordinate variables functionality with respect to reorientation of coordinate systems. """ assert BaseScalar('Ax', 0, A) == A.x assert BaseScalar('Ay', 1, A) == A.y assert BaseScalar('Az', 2, A) == A.z assert BaseScalar('Ax', 0, A).__hash__() == A.x.__hash__() assert isinstance(A.x, BaseScalar) and \ isinstance(A.y, BaseScalar) and \ isinstance(A.z, BaseScalar) assert A.scalar_map(A) == {A.x: A.x, A.y: A.y, A.z: A.z} assert A.x.system == A B = A.orient_new('B', 'Axis', [q, A.k]) assert B.scalar_map(A) == {B.z: A.z, B.y: -A.x*sin(q) + A.y*cos(q), B.x: A.x*cos(q) + A.y*sin(q)} assert A.scalar_map(B) == {A.x: B.x*cos(q) - B.y*sin(q), A.y: B.x*sin(q) + B.y*cos(q), A.z: B.z} assert express(B.x, A, variables=True) == A.x*cos(q) + A.y*sin(q) assert express(B.y, A, variables=True) == -A.x*sin(q) + A.y*cos(q) assert express(B.z, A, variables=True) == A.z assert express(B.x*B.y*B.z, A, variables=True) == \ A.z*(-A.x*sin(q) + A.y*cos(q))*(A.x*cos(q) + A.y*sin(q)) assert express(B.x*B.i + B.y*B.j + B.z*B.k, A) == \ (B.x*cos(q) - B.y*sin(q))*A.i + (B.x*sin(q) + \ B.y*cos(q))*A.j + B.z*A.k assert simplify(express(B.x*B.i + B.y*B.j + B.z*B.k, A, \ variables=True)) == \ A.x*A.i + A.y*A.j + A.z*A.k assert express(A.x*A.i + A.y*A.j + A.z*A.k, B) == \ (A.x*cos(q) + A.y*sin(q))*B.i + \ (-A.x*sin(q) + A.y*cos(q))*B.j + A.z*B.k assert simplify(express(A.x*A.i + A.y*A.j + A.z*A.k, B, \ variables=True)) == \ B.x*B.i + B.y*B.j + B.z*B.k N = B.orient_new('N', 'Axis', [-q, B.k]) assert N.scalar_map(A) == \ {N.x: A.x, N.z: A.z, N.y: A.y} C = A.orient_new('C', 'Axis', [q, A.i + A.j + A.k]) mapping = A.scalar_map(C) assert mapping[A.x] == 2*C.x*cos(q)/3 + C.x/3 - \ 2*C.y*sin(q + pi/6)/3 + C.y/3 - 2*C.z*cos(q + pi/3)/3 + C.z/3 assert mapping[A.y] == -2*C.x*cos(q + pi/3)/3 + \ C.x/3 + 2*C.y*cos(q)/3 + C.y/3 - 2*C.z*sin(q + pi/6)/3 + C.z/3 assert mapping[A.z] == -2*C.x*sin(q + pi/6)/3 + C.x/3 - \ 2*C.y*cos(q + pi/3)/3 + C.y/3 + 2*C.z*cos(q)/3 + C.z/3
def __new__(cls, name, location=None, rotation_matrix=None, parent=None, vector_names=None, variable_names=None): """ The orientation/location parameters are necessary if this system is being defined at a certain orientation or location wrt another. Parameters ========== name : str The name of the new CoordSys3D instance. location : Vector The position vector of the new system's origin wrt the parent instance. rotation_matrix : SymPy ImmutableMatrix The rotation matrix of the new coordinate system with respect to the parent. In other words, the output of new_system.rotation_matrix(parent). parent : CoordSys3D The coordinate system wrt which the orientation/location (or both) is being defined. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. """ name = str(name) Vector = sympy.vector.Vector BaseVector = sympy.vector.BaseVector Point = sympy.vector.Point if not isinstance(name, string_types): raise TypeError("name should be a string") # If orientation information has been provided, store # the rotation matrix accordingly if rotation_matrix is None: parent_orient = Matrix(eye(3)) else: if not isinstance(rotation_matrix, Matrix): raise TypeError("rotation_matrix should be an Immutable" + "Matrix instance") parent_orient = rotation_matrix # If location information is not given, adjust the default # location as Vector.zero if parent is not None: if not isinstance(parent, CoordSys3D): raise TypeError("parent should be a " + "CoordSys3D/None") if location is None: location = Vector.zero else: if not isinstance(location, Vector): raise TypeError("location should be a Vector") # Check that location does not contain base # scalars for x in location.free_symbols: if isinstance(x, BaseScalar): raise ValueError("location should not contain" + " BaseScalars") origin = parent.origin.locate_new(name + '.origin', location) else: location = Vector.zero origin = Point(name + '.origin') # All systems that are defined as 'roots' are unequal, unless # they have the same name. # Systems defined at same orientation/position wrt the same # 'parent' are equal, irrespective of the name. # This is true even if the same orientation is provided via # different methods like Axis/Body/Space/Quaternion. # However, coincident systems may be seen as unequal if # positioned/oriented wrt different parents, even though # they may actually be 'coincident' wrt the root system. if parent is not None: obj = super(CoordSys3D, cls).__new__(cls, Symbol(name), location, parent_orient, parent) else: obj = super(CoordSys3D, cls).__new__(cls, Symbol(name), location, parent_orient) obj._name = name # Initialize the base vectors if vector_names is None: vector_names = (name + '.i', name + '.j', name + '.k') latex_vects = [(r'\mathbf{\hat{i}_{%s}}' % name), (r'\mathbf{\hat{j}_{%s}}' % name), (r'\mathbf{\hat{k}_{%s}}' % name)] pretty_vects = (name + '_i', name + '_j', name + '_k') else: _check_strings('vector_names', vector_names) vector_names = list(vector_names) latex_vects = [(r'\mathbf{\hat{%s}_{%s}}' % (x, name)) for x in vector_names] pretty_vects = [(name + '_' + x) for x in vector_names] obj._i = BaseVector(vector_names[0], 0, obj, pretty_vects[0], latex_vects[0]) obj._j = BaseVector(vector_names[1], 1, obj, pretty_vects[1], latex_vects[1]) obj._k = BaseVector(vector_names[2], 2, obj, pretty_vects[2], latex_vects[2]) # Initialize the base scalars if variable_names is None: variable_names = (name + '.x', name + '.y', name + '.z') latex_scalars = [(r"\mathbf{{x}_{%s}}" % name), (r"\mathbf{{y}_{%s}}" % name), (r"\mathbf{{z}_{%s}}" % name)] pretty_scalars = (name + '_x', name + '_y', name + '_z') else: _check_strings('variable_names', vector_names) variable_names = list(variable_names) latex_scalars = [(r"\mathbf{{%s}_{%s}}" % (x, name)) for x in variable_names] pretty_scalars = [(name + '_' + x) for x in variable_names] obj._x = BaseScalar(variable_names[0], 0, obj, pretty_scalars[0], latex_scalars[0]) obj._y = BaseScalar(variable_names[1], 1, obj, pretty_scalars[1], latex_scalars[1]) obj._z = BaseScalar(variable_names[2], 2, obj, pretty_scalars[2], latex_scalars[2]) obj._h1 = S.One obj._h2 = S.One obj._h3 = S.One obj._transformation_eqs = obj._x, obj._y, obj._y obj._inv_transformation_eqs = lambda x, y, z: (x, y, z) # Assign params obj._parent = parent if obj._parent is not None: obj._root = obj._parent._root else: obj._root = obj obj._parent_rotation_matrix = parent_orient obj._origin = origin # Return the instance return obj
def test_coordinate_vars(): """ Tests the coordinate variables functionality with respect to reorientation of coordinate systems. """ A = CoordSys3D("A") # Note that the name given on the lhs is different from A.x._name assert BaseScalar(0, A, "A_x", r"\mathbf{{x}_{A}}") == A.x assert BaseScalar(1, A, "A_y", r"\mathbf{{y}_{A}}") == A.y assert BaseScalar(2, A, "A_z", r"\mathbf{{z}_{A}}") == A.z assert BaseScalar(0, A, "A_x", r"\mathbf{{x}_{A}}").__hash__() == A.x.__hash__() assert (isinstance(A.x, BaseScalar) and isinstance(A.y, BaseScalar) and isinstance(A.z, BaseScalar)) assert A.x * A.y == A.y * A.x assert A.scalar_map(A) == {A.x: A.x, A.y: A.y, A.z: A.z} assert A.x.system == A assert A.x.diff(A.x) == 1 B = A.orient_new_axis("B", q, A.k) assert B.scalar_map(A) == { B.z: A.z, B.y: -A.x * sin(q) + A.y * cos(q), B.x: A.x * cos(q) + A.y * sin(q), } assert A.scalar_map(B) == { A.x: B.x * cos(q) - B.y * sin(q), A.y: B.x * sin(q) + B.y * cos(q), A.z: B.z, } assert express(B.x, A, variables=True) == A.x * cos(q) + A.y * sin(q) assert express(B.y, A, variables=True) == -A.x * sin(q) + A.y * cos(q) assert express(B.z, A, variables=True) == A.z assert expand(express(B.x * B.y * B.z, A, variables=True)) == expand( A.z * (-A.x * sin(q) + A.y * cos(q)) * (A.x * cos(q) + A.y * sin(q))) assert (express(B.x * B.i + B.y * B.j + B.z * B.k, A) == (B.x * cos(q) - B.y * sin(q)) * A.i + (B.x * sin(q) + B.y * cos(q)) * A.j + B.z * A.k) assert (simplify( express(B.x * B.i + B.y * B.j + B.z * B.k, A, variables=True)) == A.x * A.i + A.y * A.j + A.z * A.k) assert (express(A.x * A.i + A.y * A.j + A.z * A.k, B) == (A.x * cos(q) + A.y * sin(q)) * B.i + (-A.x * sin(q) + A.y * cos(q)) * B.j + A.z * B.k) assert (simplify( express(A.x * A.i + A.y * A.j + A.z * A.k, B, variables=True)) == B.x * B.i + B.y * B.j + B.z * B.k) N = B.orient_new_axis("N", -q, B.k) assert N.scalar_map(A) == {N.x: A.x, N.z: A.z, N.y: A.y} C = A.orient_new_axis("C", q, A.i + A.j + A.k) mapping = A.scalar_map(C) assert mapping[A.x].equals(C.x * (2 * cos(q) + 1) / 3 + C.y * (-2 * sin(q + pi / 6) + 1) / 3 + C.z * (-2 * cos(q + pi / 3) + 1) / 3) assert mapping[A.y].equals(C.x * (-2 * cos(q + pi / 3) + 1) / 3 + C.y * (2 * cos(q) + 1) / 3 + C.z * (-2 * sin(q + pi / 6) + 1) / 3) assert mapping[A.z].equals(C.x * (-2 * sin(q + pi / 6) + 1) / 3 + C.y * (-2 * cos(q + pi / 3) + 1) / 3 + C.z * (2 * cos(q) + 1) / 3) D = A.locate_new("D", a * A.i + b * A.j + c * A.k) assert D.scalar_map(A) == {D.z: A.z - c, D.x: A.x - a, D.y: A.y - b} E = A.orient_new_axis("E", a, A.k, a * A.i + b * A.j + c * A.k) assert A.scalar_map(E) == { A.z: E.z + c, A.x: E.x * cos(a) - E.y * sin(a) + a, A.y: E.x * sin(a) + E.y * cos(a) + b, } assert E.scalar_map(A) == { E.x: (A.x - a) * cos(a) + (A.y - b) * sin(a), E.y: (-A.x + a) * sin(a) + (A.y - b) * cos(a), E.z: A.z - c, } F = A.locate_new("F", Vector.zero) assert A.scalar_map(F) == {A.z: F.z, A.x: F.x, A.y: F.y}
def __new__(cls, name, transformation=None, parent=None, location=None, rotation_matrix=None, vector_names=None, variable_names=None): """ The orientation/location parameters are necessary if this system is being defined at a certain orientation or location wrt another. Parameters ========== name : str The name of the new CoordSys3D instance. transformation : Lambda, Tuple, str Transformation defined by transformation equations or chosen from predefined ones. location : Vector The position vector of the new system's origin wrt the parent instance. rotation_matrix : SymPy ImmutableMatrix The rotation matrix of the new coordinate system with respect to the parent. In other words, the output of new_system.rotation_matrix(parent). parent : CoordSys3D The coordinate system wrt which the orientation/location (or both) is being defined. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. """ name = str(name) Vector = sympy.vector.Vector BaseVector = sympy.vector.BaseVector Point = sympy.vector.Point if not isinstance(name, string_types): raise TypeError("name should be a string") if transformation is not None: if (location is not None) or (rotation_matrix is not None): raise ValueError("specify either `transformation` or " "`location`/`rotation_matrix`") if isinstance(transformation, (Tuple, tuple, list)): if isinstance(transformation[0], MatrixBase): rotation_matrix = transformation[0] location = transformation[1] else: transformation = Lambda(transformation[0], transformation[1]) elif isinstance(transformation, Callable): x1, x2, x3 = symbols('x1 x2 x3', cls=Dummy) transformation = Lambda((x1, x2, x3), transformation(x1, x2, x3)) elif isinstance(transformation, string_types): transformation = Symbol(transformation) elif isinstance(transformation, (Symbol, Lambda)): pass else: raise TypeError("transformation: " "wrong type {0}".format(type(transformation))) # If orientation information has been provided, store # the rotation matrix accordingly if rotation_matrix is None: rotation_matrix = ImmutableDenseMatrix(eye(3)) else: if not isinstance(rotation_matrix, MatrixBase): raise TypeError("rotation_matrix should be an Immutable" + "Matrix instance") rotation_matrix = rotation_matrix.as_immutable() # If location information is not given, adjust the default # location as Vector.zero if parent is not None: if not isinstance(parent, CoordSys3D): raise TypeError("parent should be a " + "CoordSys3D/None") if location is None: location = Vector.zero else: if not isinstance(location, Vector): raise TypeError("location should be a Vector") # Check that location does not contain base # scalars for x in location.free_symbols: if isinstance(x, BaseScalar): raise ValueError("location should not contain" + " BaseScalars") origin = parent.origin.locate_new(name + '.origin', location) else: location = Vector.zero origin = Point(name + '.origin') if transformation is None: transformation = Tuple(rotation_matrix, location) if isinstance(transformation, Tuple): lambda_transformation = CoordSys3D._compose_rotation_and_translation( transformation[0], transformation[1], parent) r, l = transformation l = l._projections lambda_lame = CoordSys3D._get_lame_coeff('cartesian') lambda_inverse = lambda x, y, z: r.inv() * Matrix( [x - l[0], y - l[1], z - l[2]]) elif isinstance(transformation, Symbol): trname = transformation.name lambda_transformation = CoordSys3D._get_transformation_lambdas( trname) if parent is not None: if parent.lame_coefficients() != (S.One, S.One, S.One): raise ValueError('Parent for pre-defined coordinate ' 'system should be Cartesian.') lambda_lame = CoordSys3D._get_lame_coeff(trname) lambda_inverse = CoordSys3D._set_inv_trans_equations(trname) elif isinstance(transformation, Lambda): if not CoordSys3D._check_orthogonality(transformation): raise ValueError("The transformation equation does not " "create orthogonal coordinate system") lambda_transformation = transformation lambda_lame = CoordSys3D._calculate_lame_coeff( lambda_transformation) lambda_inverse = None else: lambda_transformation = lambda x, y, z: transformation(x, y, z) lambda_lame = CoordSys3D._get_lame_coeff(transformation) lambda_inverse = None if variable_names is None: if isinstance(transformation, Lambda): variable_names = ["x1", "x2", "x3"] elif isinstance(transformation, Symbol): if transformation.name == 'spherical': variable_names = ["r", "theta", "phi"] elif transformation.name == 'cylindrical': variable_names = ["r", "theta", "z"] else: variable_names = ["x", "y", "z"] else: variable_names = ["x", "y", "z"] if vector_names is None: vector_names = ["i", "j", "k"] # All systems that are defined as 'roots' are unequal, unless # they have the same name. # Systems defined at same orientation/position wrt the same # 'parent' are equal, irrespective of the name. # This is true even if the same orientation is provided via # different methods like Axis/Body/Space/Quaternion. # However, coincident systems may be seen as unequal if # positioned/oriented wrt different parents, even though # they may actually be 'coincident' wrt the root system. if parent is not None: obj = super(CoordSys3D, cls).__new__(cls, Symbol(name), transformation, parent) else: obj = super(CoordSys3D, cls).__new__(cls, Symbol(name), transformation) obj._name = name # Initialize the base vectors _check_strings('vector_names', vector_names) vector_names = list(vector_names) latex_vects = [(r'\mathbf{\hat{%s}_{%s}}' % (x, name)) for x in vector_names] pretty_vects = ['%s_%s' % (x, name) for x in vector_names] obj._vector_names = vector_names v1 = BaseVector(0, obj, pretty_vects[0], latex_vects[0]) v2 = BaseVector(1, obj, pretty_vects[1], latex_vects[1]) v3 = BaseVector(2, obj, pretty_vects[2], latex_vects[2]) obj._base_vectors = (v1, v2, v3) # Initialize the base scalars _check_strings('variable_names', vector_names) variable_names = list(variable_names) latex_scalars = [(r"\mathbf{{%s}_{%s}}" % (x, name)) for x in variable_names] pretty_scalars = ['%s_%s' % (x, name) for x in variable_names] obj._variable_names = variable_names obj._vector_names = vector_names x1 = BaseScalar(0, obj, pretty_scalars[0], latex_scalars[0]) x2 = BaseScalar(1, obj, pretty_scalars[1], latex_scalars[1]) x3 = BaseScalar(2, obj, pretty_scalars[2], latex_scalars[2]) obj._base_scalars = (x1, x2, x3) obj._transformation = transformation obj._transformation_lambda = lambda_transformation obj._lame_coefficients = lambda_lame(x1, x2, x3) obj._transformation_from_parent_lambda = lambda_inverse setattr(obj, variable_names[0], x1) setattr(obj, variable_names[1], x2) setattr(obj, variable_names[2], x3) setattr(obj, vector_names[0], v1) setattr(obj, vector_names[1], v2) setattr(obj, vector_names[2], v3) # Assign params obj._parent = parent if obj._parent is not None: obj._root = obj._parent._root else: obj._root = obj obj._parent_rotation_matrix = rotation_matrix obj._origin = origin # Return the instance return obj
def test_coordinate_vars(): """ Tests the coordinate variables functionality with respect to reorientation of coordinate systems. """ A = CoordSys3D('A') # Note that the name given on the lhs is different from A.x._name assert BaseScalar('A.x', 0, A, 'A_x', r'\mathbf{{x}_{A}}') == A.x assert BaseScalar('A.y', 1, A, 'A_y', r'\mathbf{{y}_{A}}') == A.y assert BaseScalar('A.z', 2, A, 'A_z', r'\mathbf{{z}_{A}}') == A.z assert BaseScalar('A.x', 0, A, 'A_x', r'\mathbf{{x}_{A}}').__hash__() == A.x.__hash__() assert isinstance(A.x, BaseScalar) and \ isinstance(A.y, BaseScalar) and \ isinstance(A.z, BaseScalar) assert A.x * A.y == A.y * A.x assert A.scalar_map(A) == {A.x: A.x, A.y: A.y, A.z: A.z} assert A.x.system == A assert A.x.diff(A.x) == 1 B = A.orient_new_axis('B', q, A.k) assert B.scalar_map(A) == { B.z: A.z, B.y: -A.x * sin(q) + A.y * cos(q), B.x: A.x * cos(q) + A.y * sin(q) } assert A.scalar_map(B) == { A.x: B.x * cos(q) - B.y * sin(q), A.y: B.x * sin(q) + B.y * cos(q), A.z: B.z } assert express(B.x, A, variables=True) == A.x * cos(q) + A.y * sin(q) assert express(B.y, A, variables=True) == -A.x * sin(q) + A.y * cos(q) assert express(B.z, A, variables=True) == A.z assert expand(express(B.x*B.y*B.z, A, variables=True)) == \ expand(A.z*(-A.x*sin(q) + A.y*cos(q))*(A.x*cos(q) + A.y*sin(q))) assert express(B.x*B.i + B.y*B.j + B.z*B.k, A) == \ (B.x*cos(q) - B.y*sin(q))*A.i + (B.x*sin(q) + \ B.y*cos(q))*A.j + B.z*A.k assert simplify(express(B.x*B.i + B.y*B.j + B.z*B.k, A, \ variables=True)) == \ A.x*A.i + A.y*A.j + A.z*A.k assert express(A.x*A.i + A.y*A.j + A.z*A.k, B) == \ (A.x*cos(q) + A.y*sin(q))*B.i + \ (-A.x*sin(q) + A.y*cos(q))*B.j + A.z*B.k assert simplify(express(A.x*A.i + A.y*A.j + A.z*A.k, B, \ variables=True)) == \ B.x*B.i + B.y*B.j + B.z*B.k N = B.orient_new_axis('N', -q, B.k) assert N.scalar_map(A) == \ {N.x: A.x, N.z: A.z, N.y: A.y} C = A.orient_new_axis('C', q, A.i + A.j + A.k) mapping = A.scalar_map(C) assert mapping[A.x].equals(C.x * (2 * cos(q) + 1) / 3 + C.y * (-2 * sin(q + pi / 6) + 1) / 3 + C.z * (-2 * cos(q + pi / 3) + 1) / 3) assert mapping[A.y].equals(C.x * (-2 * cos(q + pi / 3) + 1) / 3 + C.y * (2 * cos(q) + 1) / 3 + C.z * (-2 * sin(q + pi / 6) + 1) / 3) assert mapping[A.z].equals(C.x * (-2 * sin(q + pi / 6) + 1) / 3 + C.y * (-2 * cos(q + pi / 3) + 1) / 3 + C.z * (2 * cos(q) + 1) / 3) D = A.locate_new('D', a * A.i + b * A.j + c * A.k) assert D.scalar_map(A) == {D.z: A.z - c, D.x: A.x - a, D.y: A.y - b} E = A.orient_new_axis('E', a, A.k, a * A.i + b * A.j + c * A.k) assert A.scalar_map(E) == { A.z: E.z + c, A.x: E.x * cos(a) - E.y * sin(a) + a, A.y: E.x * sin(a) + E.y * cos(a) + b } assert E.scalar_map(A) == { E.x: (A.x - a) * cos(a) + (A.y - b) * sin(a), E.y: (-A.x + a) * sin(a) + (A.y - b) * cos(a), E.z: A.z - c } F = A.locate_new('F', Vector.zero) assert A.scalar_map(F) == {A.z: F.z, A.x: F.x, A.y: F.y}
def test_coordinate_vars(): """ Tests the coordinate variables functionality with respect to reorientation of coordinate systems. """ A = CoordSysCartesian('A') assert BaseScalar('Ax', 0, A, ' ', ' ') == A.x assert BaseScalar('Ay', 1, A, ' ', ' ') == A.y assert BaseScalar('Az', 2, A, ' ', ' ') == A.z assert BaseScalar('Ax', 0, A, ' ', ' ').__hash__() == A.x.__hash__() assert isinstance(A.x, BaseScalar) and \ isinstance(A.y, BaseScalar) and \ isinstance(A.z, BaseScalar) assert A.scalar_map(A) == {A.x: A.x, A.y: A.y, A.z: A.z} assert A.x.system == A B = A.orient_new_axis('B', q, A.k) assert B.scalar_map(A) == { B.z: A.z, B.y: -A.x * sin(q) + A.y * cos(q), B.x: A.x * cos(q) + A.y * sin(q) } assert A.scalar_map(B) == { A.x: B.x * cos(q) - B.y * sin(q), A.y: B.x * sin(q) + B.y * cos(q), A.z: B.z } assert express(B.x, A, variables=True) == A.x * cos(q) + A.y * sin(q) assert express(B.y, A, variables=True) == -A.x * sin(q) + A.y * cos(q) assert express(B.z, A, variables=True) == A.z assert express(B.x*B.y*B.z, A, variables=True) == \ A.z*(-A.x*sin(q) + A.y*cos(q))*(A.x*cos(q) + A.y*sin(q)) assert express(B.x*B.i + B.y*B.j + B.z*B.k, A) == \ (B.x*cos(q) - B.y*sin(q))*A.i + (B.x*sin(q) + \ B.y*cos(q))*A.j + B.z*A.k assert simplify(express(B.x*B.i + B.y*B.j + B.z*B.k, A, \ variables=True)) == \ A.x*A.i + A.y*A.j + A.z*A.k assert express(A.x*A.i + A.y*A.j + A.z*A.k, B) == \ (A.x*cos(q) + A.y*sin(q))*B.i + \ (-A.x*sin(q) + A.y*cos(q))*B.j + A.z*B.k assert simplify(express(A.x*A.i + A.y*A.j + A.z*A.k, B, \ variables=True)) == \ B.x*B.i + B.y*B.j + B.z*B.k N = B.orient_new_axis('N', -q, B.k) assert N.scalar_map(A) == \ {N.x: A.x, N.z: A.z, N.y: A.y} C = A.orient_new_axis('C', q, A.i + A.j + A.k) mapping = A.scalar_map(C) assert mapping[A.x] == 2*C.x*cos(q)/3 + C.x/3 - \ 2*C.y*sin(q + pi/6)/3 + C.y/3 - 2*C.z*cos(q + pi/3)/3 + C.z/3 assert mapping[A.y] == -2*C.x*cos(q + pi/3)/3 + \ C.x/3 + 2*C.y*cos(q)/3 + C.y/3 - 2*C.z*sin(q + pi/6)/3 + C.z/3 assert mapping[A.z] == -2*C.x*sin(q + pi/6)/3 + C.x/3 - \ 2*C.y*cos(q + pi/3)/3 + C.y/3 + 2*C.z*cos(q)/3 + C.z/3 D = A.locate_new('D', a * A.i + b * A.j + c * A.k) assert D.scalar_map(A) == {D.z: A.z - c, D.x: A.x - a, D.y: A.y - b} E = A.orient_new_axis('E', a, A.k, a * A.i + b * A.j + c * A.k) assert A.scalar_map(E) == { A.z: E.z + c, A.x: E.x * cos(a) - E.y * sin(a) + a, A.y: E.x * sin(a) + E.y * cos(a) + b } assert E.scalar_map(A) == { E.x: (A.x - a) * cos(a) + (A.y - b) * sin(a), E.y: (-A.x + a) * sin(a) + (A.y - b) * cos(a), E.z: A.z - c } F = A.locate_new('F', Vector.zero) assert A.scalar_map(F) == {A.z: F.z, A.x: F.x, A.y: F.y}
def __new__(cls, name, vector_names=None, variable_names=None, location=None, rot_type=None, rot_amounts=None, rot_order='', parent=None): """ The orientation/location parameters are necessary if this system is being defined at a certain orientation or location wrt another. For more information on the orientation parameters, please refer to the docs of orient_new method. Parameters ========== name : str The name of the new CoordSysCartesian instance. vector_names, variable_names : tuples/lists(optional) Tuples/Lists of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. location : Vector The position vector of the new system's origin wrt the parent instance. rot_type : str ('Axis'/'Body'/'Quaternion'/'Space') The type of orientation matrix that is being created. rot_amounts : list OR value The quantities that the orientation matrix will be defined by. rot_order : str (Look at the docs of orient_new for more details) If applicable, the order of a series of rotations. parent : CoordSysCartesian The coordinate system wrt which the orientation/location (or both) is being defined. docstring of orient_new ======================= """ if not isinstance(name, string_types): raise TypeError("name should be a string") #If orientation information has been provided, calculate #the DCM accordingly from sympy.vector.vector import BaseVector, Vector if rot_type is not None: for i, v in enumerate(rot_amounts): if not isinstance(v, Vector): rot_amounts[i] = sympify(v) rot_type = rot_type.upper() if rot_type == 'AXIS': parent_orient = _orient_axis(list(rot_amounts), rot_order, parent) elif rot_type == 'QUATERNION': parent_orient = _orient_quaternion(list(rot_amounts), rot_order) elif rot_type == 'BODY': parent_orient = _orient_body(list(rot_amounts), rot_order) elif rot_type == 'SPACE': parent_orient = _orient_space(list(rot_amounts), rot_order) else: raise NotImplementedError('Rotation not implemented') else: if not (rot_amounts == None and rot_order == ''): raise ValueError("No rotation type provided") parent_orient = Matrix(eye(3)) #If location information is not given, adjust the default #location as Vector.zero from sympy.vector.point import Point if parent is not None: if not isinstance(parent, CoordSysCartesian): raise TypeError("parent should be a " + "CoordSysCartesian/None") if location is None: location = Vector.zero origin = parent.origin.locate_new(name + '.origin', location) arg_parent = parent arg_self = Symbol('default') else: origin = Point(name + '.origin') arg_parent = Symbol('default') arg_self = Symbol(name) #All systems that are defined as 'roots' are unequal, unless #they have the same name. #Systems defined at same orientation/position wrt the same #'parent' are equal, irrespective of the name. #This is true even if the same orientation is provided via #different methods like Axis/Body/Space/Quaternion. #However, coincident systems may be seen as unequal if #positioned/oriented wrt different parents, even though #they may actually be 'coincident' wrt the root system. obj = super(CoordSysCartesian, cls).__new__(cls, arg_self, parent_orient, origin, arg_parent) obj._name = name #Initialize the base vectors if vector_names is None: vector_names = (name + '.i', name + '.j', name + '.k') obj._i = BaseVector(vector_names[0], 0, obj) obj._j = BaseVector(vector_names[1], 1, obj) obj._k = BaseVector(vector_names[2], 2, obj) #Initialize the base scalars if variable_names is None: variable_names = (name + '.x', name + '.y', name + '.z') obj._x = BaseScalar(variable_names[0], 0, obj) obj._y = BaseScalar(variable_names[1], 1, obj) obj._z = BaseScalar(variable_names[2], 2, obj) #Assign a Del operator instance from sympy.vector.deloperator import Del obj._del = Del(obj) #Assign params obj._parent = parent if obj._parent is not None: obj._root = obj._parent._root else: obj._root = obj obj._parent_rotation_matrix = parent_orient.T obj._origin = origin #Return the instance return obj