Newer
Older

Jeremy M Fee
committed
from typing import List, Literal, Tuple
import numpy as np
from .Absolute import Absolute
from .MeasurementType import (
MeasurementType as mt,
DECLINATION_TYPES,
INCLINATION_TYPES,
MARK_TYPES,
)
from .Measurement import AverageMeasurement, Measurement, average_measurement
from .Diagnostics import Diagnostics
def calculate(reading: Reading, adjust_reference: bool = True) -> Reading:
"""Calculate absolutes and scale value using residual method.
Parameters
-------
reading: reading to calculate absolutes from.
Returns
-------
new reading object with calculated absolutes and scale_value.
NOTE: rest of reading object is shallow copy.
# reference measurement, used to adjust absolutes
missing_types = reading.get_missing_measurement_types()
if len(missing_types) != 0:
missing_types = ", ".join(t.value for t in missing_types)
raise ValueError(f"Missing {missing_types} measurements in input reading")
reference = adjust_reference and reading[mt.WEST_DOWN][0] or None
# calculate inclination
inclination, f, i_mean = calculate_I(
hemisphere=reading.hemisphere, measurements=reading.measurements
)
corrected_f = f + reading.pier_correction
# calculate absolutes
absoluteH, absoluteZ = calculate_HZ_absolutes(
corrected_f=corrected_f,
inclination=inclination,
reference=reference,
absoluteD, meridian = calculate_D_absolute(
azimuth=reading.azimuth,
h_baseline=absoluteH.baseline,
measurements=reading.measurements,
reference=reference,
d_computed=calculate_D_computed(
measurements=reading.measurements,
h_baseline=absoluteH.baseline,
r_computed=calculate_R_computed(
measurements=reading.measurements,
h_baseline=absoluteH.baseline,
)
magnetic_south_meridian=calculate_magnetic_south_meridian(
measurements=reading.measurements,
)
scale_value = None
scale_measurements = reading[mt.NORTH_DOWN_SCALE]
if scale_measurements:
scale_value = calculate_scale_value(
corrected_f=corrected_f,
inclination=inclination,
measurements=scale_measurements,
mean_mark = calculate_mean_mark(
measurements=reading.measurements,
)
magnetic_azimuth_of_mark=calculate_magnetic_azimuth_of_mark(
mean_mark=mean_mark,
magnetic_south_meridian=magnetic_south_meridian
)
# populate diagnostics object with averaged measurements
diagnostics = Diagnostics(
inclination=inclination,
meridian=meridian,
d_computed=d_computed,
r_computed=r_computed,
magnetic_south_meridian=magnetic_south_meridian,
corrected_f=corrected_f,
scale_value=scale_value,
mean_mark=mean_mark,
magnetic_azimuth_of_mark=magnetic_azimuth_of_mark,
)
# create new reading object
calculated = Reading(
absolutes=[absoluteD, absoluteH, absoluteZ],
diagnostics=diagnostics,
**reading.dict(exclude={"absolutes", "diagnostics"}),
print("*******************************************")
print()
print("\033[91mPRINT:\033[0m", calculated.diagnostics)
print("\033[91mPRINT:\033[0m", reading)
print()
print("*******************************************")
def calculate_D_absolute(
measurements: List[Measurement],
azimuth: float,
h_baseline: float,
reference: Measurement,
) -> Tuple[Absolute, Diagnostics]:
Parameters
----------
measurements: list with at least declination and mark measurements.
azimuth: azimuth to mark in decimal degrees.
h_baseline: calculated H baseline value.
reference: reference measurement used to adjust absolute.
Returns
-------
D Absolute
Cain, Payton David
committed
"""
mean = average_measurement(measurements, DECLINATION_TYPES)
if reference:
starttime = reference.time
endtime = reference.time
else:
starttime = mean.time
endtime = mean.endtime
reference = reference or mean
average_mark = average_measurement(measurements, MARK_TYPES)
# adjust based on which is larger
mark_up = average_measurement(measurements, [mt.FIRST_MARK_UP]).angle
mark_down = average_measurement(measurements, [mt.FIRST_MARK_DOWN]).angle
if mark_up < mark_down:
average_mark.angle += 90
average_mark.angle -= 90
# declination measurements
declination_measurements = [
average_measurement(measurements, [t]) for t in DECLINATION_TYPES
]
# average declination meridian
meridian = np.average(
[
m.angle
+ np.degrees(
m.measurement_type.meridian

Jeremy M Fee
committed
* (np.arcsin(m.residual / np.sqrt((m.h + h_baseline) ** 2 + m.e**2)))
)
- np.degrees(np.arctan(m.e / (m.h + h_baseline)))
for m in declination_measurements
]
)
if azimuth > 180:
# add subtract average mark angle from average meridian angle and add
# azimuth to get the declination baseline
d_b = (meridian - average_mark.angle) + azimuth + shift
d_abs = d_b + np.degrees(np.arctan(reference.e / (reference.h + h_baseline)))
return (
Absolute(
element="D",
absolute=d_abs,
baseline=d_b,
shift=shift,
starttime=starttime,
endtime=endtime,
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
def calculate_HZ_absolutes(
inclination: float,
corrected_f: float,
mean: AverageMeasurement,
reference: Measurement,
) -> Tuple[Absolute, Absolute]:
"""Calculate H and Z absolutes.
Parameters
----------
inclination: calculated inclination.
corrected_f: calculated f with pier correction.
mean: mean of inclination ordinates.
reference: reference measurement used to adjust absolutes.
Returns
-------
Tuple
- H Absolute
- Z Absolute
"""
inclination_radians = np.radians(inclination)
h_abs = corrected_f * np.cos(inclination_radians)
z_abs = corrected_f * np.sin(inclination_radians)

Jeremy M Fee
committed
h_b = np.sqrt(h_abs**2 - mean.e**2) - mean.h
# adjust absolutes to reference measurement
h_abs = np.sqrt((h_b + reference.h) ** 2 + (reference.e) ** 2)
z_abs = z_b + reference.z
starttime = reference.time
endtime = reference.time
else:
starttime = mean.time
endtime = mean.endtime
# return absolutes
return (
Absolute(
element="H",
baseline=h_b,
absolute=h_abs,
starttime=starttime,
endtime=endtime,
),
Absolute(
element="Z",
baseline=z_b,
absolute=z_abs,
starttime=starttime,
endtime=endtime,
),
)
def calculate_I(
measurements: List[Measurement], hemisphere: Literal[-1, 1] = 1
) -> Tuple[float, float, Measurement]:
"""Calculate inclination and f from measurements.
Parameters
----------
measurements: list with at least inclination measurements.
hemisphere: +1 for northern hemisphere (default), -1 for southern hemisphere.
Returns
-------
Tuple
- inclination angle in decimal degrees
- uncorrected calculated f
- mean of inclination measurements
Cain, Payton David
committed
"""
mean = average_measurement(measurements, INCLINATION_TYPES)
inclination_measurements = [
average_measurement(measurements, [t]) for t in INCLINATION_TYPES
]
# get initial inclination angle, assumed to be the southdown angle
inclination = average_measurement(measurements, [mt.SOUTH_DOWN]).angle
if inclination >= 90:
inclination -= 180
# loop until inclination converges
last_inclination = inclination + 1
while abs(last_inclination - inclination) > 0.0001:
# set temporary inclination variable to hold previous step's inclination
last_inclination = inclination
# Update measurement f based on inclination
inclination_radians = np.radians(inclination)
m.f = (
mean.f
+ (m.h - mean.h) * np.cos(inclination_radians)
+ (m.z - mean.z) * np.sin(inclination_radians)
+ ((m.e) ** 2 - (mean.e) ** 2) / (2 * mean.f)
(
m.measurement_type.shift
+ m.measurement_type.meridian
* (
+m.angle
+ m.measurement_type.direction
* (hemisphere * np.degrees(np.arcsin(m.residual / m.f)))
# calculate uncorrected f
f = np.average([m.f for m in inclination_measurements])
def calculate_scale_value(
measurements: List[Measurement], inclination: float, corrected_f: float
) -> float:
"""Calculate scale value.
Parameters
----------
measurements: measurements to be used for scale calculation.
should have type NORTH_DOWN_SCALE.
inclination: calculated inclination.
corrected_f: calculated f with pier correction.
Returns
-------
Calculated scale value.
Cain, Payton David
committed
"""
m1, m2 = measurements[0], measurements[-1]
field_change = np.degrees(
(
-np.sin(inclination_radians) * (m2.h - m1.h)
+ np.cos(inclination_radians) * (m2.z - m1.z)
/ corrected_f
) + (m2.angle - m1.angle)
residual_change = m2.residual - m1.residual
scale_value = corrected_f * field_change / np.abs(residual_change)
return scale_value
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
def calculate_magnetic_south_meridian(
measurements: List[Measurement]) -> float:
"""Calculate magnetic_south_meridian.
Parameters
----------
measurements: measurements, should have type WEST_DOWN, EAST_DOWN, WEST_UP, EAST_UP.
Returns
-------
Calculated magnetic_south_meridian.
"""
# declination measurements
declination_measurements = [
average_measurement(measurements, [t]) for t in DECLINATION_TYPES
]
magnetic_south_meridian = np.average(
[
m.angle
for m in declination_measurements
]
)
return magnetic_south_meridian
def calculate_D_computed(
measurements: List[Measurement],
h_baseline: float,) -> float:
"""Calculate d_computed.
Parameters
----------
measurements: measurements,
h_baseline
Returns
-------
Calculated d_computed.
"""
# declination measurements
declination_measurements = [
average_measurement(measurements, [t]) for t in DECLINATION_TYPES
]
d_computed = np.average(
[np.degrees(np.arctan(m.e / (m.h + h_baseline)))
for m in declination_measurements
]
)
return d_computed
def calculate_R_computed(
measurements: List[Measurement],
h_baseline: float,) -> float:
"""Calculate r_computed.
Parameters
----------
measurements: measurements,
h_baseline
Returns
-------
Calculated r_computed.
"""
# declination measurements
declination_measurements = [
average_measurement(measurements, [t]) for t in DECLINATION_TYPES
]
r_computed = np.average(
[ np.degrees(
m.measurement_type.meridian
* (np.arcsin(m.residual / np.sqrt((m.h + h_baseline) ** 2 + m.e**2)))
)
for m in declination_measurements
]
)
return r_computed
def calculate_mean_mark(
measurements: List[Measurement],
) -> float:
"""Calculate mean_mark.
Parameters
----------
measurements: measurements,
Returns
-------
Calculated mean_mark angle.
"""
# average mark
average_mark = average_measurement(measurements, MARK_TYPES)
return average_mark.angle
def calculate_magnetic_azimuth_of_mark(
mean_mark: float,
magnetic_south_meridian:float,
) -> float:
"""Calculate magnetic_azimuth_of_mark.
Parameters
----------
mean_mark: float,
magnetic_south_meridian:float,
Returns
-------
Calculated magnetic_azimuth_of_mark
"""
magnetic_azimuth_of_mark = mean_mark - magnetic_south_meridian
return magnetic_azimuth_of_mark