patternpythonMinor
Performing calculations with a catalog of stars
Viewed 0 times
performingwithcalculationsstarscatalog
Problem
The point of my code is to:
-
Read in the observed data from the a catalog of stars (whitespace separated table).
-
Do some unit conversions on the observed data (math stuff).
-
Apply an interstellar correction factor to the observed data (more math).
-
Compare the scaled observed data to the DUSTY model data using the BC table, using a least-squares approach (comparison of observed data to theoretical models found in a large table).
-
Find the best fit models for the observed data (should be obvious).
I'm trying to rewrite 'spaghetti code' I was handed, that doesn't function quickly, nor does it allow for easy updating (adding different statistical calculations, etc.). I'm pretty new to Python, so I'm struggling with the idea of classes and this is my attempt at it.
```
class Stellar_setup:
Fbol=5.01333e-10
c=2.99792458e+8
L=1000
star_list=[]
dusty_models=np.array([]) #Array of all the dusty models
incoming_stars='' #List of incoming stars
def __init__(self):
"""Initiates the below modules."""
self.star_catalog()
self.InputKey()
def star_catalog(self):
"""Imports the star catalog"""
try:
star_catalog=raw_input('Input pathname of stellar catalog: ')
star_list=[]
with open(star_catalog) as incoming_stars:
for line in incoming_stars.readlines():
x=[item for item in line.split()]
star_list.append(x) #Appends the individual star-IDs to the empty array star_list.
print 'Stars imported successfully.'
except IOError:
print 'Star import unsuccessful. Check that the star catalog file-path is correct. Program exiting now.'
sys.exit()
def InputKey(self):
"""Imports the Input (.inp) file. Historically, InputUt.inp.
Allows for definition of parameters which are utilized later in the script."""
input_script=raw_input('Pathname of .in
-
Read in the observed data from the a catalog of stars (whitespace separated table).
-
Do some unit conversions on the observed data (math stuff).
-
Apply an interstellar correction factor to the observed data (more math).
-
Compare the scaled observed data to the DUSTY model data using the BC table, using a least-squares approach (comparison of observed data to theoretical models found in a large table).
-
Find the best fit models for the observed data (should be obvious).
I'm trying to rewrite 'spaghetti code' I was handed, that doesn't function quickly, nor does it allow for easy updating (adding different statistical calculations, etc.). I'm pretty new to Python, so I'm struggling with the idea of classes and this is my attempt at it.
```
class Stellar_setup:
Fbol=5.01333e-10
c=2.99792458e+8
L=1000
star_list=[]
dusty_models=np.array([]) #Array of all the dusty models
incoming_stars='' #List of incoming stars
def __init__(self):
"""Initiates the below modules."""
self.star_catalog()
self.InputKey()
def star_catalog(self):
"""Imports the star catalog"""
try:
star_catalog=raw_input('Input pathname of stellar catalog: ')
star_list=[]
with open(star_catalog) as incoming_stars:
for line in incoming_stars.readlines():
x=[item for item in line.split()]
star_list.append(x) #Appends the individual star-IDs to the empty array star_list.
print 'Stars imported successfully.'
except IOError:
print 'Star import unsuccessful. Check that the star catalog file-path is correct. Program exiting now.'
sys.exit()
def InputKey(self):
"""Imports the Input (.inp) file. Historically, InputUt.inp.
Allows for definition of parameters which are utilized later in the script."""
input_script=raw_input('Pathname of .in
Solution
This looks like procedural code, poorly dressed up in object-oriented style. Python doesn't require you to write object-oriented code, but if you do, you should model it properly.
Think of objects as "smart" data structures. If your classes are well designed, you can ask the objects to perform operations on themselves in such a way that you don't have to worry about the details of how it performs the task.
For example,
Once your model is defined, you can start using it!
Notice how the classes are designed to separate concerns. The
The class interfaces that you design are what prevent your code from being spaghetti. If you design your class interfaces well, you will have a loose coupling, such that you will be able to reuse the class in other programs, and modify the inner workings of the class without disturbing the code that uses your class.
A good rule to follow is that each class should represent one thing. If you can't think of a short, descriptive name for the class, that's a sign that you're on the wrong track. Also, the class name must be a noun; if it's a verb, you're using procedural rather than object-oriented thinking.
Think of objects as "smart" data structures. If your classes are well designed, you can ask the objects to perform operations on themselves in such a way that you don't have to worry about the details of how it performs the task.
For example,
StarCatalog should definitely be a class of its own. There should probably be a Star class as well. The outline of those classes might look like:class Star:
def __init__(self, id, magnitude, right_ascension, declination):
...
def id(self):
...
def magnitude(self):
...
def coordinates(self):
...
class StarCatalog:
def __init__(self):
...
def add_star(self, star):
...
def remove_star(self, id):
...
def get_star(self, id):
...
def __iter__(self):
...
class StarCatalogImporter:
def __init__(self, catalog):
...
def import_file(filename):
...Once your model is defined, you can start using it!
catalog = StarCatalog()
importer = StarCatalogImporter(catalog)
try:
importer.import_file(raw_input('Input pathname of stellar catalog: '))
print 'Stars imported successfully.'
except IOError:
print 'Star import unsuccessful. Check that the star catalog file-path is correct. Program exiting now.'
raise
corrector = InterstellarCorrector(correction_factor=0.2342)
corrected_catalog = corrector.correct(catalog)
result = least_sq_correlator.correlate(corrected_catalog, dusty_model)Notice how the classes are designed to separate concerns. The
StarCatalogImporter class knows how to add the stars listed in a file into a StarCatalog; once that is done, you can ask the catalog to enumerate its stars. The StarCatalogImporter interface should be as reusable as possible. For example, if it encounters an error while importing, it raises an exception, rather than printing a message and exiting. The code that uses the StarCatalog decides how to handle those situations. (It might print an error message and exit. It might be a GUI application, in which case it would display the error in a dialog box. It might translate the error message into another language. It might try to load a different catalog instead.) On the other hand, the code that uses a StarCatalog should make no assumptions about how the star catalog is implemented. It doesn't know if the StarCatalog internally uses an array, a dict, or a numpy matrix. Therefore, it should only use the functions exposed by the class.The class interfaces that you design are what prevent your code from being spaghetti. If you design your class interfaces well, you will have a loose coupling, such that you will be able to reuse the class in other programs, and modify the inner workings of the class without disturbing the code that uses your class.
A good rule to follow is that each class should represent one thing. If you can't think of a short, descriptive name for the class, that's a sign that you're on the wrong track. Also, the class name must be a noun; if it's a verb, you're using procedural rather than object-oriented thinking.
Code Snippets
class Star:
def __init__(self, id, magnitude, right_ascension, declination):
...
def id(self):
...
def magnitude(self):
...
def coordinates(self):
...
class StarCatalog:
def __init__(self):
...
def add_star(self, star):
...
def remove_star(self, id):
...
def get_star(self, id):
...
def __iter__(self):
...
class StarCatalogImporter:
def __init__(self, catalog):
...
def import_file(filename):
...catalog = StarCatalog()
importer = StarCatalogImporter(catalog)
try:
importer.import_file(raw_input('Input pathname of stellar catalog: '))
print 'Stars imported successfully.'
except IOError:
print 'Star import unsuccessful. Check that the star catalog file-path is correct. Program exiting now.'
raise
corrector = InterstellarCorrector(correction_factor=0.2342)
corrected_catalog = corrector.correct(catalog)
result = least_sq_correlator.correlate(corrected_catalog, dusty_model)Context
StackExchange Code Review Q#28787, answer score: 5
Revisions (0)
No revisions yet.