{-# OPTIONS_GHC -Wall #-} {-# LANGUAGE TypeSynonymInstances, FlexibleInstances #-} {-# LANGUAGE Safe #-} {- | Module : Physics.Learn.Position Copyright : (c) Scott N. Walck 2012-2018 License : BSD3 (see LICENSE) Maintainer : Scott N. Walck <walck@lvc.edu> Stability : experimental A module for working with the idea of position and coordinate systems. -} module Physics.Learn.Position ( Position , Displacement , ScalarField , VectorField , Field , CoordinateSystem , cartesian , cylindrical , spherical , cart , cyl , sph , cartesianCoordinates , cylindricalCoordinates , sphericalCoordinates , displacement , shiftPosition , shiftObject , shiftField , addFields , rHat , thetaHat , phiHat , sHat , xHat , yHat , zHat ) where import Data.VectorSpace ( AdditiveGroup ) import Physics.Learn.CarrotVec ( Vec , vec , xComp , yComp , zComp , iHat , jHat , kHat , sumV , magnitude , (^/) ) -- | A type for position. -- Position is not a vector because it makes no sense to add positions. data Position = Cart Double Double Double deriving (Show) -- | A displacement is a vector. type Displacement = Vec -- | A scalar field associates a number with each position in space. type ScalarField = Position -> Double {- -- | Scalar fields can be added, subtracted, multiplied, and negated, -- just like scalars themselves. instance Num ScalarField where (f + g) x = f x + g x (f * g) x = f x * g x (f - g) x = f x - g x negate f x = negate (f x) abs f x = abs (f x) signum f x = signum (f x) fromInteger n = const (fromInteger n) -- | Scalar fields can be divided, just like scalars themselves. instance Fractional ScalarField where (f / g) x = f x / g x recip f x = recip (f x) fromRational rat = const (fromRational rat) -- | Cosine of a scalar field, etc. instance Floating ScalarField where pi = const pi exp f x = exp (f x) sqrt f x = sqrt (f x) log f x = log (f x) (f ** g) x = f x ** g x logBase f g x = logBase (f x) (g x) sin f x = sin (f x) cos f x = cos (f x) tan f x = tan (f x) asin f x = asin (f x) acos f x = acos (f x) atan f x = atan (f x) sinh f x = sinh (f x) cosh f x = cosh (f x) tanh f x = tanh (f x) asinh f x = asinh (f x) acosh f x = acosh (f x) atanh f x = atanh (f x) -} -- | A vector field associates a vector with each position in space. type VectorField = Position -> Vec -- | Sometimes we want to be able to talk about a field without saying -- whether it is a scalar field or a vector field. type Field v = Position -> v -- | A coordinate system is a function from three parameters to space. type CoordinateSystem = (Double,Double,Double) -> Position -- | Add two scalar fields or two vector fields. addFields :: AdditiveGroup v => [Field v] -> Field v addFields flds r = sumV [fld r | fld <- flds] -- | The Cartesian coordinate system. Coordinates are (x,y,z). cartesian :: CoordinateSystem cartesian (x,y,z) = Cart x y z -- | The cylindrical coordinate system. Coordinates are (s,phi,z), -- where s is the distance from the z axis and phi is the angle -- with the x axis. cylindrical :: CoordinateSystem cylindrical (s,phi,z) = Cart (s * cos phi) (s * sin phi) z -- | The spherical coordinate system. Coordinates are (r,theta,phi), -- where r is the distance from the origin, theta is the angle with -- the z axis, and phi is the azimuthal angle. spherical :: CoordinateSystem spherical (r,th,phi) = Cart (r * sin th * cos phi) (r * sin th * sin phi) (r * cos th) -- | A helping function to take three numbers x, y, and z and form the -- appropriate position using Cartesian coordinates. cart :: Double -- ^ x coordinate -> Double -- ^ y coordinate -> Double -- ^ z coordinate -> Position cart = Cart -- | A helping function to take three numbers s, phi, and z and form the -- appropriate position using cylindrical coordinates. cyl :: Double -- ^ s coordinate -> Double -- ^ phi coordinate -> Double -- ^ z coordinate -> Position cyl s phi z = Cart (s * cos phi) (s * sin phi) z -- | A helping function to take three numbers r, theta, and phi and form the -- appropriate position using spherical coordinates. sph :: Double -- ^ r coordinate -> Double -- ^ theta coordinate -> Double -- ^ phi coordinate -> Position sph r theta phi = Cart (r * sin theta * cos phi) (r * sin theta * sin phi) (r * cos theta) -- | Returns the three Cartesian coordinates as a triple from a position. cartesianCoordinates :: Position -> (Double,Double,Double) cartesianCoordinates (Cart x y z) = (x,y,z) -- | Returns the three cylindrical coordinates as a triple from a position. cylindricalCoordinates :: Position -> (Double,Double,Double) cylindricalCoordinates (Cart x y z) = (s,phi,z) where s = sqrt(x**2 + y**2) phi = atan2 y x -- | Returns the three spherical coordinates as a triple from a position. sphericalCoordinates :: Position -> (Double,Double,Double) sphericalCoordinates (Cart x y z) = (r,theta,phi) where r = sqrt(x**2 + y**2 + z**2) theta = atan2 s z s = sqrt(x**2 + y**2) phi = atan2 y x -- | Displacement from source position to target position. displacement :: Position -- ^ source position -> Position -- ^ target position -> Displacement displacement (Cart x' y' z') (Cart x y z) = vec (x-x') (y-y') (z-z') -- | Shift a position by a displacement. shiftPosition :: Displacement -> Position -> Position shiftPosition v (Cart x y z) = Cart (x + xComp v) (y + yComp v) (z + zComp v) -- | An object is a map into 'Position'. shiftObject :: Displacement -> (a -> Position) -> (a -> Position) shiftObject d f = shiftPosition d . f -- | A field is a map from 'Position'. shiftField :: Displacement -> (Position -> v) -> (Position -> v) shiftField d f = f . shiftPosition d -- | The vector field in which each point in space is associated -- with a unit vector in the direction of increasing spherical coordinate -- r, while spherical coordinates theta and phi -- are held constant. -- Defined everywhere except at the origin. -- The unit vector 'rHat' points in different directions at different points -- in space. It is therefore better interpreted as a vector field, rather -- than a vector. rHat :: VectorField rHat rv = d ^/ magnitude d where d = displacement (cart 0 0 0) rv -- | The vector field in which each point in space is associated -- with a unit vector in the direction of increasing spherical coordinate -- theta, while spherical coordinates r and phi are held constant. -- Defined everywhere except on the z axis. thetaHat :: VectorField thetaHat r = vec (cos theta * cos phi) (cos theta * sin phi) (-sin theta) where (_,theta,phi) = sphericalCoordinates r -- | The vector field in which each point in space is associated -- with a unit vector in the direction of increasing (cylindrical or spherical) coordinate -- phi, while cylindrical coordinates s and z -- (or spherical coordinates r and theta) are held constant. -- Defined everywhere except on the z axis. phiHat :: VectorField phiHat r = vec (-sin phi) (cos phi) 0 where (_,phi,_) = cylindricalCoordinates r -- | The vector field in which each point in space is associated -- with a unit vector in the direction of increasing cylindrical coordinate -- s, while cylindrical coordinates phi and z -- are held constant. -- Defined everywhere except on the z axis. sHat :: VectorField sHat r = vec (cos phi) (sin phi) 0 where (_,phi,_) = cylindricalCoordinates r -- | The vector field in which each point in space is associated -- with a unit vector in the direction of increasing Cartesian coordinate -- x, while Cartesian coordinates y and z -- are held constant. -- Defined everywhere. xHat :: VectorField xHat = const iHat -- | The vector field in which each point in space is associated -- with a unit vector in the direction of increasing Cartesian coordinate -- y, while Cartesian coordinates x and z -- are held constant. -- Defined everywhere. yHat :: VectorField yHat = const jHat -- | The vector field in which each point in space is associated -- with a unit vector in the direction of increasing Cartesian coordinate -- z, while Cartesian coordinates x and y -- are held constant. -- Defined everywhere. zHat :: VectorField zHat = const kHat