Source code for gdt.core.geomagnetic

# CONTAINS TECHNICAL DATA/COMPUTER SOFTWARE DELIVERED TO THE U.S. GOVERNMENT WITH UNLIMITED RIGHTS
#
# Contract No.: CA 80MSFC17M0022
# Contractor Name: Universities Space Research Association
# Contractor Address: 7178 Columbia Gateway Drive, Columbia, MD 21046
#
# Copyright 2017-2022 by Universities Space Research Association (USRA). All rights reserved.
#
# Developed by: William Cleveland and Adam Goldstein
#               Universities Space Research Association
#               Science and Technology Institute
#               https://sti.usra.edu
#
# Developed by: Daniel Kocevski
#               National Aeronautics and Space Administration (NASA)
#               Marshall Space Flight Center
#               Astrophysics Branch (ST-12)
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
# in compliance with the License. You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing permissions and limitations under the
# License.
#
import os
import numpy as np

__all__ = ['SouthAtlanticAnomaly']

[docs]class SouthAtlanticAnomaly(): """A base class for a South Atlantic Anomaly (SAA) boundary in Earth latitude and longitude. This class should be further sub-classed with the following the class variables: * _latitude - A list or array of latitude points * _longitude - A list or array of longitude points """ def __init__(self): # _latitude and _longitude must be set if not hasattr(self, '_latitude'): raise AttributeError("SouthAtlanticAnomaly must have class " \ "attribute '_latitude' defined") if not hasattr(self, '_longitude'): raise AttributeError("SouthAtlanticAnomaly must have class " \ "attribute '_longitude' defined") self._latitude = np.asarray(self._latitude) self._longitude = np.asarray(self._longitude) if self._latitude.size != self._longitude.size: raise ValueError('_longitude and _latitude must be the same size') @property def latitude(self): """(np.array): The latitude points of the boundary""" return self._latitude @property def longitude(self): """(np.array): The longitude points of the boundary""" return self._longitude @property def num_points(self): """(int): Number of vertices in polygon""" return self.latitude.size
[docs] def is_closed(self): """Test if the boundary represents a closed polygon. A closed polygon is one where the first and last points are equal. Returns: (bool) """ if (self.latitude[0] == self.latitude[-1]) & \ (self.longitude[0] == self.longitude[-1]): return True else: return False
[docs] def is_convex(self): """Test if the boundary represents a convex polygon. The test is performed by measuring every interior angle of the polygon and checking if all angles are < 180 deg. The definition of a convex polygon is one where all interior angles are < 180 deg. Returns: (bool) """ # calculate the vectors dlat = self.latitude[1:] - self.latitude[:-1] dlon = self.longitude[1:] - self.longitude[:-1] dz = np.zeros_like(dlon) vec = np.vstack((dlon, dlat, dz)) norms = np.linalg.norm(vec, axis=0) winding = 0.0 angles = np.zeros(dlat.size-1) for i in range(dlat.size-1): sign = np.sign(np.cross(vec[:,i], vec[:,i+1])[-1]) angle = sign * np.arccos(np.dot(vec[:,i], vec[:,i+1]) / \ (norms[i] * norms[i+1])) angles[i] = angle winding += angle if winding < 0.0: angles += np.pi else: angles = np.pi - angles if (angles >= np.pi).sum() > 0: return False else: return True