From 7b4aa150a3731ecf51e3963466e1ed35994c744d Mon Sep 17 00:00:00 2001 From: pcain-usgs <pcain@usgs.gov> Date: Thu, 9 Apr 2020 12:27:06 -0600 Subject: [PATCH] Clean up/ add comments --- geomagio/residual/Calculation.py | 176 +++++++++--------- geomagio/residual/Reading.py | 2 +- .../residual/SpreadsheetAbsolutesFactory.py | 6 +- 3 files changed, 91 insertions(+), 93 deletions(-) diff --git a/geomagio/residual/Calculation.py b/geomagio/residual/Calculation.py index 4d407f5a6..86f3cc954 100644 --- a/geomagio/residual/Calculation.py +++ b/geomagio/residual/Calculation.py @@ -22,10 +22,7 @@ class Calculate(object): angle: float = None, residual: float = None, ordinate: Ordinate = None, - baseline: float = None, f: float = None, - inclination: float = None, - hs: int = None, ud: int = None, shift: int = None, pm: int = None, @@ -33,26 +30,26 @@ class Calculate(object): self.angle = angle self.residual = residual self.ordinate = ordinate - self.baseline = baseline self.f = f - self.inclination = inclination - self.hs = hs self.ud = ud self.shift = shift self.pm = pm def calculate(Reading): - # get average ordinate values across h, e, z, and f + """ + Calculate/recalculate absolute from a Reading object's + ordinates, measurements, and metadata. + Outputs a list of absolutes containing baseline, absolute, + and element name. Also reutrns the scale value. + """ + # define measurement types used to calculate inclination + inclination_types = [mt.NORTH_DOWN, mt.NORTH_UP, mt.SOUTH_DOWN, mt.SOUTH_UP] + # get ordinate values across h, e, z, and f for inclination measurement types inclination_ordinates = [ - o - for o in Reading.ordinates - if "West" not in o.measurement_type.capitalize() - and "East" not in o.measurement_type.capitalize() - and "NorthDownScale" not in o.measurement_type.capitalize() + o for o in Reading.ordinates if o.measurement_type in inclination_types ] - - inclination_ordinates = inclination_ordinates[0:-2] + # get average ordinate values across h, e, z, and f mean = average_ordinate(inclination_ordinates, None) # calculate inclination inclination, f = calculate_I( @@ -63,13 +60,10 @@ def calculate(Reading): Reading.metadata, ) # calculate absolutes - # FIXME: change to self.pier_correction - Habs, Zabs = calculate_absolutes( - f, inclination, Reading.metadata["pier_correction"] - ) - # calculate baselines + Habs, Zabs = calculate_absolutes(f, inclination) + # calculate baselines for H and Z Hb, Zb = calculate_baselines(Habs, Zabs, mean, Reading.pier_correction) - # calculate scale value for declination + # calculate scale value scale_ordinates = Reading.ordinate_index()["NorthDownScale"] scale_measurements = Reading.measurement_index()["NorthDownScale"] scale = calculate_scale( @@ -77,9 +71,8 @@ def calculate(Reading): scale_ordinates, scale_measurements, inclination, - Reading.metadata["pier_correction"], ) - # calculate declination and + # calculate declination absolute and baseline Db, Dabs = calculate_D( Reading.ordinate_index(), Reading.measurements, @@ -104,11 +97,10 @@ def calculate_I(measurements, ordinates, ordinates_index, mean, metadata): average ordinates from every measurement, and metadata. Returns inclination angle and calculated average f """ - # get first inclination angle, assumed to be southdown + # get first inclination angle, assumed to be the southdown angle Iprime = average_angle(measurements, "SouthDown") if Iprime >= 100: Iprime -= 200 - # Iprime = (np.pi / 200)*(Iprime) # get multiplier for hempisphere the observatory is located in # 1 if observatory is in northern hemisphere # -1 if observatory is in southern hemisphere @@ -117,7 +109,6 @@ def calculate_I(measurements, ordinates, ordinates_index, mean, metadata): southdown = Calculate( shift=-200, ud=1, - hs=hs, pm=1, angle=average_angle(measurements, "SouthDown"), residual=average_residual(measurements, "SouthDown"), @@ -127,7 +118,6 @@ def calculate_I(measurements, ordinates, ordinates_index, mean, metadata): southup = Calculate( shift=200, ud=-1, - hs=hs, pm=-1, angle=average_angle(measurements, "SouthUp"), residual=average_residual(measurements, "SouthUp"), @@ -137,7 +127,6 @@ def calculate_I(measurements, ordinates, ordinates_index, mean, metadata): northup = Calculate( shift=0, ud=-1, - hs=hs, pm=1, angle=average_angle(measurements, "NorthUp"), residual=average_residual(measurements, "NorthUp"), @@ -147,33 +136,33 @@ def calculate_I(measurements, ordinates, ordinates_index, mean, metadata): northdown = Calculate( shift=400, ud=1, - hs=hs, pm=-1, angle=average_angle(measurements, "NorthDown"), residual=average_residual(measurements, "NorthDown"), ordinate=average_ordinate(ordinates_index, "NorthDown"), ) - + # set inclination value for looping = Iprime inclination = Iprime + # add one to inclination value to enter the loop Inclination = inclination + 1 - + # loop condition while abs(Inclination - inclination) > 0.0001: + # set temporary inclination variable to hold previous step's inclination Inclination = inclination - + # calculate f for inclination measurement types southdown.f = calculate_f(southdown.ordinate, mean, inclination) northdown.f = calculate_f(northdown.ordinate, mean, inclination) southup.f = calculate_f(southup.ordinate, mean, inclination) northup.f = calculate_f(northup.ordinate, mean, inclination) - - northup.inclination = calculate_measurement_inclination(northup) - southdown.inclination = calculate_measurement_inclination(southdown) - northdown.inclination = calculate_measurement_inclination(northdown) - southup.inclination = calculate_measurement_inclination(southup) - + # gather measurements into array(necessary because f were recalculated) measurements = [southup, southdown, northup, northdown] - - inclination = np.average([i.inclination for i in measurements]) + # average f values for inclination measurement types f = np.average([i.f for i in measurements]) + # calculation inclination for each inclination measurement type and average + inclination = np.average( + [calculate_measurement_inclination(m, hs) for m in measurements] + ) + # loop exits once the difference in average inclination between steps is lower than 0.0001 return inclination, f @@ -184,15 +173,24 @@ def calculate_D(ordinates_index, measurements, measurements_index, AZ, Hb): ordinates, measurements, measurement_index(dictionary), azimuth and H baseline Returns absolute and baseline for declination. """ - # compute average angle from marks + # specify mark measurement types + mark_types = [ + mt.FIRST_MARK_DOWN, + mt.FIRST_MARK_UP, + mt.SECOND_MARK_DOWN, + mt.SECOND_MARK_UP, + ] + # average mark angles + # note that angles are being converted to geon average_mark = np.average( [ convert_to_geon(m.angle) for m in measurements - if "mark" in m.measurement_type.capitalize() + if m.measurement_type in mark_types ] ) - + # add 100 if mark up is greater than mark down + # subtract 100 otherwise if ( measurements_index["FirstMarkUp"][0].angle < measurements_index["FirstMarkDown"][0].angle @@ -201,67 +199,66 @@ def calculate_D(ordinates_index, measurements, measurements_index, AZ, Hb): else: average_mark -= 100 - # if average_mark < 200: - # average_mark += 100 - # else: - # average_mark -= 100 - - # gather calculation objects for each measurement type + # gather calculation objects for each declination measurement type + # note that the pm(plus minus) multiplier has been repurposed. + # West facing measurements have a multiplier of -1 + # East facing measurements have a multipllier of 1 westdown = Calculate( - baseline=Hb, angle=average_angle(measurements_index, "WestDown"), residual=average_residual(measurements_index, "WestDown"), ordinate=average_ordinate(ordinates_index, "WestDown"), - ud=-1, + pm=-1, ) westup = Calculate( - baseline=Hb, angle=average_angle(measurements_index, "WestUp"), residual=average_residual(measurements_index, "WestUp"), ordinate=average_ordinate(ordinates_index, "WestUp"), - ud=-1, + pm=-1, ) eastdown = Calculate( - baseline=Hb, angle=average_angle(measurements_index, "EastDown"), residual=average_residual(measurements_index, "EastDown"), ordinate=average_ordinate(ordinates_index, "EastDown"), - ud=1, + pm=1, ) eastup = Calculate( - baseline=Hb, angle=average_angle(measurements_index, "EastUp"), residual=average_residual(measurements_index, "EastUp"), ordinate=average_ordinate(ordinates_index, "EastUp"), - ud=1, + pm=1, ) - # AZ = convert_to_geon(AZ, include_seconds=False) + # convert azimuth to geon AZ = (int(AZ / 100) + (AZ % 100) / 60) / 0.9 - # gather measurements into array + # gather declination measurements into array measurements = [westdown, westup, eastdown, eastup] - # 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_abs = (meridian - average_mark) + AZ - Db = round(Db_abs * 54, 2) + # average meridian terms calculated from each declination measurements + meridian = np.average([calculate_meridian_term(i, Hb) for i in measurements]) + # add subtract average mark angle from average meridian angle and add + # azimuth(in geon) to get the declination baseline + D_b = (meridian - average_mark) + AZ + # convert decimal baseline into dms baseline + Db = round(D_b * 54, 2) Db_dms = int(Db / 60) * 100 + ((Db / 60) % 1) * 60 - # calculate declination absolute + # gather first declination measurements' H ans E ordinates wd_E_1 = ordinates_index["WestDown"][0].e wd_H_1 = ordinates_index["WestDown"][0].h - Dabs = Db_abs + np.arctan(wd_E_1 / (Hb + wd_H_1)) * (200 / np.pi) + # calculate Declination baseline + Dabs = D_b + np.arctan(wd_E_1 / (Hb + wd_H_1)) * (200 / np.pi) Dabs = round(Dabs * 54, 1) + # convert decimal absolute into dms absolute Dabs_dms = int(Dabs / 60) * 100 + ((Dabs / 60) % 1) * 60 return Db_dms, Dabs_dms -def calculate_absolutes(f, inclination, pier_correction): +def calculate_absolutes(f, inclination): """ 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 + average f value(from inclination computations) and + calculated inclination angle. + Returns baselines for H and Z """ + # convert inclination to radians i = (np.pi / 200) * (inclination) Habs = f * np.cos(i) Zabs = f * np.sin(i) @@ -271,11 +268,11 @@ def calculate_absolutes(f, inclination, pier_correction): def calculate_baselines(Habs, Zabs, mean, pier_correction): """ - Calculate baselines with H and Z absolutes, and - average ordinates across all measurements. + Calculate baselines with H and Z absolutes, + average ordinates across all measurements, + and pier correction(metadata). Returns H and Z baselines """ - # FIXME: Figure out where 0.3 comes from correction = pier_correction / 5 Hb = round(np.sqrt(Habs ** 2 - mean.e ** 2) - mean.h, 1) - correction Zb = round(Zabs - mean.z, 1) - correction @@ -283,10 +280,12 @@ def calculate_baselines(Habs, Zabs, mean, pier_correction): return Hb, Zb -def calculate_scale(f, ordinates, measurements, inclination, pier_correction): +def calculate_scale(f, ordinates, measurements, inclination): """ Calculate scale value from calulated f(from inclination computations), - calculated inclination, and pier correction(metadata) + inclination, and the measurements/ordinates taken for scaling purposes. + Such measurements usually present themselves as a set of three North Down + measurements, where the final two measuremets(and ordinates) are used for scaling. """ first_ord = ordinates[0] second_ord = ordinates[1] @@ -316,7 +315,6 @@ def average_angle(measurements, type): Compute average angle from a dictionary of measurements and specified measurement type. """ - # FIXME: change repetitive checks return np.average([convert_to_geon(m.angle) for m in measurements[type]]) @@ -333,7 +331,6 @@ def average_ordinate(ordinates, type): Compute average ordinate from a dictionary of ordinates and specified measurement type. """ - # FIXME: change repetitive checks if type is not None: ordinates = ordinates[type] o = Ordinate(measurement_type=type) @@ -349,7 +346,6 @@ def calculate_f(ordinate, mean, inclination): and calculated inclination. """ # get channel means form all ordinates - # FIXME: don't unpack ordinates # calculate f using current step's inclination angle f = ( mean.f @@ -360,39 +356,38 @@ def calculate_f(ordinate, mean, inclination): return f -def calculate_measurement_inclination(calc): +def calculate_measurement_inclination(calculation, hs): """ Calculate a measurement's inclination value using Calculate items' elements. """ - return calc.shift + calc.pm * ( - +calc.angle - + calc.ud * (calc.hs * np.arcsin(calc.residual / calc.f) * 200 / np.pi) + return calculation.shift + calculation.pm * ( + +calculation.angle + + calculation.ud + * (hs * np.arcsin(calculation.residual / calculation.f) * 200 / np.pi) ) -def calculate_meridian_term(calculation): +def calculate_meridian_term(calculation, Hb): """ Calculate meridian value from a measurement type using a Calculate object and H's baseline value. """ A1 = np.arcsin( calculation.residual - / np.sqrt( - (calculation.ordinate.h + calculation.baseline) ** 2 - + (calculation.ordinate.e) ** 2 - ) - ) - A2 = np.arctan( - calculation.ordinate.e / (calculation.ordinate.h + calculation.baseline) + / np.sqrt((calculation.ordinate.h + Hb) ** 2 + (calculation.ordinate.e) ** 2) ) + A2 = np.arctan(calculation.ordinate.e / (calculation.ordinate.h + Hb)) A1 = (200 / np.pi) * (A1) A2 = (200 / np.pi) * (A2) - meridian_term = calculation.angle + (calculation.ud * A1) - A2 + meridian_term = calculation.angle + (calculation.pm * A1) - A2 return meridian_term def convert_to_geon(angle, include_seconds=True): + """ + Convert angles from measurements to geon + """ degrees = int(angle) minutes = int((angle % 1) * 100) / 60 if include_seconds: @@ -400,4 +395,5 @@ def convert_to_geon(angle, include_seconds=True): else: seconds = 0 dms = (degrees + minutes + seconds) / 0.9 + return dms diff --git a/geomagio/residual/Reading.py b/geomagio/residual/Reading.py index aa4035114..531eb6a46 100644 --- a/geomagio/residual/Reading.py +++ b/geomagio/residual/Reading.py @@ -25,7 +25,7 @@ class Reading(BaseModel): absolutes: Optional[List[Absolute]] = None azimuth: float = 0 - hemisphere: float = 1 # maybe hemisphere should be calculated from latitude + hemisphere: float = 1 measurements: Optional[List[Measurement]] = [] ordinates: Optional[List[Ordinate]] = [] metadata: Optional[Dict] = [] diff --git a/geomagio/residual/SpreadsheetAbsolutesFactory.py b/geomagio/residual/SpreadsheetAbsolutesFactory.py index 0fd164794..1952e8429 100644 --- a/geomagio/residual/SpreadsheetAbsolutesFactory.py +++ b/geomagio/residual/SpreadsheetAbsolutesFactory.py @@ -279,8 +279,10 @@ class SpreadsheetAbsolutesFactory(object): and self._parse_measurements(measurement_sheet, metadata["date"],) or None ) - ordinates = include_measurements and self._parse_ordinates( - measurement_sheet, metadata["date"] + ordinates = ( + include_measurements + and self._parse_ordinates(measurement_sheet, metadata["date"]) + or None ) return Reading( absolutes=absolutes, -- GitLab