zemogle / chemevol Goto Github PK
View Code? Open in Web Editor NEWChemical evolution python package
Chemical evolution python package
need to have column headings written out in file output (in data.py
, which is called in main.py
)
Setting dust_source to 'LIMS+SN' didn't turn off grain growth
Make plotting smarter and neater
We need to read in Z(t-taum) in ejected_metal_mass
and ejected_dust_mass
- currently we are reading in Z (metallicity).
In line 245 of the code evolve.py there is a typo:
time_lookup = Planck12.age(redshift_lookup).value
Shouldn't this be:
time_lookup = Planck13.age(redshift_lookup).value
With the second line I could run chemevol
need to separate LIMS and SNe dust in dust_mass
- currently have grain growth and dust from stars separated and output in an array but not split into SN and LIMS. User can do this using muliple runs but that seems a bit longwinded
Currently takes 18, 21, 27s to run gasmass
, metalmass
and dustmass
routines
Python version: v3.7.6 (with iPython version 7.14.0)
Module version: v_de_vis2017
Code to reproduce issue:
In [1]: import chemevol as ch
Error message:
---------------------------------------------------------------------------
ModuleNotFoundError Traceback (most recent call last)
<ipython-input-1-7161a0cd8111> in <module>
----> 1 import chemevol as ch
~/anaconda3/lib/python3.7/site-packages/chemevol-0.3-py3.7.egg/chemevol/__init__.py in <module>
----> 1 from .evolve import *
~/anaconda3/lib/python3.7/site-packages/chemevol-0.3-py3.7.egg/chemevol/evolve.py in <module>
30 '''
31
---> 32 from functions import extra_sfh, astration, remnant_mass, imf_chab, imf_topchab, \
33 imf_salp, imf_kroup, initial_mass_function, initial_mass_function_integral, \
34 ejected_gas_mass, fresh_metals, lookup_fn, lookup_taum, mass_integral, mass_yields, \
ModuleNotFoundError: No module named 'functions'
Proposed solution:
In evolve.py Line 32, change functions to .functions
Running line_profiler
and profiling every function in evolve.py
has yeilded the following:
Timer unit: 1e-06 s
Total time: 0.059587 s
File: evolve.py
Function: load_sfh at line 96
Line # Hits Time Per Hit % Time Line Contents
==============================================================
96 @profile
97 def load_sfh(self):
98 '''
99 takes in input SFH file and extend backwards to start from 1e-3 Gyr
100 '''
101 2 6 3.0 0.0 try:
102 2 48635 24317.5 81.6 vals = np.loadtxt(self.SFH_file)
103 2 6 3.0 0.0 scale = [1e-9,1e9] # Gyr conversions for time, SFR
104 2 74 37.0 0.1 sfh = vals*scale # converts time in Gyr and SFR in Msun/Gyr
105 # extrapolates SFH back to 0.001Gyr using SFH file and power law (gamma)
106 2 9273 4636.5 15.6 final_sfh = f.extra_sfh(sfh, self.gamma)
107 2 1593 796.5 2.7 self.sfh = np.array(final_sfh)
108 except:
109 logger.error("File '%s' will not parse" % self.SFH_file)
110 self.sfh = None
Total time: 0.559438 s
File: evolve.py
Function: sfr at line 112
Line # Hits Time Per Hit % Time Line Contents
==============================================================
112 @profile
113 def sfr(self, t):
114 '''
115 define sfr as function to look up nearest sfr value at any specified time
116 '''
117 42898 20311 0.5 3.6 try:
118 42898 509412 11.9 91.1 vals = find_nearest(self.sfh,t)
119 42898 29715 0.7 5.3 return vals[1]
120 except:
121 logger.error("No SFH yet")
Total time: 95.0901 s
File: evolve.py
Function: gas_metal_dust_mass at line 123
Line # Hits Time Per Hit % Time Line Contents
==============================================================
123 @profile
124 def gas_metal_dust_mass(self, sn_rate):
125 '''
126 Calculates the gas, metal and dust mass from stars
127 note mass is only ejected after stars die ie when
128 t - taum (where taum is lifetime of star) > 0
129 '''
130 # initialize
131 2 2 1.0 0.0 mg = self.gasmass_init
132 2 2 1.0 0.0 mstars = 0
133 2 2 1.0 0.0 md = 0
134 2 2 1.0 0.0 md_all = 0
135 2 2 1.0 0.0 md_stars = 0
136 2 2 1.0 0.0 md_gg = 0
137 2 2 1.0 0.0 metals = 0
138 2 1 0.5 0.0 prev_t = 1e-3
139 2 1 0.5 0.0 metals_pre = 0
140 2 2 1.0 0.0 mstars_list = []
141 2 2 1.0 0.0 z = []
142 2 2 1.0 0.0 z_lookup = []
143 2 2 1.0 0.0 sfr_list = []
144 2 2 1.0 0.0 sfr_lookup = []
145 2 2 1.0 0.0 all_results = []
146 # Limit time to less than tend
147 2 4 2.0 0.0 time = self.sfh[:,0]
148 2 33 16.5 0.0 time = time[time < self.tend]
149 2 21 10.5 0.0 now = datetime.now()
150 # TIME integral
151 3263 6748 2.1 0.0 for item, t in enumerate(time):
152 3262 5910 1.8 0.0 r_sn = sn_rate [item]
153 3262 4627 1.4 0.0 metallicity = metals/mg
154
155 # start appending arrays for needing later
156 3262 6703 2.1 0.0 z.append([t,metallicity])
157 3262 1423655 436.4 1.5 z_lookup = np.array(z)
158 3262 90205 27.7 0.1 sfr_list.append([t,self.sfr(t)])
159 3262 1225041 375.5 1.3 sfr_lookup = np.array(sfr_list)
160
161 '''
162 STARS: dM_stars = sfr(t) * dt
163 '''
164 3262 77753 23.8 0.1 dmstars = self.sfr(t)
165
166 '''
167 GAS: dMg = (-sfr(t) + e(t) + inflows(t) - outflows(t)) * dt
168 set up astration, inflow, outflow components
169 '''
170 3262 56955 17.5 0.1 gas_ast = self.sfr(t)
171 3262 62668 19.2 0.1 gas_inf = f.inflows(self.sfr(t), self.inflows['xSFR'])
172 3262 61147 18.7 0.1 gas_out = f.outflows(self.sfr(t), self.outflows['xSFR'])
173
174 '''
175 METALS: dMz = (-Z*sfr(t) + ez(t) + Z*inflows(t) - Z*outflows(t)) * dt
176 set up astration, inflow and outflow components
177 '''
178 3262 59347 18.2 0.1 metals_ast = f.astration(metals,mg,self.sfr(t))
179 3262 4713 1.4 0.0 if self.outflows['metals']:
180 1864 33706 18.1 0.0 metals_out = metallicity*f.outflows(self.sfr(t), self.outflows['xSFR'])
181 else:
182 1398 1638 1.2 0.0 metals_out = 0.
183 3262 59859 18.4 0.1 metals_inf = self.inflows['metals']*f.inflows(self.sfr(t), self.inflows['xSFR'])
184
185 '''
186 DUST: dMd = (-Md/Mg*sfr(t) + ed(t) + Md/Mg*inflows(t) - Md/Mg*outflows(t)
187 - (1-f)*Md/t_destroy + f(1-Md/Mg)*Md/t_graingrowth) * dt
188 set up astration, inflows, outflows, destruction, grain growth components
189 '''
190 3262 4479 1.4 0.0 if self.outflows['dust']:
191 1864 33644 18.0 0.0 mdust_out = (md/mg)*f.outflows(self.sfr(t), self.outflows['xSFR'])
192 else:
193 1398 1647 1.2 0.0 mdust_out = 0.
194 3262 59203 18.1 0.1 mdust_inf = self.inflows['dust']*f.inflows(self.sfr(t), self.inflows['xSFR'])
195 3262 55883 17.1 0.1 mdust_ast = f.astration(md,mg,self.sfr(t))
196
197 3262 81253 24.9 0.1 mdust_gg, t_gg = f.graingrowth(self.choice_dust[2], self.epsilon,mg, self.sfr(t), metallicity, md, self.coldfraction)
198 3262 22796 7.0 0.0 mdust_des, t_des = f.destroy_dust(self.choice_des, self.destroy_ism, mg, r_sn, md, self.coldfraction)
199
200 '''
201 Get ejected masses from stars when they die
202 gas_ej = e(t): ejected gas mass from stars of mass m at t = taum
203 metals_stars = ez(t): ejected metal mass from stars of mass m at t = taum (fresh + recycled)
204 mdust_stars = ed(t): ejected dust mass from stars of mass m at t = taum (fresh + recycled)
205 '''
206 gas_ej, metals_stars, mdust_stars = \
207 3262 88276663 27062.1 92.8 f.mass_integral(self.choice_dust, self.reduce_sn, t, metallicity, sfr_lookup, z_lookup, self.imf)
208
209 '''
210 integrate over time for gas, metals and stars (mg, metals, md)
211 '''
212 3262 12345 3.8 0.0 dmg = -gas_ast + gas_ej + gas_inf - gas_out
213 3262 7334 2.2 0.0 dmetals = -metals_ast + metals_stars + metals_pre + metals_inf - metals_out
214 3262 7084 2.2 0.0 ddust = -mdust_ast + mdust_stars + mdust_inf - mdust_out + mdust_gg - mdust_des
215 # dust_source_all separates out the dust sources (Md vs t) wihtout including sinks (Astration etc)
216 # and grain growth separately (this is the Md vs time contributed by dust sources)
217 3262 4919 1.5 0.0 dust_source_all = mdust_stars + mdust_gg
218 3262 4751 1.5 0.0 dt = t - prev_t # calculate next time step
219 3262 4068 1.2 0.0 prev_t = t
220 3262 5564 1.7 0.0 mstars += dmstars*dt
221 3262 4789 1.5 0.0 mg += dmg*dt # gas mass integral
222 3262 5506 1.7 0.0 if mg <= 0:
223 # exit program if all ISM removed
224 1 18 18.0 0.0 print ('Oops you have no interstellar medium left')
225 1 3 3.0 0.0 break
226 3261 4682 1.4 0.0 metals += dmetals*dt # metal mass integral
227 3261 4636 1.4 0.0 md += ddust*dt # dust mass integral
228 3261 4712 1.4 0.0 md_all += dust_source_all*dt # dust mass sources integral
229 3261 4751 1.5 0.0 md_gg += mdust_gg*dt # dust source from grain growth only
230 3261 4771 1.5 0.0 md_stars += mdust_stars*dt # dust source from stars only
231 3261 1657357 508.2 1.7 Z = zip(*z_lookup) # write metallicity to an array
232 3261 1487612 456.2 1.6 s_f_r = zip(*sfr_lookup) # write SFR lookup array
233 3261 10769 3.3 0.0 if mg <= 0. or metals <=0: # write dust/metals ratio
234 1353 1740 1.3 0.0 dust_to_metals = 0.
235 else:
236 1908 3620 1.9 0.0 dust_to_metals = md/metals
237 3261 5994 1.8 0.0 all_results.append((t, mg, mstars, metals, metallicity, \
238 3261 114921 35.2 0.1 md, dust_to_metals, self.sfr(t)*1e-9, \
239 3261 6936 2.1 0.0 md_all, md_stars, md_gg, t_des, t_gg))
240 # to test code kinks
241 2 108 54.0 0.0 print("Gas, metal and dust mass exterior loop %s" % str(datetime.now()-now))
242 2 4818 2409.0 0.0 return np.array(all_results)
Total time: 2.26193 s
File: evolve.py
Function: supernova_rate at line 244
Line # Hits Time Per Hit % Time Line Contents
==============================================================
244 @profile
245 def supernova_rate(self):
246 '''
247 Calculates the SN rate at time t by integrating over mass m
248 '''
249 # initialize
250 2 4 2.0 0.0 sn_rate_list = []
251 2 2 1.0 0.0 dm = 0.01
252 2 2 1.0 0.0 prev_t = 1e-3
253 # define time array
254 2 8 4.0 0.0 time = self.sfh[:,0]
255 2 55 27.5 0.0 time = time[time < self.tend]
256 3291 3391 1.0 0.1 for t in time:
257 # need to clear the sn_rates as we don't want them adding up
258 3289 2447 0.7 0.1 sn_rate = 0.
259 3289 2478 0.8 0.1 dsn_rate = 0.
260 3289 2951 0.9 0.1 if t < 0.049:
261 2180 1374063 630.3 60.7 m = lookup_fn(t_lifetime,'lifetime_high_metals',t)[0]
262 else:
263 1109 805 0.7 0.0 m = 9.
264 119825 95893 0.8 4.2 while m < 40.:
265 116536 88941 0.8 3.9 if m > 10.:
266 111744 82717 0.7 3.7 dm = 0.5
267 116536 428777 3.7 19.0 sn_rate += f.initial_mass_function(m, self.imf_type)*dm
268 116536 95611 0.8 4.2 m += dm
269 3289 73646 22.4 3.3 r_sn = self.sfr(t)*sn_rate # units in N per Gyr
270 3289 3470 1.1 0.2 dt = t - prev_t
271 3289 2478 0.8 0.1 prev_t = t
272 3289 3895 1.2 0.2 sn_rate_list.append(r_sn)
273 2 300 150.0 0.0 return np.array(sn_rate_list)
It looks like the unzipping at lines 231 and 232 of gas_metal_dust_mass()
are taking most of the time.
I'll have a look at speeding that up.
Python version: v3.7.6 (with iPython version 7.14.0)
Module version: cloned master branch (after Nov 7, 2018 commits)
Code to reproduce issue:
In [1]: import chemevol as ch
In [2]: galaxies = ch.BulkEvolve('chemevol-master/chemevol/examples/data.csv')
In [3]: galaxies.upload_csv()
In [4]: galaxies.evolve_all()
Error message:
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-4-a33a9c8e9706> in <module>
----> 1 galaxies.evolve_all()
~/anaconda3/lib/python3.7/site-packages/chemevol-0.3-py3.7.egg/chemevol/evolve.py in evolve_all(self)
404 for item in self.inits:
405 logger.warning('Starting run on {}'.format(item['name']))
--> 406 ch = ChemModel(**item)
407
408 snrate = ch.supernova_rate()
~/anaconda3/lib/python3.7/site-packages/chemevol-0.3-py3.7.egg/chemevol/evolve.py in __init__(self, **inputs)
120 else:
121 print ('oops please check the dust sources are in the right format and try again')
--> 122 exit()
123
124 def load_sfh(self):
NameError: name 'exit' is not defined
integral mass is not the midpoint for any of the mass integrals gas_metals_dust_mass
or sn_rate
Need to validate the input dictionary to give useful error messages
For my research I plan to derive the best parameters used in chemevol to recreate observed quantities for a selection of galaxies.
I have gathered some data including the SFH, but chemevol wouldn't accept the file after converting the data to a .sfh file following the example.
After discussing it with my supervisor it seems that there are also problems when using MW.sfh.
Is there a way to use a custom .sfh file for the SFH?
The error that I get, is:
time = self.sfh[:,0] # this is in units of Gyrs
TypeError: 'NoneType' object is
Simon's test plots don't show any metallicity higher than around 0.8 gas fraction
Odd steps in metallicity === mass dm?
We have sorted out reading the correct metallicity column for lifetime in all of the evolve.py
functions except for ejected_mass
where it is needed for estimating lifetime.
needed to read correct lifetime column
ejected_dust_mass
in functions.py
giving too high a dust mass.
setting destruction to 'False' didn't seem to turn off destruction
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.