The volume and surface area of a sphere can be calculated with the following formulas. Create this as a terminal application. Write one function for volume and another function for surface area. The results should display both the volume and the surface area rounded to 2 decimal places. Use pi from Python’s math module. Include the following doctests. You must get pass
all tests to receive full credit. Pay close attention to how you name your functions. They must
match
volume examples/doctests:
round(volume_of_sphere(0), 2)
0.0
round(volume_of_sphere(1), 2)
4.19
round(volume_of_sphere(12.3), 2)
7794.78
round(volume_of_sphere(18.9), 2)
28279.65
round(volume_of_sphere(33.33), 2)
155093.84
surface area examples/doctests:
round(surface_area(0), 2)
0.0
round(surface_area(1), 2)
12.57
round(surface_area(12.3), 2)
1901.17
round(surface_area(18.9), 2)
13959.84
round(surface_area(33.33), 2)
155093.84
MY CODE:
''' Python3 program to calculate Volume and
Surface area of Sphere'''
# Importing Math library for value Of PI
import math
pi = math.pi
# Function to calculate Volume of Sphere
def volume(r):
vol = (4 / 3) * pi * r * r * r
return vol
# Function To Calculate Surface Area of Sphere
def surfacearea(s):
sur_ar = 4 * pi * r * r
return sur_ar
# Driver Code
radius = round(volume(1), 2)
area = round(area(0), 2)
print( "Volume Of Sphere : ", volume(radius) )
print( "Surface Area Of Sphere : ", surfacearea(area) )
The two programs below will find the surface area and the volume of a sphere with the radius. This is just a simpler way. The first program is more accurate but both will do the job.
pi=22/7
radian = float(input('Radius of sphere: '))
sur_area = 4 * pi * radian **2
volume = (4/3) * (pi * radian ** 3)
print("Surface Area is: ", sur_area)
print("Volume is: ", volume)
or
PI = 3.14
radius = float(input('Please Enter the Radius of a Sphere: '))
sa = 4 * PI * radius * radius
Volume = (4 / 3) * PI * radius * radius * radius
print("\n The Surface area of a Sphere = %.2f" %sa)
print("\n The Volume of a Sphere = %.2f" %Volume)
Since there is no obvious question here, I am assuming the objective is to complete the mathematical functions and pass the doctests. Having said that, it would be quite impossible to do that without being mathematically incorrect because the last two doctests for the surface area function are wrong, round(surface_area(18.9), 2) should be 4488.83 not 13959.84 and round(surface_area(33.33), 2) should be 13934.72 and not 155093.84.
Related
A car should go from A to B. But not in the direct line. As in reality, it should drive in 2 arcs as shown in the diagram. Is there some kind of function for this? How would it be used?
You can consider this as an ellipse and calculate the perimeter of ellipse by giving length and magnitude, you can get your path length
import math
def calculate_perimeter(a,b):
perimeter = math.pi * ( 3*(a+b) - math.sqrt( (3*a + b) * (a + 3*b) ) )
return perimeter
calculate_perimeter(distance/2, magnitude_of_deviation/2)
Edit
distance = absolute(p1-p2)
= math.sqrt((x2-x1)**2 + (y2-y1)**2)
you have start p1(x,y) and p2 (x2,y2), absolute distance is distance at here and deviation magnitude is your choice and one eclipse would work for all distance
How to generate random latitude and longitude using Python 3 random module? I already googled and read documentation and not found a way to do this.
The problem when using uniform distributions for both the latitude and the longitude
is that physically, the latitude is NOT uniformly distributed.
So if you plan to use these random points for something like some statiscal averaging computation,
or a physics Monte-Carlo simulation, the results will risk being incorrect.
And if you plot a graphical representation of the “uniform” random points, they will seem to cluster in the polar regions.
To picture that, consider on planet Earth the zone that lies between 89 and 90 degrees of latitude (North).
The length of a degree of latitude is 10,000/90 = 111 km. That zone is a circle of radius 111 km,
centered around the North Pole. Its area is about 3.14 * 111 * 111 ≈ 39,000 km2
On the other hand, consider the zone that lies between 0 and 1 degree of latitude.
This is a strip whose length is 40,000 km (the Equator) and whose width is 111 km,
so its area is 4.44 millions km2. Much larger than the polar zone.
A simple algorithm:
A possibility is to use Gaussian-distributed random variables, as provided by the Python library.
If we build a 3D vector whose 3 components have Gaussian distributions, the overall
probability distribution is like
exp(-x2) * exp(-y2) * exp(-z2)
but this is the same thing as exp(-(x2 + y2 + z2))
or exp(-r2), where r is the distance from the origin.
So these vectors have no privileged direction. Once normalized to unit length, they are uniformly
distributed on the unit sphere. They solve our problem with the latitude distribution.
The idea is implemented by the following Python code:
import math
import random
def randlatlon1():
pi = math.pi
cf = 180.0 / pi # radians to degrees Correction Factor
# get a random Gaussian 3D vector:
gx = random.gauss(0.0, 1.0)
gy = random.gauss(0.0, 1.0)
gz = random.gauss(0.0, 1.0)
# normalize to an equidistributed (x,y,z) point on the unit sphere:
norm2 = gx*gx + gy*gy + gz*gz
norm1 = 1.0 / math.sqrt(norm2)
x = gx * norm1
y = gy * norm1
z = gz * norm1
radLat = math.asin(z) # latitude in radians
radLon = math.atan2(y,x) # longitude in radians
return (round(cf*radLat, 5), round(cf*radLon, 5))
A sanity check:
Euclidean geometry provides a formula for the probability of a spherical zone
defined by minimal/maximal latitude and longitude. The corresponding Python code is like this:
def computeProbaG(minLat, maxLat, minLon, maxLon):
pi = math.pi
rcf = pi / 180.0 # degrees to radians Correction Factor
lonProba = (maxLon - minLon) / 360.0
minLatR = rcf * minLat
maxLatR = rcf * maxLat
latProba = (1.0/2.0) * (math.sin(maxLatR) - math.sin(minLatR))
return (lonProba * latProba)
And we can also compute an approximation of that same probability by random sampling, using
the random points provided by a function such as randlatlon1, and counting what
percentage of them happen to fall within the selected zone:
def computeProbaR(randlatlon, ranCount, minLat, maxLat, minLon, maxLon):
norm = 1.0 / ranCount
pairs = [randlatlon() for i in range(ranCount)]
acceptor = lambda p: ( (p[0] > minLat) and (p[0] < maxLat) and
(p[1] > minLon) and (p[1] < maxLon) )
selCount = sum(1 for p in filter(acceptor, pairs))
return (norm * selCount)
Equipped with these two functions, we can check for various geometric parameter sets
that the geometric and probabilistic results are in good agreement, with ranCount set to one million random points:
ranCount = 1000*1000
print (" ")
probaG1 = computeProbaG( 30, 60, 45, 90)
probaR1 = computeProbaR(randlatlon1, ranCount, 30, 60, 45, 90)
print ("probaG1 = %f" % probaG1)
print ("probaR1 = %f" % probaR1)
print (" ")
probaG2 = computeProbaG( 10, 55, -40, 160)
probaR2 = computeProbaR(randlatlon1, ranCount, 10, 55, -40, 160)
print ("probaG2 = %f" % probaG2)
print ("probaR2 = %f" % probaR2)
print (" ")
Execution output:
$ python3 georandom.py
probaG1 = 0.022877
probaR1 = 0.022852
probaG2 = 0.179307
probaR2 = 0.179644
$
So the two sort of numbers appears to agree reasonably here.
Addendum:
For the sake of completeness, we can add a second algorithm which is less intuitive but derives from a wider statistical principle.
To solve the problem of the latitude distribution, we can use the Inverse Transform Sampling theorem. In order to do so, we need some formula for the probability of the latitude to be less than an arbitrary prescribed value, φ.
The region of the unit 3D sphere whose latitude is less than a given φ is known as a spherical cap. Its area can be obtained thru elementary calculus, as described here for example.
The spherical cap area is given by formula: A = 2π * (1 + sin(φ))
The corresponding probability can be obtained by dividing this area by the overall area of the unit 3D sphere, that is 4π, corresponding to φ = φmax = π/2. Hence:
p = Proba{latitude < φ} = (1/2) * (1 + sin(φ))
Or, conversely:
φ = arcsin (2*p - 1)
From the Inverse Transform Sampling theorem, a fair sampling of the latitude (in radians) is obtained by replacing the probability p by a random variable uniformly distributed between 0 and 1. In Python, this gives:
lat = math.asin(2*random.uniform(0.0, 1.0) - 1.0)
As for the longitude, this is an independent random variable that is still uniformly distributed between -π and +π (in radians). So the overall Python sampler code is:
def randlatlon2r():
pi = math.pi
cf = 180.0 / pi # radians to degrees Correction Factor
u0 = random.uniform(0.0, 1.0)
u1 = random.uniform(0.0, 1.0)
radLat = math.asin(2*u0 - 1.0) # angle with Equator - from +pi/2 to -pi/2
radLon = (2*u1 - 1) * pi # longitude in radians - from -pi to +pi
return (round(radLat*cf,5), round(radLon*cf,5))
This code has been found to pass successfully the sanity check as described above.
Generate a random number between
Latitude: -85 to +85 (actually -85.05115 for some reason)
Longitude: -180 to +180
As #tandem wrote in his answer, the range for latitude is almost -90 to +90 (it is cut on maps) and for longitude it is -180 to +180. To generate random float numbers in this range use random.uniform function:
import random
# returns (lat, lon)
def randlatlon():
return (round(random.uniform( -90, 90), 5),
round(random.uniform(-180, 180), 5))
It is rounded to 5 digits after comma because that extra accuracy is unnecessary.
How would I calculate the area below an EarthSatellite so that I can plot the swath of land covered as the satellite passes over?
Is there anything in Skyfield that would facilitate that?
Edit: Just thought I'd clarify what I mean by area below the satellite. I need to plot the maximum area below the satellite possible to observe given that the Earth is a spheroid. I know how to plot the satellite path, but now I need to plot some lines to represent the area visible by that satellite as it flies over the earth.
Your edit made it clear what you want. The visible area from a satellite can be easily calculated (when the earth is seen as a sphere). A good source to get some background on the visible portion can be found here. To calculate the visible area when the earth is seen as an oblate spheroid will be a lot harder (and maybe even impossible). I think it's better to reform that part of the question and post it on Mathematics.
If you want to calculate the visible area when the earth is seen as a sphere we need to make some adjustments in Skyfield. With a satellite loaded using the TLE api you can easily get a sub point with the position on earth. The library is calling this the Geocentric position, but actually it's the Geodetic position (where the earth is seen as an oblate spheroid). To correct this we need to adjust subpoint of the Geocentric class to use the calculation for the Geocentric position and not the Geodetic position. Due to a bug and missing information in the reverse_terra function we also need to replace that function. And we need to be able to retrieve the earth radius. This results in the following:
from skyfield import api
from skyfield.positionlib import ICRF, Geocentric
from skyfield.constants import (AU_M, ERAD, DEG2RAD,
IERS_2010_INVERSE_EARTH_FLATTENING, tau)
from skyfield.units import Angle
from numpy import einsum, sqrt, arctan2, pi, cos, sin
def reverse_terra(xyz_au, gast, iterations=3):
"""Convert a geocentric (x,y,z) at time `t` to latitude and longitude.
Returns a tuple of latitude, longitude, and elevation whose units
are radians and meters. Based on Dr. T.S. Kelso's quite helpful
article "Orbital Coordinate Systems, Part III":
https://www.celestrak.com/columns/v02n03/
"""
x, y, z = xyz_au
R = sqrt(x*x + y*y)
lon = (arctan2(y, x) - 15 * DEG2RAD * gast - pi) % tau - pi
lat = arctan2(z, R)
a = ERAD / AU_M
f = 1.0 / IERS_2010_INVERSE_EARTH_FLATTENING
e2 = 2.0*f - f*f
i = 0
C = 1.0
while i < iterations:
i += 1
C = 1.0 / sqrt(1.0 - e2 * (sin(lat) ** 2.0))
lat = arctan2(z + a * C * e2 * sin(lat), R)
elevation_m = ((R / cos(lat)) - a * C) * AU_M
earth_R = (a*C)*AU_M
return lat, lon, elevation_m, earth_R
def subpoint(self, iterations):
"""Return the latitude an longitude directly beneath this position.
Returns a :class:`~skyfield.toposlib.Topos` whose ``longitude``
and ``latitude`` are those of the point on the Earth's surface
directly beneath this position (according to the center of the
earth), and whose ``elevation`` is the height of this position
above the Earth's center.
"""
if self.center != 399: # TODO: should an __init__() check this?
raise ValueError("you can only ask for the geographic subpoint"
" of a position measured from Earth's center")
t = self.t
xyz_au = einsum('ij...,j...->i...', t.M, self.position.au)
lat, lon, elevation_m, self.earth_R = reverse_terra(xyz_au, t.gast, iterations)
from skyfield.toposlib import Topos
return Topos(latitude=Angle(radians=lat),
longitude=Angle(radians=lon),
elevation_m=elevation_m)
def earth_radius(self):
return self.earth_R
def satellite_visiable_area(earth_radius, satellite_elevation):
"""Returns the visible area from a satellite in square meters.
Formula is in the form is 2piR^2h/R+h where:
R = earth radius
h = satellite elevation from center of earth
"""
return ((2 * pi * ( earth_radius ** 2 ) *
( earth_radius + satellite_elevation)) /
(earth_radius + earth_radius + satellite_elevation))
stations_url = 'http://celestrak.com/NORAD/elements/stations.txt'
satellites = api.load.tle(stations_url)
satellite = satellites['ISS (ZARYA)']
print(satellite)
ts = api.load.timescale()
t = ts.now()
geocentric = satellite.at(t)
geocentric.subpoint = subpoint.__get__(geocentric, Geocentric)
geocentric.earth_radius = earth_radius.__get__(geocentric, Geocentric)
geodetic_sub = geocentric.subpoint(3)
print('Geodetic latitude:', geodetic_sub.latitude)
print('Geodetic longitude:', geodetic_sub.longitude)
print('Geodetic elevation (m)', int(geodetic_sub.elevation.m))
print('Geodetic earth radius (m)', int(geocentric.earth_radius()))
geocentric_sub = geocentric.subpoint(0)
print('Geocentric latitude:', geocentric_sub.latitude)
print('Geocentric longitude:', geocentric_sub.longitude)
print('Geocentric elevation (m)', int(geocentric_sub.elevation.m))
print('Geocentric earth radius (m)', int(geocentric.earth_radius()))
print('Visible area (m^2)', satellite_visiable_area(geocentric.earth_radius(),
geocentric_sub.elevation.m))
I'm trying to calculate the drag of a sphere if it were to be dropped off a building, the program runs but the equations wrong. It could be that I'm just making this overly complexed, but I'm stuck right now.. What I am trying to do is determine the amount of distance the sphere has traveled in the allotted time (Which works), but I am unable to figure out a way to use drag as a factor. Any help would be appreciated
import math
height = float(raw_input("Enter the height of the building: ")) #meters
weight = float(raw_input("Enter the weight of the sphere: ")) #weight of sphere in kilograms
mass = float(raw_input("Mass of the sphere: ")) #mass of the sphere
time = float(raw_input("Enter the time interval: ")) #determines how long to continue the experiment after the sphere has been dropped
# kilograms
#variables
velocity = math.sqrt(2) * height * weight #calculate the velocity
energy = 1 / 2 * mass * velocity ** 2 #kinetic energy
gravity = 9.81 #gravity
radius = 0.5 #radius of the sphere being dropped
volume = 4.3 * math.pi * radius ** 3 #calculate the volume
speed = gravity * time #determine the maximum speed in the time allotted
density = mass / volume #determine the density of the sphere
force = mass * gravity #determine the force in newtons
drag = gravity * density * speed ** 2 #calculate the drag
distance = .5 * gravity * time ** 2 #calculate the distance traveled
print "Force = {} Newtons".format(force)
print "The ball is", height - distance, "meters from the ground"
print "The maximum speed of the ball was:", speed
print "It would take the ball {} seconds to reach terminal velocity"#.format(None)
print "Density:", density
print "Drag: ", drag
print "Mass: ", mass
print "Volume: ", volume
print "Velocity: ", velocity
Python 2.7 defaults to integer division, so
energy = 1 / 2 * mass * vellocity ** 2
is equivalent to
energy = (1 // 2) * mass * velocity ** 2 = 0 * mass * velocity ** 2 = 0
To default to floating point division, place the following line at the top of your script:
from __future__ import division
or simply write energy as:
energy = 0.5 * mass * velocity ** 2
You are given the diameter across, and the length of the segment or chord. The diameter for my question is 12, and the chord is 10. You have to find the height of the shaded segment, and then print the area. The original formula is A=2/3ch + h^3/2c. My classmates got 18 for the area, but when I use my code I get 41.
This is the closest picture representation I can find. However there is a dashed line from ϴ to s.
from math import sqrt
diamStr=input("Enter the length of the diameter: ")
diameter=int(diamStr)
chordStr = input( " Enter the chord length: ")
chord = int(chordStr)
radius = (diameter/2)
s = sqrt (diameter**2+chord**2)
h = (s/2-radius)
i= (2/3*chord*h)
j=(h**3/2*chord)
area = (i+j)
print (area)
Unfortunately there's something wrong with your formula but if look at the problem with some elementary mathematics you may notice that the angle ϴ can be found using the cosine rule since we know the 3 lengths (the two radius and chord length)
In Python it would be:
theta = math.acos((radius**2 + radius**2 - chord**2)/(2*radius**2))
Since the variable theta is already in radians we can use this formula to calculate the area of the segment :
which in python would be area = 1/2 * (theta - math.sin(theta)) * radius**2
Therefore after merging all of these we come up with a elegant solution:
import math
diamStr=input("Enter the length of the diameter: ")
diameter=int(diamStr)
chordStr = input( " Enter the chord length: ")
chord = int(chordStr)
radius = (diameter/2)
theta = math.acos((radius**2 + radius**2 - chord**2)/(2*radius**2))
area = 1/2 * (theta - math.sin(theta)) * radius**2
#print(round((area),2))
print(area)
If you enter diameter as 12cm and chord length as 10 you'll get 18.880864248381847 but you can round it to any number of decimal places you want by the round() function.
eg: print(round((area),2)) prints 18.88