Physique

Mini Table of Contents

  • Using Physique from a working directory not containing Physique itself
  • NIST Fundamental Constants
  • NIST Official Conversions (to metric)
  • Webscraping example: JPL Solar System Dynamics (JPL SSD) - Planets and Pluto

Using Physique from a working directory not containing Physique itself


In [4]:
import os, sys

Get the current directory


In [10]:
currentdir = os.getcwd(); os.getcwd();

Then append the directory containing the Physique package/library (it's just a folder) with sys.path.append; the absolute path for where I placed it just happened to be "/Users/ernestyeung/Documents/TeslaModelSP85D": substitute that for the absolute path you find (look at your Finder or File organizing program)


In [11]:
currentdir # I'm on a different computer now


Out[11]:
'/home/topolo/PropD/Propulsion/Physique'

In [5]:
sys.path.append('/home/topolo/PropD/Propulsion/')

In [6]:
import Physique


/home/topolo/PropD/Propulsion/Physique
/home/topolo/PropD/Propulsion/Physique/rawdata/

Programming note: __init__.py in the main directory uses os.path.dirname(__file__) with __file__ (literally that, it's not a placeholder name) being the string with the absolute pathname of the "file from which the module was loaded, if it was loaded from a file" (cf. stackoverflow Python file attribute absolute or relative?), i.e. "When a module is loaded in Python, __file__ is set to its name. You can then use that with other functions to find the directory that the file is located in." (cf. stackoverflow what does the file wildcard mean/do?)

NIST Fundamental Constants


In [21]:
from Physique import FundConst
print Physique.FundConst.columns
Physique.FundConst


Index([u'Quantity', u'Value', u'Uncertainty', u'Unit'], dtype='object')
Out[21]:
Quantity Value Uncertainty Unit
0 {220} lattice spacing of silicon 1.920155714E-10 3.2E-18 m
1 alpha particle-electron mass ratio 7294.29954136 2.4E-7
2 alpha particle mass 6.644657230E-27 8.2E-35 kg
3 alpha particle mass energy equivalent 5.971920097E-10 7.3E-18 J
4 alpha particle mass energy equivalent in MeV 3727.379378 0.000023 MeV
5 alpha particle mass in u 4.001506179127 6.3E-11 u
6 alpha particle molar mass 0.004001506179127 6.3E-14 kg mol^-1
7 alpha particle-proton mass ratio 3.97259968907 3.6E-10
8 Angstrom star 1.00001495E-10 9.0E-17 m
9 atomic mass constant 1.660539040E-27 2.0E-35 kg
10 atomic mass constant energy equivalent 1.492418062E-10 1.8E-18 J
11 atomic mass constant energy equivalent in MeV 931.4940954 0.0000057 MeV
12 atomic mass unit-electron volt relationship 931494095.4 5.7 eV
13 atomic mass unit-hartree relationship 34231776.902 0.016 E_h
14 atomic mass unit-hertz relationship 2.2523427206E+23 1.0E+14 Hz
15 atomic mass unit-inverse meter relationship 7.5130066166E+14 3.4E+5 m^-1
16 atomic mass unit-joule relationship 1.492418062E-10 1.8E-18 J
17 atomic mass unit-kelvin relationship 1.08095438E+13 6.2E+6 K
18 atomic mass unit-kilogram relationship 1.660539040E-27 2.0E-35 kg
19 atomic unit of 1st hyperpolarizability 3.206361329E-53 2.0E-61 C^3 m^3 J^-2
20 atomic unit of 2nd hyperpolarizability 6.235380085E-65 7.7E-73 C^4 m^4 J^-3
21 atomic unit of action 1.054571800E-34 1.3E-42 J s
22 atomic unit of charge 1.6021766208E-19 9.8E-28 C
23 atomic unit of charge density 1.0812023770E+12 6.7E+3 C m^-3
24 atomic unit of current 0.006623618183 4.1E-11 A
25 atomic unit of electric dipole mom. 8.478353552E-30 5.2E-38 C m
26 atomic unit of electric field 5.142206707E+11 3.2E+3 V m^-1
27 atomic unit of electric field gradient 9.717362356E+21 6.0E+13 V m^-2
28 atomic unit of electric polarizability 1.6487772731E-41 1.1E-50 C^2 m^2 J^-1
29 atomic unit of electric potential 27.21138602 1.7E-7 V
... ... ... ... ...
305 standard-state pressure 100000 None Pa
306 Stefan-Boltzmann constant 5.670367E-8 1.3E-13 W m^-2 K^-4
307 tau Compton wavelength 6.97787E-16 6.3E-20 m
308 tau Compton wavelength over 2 pi 1.11056E-16 1.0E-20 m
309 tau-electron mass ratio 3477.15 0.31
310 tau mass 3.16747E-27 2.9E-31 kg
311 tau mass energy equivalent 2.84678E-10 2.6E-14 J
312 tau mass energy equivalent in MeV 1776.82 0.16 MeV
313 tau mass in u 1.90749 0.00017 u
314 tau molar mass 0.00190749 1.7E-7 kg mol^-1
315 tau-muon mass ratio 16.8167 0.0015
316 tau-neutron mass ratio 1.89111 0.00017
317 tau-proton mass ratio 1.89372 0.00017
318 Thomson cross section 6.6524587158E-29 9.1E-38 m^2
319 triton-electron mass ratio 5496.92153588 2.6E-7
320 triton g factor 5.957924920 2.8E-8
321 triton mag. mom. 1.504609503E-26 1.2E-34 J T^-1
322 triton mag. mom. to Bohr magneton ratio 0.0016223936616 7.6E-12
323 triton mag. mom. to nuclear magneton ratio 2.978962460 1.4E-8
324 triton mass 5.007356665E-27 6.2E-35 kg
325 triton mass energy equivalent 4.500387735E-10 5.5E-18 J
326 triton mass energy equivalent in MeV 2808.921112 0.000017 MeV
327 triton mass in u 3.01550071632 1.1E-10 u
328 triton molar mass 0.00301550071632 1.1E-13 kg mol^-1
329 triton-proton mass ratio 2.99371703348 2.2E-10
330 unified atomic mass unit 1.660539040E-27 2.0E-35 kg
331 von Klitzing constant 25812.8074555 0.0000059 ohm
332 weak mixing angle 0.2223 0.0021
333 Wien frequency displacement law constant 5.8789238E+10 3.4E+4 Hz K^-1
334 Wien wavelength displacement law constant 0.0028977729 1.7E-9 m K

335 rows × 4 columns

Find a Fundamental Constant you are interested in using the usual panda modules


In [41]:
g_0pd = FundConst[ FundConst["Quantity"].str.contains("gravity") ] 
# standard acceleration of gravity as a panda DataFrame
g_0pd


Out[41]:
Quantity Value Uncertainty Unit
303 standard acceleration of gravity 9.80665 None m s^-2

In [32]:
# access the values you're interested in 
print g_0pd.Quantity
print g_0pd.Value.get_values()[0] 
print g_0pd.Unit.get_values()[0]


303    standard acceleration of gravity
Name: Quantity, dtype: object
9.80665
m s^-2

In [43]:
# you can also grab just the 1 entry from this DataFrame using the .loc module
FundConst[FundConst["Quantity"].str.contains("Boltzmann")].loc[49,:]


Out[43]:
Quantity       standard acceleration of gravity
Value                                   9.80665
Uncertainty                                None
Unit                                     m s^-2
Name: 303, dtype: object

In [44]:
g_0pd.loc[303,:]


Out[44]:
Quantity       standard acceleration of gravity
Value                                   9.80665
Uncertainty                                None
Unit                                     m s^-2
Name: 303, dtype: object

NIST Official Conversions (to metric)

This is the pandas DataFrame containing all the NIST Official Conversions to SI.


In [11]:
convDF = Physique.conv

In [12]:
convDF.columns


Out[12]:
Index([u'Toconvertfrom', u'to', u'Multiplyby'], dtype='object')

From the list of columns, search for the quantity you desired by trying out different search terms: e.g. I'm reading Huzel and Huang's Modern Engineering for Design of Liquid-Propellant Rocket Engines and I want to know how to convert from

  • lb (pound or pound-force) for thrust into force in Newton (N)
  • psia (pounds per square inch absolute) for (chamber) pressure into pressure in Pascal (Pa)

We can try to look up the U.S. or Imperial units from the Toconvertfrom column.


In [13]:
convDF[convDF['Toconvertfrom'].str.contains("pound-force ")]


Out[13]:
Toconvertfrom to Multiplyby
175 foot pound-force (ft · lbf) joule (J) 1.355818
176 foot pound-force per hour (ft · lbf/h) watt (W) 0.0003766161
177 foot pound-force per minute (ft · lbf/min) watt (W) 0.02259697
178 foot pound-force per second (ft · lbf/s) watt (W) 1.355818
340 pound-force (lbf) 23 newton (N) 4.448222
341 pound-force foot (lbf · ft) newton meter (N · m) 1.355818
342 pound-force foot per inch (lbf · ft/in) newton meter per meter (N · m/m) 53.37866
343 pound-force inch (lbf · in) newton meter (N · m) 0.1129848
344 pound-force inch per inch (lbf · in/in) newton meter per meter (N · m/m) 4.448222
345 pound-force per foot (lbf/ft) newton per meter (N/m) 14.59390
346 pound-force per inch (lbf/in) newton per meter (N/m) 175.1268
347 pound-force per pound (lbf/lb) \n (thrust t... newton per kilogram (N/kg) 9.80665
348 pound-force per square foot (lbf/ft2) pascal (Pa) 47.88026
349 pound-force per square inch (psi) \n (lbf/in2) pascal (Pa) 6894.757
350 pound-force per square inch (psi) (lbf/in2) kilopascal (kPa) 6.894757
351 pound-force second per square foot \n (lbf ... pascal second (Pa · s) 47.88026
352 pound-force second per square inch \n (lbf ... pascal second (Pa · s) 6894.757
372 psi (pound-force per square inch) (lbf/in2) pascal (Pa) 6894.757
373 psi (pound-force per square inch) (lbf/in2) kilopascal (kPa) 6.894757

Or we can look up the SI unit we want to convert to.


In [14]:
convDF[convDF['to'].str.contains("newton ")]


Out[14]:
Toconvertfrom to Multiplyby
137 dyne (dyn) newton (N) 0.000010
138 dyne centimeter (dyn · cm) newton meter (N · m) 1.0E-7
238 kilogram-force (kgf) newton (N) 9.80665
239 kilogram-force meter (kgf · m) newton meter (N · m) 9.80665
247 kilopond (kilogram-force) (kp) newton (N) 9.80665
250 kip (1 kip= 1000 lbf) newton (N) 4448.222
251 kip (1 kip= 1000 lbf) kilonewton (kN) 4.448222
300 ounce (avoirdupois)-force (ozf) newton (N) 0.2780139
301 ounce (avoirdupois)-force inch (ozf · in) newton meter (N · m) 0.007061552
302 ounce (avoirdupois)-force inch (ozf · in) millinewton meter (mN · m) 7.061552
336 poundal newton (N) 0.1382550
340 pound-force (lbf) 23 newton (N) 4.448222
341 pound-force foot (lbf · ft) newton meter (N · m) 1.355818
342 pound-force foot per inch (lbf · ft/in) newton meter per meter (N · m/m) 53.37866
343 pound-force inch (lbf · in) newton meter (N · m) 0.1129848
344 pound-force inch per inch (lbf · in/in) newton meter per meter (N · m/m) 4.448222
345 pound-force per foot (lbf/ft) newton per meter (N/m) 14.59390
346 pound-force per inch (lbf/in) newton per meter (N/m) 175.1268
347 pound-force per pound (lbf/lb) \n (thrust t... newton per kilogram (N/kg) 9.80665
423 ton-force (2000 lbf) newton (N) 8896.443
424 ton-force (2000 lbf) kilonewton (kN) 8.896443

Look at what you want and see the index; it happens to be 340 in this example.


In [16]:
lbf2N = convDF.loc[340,:]; lbf2N


Out[16]:
Toconvertfrom    pound-force (lbf) 23
to                         newton (N)
Multiplyby                   4.448222
Name: 340, dtype: object

Then the attributes can accessed by the column names.


In [19]:
print lbf2N.Toconvertfrom, lbf2N.to, lbf2N.Multiplyby


pound-force (lbf) 23 newton (N) 4.448222

So for example, the reusable SSME delivers a vacuum thrust of 470000 lb or


In [21]:
print 470000*lbf2N.Multiplyby, lbf2N.to


2090664.340000 newton (N)

To obtain the conversion for pressure in psia, which we search for with "psi"


In [22]:
convDF[convDF['Toconvertfrom'].str.match("psi")]


Out[22]:
Toconvertfrom to Multiplyby
372 psi (pound-force per square inch) (lbf/in2) pascal (Pa) 6894.757
373 psi (pound-force per square inch) (lbf/in2) kilopascal (kPa) 6.894757

So for a chamber pressure of 3028 psia for the SSME,


In [23]:
psi2Pa = convDF.loc[372,:]

In [24]:
print 3028*psi2Pa.Multiplyby, psi2Pa.to


20877324.196 pascal (Pa)

Also, get the conversion for atmospheres (atm):


In [26]:
convDF[convDF['Toconvertfrom'].str.match("atm")]


Out[26]:
Toconvertfrom to Multiplyby
15 atmosphere, standard (atm) pascal (Pa) 101325
16 atmosphere, standard (atm) kilopascal (kPa) 101.325
17 atmosphere, technical (at) 8 pascal (Pa) 98066.5
18 atmosphere, technical (at) 8 kilopascal (kPa) 98.0665

In [27]:
atm2Pa = convDF.loc[15,:]

In [29]:
print 3028*psi2Pa.Multiplyby/atm2Pa.Multiplyby, atm2Pa.Toconvertfrom


206.0431699580557611645694547 atmosphere, standard (atm)

Webscraping example: JPL Solar System Dynamics (JPL SSD) - Planets and Pluto

Take a look at the file scrape_BS.py in this Physique folder. BS stands for the BeautifulSoup python module that's extensively used here. Start at the class called scraped_BS which will use the python module requests to put the html out from a url address into a BeautifulSoup object.


In [11]:
JPL_SSD_URL = "http://ssd.jpl.nasa.gov/" # JPL NASA Solar System Dynamics webpage

In [12]:
jpl_ssd_BS = Physique.scrape_BS.scraped_BS(JPL_SSD_URL)


/home/topolo/Public/anaconda2/lib/python2.7/site-packages/bs4/__init__.py:166: UserWarning: No parser was explicitly specified, so I'm using the best available HTML parser for this system ("lxml"). This usually isn't a problem, but if you run this code on another system, or in a different virtual environment, it may use a different parser and behave differently.

To get rid of this warning, change this:

 BeautifulSoup([your markup])

to this:

 BeautifulSoup([your markup], "lxml")

  markup_type=markup_type))

Take a look at it with the usual BeautifulSoup modules (i.e. functions).

Now, as the Udacity Data Wrangling instructor said, Shannon Bradshaw, taught, we're going to need to use the Inspect Element (Firefox), or Develop -> Web Inspector (Mac OS X Safari) functions on your web browswer to see what the relevant html codes are.

Now in this particular case (webpage formats are all different; assume the worst), there are no distinguishing classes for the tables (they're just nested tables on tables). cf. stackoverflow.com BeautifulSoup scraping nested tables I'm using the solution from this stackoverflow answer.


In [35]:
# for table in jpl_ssd_BS.soup.find_all("table"):
#    for subtable in table.find_all("table"):
#        print subtable.find("table") # uncomment this out and run it to see the whole darn thing

Let's just focus on the Physical Data subpage for today. This is the way to find a specific tag (in this case img) with a specific attribute (in this case alt="PHYSICAL DATA"), and then the parent module gets its parent. Then the href index in the square brackets [] gets the web address we desire.


In [46]:
jpl_ssd_BS.soup.find('img',{"alt":"PHYSICAL DATA"}).parent['href']


Out[46]:
'/?phys_data'

In [48]:
JPL_SSD_PHYS_DATA_URL = JPL_SSD_URL + jpl_ssd_BS.soup.find('img',{"alt":"PHYSICAL DATA"}).parent['href'][1:]
JPL_SSD_PHYS_DATA_URL


Out[48]:
'http://ssd.jpl.nasa.gov/?phys_data'

In [49]:
jpl_ssd_phys_data_BS = Physique.scrape_BS.scraped_BS(JPL_SSD_PHYS_DATA_URL)

At this point, I wish there was a rational and civilized manner to scrape all the relevant quantitative data from here for all the links (using Scrapy?) but I need help at this point for that endeavor. Otherwise, I manually look at the webpage itself and manually use Inspect Element to find what I want and then use BeautifulSoup accordingly.


In [81]:
jpl_ssd_phys_data_BS.soup.find('h2',text="Planets").find_next('a')


Out[81]:
'?planet_phys_par'

In [82]:
JPL_SSD_PLANET_PHYS_PAR_URL = JPL_SSD_URL + jpl_ssd_phys_data_BS.soup.find('h2',text="Planets").find_next('a')['href']
jpl_ssd_planet_phys_par_BS = Physique.scrape_BS.scraped_BS(JPL_SSD_PLANET_PHYS_PAR_URL)

In [104]:
jpl_ssd_planet_phys_parTBL = jpl_ssd_planet_phys_par_BS.soup.find("div", {"class":"page_title"}).find_next("table")

Time to scrape the actual html code for the table we desire: jpl_ssd_planet_phys_parTBL. Take a look at the function make_conv_lst in scrape_BS.py and take a look at that first for loop. That's the procedure we'll take (and I confirmed that this is in practice what's done on stackoverflow). But wait: the data values are themselves tables. So again, there is no rhyme or reason for the logic or rationale for the html tables for data, in general, for any websites. So I'll get the headers first (which makes sense) and do an ugly hack for the data values (also notice the recursive=False option).


In [197]:
data = []
for row in jpl_ssd_planet_phys_parTBL.find_all('tr', recursive=False):
    cols = row.find_all('td', recursive=False)
    cols = [ele.text if ele.text != u'\xa0' else u'' for ele in cols]
    data.append(cols) 
hdrs = data[:2]    # get the headers first

In [198]:
jpl_ssd_planet_phys_parTBL.find_all('tr')[2].find_all('td')[18].text
data = [[row[0].replace(u'\xa0',''),]+row[1:] for row in data[2:]]  # remove the space, \xa0 from each of the planet's names
data = [[row[0],]+[ele.replace('\n','') for ele in row[1:]] for row in data] # remove the '\n' strings
data = [[row[0],]+[ele.split(u'\xb1')[0] for ele in row[1:]] for row in data] # let's just get the values 
data = [[row[0],]+[ele.split(u'\xa0')[0] for ele in row[1:]] for row in data] # let's just get the values

I'll add back the units as part of the data (I don't know a sane and civilized way of attaching to each of the column names in pandas, a pandas DataFrame, the units, as extra information)


In [199]:
data = [hdrs[1],] + data

In [202]:
import pandas as pd
data = pd.DataFrame( data )
data.columns = hdrs[0]

In [203]:
data


Out[203]:
Planet EquatorialRadius MeanRadius Mass BulkDensity SiderealRotation Period SiderealOrbit Period V(1,0) GeometricAlbedo EquatorialGravity EscapeVelocity
0 (km) (km) (x 1024 kg) (g cm-3) (d) (y) (mag) (m s-2) (km s-1)
1 Mercury 2439.7 2439.7 0.330104 5.427 58.6462 0.2408467 -0.60 0.106 3.70 4.25
2 Venus 6051.8 6051.8 4.86732 5.243 -243.018 0.61519726 -4.47 0.65 8.87 10.36
3 Earth 6378.14 6371.00 5.97219 5.5134 0.99726968 1.0000174 -3.86 0.367 9.80 11.19
4 Mars 3396.19 3389.50 0.641693 3.9340 1.02595676 1.8808476 -1.52 0.150 3.71 5.03
5 Jupiter 71492 69911 1898.13 1.3262 0.41354 11.862615 -9.40 0.52 24.79 60.20
6 Saturn 60268 58232 568.319 0.6871 0.44401 29.447498 -8.88 0.47 10.44 36.09
7 Uranus 25559 25362 86.8103 1.270 -0.71833 84.016846 -7.19 0.51 8.87 21.38
8 Neptune 24764 24622 102.410 1.638 0.67125 164.79132 -6.87 0.41 11.15 23.56
9 Pluto 1151 1151 .01309 2.05 -6.3872 247.92065 -1.0 0.3 0.66 1.23

Time to save our work as a "pickle'd" pandas DataFrame.


In [204]:
data.to_pickle('./rawdata/JPL_NASA_SSD_Planet_Phys_Par_values.pkl') # values only

And so to access this, to use in Python, do the following, using .read_pickle of pandas:


In [207]:
PlanetParDF = pd.read_pickle('./rawdata/JPL_NASA_SSD_Planet_Phys_Par_values.pkl')

In [ ]: