def get_motion_vector(ra, dec, pmra, pmdec, parallax): # Return the space motion vector of a star # Requirements: # - astropy coordinate object # - proper motion in ra and dec (mas per year) # - parallax (mas) # - radial velocity (km/s) # Returns astropy cartesian representation of space motion vector # see eqns. # - 11.2 # - 12.36 # in 'Spherical Astronomy' by R.M. Green ra = ra * deg2rad dec = dec * deg2rad vt_ra = pmra / parallax vt_dec = pmdec / parallax Vtan = numpy.array([ -vt_ra * np.sin(ra) - vt_dec * np.cos(ra) * np.sin(dec), vt_ra * np.cos(ra) - vt_dec * np.sin(ra) * np.sin(dec), vt_dec * np.cos(dec) ]) return Vtan
def SphToCartU(trd, plg, k): ''' SphToCartU converts from spherical to cartesian coordinates SphToCartU(trd,plg,k) returns the north (cn), east (ce), and down (cd) direction cosines of a line. Notice that these direction cosines have uncertainties k is an integer to tell whether the trend and plunge of a line (k = 0) or strike and dip of a plane in right hand rule (k = 1) are being sent in the trdu and plgu slots. In this last case, the direction cosines of the pole to the plane are returned NOTE: trdu and plgu are in radians and they have uncertainties in radians SphToCartU uses the uncertainties package from Eric O. Lebigot Based on Python function SphToCart ''' # If line if k == 0: cn = umath.cos(trd) * umath.cos(plg) ce = umath.sin(trd) * umath.cos(plg) cd = umath.sin(plg) # Else pole to plane elif k == 1: cn = umath.sin(trd) * umath.sin(plg) ce = -umath.cos(trd) * umath.sin(plg) cd = umath.cos(plg) return cn, ce, cd
def calculate_bucket_area_uncertain(radius, wedge_inner, wedge_outer, wedge_length): """Calculate bucket area Area circle + Area wedge """ from uncertainties.umath import sin from pandas import Series circumference = 2 * np.pi * radius wedge_angle = 2 * np.pi * wedge_inner / circumference wedge_area_outside = (wedge_outer * wedge_length + abs(wedge_inner - wedge_outer) * wedge_length) wedge_triangle_p = (radius * 2 + wedge_inner) / 2 wedge_area_inside = (wedge_triangle_p * (wedge_triangle_p - radius)**2 * (wedge_triangle_p - wedge_inner))**0.5 bucket_area_inside = ( np.pi * radius**2 - 0.5 * radius**2 * (wedge_angle - (sin(wedge_angle) if not isinstance(wedge_angle, Series) else wedge_angle.apply(lambda x: sin(x)))) + (wedge_triangle_p * (wedge_triangle_p - radius)**2 * (wedge_triangle_p - wedge_inner))**0.5) bucket_area = (bucket_area_inside + wedge_area_inside + wedge_area_outside) / 10_000 # m^2 return bucket_area
def angular_to_cartesian(ra,dec): """Calculates unit cartesian vector of angular coordinates Right acession and declination [degrees] """ ra = ra * deg2rad dec = dec * deg2rad return numpy.array([np.cos(ra) * np.cos(dec), np.sin(ra) * np.cos(dec), np.sin(dec)])
def measurement_to_xyz(measurement): theta_step, phi_step, dist = measurement dist = uncertainties.ufloat(dist, LIDAR_UNCERT) theta_step = uncertainties.ufloat(theta_step, 0.05) phi_step = uncertainties.ufloat(phi_step, 0.05) return np.array([ dist * umath.cos(theta_step * 360 / STEPS_PER_ROTATION * np.pi / 180) * umath.cos(phi_step * 360 / STEPS_PER_ROTATION * np.pi / 180), dist * umath.sin(theta_step * 360 / STEPS_PER_ROTATION * np.pi / 180) * umath.cos(phi_step * 360 / STEPS_PER_ROTATION * np.pi / 180), dist * umath.sin(phi_step * 360 / STEPS_PER_ROTATION * np.pi / 180), ])
def rutherford(theta, T, Zi, Zt, which="inc"): """ Rutherford Scattering in the center-of-mass system Arguments --------- theta : scattering angle in the center-of-mass system T : kinetic energy of incident particle in the center-of-mass system Zi : atomic number of incident particle; charge in units of e Zt : atomic number of target particle; charge in units of e which : if which="inc", calc dσ/dΩ(θ) of incident particle. if which="tar", calc dσ/dΩ(θ) of target particle. if which="sum", calc dσ/dΩ(θ) of incident particle + dσ/dΩ(θ) of target particle. Return ------ dσ/dΩ(θ) in the center-of-mass system [mb/str] """ # dσ/dΩ[mb/str] # 10.0 : fm^2 --> mb if which == "inc": # incident particle if isinstance(theta, uncertainties.core.AffineScalarFunc): return 10.0 * (Zi * Zt * E2 / (4.0 * T))**2.0 * umath.pow(umath.sin(theta / 2.0), -4.0) elif isinstance(theta, np.ndarray) and isinstance(theta[0], uncertainties.core.AffineScalarFunc): return 10.0 * (Zi * Zt * E2 / (4.0 * T))**2.0 * unp.pow(unp.sin(theta / 2.0), -4.0) else: return 10.0 * (Zi * Zt * E2 / (4.0 * T))**2.0 * np.power(np.sin(theta / 2.0), -4.0) elif which == "tar": # target particle if isinstance(theta, uncertainties.core.AffineScalarFunc): return 10.0 * (Zi * Zt * E2 / (4.0 * T))**2.0 * umath.pow(umath.cos(theta / 2.0), -4.0) elif isinstance(theta, np.ndarray) and isinstance(theta[0], uncertainties.core.AffineScalarFunc): return 10.0 * (Zi * Zt * E2 / (4.0 * T))**2.0 * unp.pow(unp.cos(theta / 2.0), -4.0) else: return 10.0 * (Zi * Zt * E2 / (4.0 * T))**2.0 * np.power(np.cos(theta / 2.0), -4.0) elif which == "sum": # incident particle + target particle if isinstance(theta, uncertainties.core.AffineScalarFunc): return 10.0 * (Zi * Zt * E2 / (4.0 * T))**2.0 \ * (umath.pow(umath.sin(theta / 2.0), -4.0) + umath.pow(umath.cos(theta / 2.0), -4.0)) elif isinstance(theta, np.ndarray) and isinstance(theta[0], uncertainties.core.AffineScalarFunc): return 10.0 * (Zi * Zt * E2 / (4.0 * T))**2.0 \ * (unp.pow(unp.sin(theta / 2.0), -4.0) + unp.power(unp.cos(theta / 2.0), -4.0)) else: return 10.0 * (Zi * Zt * E2 / (4.0 * T))**2.0 \ * (np.power(np.sin(theta / 2.0), -4.0) + np.power(np.cos(theta / 2.0), -4.0)) else: raise ValueError( f"Unrecognized which option:{which}. which must be inc/tar/sum.")
def test_numerical_example(): "Test specific numerical examples" x = ufloat(3.14, 0.01) result = umath.sin(x) # In order to prevent big errors such as a wrong, constant value # for all analytical and numerical derivatives, which would make # test_fixed_derivatives_math_funcs() succeed despite incorrect # calculations: assert ("%.6f +/- %.6f" % (result.nominal_value, result.std_dev) == "0.001593 +/- 0.010000") # Regular calculations should still work: assert ("%.11f" % umath.sin(3) == "0.14112000806")
def test_numerical_example(): "Test specific numerical examples" x = uncertainties.ufloat((3.14, 0.01)) result = umath.sin(x) # In order to prevent big errors such as a wrong, constant value # for all analytical and numerical derivatives, which would make # test_fixed_derivatives_math_funcs() succeed despite incorrect # calculations: assert ("%.6f +/- %.6f" % (result.nominal_value, result.std_dev()) == "0.001593 +/- 0.010000") # Regular calculations should still work: assert("%.11f" % umath.sin(3) == "0.14112000806")
def trail(rF, lam, fo): '''Calculate the trail and mechanical trail. Parameters ---------- rF : float The front wheel radius lam : float The steer axis tilt (pi/2 - headtube angle). The angle between the headtube and a vertical line. fo : float The fork offset Returns ------- c: float Trail cm: float Mechanical Trail ''' # trail c = (rF * umath.sin(lam) - fo) / umath.cos(lam) # mechanical trail cm = c * umath.cos(lam) return c, cm
def inclination(b, a, e=0, w=90): """ Function to convert impact parameter b to inclination in degrees. Parameters: ---------- b: Impact parameter of the transit. a: Scaled semi-major axis i.e. a/R*. e: float; eccentricity of the orbit. w: float; longitude of periastron in degrees Returns -------- inc: The inclination of the planet orbit in degrees. """ ecc_factor = (1 - e**2) / (1 + e * sin(radians(w))) inc = degrees(acos(b / (a * ecc_factor))) return inc
def updateMeasurement(z, R): tm = np.array([[sin(z[4]) * z[0], cos(z[4]) * z[0], z[2], z[3], z[4]]]).T theta_uncertain = ufloat(z[4], 0.5) v_uncertain = ufloat(z[0], 0.5) R[2, 0] = (umath.sin(theta_uncertain) * v_uncertain).std_dev R[3, 0] = (umath.cos(theta_uncertain) * v_uncertain).std_dev return [tm, R]
def theta(theta_cm, n): """ function to convert θ in the center-of-mass system to θ in the lab system Arguments --------- theta_cm : scattering angle in the center-of-mass system [rad] n : A_t / A_i; A_t, A_i means mass number of target particle or incident particle Return ------ theta_lab : scattering angle in the lab system [rad] Notice ------ This function does not consider relativity """ if isinstance(theta_cm, uncertainties.core.AffineScalarFunc): return umath.arctan( umath.sin(theta_cm) / (1.0 / n + umath.cos(theta_cm))) elif isinstance(theta_cm, np.ndarray) and isinstance( theta_cm[0], uncertainties.core.AffineScalarFunc): return unp.arctan(unp.sin(theta_cm) / (1.0 / n + unp.cos(theta_cm))) else: return np.arctan(np.sin(theta_cm) / (1.0 / n + np.cos(theta_cm)))
def dS(self, a): """ Arguments --------- a : angle of rotation [rad] Return ------ ΔS : detection area [mm^2] """ Rd = self.R + self.d r = self.r AT = self.AT D0 = self.D(0.0) A0 = umath.acos((Rd**2.0 + D0**2.0 - r**2.0) / (2.0 * Rd * D0)) d = self.d w = self.w h = self.h if isinstance(a, (int, float, np.number, uncertainties.core.AffineScalarFunc)): phi = umath.fabs(a - A0 - self.theta(a)) # ΔS return w * h * umath.cos(phi) - d * h * umath.sin(phi) elif isinstance(a, np.ndarray): phi = unp.fabs(a - A0 - self.theta(a)) return w * h * unp.cos(phi) - d * h * unp.sin(phi) else: raise ValueError( f"This function not supported for the input types. argument 'a' must be number or array")
def test_math_module(): "Operations with the math module" x = uncertainties.ufloat((-1.5, 0.1)) # The exponent must not be differentiated, when calculating the # following (the partial derivative with respect to the exponent # is not defined): assert (x**2).nominal_value == 2.25 # Regular operations are chosen to be unchanged: assert isinstance(umath.sin(3), float) # Python >=2.6 functions: if sys.version_info[:2] >= (2, 6): # factorial() must not be "damaged" by the umath module, so as # to help make it a drop-in replacement for math (even though # factorial() does not work on numbers with uncertainties # because it is restricted to integers, as for # math.factorial()): assert umath.factorial(4) == 24 # Boolean functions: assert not umath.isinf(x) # Comparison, possibly between an AffineScalarFunc object and a # boolean, which makes things more difficult for this code: assert umath.isinf(x) == False # fsum is special because it does not take a fixed number of # variables: assert umath.fsum([x, x]).nominal_value == -3
def distance_to_steer_axis(w, c, lam, point): """Returns the minimal distance from the steer axis to the given point when the bicycle is in the nominal configuration. Parameters ---------- w : float or ufloat Wheelbase. c : float or ufloat Trail. lam : float or ufloat Steer axis tilt in radians. point : narray, shape(3,) A point that lies in the symmetry plane of the bicycle. Returns ------- d : float or ufloat The minimal distance from the given point to the steer axis. """ pointOnAxis1 = np.array([w + c, 0., 0.]) pointOnAxis2 = pointOnAxis1 +\ np.array([-umath.sin(lam), 0., -umath.cos(lam)]) pointsOnLine = np.array([pointOnAxis1, pointOnAxis2]).T # this is the distance from the assembly com to the steer axis return point_to_line_distance(point, pointsOnLine)
def CalcR2eff(kR1p, pB, pC, dwB, dwC, kexAB, kexAC, kexBC, R1, w1, wrf, lf, AlignMag = "auto", Error = False): # Convert w1, wrf to rad/sec from Hz w1 = float(w1) * 2. * pi wrf = float(wrf) * 2. * pi # Calc other simple parameters pA = 1. - (pB + pC) lf = float(lf) #Convert dw from ppm to rad/s dwB = dwB * lf * 2. * pi # dw(ppm) * base-freq (eg 151 MHz, but just 151) * 2PI, gives rad/s dwC = dwC * lf * 2. * pi ################################ ##### R2eff Calculations ##### ################################ # Calculate pertinent frequency offsets/etc for alignment and projection lOmegaA, lOmegaB, lOmegaC, uOmega1, uOmega2, uOmega3, uOmegaAvg,\ delta1, delta2, delta3, deltaAvg, theta1, theta2, theta3, thetaAvg = \ AlignMagVec(w1, wrf, pA, pB, pC, dwB, dwC, kexAB, kexAC, kexBC, AlignMag) if Error == False: r2e = (kR1p/sin(thetaAvg)**2.) - (R1/(tan(thetaAvg)**2.)) return r2e else: r2e = (kR1p/umath.sin(thetaAvg)**2.) - (R1/(umath.tan(thetaAvg)**2.)) return r2e
def dOmega(theta_lab, n): """ function to find dΩlab/dΩcm Arguments --------- theta_lab : scattering angle in the lab system [rad] n : A_t / A_i; A_t, A_i means mass number of target particle or incident particle Return ------ dΩlab/dΩcm : factor to convert differential cross-section in the lab system to differential cross-section in the center-of-mass system Notice ------ This function do not consider relativity """ if isinstance(theta_lab, uncertainties.core.AffineScalarFunc): return umath.pow( 2.0 * umath.cos(theta_lab) / n + (1.0 + umath.cos(2.0 * theta_lab) / (n**2.0)) / umath.sqrt(1.0 - umath.pow(umath.sin(theta_lab) / n, 2.0)), -1.0) elif isinstance(theta_lab, np.ndarray) and isinstance( theta_lab[0], uncertainties.core.AffineScalarFunc): return unp.pow( 2.0 * unp.cos(theta_lab) / n + (1.0 + unp.cos(2.0 * theta_lab) / (n**2.0)) / unp.sqrt(1.0 - unp.pow(unp.sin(theta_lab) / n, 2.0)), -1.0) else: return np.power( 2.0 * np.cos(theta_lab) / n + (1.0 + np.cos(2.0 * theta_lab) / (n**2.0)) / np.sqrt(1.0 - np.power(np.sin(theta_lab) / n, 2.0)), -1.0)
def measurement_to_xyz(measurement): try: theta_step, phi_step, dist = measurement except Exception as e: print("unpacking point failed") return np.array([0, 0, 0]) dist = uncertainties.ufloat(dist, LIDAR_UNCERT) theta_step = uncertainties.ufloat(theta_step, 0.05) phi_step = uncertainties.ufloat(-phi_step, 0.05) return np.array([ dist * umath.cos(theta_step * 360 / STEPS_PER_ROTATION * np.pi / 180) * umath.cos(phi_step * 360 / STEPS_PER_ROTATION * np.pi / 180), dist * umath.sin(theta_step * 360 / STEPS_PER_ROTATION * np.pi / 180) * umath.cos(phi_step * 360 / STEPS_PER_ROTATION * np.pi / 180), dist * umath.sin(phi_step * 360 / STEPS_PER_ROTATION * np.pi / 180), ])
def transit_prob(Rp, aR, e=0, w=90): """ Function to calculate period of rotation of a planet Parameters ----------- Rp: float; radius of the planet in unit f the stellar radius aR: float; Scaled semi-major axis i.e. a/R*. e: float; eccentricity of the orbit. w: float; longitude of periastron in degrees """ #eqn 5 - Kane & von Braun 2008, https://core.ac.uk/reader/216127860 prob = (1 + Rp)/aR * (1 + e*sin(radians(w))/(1-e**2) ) return prob
def output_params(timedays, NormFlux, fit, success, period, ecc, arg_periapsis): Flux, Ing, Egr = transiterout(np.arange(0, np.size(NormFlux)), fit[0], fit[1], fit[2], fit[3], fitting=True) print Ing # Get values and uncertainties from the fit Rp = ufloat((fit[0], np.sqrt(success[0][0]))) b1 = ufloat((fit[1], np.sqrt(success[1][1]))) vel = ufloat((fit[2], np.sqrt(success[2][2]))) midtrantime = ufloat((fit[3], np.sqrt(success[3][3]))) # gam1=ufloat((fit[4],np.sqrt(success[4][4]))) # gam2=ufloat((fit[5],np.sqrt(success[5][5]))) P = period ecc_corr = np.sqrt(1 - ecc ** 2) / (1 + ecc * umath.sin(arg_periapsis * np.pi / 180.0)) Ttot = (Egr[np.size(Egr) - 1] - Ing[0]) * ecc_corr Tfull = (Egr[0] - Ing[np.size(Ing) - 1]) * ecc_corr # delta=ufloat((1-Flux[fit[3]],1-Flux[fit[3]]+sqrt(success[3][3]))) delta = Rp ** 2 dt = timedays[2] - timedays[1] aRstar = ( 2 * delta ** 0.25 * P / (np.pi * dt * umath.sqrt(Ttot ** 2 - Tfull ** 2)) ) # *umath.sqrt(1-ecc**2)/(1+ecc*sin(arg_periapsis*pi/180.)) # bmodel=umath.sqrt((1-(Tfull/Ttot)**2)/((1-umath.sqrt(delta))**2-(Tfull/Ttot)**2 * (1+umath.sqrt(delta))**2)) #Not too sure why this doesn't work inc = (180 / np.pi) * umath.acos(b1 / aRstar) # print bmodel poutnames = ("Rp", "b1", "vel", "midtrantime", "gam1", "gam2") for iz in range(0, np.size(fit)): print poutnames[iz], fit[iz], np.sqrt(success[iz][iz]) print "--------------------------------" # Useful Conversions # R_Jup/R_Sun = 0.10279 # R_Sun = 0.00464913034 AU aRstarFIT = vel * P / (dt * 2 * np.pi) incFIT = (180 / np.pi) * umath.acos(b1 / aRstarFIT) # midtrantime_convert=midtrantime*dt*24*3600+time_days[0] # midtrantime_MJD=timedays[midtrantime]+54964.00111764 timebetween = timedays[int(midtrantime.nominal_value) + 1] - timedays[int(midtrantime.nominal_value)] print timebetween * dt # print "Midtrantime",midtrantime_convert.std_dev()#midtrantime_MJD print "aRstarFIT", aRstarFIT print "inclination", incFIT print "frac. rad.", Rp print "aRstar_mod", aRstar aRs = (aRstarFIT + aRstar) / 2 print "--------------------------------" print "Planetary Radius/Star Radius: ", Rp print "Inclination: ", incFIT print "Semi - Major Axis / Stellar Radius: ", aRs print "Mid-Transit Time [MJD]", pyplot.plot(time, NormFlux, linestyle="None", marker=".") pyplot.plot(time, transiter(np.arange(np.size(NormFlux)), fit[0], fit[1], fit[2], fit[3])) pyplot.show() return Flux, Rp, aRstarFIT, incFIT, aRstar, midtrantime
def rotate_inertia_tensor(I, angle): '''Returns inertia tensor rotated through angle. Only for 2D''' ca = umath.cos(angle) sa = umath.sin(angle) C = np.array([[ca, 0., -sa], [0., 1., 0.], [sa, 0., ca]]) Irot = np.dot(C, np.dot(I, C.T)) return Irot
def get_angular_sep1(ra1, dec1, ra2, dec2): """Calculates the angular separation of two points on the sphere using great circles distance formula. returns angular separation in [mas] """ ra1 = ra1 * deg2rad ra2 = ra2 * deg2rad dec1 = dec1 * deg2rad dec2 = dec2 * deg2rad dist = np.acos( np.sin(dec1) * np.sin(dec2) + (np.cos(dec1) * np.cos(dec2) * np.cos(ra1 - ra2))) return (dist / deg2rad) * 3600.0 * 1000.0
def test_compound_expression(): """ Test equality between different formulas. """ x = uncertainties.ufloat((3, 0.1)) # Prone to numerical errors (but not much more than floats): assert umath.tan(x) == umath.sin(x)/umath.cos(x)
def get_angular_sep(ra1, dec1, ra2, dec2): ra1 = ra1 * deg2rad ra2 = ra2 * deg2rad dec1 = dec1 * deg2rad dec2 = dec2 * deg2rad top = np.sqrt((np.cos(dec2) * np.sin(ra2 - ra1))**(2) + (np.cos(dec1) * np.sin(dec2) - np.sin(dec1) * np.cos(dec2) * np.cos(ra2 - ra1))**(2)) bottom = (np.sin(dec1) * np.sin(dec2)) + (np.cos(dec1) * np.cos(dec2) * np.cos(ra2 - ra1)) dist = np.atan2(top, bottom) return (dist / deg2rad) * 3600.0 * 1000.0
def test_compound_expression(): """ Test equality between different formulas. """ x = ufloat(3, 0.1) # Prone to numerical errors (but not much more than floats): assert umath.tan(x) == umath.sin(x) / umath.cos(x)
def test_math_module(): "Operations with the math module" x = ufloat(-1.5, 0.1) # The exponent must not be differentiated, when calculating the # following (the partial derivative with respect to the exponent # is not defined): assert (x**2).nominal_value == 2.25 # Regular operations are chosen to be unchanged: assert isinstance(umath.sin(3), float) # Python >=2.6 functions: if sys.version_info >= (2, 6): # factorial() must not be "damaged" by the umath module, so as # to help make it a drop-in replacement for math (even though # factorial() does not work on numbers with uncertainties # because it is restricted to integers, as for # math.factorial()): assert umath.factorial(4) == 24 # Boolean functions: assert not umath.isinf(x) # Comparison, possibly between an AffineScalarFunc object and a # boolean, which makes things more difficult for this code: assert umath.isinf(x) == False # fsum is special because it does not take a fixed number of # variables: assert umath.fsum([x, x]).nominal_value == -3 # The same exceptions should be generated when numbers with uncertainties # are used: ## !! The Nose testing framework seems to catch an exception when ## it is aliased: "exc = OverflowError; ... except exc:..." ## surprisingly catches OverflowError. So, tests are written in a ## version-specific manner (until the Nose issue is resolved). if sys.version_info < (2, 6): try: math.log(0) except OverflowError, err_math: # "as", for Python 2.6+ pass else: raise Exception('OverflowError exception expected') try: umath.log(0) except OverflowError, err_ufloat: # "as", for Python 2.6+ assert err_math.args == err_ufloat.args
def transit_duration(P, Rp, a, b=0, e=0, w=90, inc=None, total=True): """ Function to calculate the total (T14) or full (T23) transit duration Parameters: ---------- P: Period of planet orbit in days Rp: Radius of the planet in units of stellar radius b: Impact parameter of the planet transit [0, 1+Rp] a: scaled semi-major axis of the planet in units of solar radius inc: inclination of the orbit. Optional. If given b is not used. if None, b is used to calculate inc total: if True calculate the the total transit duration T14, else calculate duration of full transit T23 Returns ------- Tdur: duration of transit in same unit as P """ #eqn 30 and 31 of Kipping 2010 https://doi.org/10.1111/j.1365-2966.2010.16894.x factor = (1-e**2)/(1+e*sin(radians(w))) if inc == None: inc = inclination(b,a,e,w) if total is False: Rp = -Rp sini = sin(radians(inc)) cosi = cos(radians(inc)) denom = a*factor*sini tdur= (P/np.pi) * (factor**2/sqrt(1-e**2)) * (asin ( sqrt((1+Rp)**2 - (a*factor*cosi)**2)/ denom ) ) return tdur
def GetOtherFacts(s1, s2, s3, a1, a2, a3, d): '''Calculate the other relevant measures of the triangle. ''' A = s1*s2*sin(a3)/2 s = (s1 + s2 + s3)/2 r = A/s R = s1*s2*s3/(4*A) d["area"] = A d["perimeter"] = 2*s d["r_inscribed"] = r d["R_circumscribed"] = R
def TrueThicknessU(strike,dip,top,base): ''' TrueThicknessU calculates the thickness (t) of a unit given the strike (strike) and dip (dip) of the unit, and points at its top (top) and base (base). strike and dip, as well as the points have uncertainties. top and base are 1 x 3 arrays defining the location of top and base points in an ENU coordinate system. For each one of these arrays, the first, second and third entries are the E, N and U coordinates. These coordinates have uncertainties NOTE: strike and dip should be input in radians and they have uncertainties in radians. The returned thickness have also uncertainties ''' # make the transformation matrix from ENU coordinates # to SDP coordinates. Eq. 5.10 sinStr = umath.sin(strike) cosStr = umath.cos(strike) sinDip = umath.sin(dip) cosDip = umath.cos(dip) a = np.array([[sinStr, cosStr, unc.ufloat(0,0)], [cosStr*cosDip, -sinStr*cosDip, -sinDip], [-cosStr*sinDip, sinStr*sinDip, -cosDip]]) # transform the top and base points # from ENU to SDP coordinates. Eq. 5.4 topn = np.array([unc.ufloat(0,0), unc.ufloat(0,0), unc.ufloat(0,0)]) basen = np.array([unc.ufloat(0,0), unc.ufloat(0,0), unc.ufloat(0,0)]) for i in range(0,3): for j in range(0,3): topn[i] = a[i,j]*top[j] + topn[i] basen[i] = a[i,j]*base[j] + basen[i] # compute the thickness of the unit. Eq. 5.12 t = np.abs(basen[2] - topn[2]) return t
def fwheel_to_handlebar_ref(lam, l1, l2): '''Returns the distance along the benchmark coordinates from the front wheel center to the handlebar reference center. Parameters ---------- lam : float Steer axis tilt. l1, l2 : float The distance from the front wheel center to the handlebar refernce center perpendicular to and along the steer axis. Returns ------- u1, u2 : float ''' u1 = l2 * umath.sin(lam) - l1 * umath.cos(lam) u2 = u1 / umath.tan(lam) + l1 / umath.sin(lam) return u1, u2
def get_angular_sep(ra1, dec1, ra2, dec2): """ implements the vincinerty distance formular in the case of a sphere. """ ra1 = ra1 * deg2rad ra2 = ra2 * deg2rad dec1 = dec1 * deg2rad dec2 = dec2 * deg2rad top = np.sqrt((np.cos(dec2) * np.sin(ra2 - ra1))**(2) + (np.cos(dec1) * np.sin(dec2) - np.sin(dec1) * np.cos(dec2) * np.cos(ra2 - ra1))**(2)) bottom = (np.sin(dec1) * np.sin(dec2)) + (np.cos(dec1) * np.cos(dec2) * np.cos(ra2 - ra1)) dist = np.atan2(top, bottom) return (dist / deg2rad) * 3600.0 * 1000.0
def get_earth_observer_vector_fast(time): """Calculate the position vector of an observer on the earth in barcentric cartesian coordinates, approximately and hopefully abit faster. """ n = time-Time('2000-01-01T12:00:00', format='isot', scale='utc') # mean longitude of the sun L = (280.460 + 0.9856474*n.jd) % 360.0 # mean anomaly of the sun g = (357.528 + 0.9856003*n.jd) % 360.0 # ecliptic longitude of the sun l = L + 1.915*np.sin(np.radians(g)) + 0.020*np.sin(np.radians(2*g)) # axial tilt of the earth # Obliquity of the ecliptic epsilon = 23.439 - 0.0000004*n.jd return np.array([ np.cos(np.radians(l)), np.cos(np.radians(epsilon))*np.sin(np.radians(l)), np.sin(np.radians(epsilon))*np.sin(np.radians(l))]) * -1.0
def calculate_benchmark_geometry(mp, par): '''Returns the wheelbase, steer axis tilt and the trail. Parameters ---------- mp : dictionary Dictionary with the measured parameters. par : dictionary Dictionary with the benchmark parameters. Returns ------- par : dictionary par with the benchmark geometry added. ''' # calculate the wheel radii par['rF'] = mp['dF'] / 2. / pi / mp['nF'] par['rR'] = mp['dR'] / 2. / pi / mp['nR'] # calculate the frame/fork fundamental geometry if 'w' in mp.keys(): # if there is a wheelbase # steer axis tilt in radians par['lam'] = pi / 180. * (90. - mp['gamma']) # wheelbase par['w'] = mp['w'] # fork offset forkOffset = mp['f'] else: h = (mp['h1'], mp['h2'], mp['h3'], mp['h4'], mp['h5']) d = (mp['d1'], mp['d2'], mp['d3'], mp['d4'], mp['d']) a, b, c = calculate_abc_geometry(h, d) par['lam'] = lambda_from_abc(par['rF'], par['rR'], a, b, c) par['w'] = (a + b) * umath.cos(par['lam']) + c * umath.sin(par['lam']) forkOffset = b # trail par['c'] = trail(par['rF'], par['lam'], forkOffset)[0] # this will simply transfer the lateral force point through to the # benchmark parameters, as they are in the benchmark coordinate system try: par['xcl'] = mp['xcl'] par['zcl'] = mp['zcl'] except KeyError: pass return par
def calculate_benchmark_geometry(mp, par): '''Returns the wheelbase, steer axis tilt and the trail. Parameters ---------- mp : dictionary Dictionary with the measured parameters. par : dictionary Dictionary with the benchmark parameters. Returns ------- par : dictionary par with the benchmark geometry added. ''' # calculate the wheel radii par['rF'] = mp['dF'] / 2./ pi / mp['nF'] par['rR'] = mp['dR'] / 2./ pi / mp['nR'] # calculate the frame/fork fundamental geometry if 'w' in mp.keys(): # if there is a wheelbase # steer axis tilt in radians par['lam'] = pi / 180. * (90. - mp['gamma']) # wheelbase par['w'] = mp['w'] # fork offset forkOffset = mp['f'] else: h = (mp['h1'], mp['h2'], mp['h3'], mp['h4'], mp['h5']) d = (mp['d1'], mp['d2'], mp['d3'], mp['d4'], mp['d']) a, b, c = calculate_abc_geometry(h, d) par['lam'] = lambda_from_abc(par['rF'], par['rR'], a, b, c) par['w'] = (a + b) * umath.cos(par['lam']) + c * umath.sin(par['lam']) forkOffset = b # trail par['c'] = trail(par['rF'], par['lam'], forkOffset)[0] # this will simply transfer the lateral force point through to the # benchmark parameters, as they are in the benchmark coordinate system try: par['xcl'] = mp['xcl'] par['zcl'] = mp['zcl'] except KeyError: pass return par
def get_source_apparent_pos(self, epoch, enlargeFactor=1.0): lensPos = self._lens.getRaDec(epoch) sourcePos = self._source.getRaDec(epoch) shift_mag = self.get_unresolved_centroid_shift_at_epoch(epoch) shift_angle = np.atan2( (sourcePos[0] - lensPos[0]) * np.cos(numpy.deg2rad(lensPos[1])), sourcePos[1] - lensPos[1]) appSourceRa = sourcePos[0] + ( (enlargeFactor * shift_mag * np.cos(shift_angle)) / (3600 * 1000)) appSourceDec = sourcePos[1] + ( (enlargeFactor * shift_mag * np.sin(shift_angle)) / (36000 * 1000)) return numpy.array([appSourceRa, appSourceDec])
def test_against_uncertainties_package(): try: from uncertainties import ufloat from uncertainties import umath from math import sqrt as math_sqrt except ImportError: return X, varX = 0.5, 0.04 Y, varY = 3, 0.09 N = 3 ux = ufloat(X, math_sqrt(varX)) uy = ufloat(Y, math_sqrt(varY)) def _compare(result, u): Z, varZ = result assert abs(Z-u.n)/u.n < 1e-13 and (varZ-u.s**2)/u.s**2 < 1e-13, \ "expected (%g,%g) got (%g,%g)"%(u.n, u.s**2, Z, varZ) def _check_pow(u): _compare(pow(X, varX, N), u) def _check_unary(op, u): _compare(op(X, varX), u) def _check_binary(op, u): _compare(op(X, varX, Y, varY), u) _check_pow(ux**N) _check_binary(add, ux + uy) _check_binary(sub, ux - uy) _check_binary(mul, ux * uy) _check_binary(div, ux / uy) _check_binary(pow2, ux**uy) _check_unary(exp, umath.exp(ux)) _check_unary(log, umath.log(ux)) _check_unary(sin, umath.sin(ux)) _check_unary(cos, umath.cos(ux)) _check_unary(tan, umath.tan(ux)) _check_unary(arcsin, umath.asin(ux)) _check_unary(arccos, umath.acos(ux)) _check_unary(arctan, umath.atan(ux)) _check_binary(arctan2, umath.atan2(ux, uy))
def test_against_uncertainties_package(): try: from uncertainties import ufloat from uncertainties import umath from math import sqrt as math_sqrt except ImportError: return X, varX = 0.5, 0.04 Y, varY = 3, 0.09 N = 3 ux = ufloat(X, math_sqrt(varX)) uy = ufloat(Y, math_sqrt(varY)) def _compare(result, u): Z, varZ = result assert abs(Z-u.n)/u.n < 1e-13 and (varZ-u.s**2)/u.s**2 < 1e-13, \ "expected (%g,%g) got (%g,%g)"%(u.n,u.s**2,Z,varZ) def _check_pow(u): _compare(pow(X, varX, N), u) def _check_unary(op, u): _compare(op(X, varX), u) def _check_binary(op, u): _compare(op(X, varX, Y, varY), u) _check_pow(ux**N) _check_binary(add, ux+uy) _check_binary(sub, ux-uy) _check_binary(mul, ux*uy) _check_binary(div, ux/uy) _check_binary(pow2, ux**uy) _check_unary(exp, umath.exp(ux)) _check_unary(log, umath.log(ux)) _check_unary(sin, umath.sin(ux)) _check_unary(cos, umath.cos(ux)) _check_unary(tan, umath.tan(ux)) _check_unary(arcsin, umath.asin(ux)) _check_unary(arccos, umath.acos(ux)) _check_unary(arctan, umath.atan(ux)) _check_binary(arctan2, umath.atan2(ux, uy))
def benchmark_par_to_canonical(p): '''Returns the canonical matrices of the Whipple bicycle model linearized about the upright constant velocity configuration. It uses the parameter definitions from Meijaard et al. 2007. Parameters ---------- p : dictionary A dictionary of the benchmark bicycle parameters. Make sure your units are correct, best to ue the benchmark paper's units! Returns ------- M : ndarray, shape(2,2) The mass matrix. C1 : ndarray, shape(2,2) The damping like matrix that is proportional to the speed, v. K0 : ndarray, shape(2,2) The stiffness matrix proportional to gravity, g. K2 : ndarray, shape(2,2) The stiffness matrix proportional to the speed squared, v**2. Notes ----- This function handles parameters with uncertanties. ''' mT = p['mR'] + p['mB'] + p['mH'] + p['mF'] xT = (p['xB'] * p['mB'] + p['xH'] * p['mH'] + p['w'] * p['mF']) / mT zT = (-p['rR'] * p['mR'] + p['zB'] * p['mB'] + p['zH'] * p['mH'] - p['rF'] * p['mF']) / mT ITxx = (p['IRxx'] + p['IBxx'] + p['IHxx'] + p['IFxx'] + p['mR'] * p['rR']**2 + p['mB'] * p['zB']**2 + p['mH'] * p['zH']**2 + p['mF'] * p['rF']**2) ITxz = (p['IBxz'] + p['IHxz'] - p['mB'] * p['xB'] * p['zB'] - p['mH'] * p['xH'] * p['zH'] + p['mF'] * p['w'] * p['rF']) p['IRzz'] = p['IRxx'] p['IFzz'] = p['IFxx'] ITzz = (p['IRzz'] + p['IBzz'] + p['IHzz'] + p['IFzz'] + p['mB'] * p['xB']**2 + p['mH'] * p['xH']**2 + p['mF'] * p['w']**2) mA = p['mH'] + p['mF'] xA = (p['xH'] * p['mH'] + p['w'] * p['mF']) / mA zA = (p['zH'] * p['mH'] - p['rF']* p['mF']) / mA IAxx = (p['IHxx'] + p['IFxx'] + p['mH'] * (p['zH'] - zA)**2 + p['mF'] * (p['rF'] + zA)**2) IAxz = (p['IHxz'] - p['mH'] * (p['xH'] - xA) * (p['zH'] - zA) + p['mF'] * (p['w'] - xA) * (p['rF'] + zA)) IAzz = (p['IHzz'] + p['IFzz'] + p['mH'] * (p['xH'] - xA)**2 + p['mF'] * (p['w'] - xA)**2) uA = (xA - p['w'] - p['c']) * umath.cos(p['lam']) - zA * umath.sin(p['lam']) IAll = (mA * uA**2 + IAxx * umath.sin(p['lam'])**2 + 2 * IAxz * umath.sin(p['lam']) * umath.cos(p['lam']) + IAzz * umath.cos(p['lam'])**2) IAlx = (-mA * uA * zA + IAxx * umath.sin(p['lam']) + IAxz * umath.cos(p['lam'])) IAlz = (mA * uA * xA + IAxz * umath.sin(p['lam']) + IAzz * umath.cos(p['lam'])) mu = p['c'] / p['w'] * umath.cos(p['lam']) SR = p['IRyy'] / p['rR'] SF = p['IFyy'] / p['rF'] ST = SR + SF SA = mA * uA + mu * mT * xT Mpp = ITxx Mpd = IAlx + mu * ITxz Mdp = Mpd Mdd = IAll + 2 * mu * IAlz + mu**2 * ITzz M = np.array([[Mpp, Mpd], [Mdp, Mdd]]) K0pp = mT * zT # this value only reports to 13 digit precision it seems? K0pd = -SA K0dp = K0pd K0dd = -SA * umath.sin(p['lam']) K0 = np.array([[K0pp, K0pd], [K0dp, K0dd]]) K2pp = 0. K2pd = (ST - mT * zT) / p['w'] * umath.cos(p['lam']) K2dp = 0. K2dd = (SA + SF * umath.sin(p['lam'])) / p['w'] * umath.cos(p['lam']) K2 = np.array([[K2pp, K2pd], [K2dp, K2dd]]) C1pp = 0. C1pd = (mu*ST + SF*umath.cos(p['lam']) + ITxz / p['w'] * umath.cos(p['lam']) - mu*mT*zT) C1dp = -(mu * ST + SF * umath.cos(p['lam'])) C1dd = (IAlz / p['w'] * umath.cos(p['lam']) + mu * (SA + ITzz / p['w'] * umath.cos(p['lam']))) C1 = np.array([[C1pp, C1pd], [C1dp, C1dd]]) return M, C1, K0, K2
def lam_equality(lam, rF, rR, a, b, c): return umath.sin(lam) - (rF - rR + c * umath.cos(lam)) / (a + b)
def test_math_module(): "Operations with the math module" x = ufloat(-1.5, 0.1) # The exponent must not be differentiated, when calculating the # following (the partial derivative with respect to the exponent # is not defined): assert (x**2).nominal_value == 2.25 # Regular operations are chosen to be unchanged: assert isinstance(umath.sin(3), float) # factorial() must not be "damaged" by the umath module, so as # to help make it a drop-in replacement for math (even though # factorial() does not work on numbers with uncertainties # because it is restricted to integers, as for # math.factorial()): assert umath.factorial(4) == 24 # fsum is special because it does not take a fixed number of # variables: assert umath.fsum([x, x]).nominal_value == -3 # Functions that give locally constant results are tested: they # should give the same result as their float equivalent: for name in umath.locally_cst_funcs: try: func = getattr(umath, name) except AttributeError: continue # Not in the math module, so not in umath either assert func(x) == func(x.nominal_value) # The type should be left untouched. For example, isnan() # should always give a boolean: assert type(func(x)) == type(func(x.nominal_value)) # The same exceptions should be generated when numbers with uncertainties # are used: ## !! The Nose testing framework seems to catch an exception when ## it is aliased: "exc = OverflowError; ... except exc:..." ## surprisingly catches OverflowError. So, tests are written in a ## version-specific manner (until the Nose issue is resolved). try: math.log(0) except ValueError as err_math: # Python 3 does not make exceptions local variables: they are # restricted to their except block: err_math_args = err_math.args else: raise Exception('ValueError exception expected') try: umath.log(0) except ValueError as err_ufloat: assert err_math_args == err_ufloat.args else: raise Exception('ValueError exception expected') try: umath.log(ufloat(0, 0)) except ValueError as err_ufloat: assert err_math_args == err_ufloat.args else: raise Exception('ValueError exception expected') try: umath.log(ufloat(0, 1)) except ValueError as err_ufloat: assert err_math_args == err_ufloat.args else: raise Exception('ValueError exception expected')
def BMSim(ParD, wrf, w1, time, dec_err=0.0, dec_mc=500, rho_err=0.0, rho_mc=500): # Numpy array to store mag vectors magVecs = zeros(13) # Numpy array to store eigenvalues eigVals = zeros(9) # Decay sim flag - 2pt or monoexp fit decFlag = False # Check to see if vdlist is defined if len(time) > 2: decFlag = True kR1p = 2. tmax = 1./kR1p else: kR1p = 2. # Estimate maximum Trelax needed to efficiently calculate a 2-point exponential decay # Use known R1rho value if it is given, as 1/R1p will give int decay to ~0.36 if kR1p is not None: tmax = 1./kR1p # Unpack Parameters pB,pC,dwB,dwC = ParD['pb'], ParD['pc'], ParD['dwb'], ParD['dwc'] kexAB,kexAC,kexBC = ParD['kexab'], ParD['kexac'], ParD['kexbc'] R1,R1b,R1c = ParD['r1'], ParD['r1b'], ParD['r1c'] R2,R2b,R2c = ParD['r2'], ParD['r2b'], ParD['r2c'] lf, AlignMag = ParD['lf'], ParD['alignmag'] pA = 1. - (pB + pC) ################################ ##### Pre-run Calculations ##### ################################ # Convert w1, wrf to rad/sec from Hz w1 = w1 * 2. * pi wrf = wrf * 2. * pi #Convert dw from ppm to rad/s dwB = dwB * lf * 2. * pi # dw(ppm) * base-freq (eg 151 MHz, but just 151) * 2PI, gives rad/s dwC = dwC * lf * 2. * pi #Define forward/backward exchange rates k12 = kexAB * pB / (pB + pA) k21 = kexAB * pA / (pB + pA) k13 = kexAC * pC / (pC + pA) k31 = kexAC * pA / (pC + pA) if kexBC != 0.: k23 = kexBC * pC / (pB + pC) k32 = kexBC * pB / (pB + pC) else: k23 = 0. k32 = 0. # Calculate pertinent frequency offsets/etc for alignment and projection lOmegaA, lOmegaB, lOmegaC, uOmega1, uOmega2, uOmega3, uOmegaAvg,\ delta1, delta2, delta3, deltaAvg, theta1, theta2, theta3, thetaAvg = \ AlignMagVec(w1, wrf, pA, pB, pC, dwB, dwC, kexAB, kexAC, kexBC, AlignMag) #Calculate initial magnetization Ma = pA*lOmegaA # GS Mb = pB*lOmegaB # ES1 Mc = pC*lOmegaC # ES2 # Magnetization matrix Ms = MatrixBM3(k12,k21,k13,k31,k23,k32,delta1,delta2,delta3, w1, R1, R2, R1b, R1c, R2b, R2c) # Initial magnetization of GS (Ma), ES1 (Mb), ES2 (Mc) M0 = array([Ma[0],Mb[0],Mc[0],Ma[1],Mb[1],Mc[1],Ma[2],Mb[2],Mc[2]], float64) ################################################################# #### Calculate Evolution of Magnetization for Fitting Func ###### ################################################################# if decFlag == True: # Calculate evolving magnetization at a given time increment # Returns array of projected magnetizations and indv components of mag # Col0 = Peff - mag projected along average # Col1 = Peff_err, if any # Col2,3,4 = PeffA,B,C - Projected along respective states # Col5,6,7 = Mxa, Mya, Mza # Col8,9,10 = Mxb, Myb, Mzb # Col11,12,13 = Mxc, Myc, Mzc # Col14 = time magVecs = asarray([SimMagVecs(x,M0,Ms,lOmegaA,lOmegaB,lOmegaC,w1,wrf) for x in time]) # Append time to vectors magVecs = append(magVecs, time[:,None], axis=1) ## -- Monoexp Decay Error Corruption -- ## if dec_err != 0.0: # MC error number mcnum = dec_mc err = magVecs[:,0].max() * dec_err # Get normal distributions given error scaled to max int value # Generates a 2xN array of error corrupted Peff and Peff_err given # a normal fit to the mcnum of random values # tp = array([normDist.fit(normal(x, err, size=mcnum)) for x in magVecs[:,0]]) tp = array([normal(x, err, size=mcnum) for x in magVecs[:,0]]) # Get mu and sigma for plots # Get mu from first random normal selection of Peff values magVecs[:,0] = tp[:,0] # magVecs[:,0] = tp.mean(axis=1) magVecs[:,1] = tp.std(axis=1) # Calculate eigenvalues for export # append offset and slp (Hz) to front of eigenvalues eigVals = array([wrf/(2.*pi), w1/(2.*pi)]) eigVals = append(eigVals, matrix_exponential(Ms, w1, wrf, 0.0, EigVal=True)[1]) # If mag vecs are not nan if not isnan(magVecs.sum()): ## -- Monoexp fitting -- ## # If decay noise corruption non-zero, noise corrupt fitted R1rhos if dec_err != 0.0: # Weighted fit to get best R1rho value popt, pcov = curve_fit(ExpDecay, time, magVecs[:,0], (1., R1), sigma=magVecs[:,1]) # MC error generation of R1ho from noise corrupted intensities popts = array([curve_fit(ExpDecay, time, x, (1., R1))[0] for x in tp.T]) preExp, R1p, R1p_err = popt[0], popt[1], popts.std(axis=0)[1] # If no decay corruption, simply fit for R1rho else: popt, pcov = curve_fit(ExpDecay, time, magVecs[:,0], (1., R1)) R1p = popt[1] R1p_err = 0.0 preExp = popt[0] else: R1p = 0.0 R1p_err = 0.0 preExp = 1. else: # Calculate effective magnetization at Tmax and Tmin, respectively # Returns floats corresponding to magnetization projected back along Meff at time T magMin,magMax = AltCalcMagT(tmax,M0,Ms,lOmegaA,lOmegaB,lOmegaC,w1,wrf),\ AltCalcMagT(time[0],M0,Ms,lOmegaA,lOmegaB,lOmegaC,w1,wrf) # Check to make sure magnetization at Tmax is not <= 0, would give errorneous result if magMin <= 0.: # Project magnetization along average state in Jameson way # Note: this PeffVec + Fit Exp gives nearly identical # values to Flag 2 way PeffVec = asarray([AltCalcMagT(x,M0,Ms,lOmegaA,lOmegaB,lOmegaC,w1,wrf) for x in time]) popt, pcov = curve_fit(ExpDecay, time, PeffVec, (1., 5.)) R1p = popt[1] ## R1rho Calc Opt #1 # Kay method (Korhznev, JACS, 2004) Solve with 2-pts # R1rho = -1/Tmax*ln(I1/I0), where I1 is Peff at Tmax # NOTE: If use this, don't calc Peff above # Kay Method with Jameson Alt. Calc. Mag. T else: # If magnetization at Tmax is < 0, # Means odd exponential decay # In this case, walk backwards along time vector # until the time where magMin(t) > 0 # Then solve for R1rho with new min magnetization R1p = -1./tmax*log(magMin/magMax) if isnan(R1p) == True: return array([0., 0., 1.]), magVecs, eigVals # If R1p is not NaN else: ## -- R1rho Direct Error Corruption -- ## if rho_err != 0.: tv = normal(R1p, R1p*rho_err, size=rho_mc) # Pick mean R1rho from first random normal distribution R1p = tv[0] R1p_err = tv.std() # Calculate R2eff - take on-res in to account # If on-resonance, thetaAvg = pi/2 if deltaAvg == 0.: thetaAvg = pi/2. # Propagate error in R2eff, if applicable if R1p_err == 0.0: R2eff = (R1p/sin(thetaAvg)**2.) - (R1/(tan(thetaAvg)**2.)) R2eff_err = 0.0 else: R2eff = (ufloat(R1p, R1p_err)/umath.sin(thetaAvg)**2.) - (R1/(umath.tan(thetaAvg)**2.)) R2eff_err = R2eff.std_dev R2eff = R2eff.n return array([R1p, R1p_err, R2eff, R2eff_err, preExp]), magVecs, eigVals
def SolveProblem(d): # Get our needed variables for k in d["vars"]: if k in set(("S1", "S2", "S3", "A1", "A2", "A3")): exec("%s = d['vars']['%s']" % (k, k)) angle_conv = d["angle_measure"] # Converts angle measure to radians prob = d["problem_type"] try: if prob == "sss": # Law of cosines to find two angles, angle law to find third. A1 = acos((S2**2 + S3**2 - S1**2)/(2*S2*S3)) A2 = acos((S1**2 + S3**2 - S2**2)/(2*S1*S3)) A3 = pi - A1 - A2 elif prob == "ssa": # Law of sines to find the other two angles and remaining # side. Note it can have two solutions (the second solution's # data will be in the variables s1_2, s2_2, etc.). A1 *= angle_conv # Make sure angle is in radians A2 = asin((S2/S1*sin(A1))) A3 = pi - A1 - A2 S3 = S2*sin(A3)/sin(A2) # Check for other solution A1_2 = A1 A2_2 = pi - A2 A3_2 = pi - A1_2 - A2_2 if A1_2 + A2_2 + A3_2 > pi: # Second solution not possible del A1_2 del A2_2 del A3_2 else: # Second solution is possible S1_2 = S1 S2_2 = S2 S3_2 = S2_2*sin(A3_2)/sin(A2_2) elif prob == "sas": # Law of cosines to find third side; law of sines to find # another angle; angle law for other angle. Note we rename # the incoming angle to be consistent with a solution diagram. A3 = A1*angle_conv # Make sure angle is in radians S3 = sqrt(S1**2 + S2**2 - 2*S1*S2*cos(A3)) A2 = asin(S2*sin(A3)/S3) A1 = pi - A2 - A3 elif prob == "asa": # Third angle from angle law; law of sines for other two # sides. Note we rename the sides for consistency with a # diagram. A1 *= angle_conv # Make sure angle is in radians A2 *= angle_conv # Make sure angle is in radians A3 = pi - A1 - A2 S3 = S1 S2 = S3*sin(A2)/sin(A3) S1 = S3*sin(A1)/sin(A3) elif prob == "saa": # Third angle from angle law; law of sines for other two # sides. A1 *= angle_conv # Make sure angle is in radians A2 *= angle_conv # Make sure angle is in radians A3 = pi - A1 - A2 S2 = S1*sin(A2)/sin(A1) S3 = S1*sin(A3)/sin(A1) else: raise ValueError("Bug: unrecognized problem") except UnboundLocalError as e: s = str(e) loc = s.find("'") s = s[loc + 1:] loc = s.find("'") s = s[:loc] Error("Variable '%s' not defined" % s) except ValueError as e: msg = "Can't solve the problem:\n" msg += " Error: %s" % str(e) Error(msg) # Collect solution information solution = {} vars = set(( "S1", "S2", "S3", "A1", "A2", "A3", "S1_2", "S2_2", "S3_2", "A1_2", "A2_2", "A3_2", )) for k in vars: if k in locals(): exec("solution['%s'] = %s" % (k, k)) d["solution"] = solution
def Test(): '''The following test cases came from the sample problems at http://www.mathsisfun.com/algebra/trig-solving-triangles.html ''' eps, r2d, d2r = 1e-14, 180/pi, pi/180 d = { "angle_measure" : d2r, } # sss d["vars"] = { "S1" : 6, "S2" : 7, "S3" : 8, } d["problem_type"] = "sss" SolveProblem(d) k = d["solution"] assert abs(k["A1"] - acos(77/112)) < eps assert abs(k["A2"] - (pi - k["A3"] - k["A1"])) < eps assert abs(k["A3"] - acos(1/4)) < eps # ssa d["vars"] = { "S1" : 8, "S2" : 13, "A1" : 31, # Angle in degrees } d["problem_type"] = "ssa" SolveProblem(d) k = d["solution"] a2 = asin(13*sin(31*d2r)/8) assert abs(k["A2"] - a2) < eps a3 = pi - k["A2"] - k["A1"] assert abs(k["A3"] - a3) < eps assert abs(k["S3"] - sin(a3)*8/sin(31*d2r)) < eps # Check other solution a2_2 = pi - asin(13*sin(31*d2r)/8) assert abs(k["A2_2"] - a2_2) < eps a3_2 = pi - k["A2_2"] - k["A1_2"] assert abs(k["A3_2"] - a3_2) < eps assert abs(k["S3_2"] - sin(a3_2)*8/sin(31*d2r)) < eps # sas d["vars"] = { "S1" : 5, "S2" : 7, "A1" : 49, # Angle in degrees } d["problem_type"] = "sas" SolveProblem(d) k = d["solution"] # asa d["vars"] = { "S1" : 9, "A1" : 76, # Angle in degrees "A2" : 34, # Angle in degrees } d["problem_type"] = "asa" SolveProblem(d) k = d["solution"] assert abs(k["S2"] - 9*sin(34*d2r)/sin(70*d2r)) < eps assert abs(k["S1"] - 9*sin(76*d2r)/sin(70*d2r)) < eps assert abs(k["A3"] - 70*d2r) < eps # saa d["vars"] = { "S1" : 7, "A1" : 62, # Angle in degrees "A2" : 35, # Angle in degrees } d["problem_type"] = "saa" SolveProblem(d) k = d["solution"] assert abs(k["A3"] - 83*d2r) < eps assert abs(k["S2"] - 7*sin(35*d2r)/sin(62*d2r)) < eps assert abs(k["S3"] - 7*sin(83*d2r)/sin(62*d2r)) < eps out("Tests passed")
def sin(self): if self.unit.is_angle: return unp.sin(self.value * self.unit.conversion_factor_to(_unit_table['rad'])) else: raise UnitError('Argument of sin must be an angle')