"""A magnetic field generated by a conical current.

A magnetic field generated by a conical current.

Authors
-------
G.K. Stephens
Eric Winter (eric.winter@jhuapl.edu)
"""


from math import cos, sin

from emmpy.magmodel.math.trigparity import ODD
from emmpy.magmodel.math.vectorfields.sphericalvectorfield import (
    SphericalVectorField
)
from emmpy.magmodel.modeling.fac.tfunction import TFunction
from emmpy.math.coordinates.sphericalvector import SphericalVector


class ConicalCurrentMagneticField(SphericalVectorField):
    """A magnetic field generated by a conical current.

    Represents the magnetic field of an azimuthal harmonic of a finite
    thickness conical current sheet

    As described in "Methods for quantitative modeling of the magnetic
    field from Birkeland currents" by N. A. Tsyganenko. See eq. (16). The
    cone's axis is the +Z axis.

    The magnetic field is the curl of the following vector potential:
    see http://www.sciencedirect.com/science/article/pii/003206339190058I
    (Tsyganenko, 1990)

           SUBROUTINE ONE_CONE(A,X,Y,Z,BX,BY,BZ)
    c
    c  RETURNS FIELD COMPONENTS FOR A DEFORMED CONICAL CURRENT SYSTEM, FITTED
    c  TO A BIOSAVART FIELD
    c    BY SIM_14.FOR.  HERE ONLY THE NORTHERN CONE IS TAKEN INTO ACCOUNT.

    Attributes
    ----------
    tFunction : TFunction
        tFunction
    mode : int
        mode
    trigParity : TrigParity
        trigParity
    """

    def __init__(self, tFunction, mode, trigParity):
        """Initialize a new ConicalCurrentMagneticField object.

        Initialize a new ConicalCurrentMagneticField object.

        Parameters
        ----------
        tFunction : TFunction
            tFunction
        mode : int
            mode
        trigParity : TrigParity
            trigParity
        """
        self.tFunction = tFunction
        self.mode = mode
        self.trigParity = trigParity

    @staticmethod
    def create(theta0, deltaTheta, mode, trigParity):
        """Create a new ConicalCurrentMagneticField object.

        Creates a ConicalCurrentMagneticField where the current sheet is
        centered at theta0 and has a half thickness of deltaTheta.

        The theta co-latitude dependence (theta) is determined by the
        TFunction.

        Parameters
        ----------
        theta0 : float
            A polar angle (colatitude) that is the center of the conical
            current sheet.
        deltaTheta : float
            The half thickness of the conical current sheet.
        mode : int
            The mode of the harmonic (m).
        trigParity : TrigParity
            The parity of the harmonic (EVEN for cosine and ODD for sine).
        
        Returns
        -------
        result : ConicalCurrentMagneticField
            The new object.
        """
        return ConicalCurrentMagneticField(
            TFunction.createFromDelta(theta0, deltaTheta, mode),
            mode, trigParity
        )

    def evaluate(self, location):
        """Evaluate the field at the given position.

        Evaluate the field at the given position.

        Parameters
        ----------
        location : SphericalVector
            Location to evaluate the field, in spherical coordinates.
        
        Returns
        -------
        result : SphericalVector
            The result of the evaluation.
        """
        # This is the curl of equation 16.
        r = location.r
        phi = location.phi
        theta = location.theta
        t = self.tFunction.evaluate(theta)
        dt_dTheta = self.tFunction.differentiate(theta)
        # Even or odd.
        if self.trigParity is ODD:
            sinMphi = sin(self.mode*phi)
            cosMphi = cos(self.mode*phi)
        else:
            sinMphi = cos(self.mode*phi)
            cosMphi = -sin(self.mode*phi)
        br = 0.0
        bTheta = self.mode*t*cosMphi/(r*sin(theta))
        bPhi = -dt_dTheta*sinMphi/r
        return SphericalVector(br, bTheta, bPhi)
