Skip to content
Snippets Groups Projects
Calculation.py 10.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • import numpy as np
    from .Ordinate import Ordinate
    
        """
        Class object for performing calculations.
        Contains the following:
        angle: average angle across a measurement type
        residual: average residual across a measurement type
        hs: Multiplier for inclination claculations. +1 if measurment was taken in northern hemisphere, -1 if measurement was taken in the southern hemishpere.
        ordinate: Variometer data. Ordinate object(contains a datapoint for H, E, Z, and F)
        ud: Multiplier for inclination calculations. +1 if instrument is oriented upward, -1 if instrument if oriented downward.
        shift: Degree shift in inclination measurements.
        """
    
    
            hs: int = None,
            ud: int = None,
            shift: int = None,
    
    def calculate_I(measurements, ordinates, ordinates_index, total_ordinate, metadata):
    
        """
        Calculate inclination angles from measurements, ordinates,
        average ordinates from every measurement, and metadata.
        Returns inclination angle and calculated average f
        """
    
        # get first inclination angle, assumed to be southdown
        Iprime = average_angle(measurements, "SouthDown")
    
        if Iprime >= 90:
            Iprime -= 180
        Iprime = np.deg2rad(Iprime)
    
        # get multiplier for hempisphere the observatory is located in
        # 1 if observatory is in northern hemisphere
        # -1 if observatory is in southern hemisphere
        hs = metadata["hemisphere"]
    
        # gather calculation objects for each measurement type
    
            shift=-180,
            inclination=Iprime,
            ud=-1,
            measurements=measurements,
    
            ordinates=ordinates_index,
    
            total_ordinate=total_ordinate,
            type="SouthDown",
            hs=hs,
    
    Cain, Payton David's avatar
    Cain, Payton David committed
        )
        southup = process_type(
    
            shift=180,
            inclination=Iprime,
            ud=1,
            measurements=measurements,
    
            ordinates=ordinates_index,
    
            total_ordinate=total_ordinate,
            type="SouthUp",
            hs=hs,
    
    Cain, Payton David's avatar
    Cain, Payton David committed
        )
        northup = process_type(
    
            shift=0,
            inclination=Iprime,
            ud=1,
            measurements=measurements,
    
            ordinates=ordinates_index,
    
            total_ordinate=total_ordinate,
            type="NorthUp",
            hs=hs,
    
        northdown = process_type(
            shift=0,
            inclination=Iprime,
            ud=-1,
            measurements=measurements,
    
            ordinates=ordinates_index,
    
            total_ordinate=total_ordinate,
            type="NorthDown",
            hs=hs,
    
        # gather measurements into array
        measurements = [southdown, southup, northdown, northup]
        # Get average inclination from measurments
    
            [calculate_measurement_inclination(i, total_ordinate.f) for i in measurements]
    
        # iterate calculations until the difference in the resultant inclination angle is less than 0.0001
        # intialize inclination for current step to be outside threshold specified in condition
        Inclination = inclination + 1
        while abs(inclination - Inclination) >= 0.0001:
            # establish the inclination angle as the previously calculated average inclination angle
            Inclination = inclination
            # calculate average f component from each measurement
    
                [calculate_f(i, total_ordinate, Inclination) for i in ordinates]
    
            # update ordinate's f value as the average f component
            # used in next iterations f_avg calculation
    
            total_ordinate.f = f_avg
    
            # re-calculate inclination for measurement types
            inclination = np.average(
    
                [
                    calculate_measurement_inclination(i, total_ordinate.f)
                    for i in measurements
                ]
    
            # transfer inclination angle from degrees to radians
            inclination = np.deg2rad(inclination)
    
    Cain, Payton David's avatar
    Cain, Payton David committed
    def calculate_D(ordinates, measurements, measurements_index, AZ, Hb):
    
        """
        Calculate declination absolute and declination baseline from
        ordinates, measurements, measurement_index(dictionary), azimuth and H baseline
        Returns absolute and baseline for declination.
        """
    
        # compute average angle from marks
        average_mark = np.average(
    
            [m.angle for m in measurements if "mark" in m.measurement_type.capitalize()]
    
        # gather calculation objects for each measurement type
    
        southdown = process_type(
            measurements=measurements_index,
            ordinates=ordinates,
            baseline=Hb,
            type="SouthDown",
        )
        southup = process_type(
            measurements=measurements_index,
            ordinates=ordinates,
            baseline=Hb,
            type="SouthUp",
        )
        northdown = process_type(
            measurements=measurements_index,
            ordinates=ordinates,
            baseline=Hb,
            type="NorthDown",
        )
        northup = process_type(
            measurements=measurements_index,
            ordinates=ordinates,
            baseline=Hb,
            type="NorthUp",
        )
        # gather measurements into array
        measurements = [southdown, southup, northup, northdown]
        # get average meridian angle from measurement types
    
        meridian = np.average([calculate_meridian_term(i) for i in measurements])
    
        # add average mark, meridian, and azimuth angle to get declination baseline
    
        Db = (average_mark + meridian + AZ) * 60
        # calculate declination absolute
        Dabs = Db + np.arctan(southdown.ordinate.e / (Hb + southdown.ordinate.h)) * (
            10800 / np.pi
        )
    
    def calculate_absolutes(f, inclination, pier_correction):
        """
        Calculate absolutes for H, Z and F from computed
        average f value(from inclination computations),
        calculated inclination angle, and pier correction(metadata).
        Returns baselines for H, Z, and F
        """
        i = np.deg2rad(inclination)
    
        Fabs = f + pier_correction
        Habs = Fabs * np.cos(i)
        Zabs = Fabs * np.sin(i)
    
        return Habs, Zabs, Fabs
    
    
    def calculate_baselines(Habs, Zabs, total_ordinate):
    
        """
        Calculate baselines with H and Z absolutes, and
        average ordinates across all measurements.
        Returns H and Z baselines
        """
    
        h_mean = total_ordinate.h
        e_mean = total_ordinate.e
        z_mean = total_ordinate.z
    
        Hb = np.sqrt(Habs ** 2 - e_mean ** 2) - h_mean
        Zb = Zabs - z_mean
    
        return Hb, Zb
    
    
    
    def calculate_scale(f, measurements, inclination, pier_correction):
        """
        Calculate scale value from calulated f(from inclination computations),
        calculated inclination, and pier correction(metadata)
        """
        i = np.deg2rad(inclination)
    
        angle_diff = (np.diff([m.angle for m in measurements]) / f)[0]
    
        A = np.cos(i) * angle_diff
        B = np.sin(i) * angle_diff
        delta_f = np.rad2deg(A - B)
    
        detla_r = abs(np.diff([m.residual for m in measurements]))[0]
        time_delta = np.diff([m.time for m in measurements])[0]
    
        delta_b = delta_f + (time_delta / 60.0)
    
        scale_value = f * np.deg2rad(delta_b / detla_r)
    
        return scale_value
    
    
    def average_angle(measurements, type):
    
        """
        Compute average angle from a dictionary of
        measurements and specified measurement type.
        """
    
            # exclude final measurement, which is only used for scaling
    
            measurements = measurements[type][:-1]
        else:
            measurements = measurements[type]
        return np.average([m.angle for m in measurements])
    
        """
        Compute average residual from a dictionary
        of measurements and specified measurement type.
        """
    
            # exclude final measurement, which is only used for scaling
    
            measurements = measurements[type][:-1]
        else:
            measurements = measurements[type]
        return np.average([m.residual for m in measurements])
    
    Cain, Payton David's avatar
    Cain, Payton David committed
    def average_ordinate(ordinates, type):
    
        """
        Compute average ordinate from a dictionary
        of ordinates and specified measurement type.
        """
    
            # exclude final measurement, which is only used for scaling
    
    Cain, Payton David's avatar
    Cain, Payton David committed
            ordinates = ordinates[type][:-1]
    
        elif type is not None:
    
    Cain, Payton David's avatar
    Cain, Payton David committed
            ordinates = ordinates[type]
    
        elif type is None:
            ordinates = ordinates[:-1]
    
        o = Ordinate(measurement_type=type)
    
    Cain, Payton David's avatar
    Cain, Payton David committed
        avgs = np.average([[o.h, o.e, o.z, o.f] for o in ordinates], axis=0,)
    
        o.h, o.e, o.z, o.f = avgs
        return o
    
    def calculate_f(ordinate, total_ordinate, inclination):
        """
        calculate f for a measurement type using a measurement's
        average ordinates, average ordinate across all measurements,
        and calculated inclination.
        """
    
        # get channel means form all ordinates
        h_mean = total_ordinate.h
        e_mean = total_ordinate.e
        z_mean = total_ordinate.z
        f_mean = total_ordinate.f
        # get individual ordinate means
        h = ordinate.h
        e = ordinate.e
        z = ordinate.z
        # calculate f using current step's inclination angle
        f = (
            f_mean
    
            + (h - h_mean) * np.cos(inclination)
            + (z - z_mean) * np.sin(inclination)
    
            + ((e) ** 2 - (e_mean) ** 2) / (2 * f_mean)
        )
        return f
    
    
    
    def calculate_measurement_inclination(calculation, f):
    
        """
        Calculate a measurement's inclination value using
        Calculate items' elements.
        """
        shift = calculation.shift
        angle = calculation.angle
        ud = calculation.ud
        hs = calculation.hs
        r = calculation.residual
        return shift + angle + ud * np.rad2deg(hs * np.sin(r / f))
    
    
    def process_type(
        measurements,
        ordinates,
        type,
        total_ordinate=None,
        shift=None,
        ud=None,
        inclination=None,
        baseline=None,
        hs=None,
    ):
        """
        Create a Calculation object for each
        measurement within a measurement type.
        """
    
    Cain, Payton David's avatar
    Cain, Payton David committed
        c = Calculate()
    
        c.angle = average_angle(measurements, type)
        c.residual = average_residual(measurements, type)
        c.ordinate = average_ordinate(ordinates, type)
    
        c.baseline = baseline
    
    def calculate_meridian_term(calculation):
    
        """
        Calculate meridian value from a measurement type
        using a Calculate object and H's baseline value.
        """
    
    Cain, Payton David's avatar
    Cain, Payton David committed
        A1 = np.arcsin(
    
                (calculation.ordinate.h + calculation.baseline) ** 2
                + (calculation.ordinate.e) ** 2
    
        A2 = np.arctan(
            calculation.ordinate.e / (calculation.ordinate.h + calculation.baseline)
        )
    
        A1 = np.rad2deg(A1)
        A2 = np.rad2deg(A2)
        meridian_term = calculation.angle - A1 - A2
        return meridian_term