<commit_before># -*- coding: utf-8 -*-

from __future__ import division, print_function, absolute_import

import os
import warnings
import datetime as dt

import numpy as np

from . import helpers
from .helpers import d2r, r2d

# below try..catch required for autodoc to work on readthedocs
try:
    from . import fortranapex as fa
except:
    print("ERROR: fortranapex module could not be imported. apexpy probably won't work")


# make sure invalid warnings are always shown
warnings.filterwarnings('always', message='.*set to -9999 where*', module='apexpy.apex')


class ApexHeightError(ValueError):
    pass


class Apex(object):
    '''Performs coordinate conversions, field-line mapping and base vector calculations.

    Parameters
    ==========
    date : float (decimal year) or instance of :class:`datetime.date` or :class:`datetime.datetime`, optional
        Determines which IGRF coefficients are used in conversions. Uses current date as default.
    refh : float, optional
        Reference height in km for apex coordinates (the field lines are mapped to this height)
    datafile : str, optional
        Path to custom coefficient file

    Attributes
    ==========
    year : float
        Decimal year used for the IGRF model
    refh : float
        Reference height in km for apex coordinates
    datafile : str
        Path to coefficient file

    Notes
    =====
    The calculations use IGRF-12 with coefficients from 1900 to 2020 [1]_.

    References
    ==========

    .. [1] <NAME>. et al. (2015), International Geomagnetic Reference
           Field: the 12th generation, Earth, Planets and Space, 67(1), 79,
           doi:10.1186/s40623-015-0228-9.

    '''

    def __init__(self, date=None, refh=0, datafile=None):

        if datafile is None:
            datafile = os.path.join(os.path.dirname(__file__), 'apexsh.dat')

        self.RE = 6371.009  # mean Earth radius
        self.set_refh(refh)  # reference height

        if date is None:
            self.year = helpers.toYearFraction(dt.datetime.now())
        else:
            try:
                # convert date/datetime object to decimal year
                self.year = helpers.toYearFraction(date)
            except:
                # failed so date is probably int/float, use directly
                self.year = date

        if not os.path.isfile(datafile):
            raise IOError('Datafile does not exist: {}'.format(datafile))

        self.datafile = datafile
        self.set_epoch(self.year)

        # vectorize fortran functions
        self._geo2qd = np.frompyfunc(
            lambda glat, glon, height: fa.apxg2q(glat, (glon + 180) % 360 - 180, height, 0)[:2], 3, 2)
        self._geo2apex = np.frompyfunc(
            lambda glat, glon, height: fa.apxg2all(glat, (glon + 180) % 360 - 180, height, self.refh, 0)[2:4], 3, 2)
        self._geo2apexall = np.frompyfunc(
            lambda glat, glon, height: fa.apxg2all(glat, (glon + 180) % 360 - 180, height, self.refh, 1), 3, 14)
        self._qd2geo = np.frompyfunc(
            lambda qlat, qlon, height, precision: fa.apxq2g(qlat, (qlon + 180) % 360 - 180, height, precision), 4, 3)
        self._basevec = np.frompyfunc(
            lambda glat, glon, height: fa.apxg2q(glat, (glon + 180) % 360 - 180, height, 1)[2:4], 3, 2)

        # vectorize other nonvectorized functions
        self._apex2qd = np.frompyfunc(self._apex2qd_nonvectorized, 3, 2)
        self._qd2apex = np.frompyfunc(self._qd2apex_nonvectorized, 3, 2)

    def convert(self, lat, lon, source, dest, height=0, datetime=None, precision=1e-10, ssheight=50*6371):
        '''Converts between geodetic, modified apex, quasi-dipole and MLT.

        Parameters
        ==========
        lat, lon : array_like
            Latitude and longitude/MLT
        source : {'geo', 'apex', 'qd', 'mlt'}
            Input coordinate system
        dest : {'geo', 'apex', 'qd', 'mlt'}
            Output coordinate system
        height : array_like, optional
            Altitude in km
        datetime : :class:`datetime.datetime`
            Date and time for MLT conversions (required for MLT conversions)
        precision : float, optional
            Precision of output (degrees) when converting to geo. A negative
            value of this argument produces a low-precision calculation of
            geodetic lat/lon based only on their spherical harmonic representation.
            A positive value causes the underlying Fortran routine to iterate
            until feeding the output geo lat/lon into geo2qd (APXG2Q) reproduces
            the input QD lat/lon to within the specified precision (all
            coordinates being converted to geo are converted to QD first and
            passed through APXG2Q).
        ssheight : float, optional
            Altitude in km to use for converting the subsolar point from
            geographic to magnetic coordinates. A high altitude is used
            to ensure the subsolar point is mapped to high latitudes, which
            prevents the South-Atlantic Anomaly (SAA) from influencing the MLT.

        Returns
        =======
        lat, lon : ndarray or float
            Converted latitude and longitude/MLT

        .. note::
            If converting to MLT, output latitude is apex.

        '''

        if datetime is None and ('mlt' in [source, dest]):
            raise ValueError('datetime must be given for MLT calculations')

        lat = helpers.checklat(lat)
<commit_msg>update documentation for napoleon<commit_after># -*- coding: utf-8 -*-

from __future__ import division, print_function, absolute_import

import os
import warnings
import datetime as dt

import numpy as np

from . import helpers
from .helpers import d2r, r2d

# below try..catch required for autodoc to work on readthedocs
try:
    from . import fortranapex as fa
except:
    print("ERROR: fortranapex module could not be imported. apexpy probably won't work")


# make sure invalid warnings are always shown
warnings.filterwarnings('always', message='.*set to -9999 where*', module='apexpy.apex')


class ApexHeightError(ValueError):
    pass


class Apex(object):
    '''Performs coordinate conversions, field-line mapping and base vector calculations.

    Parameters
    ==========
    date : float (decimal year) or :class:`datetime.date` or :class:`datetime.datetime`, optional
        Determines which IGRF coefficients are used in conversions. Uses current date as default.
    refh : float, optional
        Reference height in km for apex coordinates (the field lines are mapped to this height)
    datafile : str, optional
        Path to custom coefficient file

    Attributes
    ==========
    year : float
        Decimal year used for the IGRF model
    refh : float
        Reference height in km for apex coordinates
    datafile : str
        Path to coefficient file

    Notes
    =====
    The calculations use IGRF-12 with coefficients from 1900 to 2020 [1]_.

    References
    ==========

    .. [1] <NAME> al. (2015), International Geomagnetic Reference
           Field: the 12th generation, Earth, Planets and Space, 67(1), 79,
           doi:10.1186/s40623-015-0228-9.

    '''

    def __init__(self, date=None, refh=0, datafile=None):

        if datafile is None:
            datafile = os.path.join(os.path.dirname(__file__), 'apexsh.dat')

        self.RE = 6371.009  # mean Earth radius
        self.set_refh(refh)  # reference height

        if date is None:
            self.year = helpers.toYearFraction(dt.datetime.now())
        else:
            try:
                # convert date/datetime object to decimal year
                self.year = helpers.toYearFraction(date)
            except:
                # failed so date is probably int/float, use directly
                self.year = date

        if not os.path.isfile(datafile):
            raise IOError('Datafile does not exist: {}'.format(datafile))

        self.datafile = datafile
        self.set_epoch(self.year)

        # vectorize fortran functions
        self._geo2qd = np.frompyfunc(
            lambda glat, glon, height: fa.apxg2q(glat, (glon + 180) % 360 - 180, height, 0)[:2], 3, 2)
        self._geo2apex = np.frompyfunc(
            lambda glat, glon, height: fa.apxg2all(glat, (glon + 180) % 360 - 180, height, self.refh, 0)[2:4], 3, 2)
        self._geo2apexall = np.frompyfunc(
            lambda glat, glon, height: fa.apxg2all(glat, (glon + 180) % 360 - 180, height, self.refh, 1), 3, 14)
        self._qd2geo = np.frompyfunc(
            lambda qlat, qlon, height, precision: fa.apxq2g(qlat, (qlon + 180) % 360 - 180, height, precision), 4, 3)
        self._basevec = np.frompyfunc(
            lambda glat, glon, height: fa.apxg2q(glat, (glon + 180) % 360 - 180, height, 1)[2:4], 3, 2)

        # vectorize other nonvectorized functions
        self._apex2qd = np.frompyfunc(self._apex2qd_nonvectorized, 3, 2)
        self._qd2apex = np.frompyfunc(self._qd2apex_nonvectorized, 3, 2)

    def convert(self, lat, lon, source, dest, height=0, datetime=None, precision=1e-10, ssheight=50*6371):
        '''Converts between geodetic, modified apex, quasi-dipole and MLT.

        Parameters
        ==========
        lat : array_like
            Latitude
        lon : array_like
            Longitude/MLT
        source : {'geo', 'apex', 'qd', 'mlt'}
            Input coordinate system
        dest : {'geo', 'apex', 'qd', 'mlt'}
            Output coordinate system
        height : array_like, optional
            Altitude in km
        datetime : :class:`datetime.datetime`
            Date and time for MLT conversions (required for MLT conversions)
        precision : float, optional
            Precision of output (degrees) when converting to geo. A negative
            value of this argument produces a low-precision calculation of
            geodetic lat/lon based only on their spherical harmonic representation.
            A positive value causes the underlying Fortran routine to iterate
            until feeding the output geo lat/lon into geo2qd (APXG2Q) reproduces
            the input QD lat/lon to within the specified precision (all
            coordinates being converted to geo are converted to QD first and
            passed through APXG2Q).
        ssheight : float, optional
            Altitude in km to use for converting the subsolar point from
            geographic to magnetic coordinates. A high altitude is used
            to ensure the subsolar point is mapped to high latitudes, which
            prevents the South-Atlantic Anomaly (SAA) from influencing the MLT.

        Returns
        =======
        lat : ndarray or float
            Converted latitude
        lat : ndarray or float
            Converted longitude/MLT

        Note
        ====
        If converting to MLT, output latitude is apex.

        '''

        if datetime is None and ('mlt' in [source, dest]):
            raise ValueError('datetime must be given for MLT calculations')

        lat = helpers.checklat(lat)

{'fraction_non_alphanumeric': 0.09063745019920319, 'fraction_numerical': 0.027526258601955813, 'mean_word_length': 2.3622526636225265, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1311556', 'n_tokens_mistral': 3464, 'n_tokens_neox': 3095, 'n_words': 1119}