forked from kammerje/P-pop-second-version
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSystem.py
More file actions
executable file
·330 lines (267 loc) · 13 KB
/
System.py
File metadata and controls
executable file
·330 lines (267 loc) · 13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
"""
# =============================================================================
# P-POP
# A Monte-Carlo tool to simulate exoplanet populations
# =============================================================================
"""
# =============================================================================
# IMPORTS
# =============================================================================
import numpy as np
import scipy.optimize as so
# =============================================================================
# SYSTEM
# =============================================================================
class System():
def __init__(self,
Star,
PlanetDistribution,
MassModel,
EccentricityModel,
OrbitModel,
AlbedoModel,
ExozodiModel,
StabilityModel=None,
Nstar=0,
Nuniverse=0,
Scale=1.):
"""
Parameters
----------
Star: instance
Instance of class Star.
PlanetDistribution: instance
Instance of class PlanetDistribution.
MassModel: instance
Instance of class MassModel.
EccentricityModel: instance
Instance of class EccentricityModel.
OrbitModel: instance
Instance of class OrbitModel.
AlbedoModel: instance
Instance of class AlbedoModel.
ExozodiModel: instance
Instance of class ExozodiModel.
StabilityModel: instance
Instance of class StabilityModel.
Nstar: int
Number of the host star to which the system belongs to.
Nuniverse: int
Number of the universe to which the system belongs to.
Scale: float
Scaling factor for the planet occurrence rates.
"""
# Constants.
self.G = 6.674e-11 # m^3/kg/s^2
self.Rsun = 695700000. # m
self.Msun = 1.989e30 # kg
self.au = 149597870700. # m
self.sigma = 5.670e-8 # W/m^2/K^4
self.Star = Star
self.Nstar = Nstar
self.Nuniverse = Nuniverse
self.Scale = Scale
if (StabilityModel is None):
if (PlanetDistribution.returns == ['Rp', 'Porb']):
# Draw planet radius and planet orbital period.
self.Rp, self.Porb = PlanetDistribution.draw(Scale=self.Scale,
Star=self.Star) # Rearth, d
# Sort planets by orbital period.
ww = np.argsort(self.Porb)
self.Rp = self.Rp[ww] # Rearth
self.Porb = self.Porb[ww] # d
# Draw planet mass and planet eccentricity.
self.Mp = MassModel.RadiusToMass(self.Rp) # Mearth
self.ep = EccentricityModel.getEccentricity(self.Porb)
elif (PlanetDistribution.returns == ['Mp', 'Porb']):
# Draw planet mass and planet orbital period.
self.Mp, self.Porb = PlanetDistribution.draw(Scale=self.Scale,
Star=self.Star) # Mearth, d
# Sort planets by orbital period.
ww = np.argsort(self.Porb)
self.Mp = self.Mp[ww] # Rearth
self.Porb = self.Porb[ww] # d
# Draw planet radius and planet eccentricity.
self.Rp = MassModel.MassToRadius(self.Mp) # Rearth
self.ep = EccentricityModel.getEccentricity(self.Porb)
else:
raise UserWarning()
else:
# Draw a stable system.
self.Rp, self.Porb, self.Mp, self.ep = StabilityModel.draw(Star,
PlanetDistribution,
MassModel,
EccentricityModel,
Scale=self.Scale) # Rearth, d, Mearth
# Draw planet orbits.
self.ip, self.Omegap, self.omegap, self.thetap = OrbitModel.getOrbit(self.ep) # rad, rad, rad, rad
# Draw planet albedos.
self.Abond = AlbedoModel.getAbond(self.Rp)
self.AgeomVIS = AlbedoModel.getAgeomVIS(self.Rp)
self.AgeomMIR = AlbedoModel.getAgeomMIR(self.Rp)
# Draw system exozodiacal dust level.
self.z = ExozodiModel.getExozodiLevel()
# Compute the other properties of the drawn planets.
self.ap = self.getap() # au
self.rp = self.getrp() # au
self.rpproj = self.getrpproj() # au
self.AngSep = self.getAngSep() # arcsec
self.maxrpproj = self.getmaxrpproj() # au
self.maxAngSep = self.getmaxAngSep() # arcsec
self.Fp = self.getFp() # Searth
self.fp = self.getfp()
self.Tp = self.getTp() # K
pass
def getap(self):
"""
Returns
-------
ap: array
Semi-major axis (au) of drawn planets.
"""
return ((self.G*self.Star.Mass*self.Msun*(self.Porb*86400.)**2)/(4.*np.pi**2))**(1./3.)/self.au
def getrp(self):
"""
Returns
-------
rp: array
Physical separation (au) of drawn planets.
"""
return self.ap*(1.-self.ep**2)/(1.+self.ep*np.cos(self.thetap))
def getrpproj(self):
"""
Returns
-------
rpproj: array
Projected separation (au) of drawn planets.
"""
return self.rp*np.sqrt(np.cos(self.omegap+self.thetap)**2+np.cos(self.ip)**2*np.sin(self.omegap+self.thetap)**2)
def getAngSep(self):
"""
Returns
-------
AngSep: array
Projected angular separation (arcsec) of drawn planets.
"""
return self.rpproj/self.Star.Dist
def getmaxrpproj(self):
"""
Returns
-------
maxrpproj: array
Max projected separation (au) of drawn planets.
"""
maxrpproj = [] # au
for i in range(len(self.Rp)):
# Function for computing the projected separation of the drawn
# planets and its derivative with respect to the true anomaly of
# the drawn planets.
f = lambda theta: self.ap[i]*(1.-self.ep[i]**2)/(1.+self.ep[i]*np.cos(theta))*np.sqrt(np.cos(self.omegap[i]+theta)**2+np.cos(self.ip[i])**2*np.sin(self.omegap[i]+theta)**2)
df = lambda theta: self.ap[i]*(1.-self.ep[i]**2)*self.ep[i]*np.sin(theta)/(1.+self.ep[i]*np.cos(theta))**2*np.sqrt(np.cos(self.omegap[i]+theta)**2+np.cos(self.ip[i])**2*np.sin(self.omegap[i]+theta)**2)+self.ap[i]*(1.-self.ep[i]**2)/(1.+self.ep[i]*np.cos(theta))*0.5*(np.cos(self.omegap[i]+theta)**2+np.cos(self.ip[i])**2*np.sin(self.omegap[i]+theta)**2)**(-1./2.)*(2.*np.cos(self.ip[i])**2-2.)*np.sin(self.omegap[i]+theta)*np.cos(self.omegap[i]+theta)
# Maximize the above function based on different priors for the
# true anomaly of the drawn planets.
x0 = np.linspace(0., 2.*np.pi, 8, endpoint=False)
xx = so.fsolve(df, x0)
ff = f(xx)
maxrpproj += [np.max(ff)] # au
return np.array(maxrpproj)
def getmaxAngSep(self):
"""
Returns
-------
maxAngSep: array
Max projected angular separation (arcsec) of drawn planets.
"""
return self.maxrpproj/self.Star.Dist
def getFp(self):
"""
Returns
-------
Fp: array
Host star flux (Searth) incident on drawn planets.
"""
return self.sigma*self.Star.Teff**4*(self.Star.Rad*self.Rsun)**2/(self.rp*self.au)**2/1361.
def getfp(self):
"""
Returns
-------
fp: array
Lambertian reflectance of drawn planets.
"""
# Compute phase angle.
alphap = np.arccos(-np.sin(self.ip)*np.sin(self.omegap+self.thetap)) # rad
return np.abs((np.sin(alphap)+(np.pi-alphap)*np.cos(alphap))/np.pi)
def getTp(self):
"""
Returns
-------
Tp: array
Equilibrium temperature (K) of drawn planets.
"""
return ((self.Star.Rad*self.Rsun)**2*(1.-self.Abond)/(4.*(self.rp*self.au)**2))**(1./4.)*self.Star.Teff
def write(self,
Name):
"""
Parameters
----------
Name: str
Name of the output planet table.
"""
Table = open(Name+'.txt', 'w')
# Old header.
Table.write('nMC\tRp\tPorb\tMp\tecc\tinc\tOmega\tomega\ttheta\tAbond\tAgeomVIS\tAgeomMIR\tzodis\ta\trp\tang_sep\tang_sep_max\tFinc\tf\tTp\tnstar\tRs\tMs\tTs\tdist\tstype\tra\tdec\tlGal\tbGal\t\n')
# New header.
Table.write('Nuniverse\tRp\tPorb\tMp\tep\tip\tOmegap\tomegap\tthetap\tAbond\tAgeomVIS\tAgeomMIR\tz\tap\trp\tAngSep\tmaxAngSep\tFp\tfp\tTp\tNstar\tRs\tMs\tTs\tDs\tStype\tRA\tDec\tlGal\tbGal\t\n')
Table.close()
self.append(Name)
pass
def append(self,
Name):
"""
Parameters
----------
Name: str
Name of the output planet table.
..Notes::
Table of planets with the following columns:
- Nuniverse: number of the universe to which the planet belongs to.
- Rp: planet radius (Rearth).
- Porb: planet orbital period (d).
- Mp: planet mass (Mearth).
- ep: planet eccentricity.
- ip: planet inclination (rad).
- Omegap: planet longitude of ascending node (rad).
- omegap: planet argument of periapsis (rad).
- thetap: planet true anomaly (rad).
- Abond: planet Bond albedo.
- AgeomVIS: planet geometric albedo in the visible.
- AgeomMIR: planet geometric albedo in the mid-infrared.
- z: exozodiacal dust level.
- ap: planet semi-major axis (au).
- rp: planet physical separation (au).
- AngSep: planet projected angular separation (arcsec).
- maxAngSep: max planet projected angular separation (arcsec).
- Fp: planet incident host star flux (Searth).
- fp: planet Lambertian reflectance.
- Tp: planet equilibrium temperature (K).
- Nstar: number of the star.
- Rs: host star radius (Rsun).
- Ms: host star mass (Msun).
- Ts: host star effective temperature (K).
- Ds: host star distance (pc).
- Stype: host star spectral type.
- RA: host star right ascension (deg).
- Dec: host star declination (deg).
- lGal: Galactic longitude (deg).
- bGal: Galactic latitude (deg).
"""
Table = open(Name+'.txt', 'a')
# Write the simulated planets to the planet population table.
if (self.Star.lGal is None or self.Star.bGal is None):
for i in range(len(self.Rp)):
Table.write('%.0f\t' % self.Nuniverse+'%.5f\t' % self.Rp[i]+'%.5f\t' % self.Porb[i]+'%.5f\t' % self.Mp[i]+'%.5f\t' % self.ep[i]+'%.5f\t' % self.ip[i]+'%.5f\t' % self.Omegap[i]+'%.5f\t' % self.omegap[i]+'%.5f\t' % self.thetap[i]+'%.5f\t' % self.Abond[i]+'%.5f\t' % self.AgeomVIS[i]+'%.5f\t' % self.AgeomMIR[i]+'%.5f\t' % self.z+'%.5f\t' % self.ap[i]+'%.5f\t' % self.rp[i]+'%.5f\t' % self.AngSep[i]+'%.5f\t' % self.maxAngSep[i]+'%.5f\t' % self.Fp[i]+'%.5f\t' % self.fp[i]+'%.5f\t' % self.Tp[i]+'%.0f\t' % self.Nstar+'%.5f\t' % self.Star.Rad+'%.5f\t' % self.Star.Mass+'%.5f\t' % self.Star.Teff+'%.5f\t' % self.Star.Dist+self.Star.Stype+'\t%.5f\t' % self.Star.RA+'%.5f\t' % self.Star.Dec+'None\t'+'None\t\n')
else:
for i in range(len(self.Rp)):
Table.write('%.0f\t' % self.Nuniverse+'%.5f\t' % self.Rp[i]+'%.5f\t' % self.Porb[i]+'%.5f\t' % self.Mp[i]+'%.5f\t' % self.ep[i]+'%.5f\t' % self.ip[i]+'%.5f\t' % self.Omegap[i]+'%.5f\t' % self.omegap[i]+'%.5f\t' % self.thetap[i]+'%.5f\t' % self.Abond[i]+'%.5f\t' % self.AgeomVIS[i]+'%.5f\t' % self.AgeomMIR[i]+'%.5f\t' % self.z+'%.5f\t' % self.ap[i]+'%.5f\t' % self.rp[i]+'%.5f\t' % self.AngSep[i]+'%.5f\t' % self.maxAngSep[i]+'%.5f\t' % self.Fp[i]+'%.5f\t' % self.fp[i]+'%.5f\t' % self.Tp[i]+'%.0f\t' % self.Nstar+'%.5f\t' % self.Star.Rad+'%.5f\t' % self.Star.Mass+'%.5f\t' % self.Star.Teff+'%.5f\t' % self.Star.Dist+self.Star.Stype+'\t%.5f\t' % self.Star.RA+'%.5f\t' % self.Star.Dec+'%.5f\t' % self.Star.lGal+'%.5f\t\n' % self.Star.bGal)
Table.close()
pass