Example #1
0
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
Example #2
0
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
Example #3
0
    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")
Example #4
0
    def theta(self, a):
        """
        Arguments
        ---------
        a : angle of rotation [rad]

        Return
        ------
        θ : scattering angle in the lab system [rad]
        """
        D0 = self.D(0.0)
        D = self.D(a)
        Rd = self.R + self.d
        if isinstance(a, (int, float, np.number, uncertainties.core.AffineScalarFunc)):
            return np.sign(a) * umath.acos(
                (D0**2.0 + D**2.0 - 2.0 * Rd**2.0 *
                 (1.0 - umath.cos(a))) / (2.0 * D0 * D)
            )
        elif isinstance(a, np.ndarray):
            return np.sign(a) * unp.arccos(
                (D0**2.0 + D**2.0 - 2.0 * Rd**2.0 *
                 (1.0 - unp.cos(a))) / (2.0 * D0 * D)
            )
        else:
            raise ValueError(
                f"This function not supported for the input types. argument 'a' must be number or array")
Example #5
0
 def _orient(self, t, axis, deg=True):
     "Return the angle of the nromal vector n to axis at time t."
     n = self._construct_n(t)
     axis = axis / np.linalg.norm(axis, ord=2)
     angle = acos(np.dot(n, axis))
     if deg:
         angle = degrees(angle)
     return angle
Example #6
0
 def _orient(self, t, axis, deg=True):
     "Return the angle of the nromal vector n to axis at time t."
     n = self._construct_n(t)
     axis = axis/np.linalg.norm(axis, ord=2)
     angle = acos(np.dot(n, axis))
     if deg:
         angle = degrees(angle)
     return angle
Example #7
0
def task_6():
    m_W = ufloat(80.46, 0.06)
    m_Z = ufloat(91.1876, 0.0021)

    theta_W = umath.acos(m_W/m_Z)

    print("W mass:", m_W, "GeV")
    print("Z mass:", m_W, "GeV")
    print("weinberg:", umath.degrees(theta_W), "degrees")
    
    sin_theta_W_2 = 1 - umath.pow(m_W/m_Z, 2)
    print("sin(weinberg)^2:", sin_theta_W_2)
Example #8
0
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
Example #9
0
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))
Example #10
0
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))
Example #11
0
    def u_get_zenith_azimuth(self, u_dir_x, u_dir_y, u_dir_z, with_flip=True):
        """Get zeniths and azimuths [in radians] from direction vector.

        Parameters
        ----------
        u_dir_x : unumpy.array
            The x-component of the direction vector with uncertainty.
        u_dir_y : unumpy.array
            The y-component of the direction vector with uncertainty.
        u_dir_z : unumpy.array
            The z-component of the direction vector with uncertainty.
        with_flip : bool, optional
            If True, then the direction vectors show in the opposite direction
            than the zenith/azimuth pairs. This is common within IceCube
            software, since the direction vector shows along the particle
            direction, whereas the zenith/azimuth shows to the source position.

        Returns
        -------
        unumpy.array, unumpy.array
            The zenith and azimuth angles with uncertainties.
        """
        # normalize
        if not self.is_normalized(u_dir_x.nominal_value, u_dir_y.nominal_value,
                                  u_dir_z.nominal_value):
            u_dir_x, u_dir_y, u_dir_z = \
                self.u_normalize_dir(u_dir_x, u_dir_y, u_dir_z)

        if with_flip:
            u_dir_x *= -1
            u_dir_y *= -1
            u_dir_z *= -1

        if np.abs(u_dir_z.nominal_value) > 1.:
            raise ValueError('Z-component |{!r}| > 1!'.format(
                u_dir_z.nominal_value))
        zenith = umath.acos(u_dir_z)
        azimuth = (umath.atan2(u_dir_y, u_dir_x) + 2 * np.pi) % (2 * np.pi)

        return zenith, azimuth
Example #12
0
def theta(theta_lab, n):
    """
    function to convert θ in the lab system to θ in the center-of-mass system

    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
    ------
    theta_cm  : scattering angle in the center-of-mass system [rad]

    Notice
    ------
    This function do not consider relativity
    """
    if isinstance(theta_lab, uncertainties.core.AffineScalarFunc):
        coslab2 = umath.pow(umath.cos(theta_lab), 2.0)
        coscm = (coslab2 - 1.0) / n \
            + umath.sqrt((1.0 - 1.0 / n**2.0) * coslab2 +
                         umath.pow(coslab2 / n, 2.0))
        return np.sign(theta_lab) * umath.acos(coscm)
    elif isinstance(theta_lab, np.ndarray) and isinstance(
            theta_lab[0], uncertainties.core.AffineScalarFunc):
        coslab2 = unp.pow(unp.cos(theta_lab), 2.0)
        coscm = (coslab2 - 1.0) / n \
            + unp.sqrt((1.0 - 1.0 / n**2.0) * coslab2 +
                       unp.pow(coslab2 / n, 2.0))
        return np.sign(theta_lab) * unp.arccos(coscm)
    else:
        coslab2 = np.power(np.cos(theta_lab), 2.0)
        coscm = (coslab2 - 1.0) / n \
            + np.sqrt((1.0 - 1.0 / n**2.0) * coslab2 +
                      np.power(coslab2 / n, 2.0))
        return np.sign(theta_lab) * np.arccos(coscm)
Example #13
0
            try:
                __x = InterpretNum(__s, Dict(locals()))
                return __x
            except Exception as e:
                print("Number not correct:  %s" % str(e))

# To utilize Marv's code, here are definitions for the macros and
# constants/variables he uses.
ABS = abs
SGN = lambda a: -1 if a < 0 else 0 if a == 0 else 1
DPR = 180/pi
RPD = pi/180
COSD = lambda a:  cos(a*RPD)
SIND = lambda a:  sin(a*RPD)
ASND = lambda a:  DPR*asin(a if abs(a) < 1 else SGN(a))
ACSD = lambda a:  DPR*acos(a if abs(a) < 1 else SGN(a))

def Calculate(__vars, __d):
    # Get vars into our local namespace
    if __vars is not None:
        for __k in __vars:
            if len(__k) > 2 and __k[:2] == "__":
                continue
            exec("%s = __vars['%s']" % (__k, __k))
    try:
        if radius and angle:
            if dbg:
                print("radius, angle", sig(radius), sig(angle))
            z = radius*COSD(0.5*angle)
            height = radius - z
            chord = 2.*radius*SIND(0.5*angle)
Example #14
0
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.))
    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
Example #15
0
def AnglesU(trd1,plg1,trd2,plg2,ans0):
	'''
	AnglesU calculates the angles between two lines,
	between two planes, the line which is the intersection
	of two planes, or the plane containing two apparent dips

	AnglesU operates on two lines or planes with
	trend/plunge or strike/dip equal to trd1/plg1 and
	trd2/plg2. These angles have uncertainties

	ans0 is a character that tells the function what
	to calculate:

		ans0 = 'a' -> plane from two apparent dips
		ans0 = 'l' -> the angle between two lines

		In the above two cases, the user sends the trend
		and plunge of two lines

		ans0 = 'i' -> the intersection of two planes
		ans0 = 'p' -> the angle between two planes
 
		In the above two cases the user sends the strike
		and dip of two planes in RHR format

	NOTE: Input/Output angles are in radians and they
	have uncertainties in radians

	Angles uses functions SphToCartU, CartToSphU and Pole
	It also uses the uncertainties package from
	Eric O. Lebigot

	Based on Python function Angles
	'''
	# If planes have been entered
	if ans0 == 'i' or ans0 == 'p':
		k = 1
	# Else if lines have been entered
	elif ans0 == 'a' or ans0 == 'l':
		k = 0
	
	# Calculate the direction cosines of the lines or poles to planes
	cn1, ce1, cd1 = SphToCartU(trd1,plg1,k)
	cn2, ce2, cd2 = SphToCartU(trd2,plg2,k)
	
	# If angle between 2 lines or between the poles to 2 planes
	if ans0 == 'l' or ans0 == 'p':
		# Use dot product = Sum of the products of the direction cosines
		ans1 = umath.acos(cn1*cn2 + ce1*ce2 + cd1*cd2)
		ans2 = math.pi - ans1
	
	# If intersection of two planes or pole to a plane containing two
	# apparent dips
	if ans0 == 'a' or ans0 == 'i':
		# If the 2 planes or apparent dips are parallel return an error
		# Uncertainties are not needed for this comparison
		if trd1.n == trd2.n and plg1.n == plg2.n:
			raise ValueError('Error: lines or planes are parallel')
		# Else use cross product
		else:
			cn = ce1*cd2 - cd1*ce2
			ce = cd1*cn2 - cn1*cd2
			cd = cn1*ce2 - ce1*cn2
			# Make sure the vector points down into the lower hemisphere
			if cd < 0.0:
				cn = -cn
				ce = -ce
				cd = -cd
			# Convert vector to unit vector by dividing it by its length
			r = umath.sqrt(cn*cn+ce*ce+cd*cd)
			# Calculate line of intersection or pole to plane
			trd, plg = CartToSphU(cn/r,ce/r,cd/r)
			# If intersection of two planes
			if ans0 == 'i':
				ans1 = trd
				ans2 = plg
			# Else if plane containing two dips, calculate plane from its pole
			elif ans0 == 'a':
				ans1, ans2 = Pole(trd,plg,0)
	
	return ans1, ans2
Example #16
0
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")
Example #17
0
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