Skip to content

mors.miscellaneous

miscellaneous

Module for holding miscellaneous functions that can be used by many other modules.

ActivityLifetime(Age=None, Track=None, Threshold=None, AgeMax=None)

Takes evolutionary track for parameter, calculates when value drops below threshold.

This function can be used to determine when a star's emission crosses a given threshold value for a few activity quantities. These are Lx, Fx, Rx, and FxHZ for X-rays, and similar values for EUV1, EUV2, EUV, XUV, and Ly-alpha. If the star crosses the threshold (from above it to below it) multiple times, this will find the final time it will cross the threshold. If the user wants to set a maximum age so that the code only looks for crossings of the threshold below this age then this can be done using the AgeMax keyword argument. If the track is always below this threshold value then the function returns 0.0.

Parameters:

Name Type Description Default
Age ndarray

Age array for evolutionary track.

None
Track ndarray

Value array for evolutionary track.

None
Threshold float

Value for threshold in units of quantity.

None
AgeMax float

End age of track to consider in Myr.

None

Returns:

Name Type Description
AgeActive float

Activity lifetime in Myr.

Source code in src/mors/miscellaneous.py
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
def ActivityLifetime(Age=None,Track=None,Threshold=None,AgeMax=None):
    """
    Takes evolutionary track for parameter, calculates when value drops below threshold.

    This function can be used to determine when a star's emission crosses a given threshold value for a few
    activity quantities. These are Lx, Fx, Rx, and FxHZ for X-rays, and similar values for EUV1, EUV2, EUV,
    XUV, and Ly-alpha. If the star crosses the threshold (from above it to below it) multiple times, this
    will find the final time it will cross the threshold. If the user wants to set a maximum age so that the
    code only looks for crossings of the threshold below this age then this can be done using the AgeMax
    keyword argument. If the track is always below this threshold value then the function returns 0.0.

    Parameters
    ----------
    Age : numpy.ndarray
        Age array for evolutionary track.
    Track : numpy.ndarray
        Value array for evolutionary track.
    Threshold : float
        Value for threshold in units of quantity.
    AgeMax : float , optional
        End age of track to consider in Myr.

    Returns
    ----------
    AgeActive : float
        Activity lifetime in Myr.

    """

    # Make sure parameters set
    if Age is None:
        raise Exception("required argument Age not set")
    if Track is None:
        raise Exception("required argument Track not set")
    if Threshold is None:
        raise Exception("required argument Threshold not set")

    # Make sure Age and Track same length
    if not ( len(Age) == len(Track) ):
        raise Exception("Age and Track are different lengths")

    # Change Age and Track to only be ages below AgeMax, if AgeMax is set
    if not AgeMax is None:
        includeAges = np.where( Age <= AgeMax )
        Age = Age[includeAges]
        Track = Track[includeAges]

    # See if final value below threshold, otherwise return final age
    if ( Track[-1] > Threshold ):
        return Age[-1]

    # Start at end of array and loop backwards
    for iAge in range(len(Age)-1,0,-1):

        # Make sure next one back is not equal to threshold
        if ( Track[iAge-1] == Threshold ):
            return Age[iAge-1]

        # Check if this age bin is when it drops past the threshold
        if ( ( Track[iAge] < Threshold ) and ( Track[iAge-1] > Threshold ) ):

            # Do interpoaltion to get when it crosses
            # Assume here Age = m*Track + c
            mInterp = ( Age[iAge] - Age[iAge-1] ) / ( Track[iAge] - Track[iAge-1] )
            cInterp = Age[iAge] - mInterp * Track[iAge]
            return mInterp*Threshold + cInterp

    return 0.0

IntegrateEmission(AgeMin=None, AgeMax=None, Age=None, Luminosity=None, aOrb=None)

Takes evolutionary track for parameter, calculates when value drops below threshold.

This code can be used to integrate a star's luminosity between two ages. This can be applied to Lx, Leuv, or any other luminosity and the result is a total energy emitted in this time in erg. If the user also specifies an orbital distance using the aOrb keyword argument, the code integrates the flux at this obital distance returns a fluence in erg cm^-2.

Parameters:

Name Type Description Default
AgeMin float

Start of time period to integrate in Myr.

None
AgeMax float

End of time period to integrate in Myr.

None
Age ndarray

Age array for evolutionary track.

None
Luminosity ndarray

Value array for evolutionary track.

None
aOrb float

Orbital distance to get fluence at in AU.

None

Returns:

Name Type Description
Energy float

Integrated luminosity of flux in erg or erg cm^-2.

Source code in src/mors/miscellaneous.py
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
def IntegrateEmission(AgeMin=None,AgeMax=None,Age=None,Luminosity=None,aOrb=None):
    """
    Takes evolutionary track for parameter, calculates when value drops below threshold.

    This code can be used to integrate a star's luminosity between two ages. This can be applied to Lx, Leuv, or any
    other luminosity and the result is a total energy emitted in this time in erg. If the user also specifies an orbital
    distance using the aOrb keyword argument, the code integrates the flux at this obital distance returns a fluence
    in erg cm^-2.

    Parameters
    ----------
    AgeMin : float
        Start of time period to integrate in Myr.
    AgeMax : float
        End of time period to integrate in Myr.
    Age : numpy.ndarray
        Age array for evolutionary track.
    Luminosity : numpy.ndarray
        Value array for evolutionary track.
    aOrb : float , optional
        Orbital distance to get fluence at in AU.

    Returns
    ----------
    Energy : float
        Integrated luminosity of flux in erg or erg cm^-2.

    """

    # Make sure parameters set
    if AgeMin is None:
        raise Exception("required argument AgeMin not set")
    if AgeMax is None:
        raise Exception("required argument AgeMax not set")
    if Age is None:
        raise Exception("required argument Age not set")
    if Luminosity is None:
        raise Exception("required argument Luminosity not set")

    # Make sure Age and Luminosity same length
    if not ( len(Age) == len(Luminosity) ):
        raise Exception("Age and Luminosity are different lengths")

    # Make sure AgeMin and AgeMax is in track
    if not ( ( AgeMin >= Age[0] ) and ( AgeMin <= Age[-1] ) ):
        raise Exception("AgeMin not in range of evolutionary track")
    if not ( ( AgeMax >= Age[0] ) and ( AgeMax <= Age[-1] ) ):
        raise Exception("AgeMax not in range of evolutionary track")

    # Get track to actually integrate
    Track = copy.deepcopy(Luminosity)
    if not aOrb is None:
        Track *= 1.0 / ( 4.0 * const.Pi * (aOrb*const.AU)**2.0 )

    # Get index of first age bin with age above AgeMin
    indexMin = _getIndexGT(Age,AgeMin)

    # Get index of final age bin with age below AgeMax
    indexMax = _getIndexLT(Age,AgeMax)

    # Initially take no energy then add up energy from bins
    Energy = 0.0

    # Add energy from first bin if needed (simple assumption for luminosity constant ove age bin)
    if ( AgeMin < Age[indexMin] ):
        Energy += ( Age[indexMin] - AgeMin ) * Track[indexMin]

    # Intergate over all full bins (only if there is something to integrate)
    if not ( indexMin == indexMax ):
        for iAge in range(indexMin,indexMax):

            # Do integration using trapezoidal rule (not the chained version)
            Energy += 0.5 * ( Age[iAge+1] - Age[iAge] ) * ( Track[iAge] + Track[iAge+1] )

    # Add energy from final bin if needed (simple assumption for luminosity constant ove age bin)
    if ( AgeMax > Age[indexMax] ):
        Energy += ( AgeMax - Age[indexMax] ) * Track[indexMax]

    # So far, units of Age were in Myr when integrating, so include also Myr to s conversion
    Energy *= const.Myr

    return Energy

Load(filename)

Takes filename of saved star or cluster and loads object.

Source code in src/mors/miscellaneous.py
56
57
58
59
60
61
62
63
64
65
66
def Load(filename):
    """Takes filename of saved star or cluster and loads object."""

    # Load the object
    with open(filename,'rb') as f:
        obj = pickle.load(f)

    # Setup the quantity functions (which for some reason do not work on objects loaded from pickle)
    obj._setupQuantityFunctions()

    return obj

ModelCluster()

Reads the model cluster used in Johnstone et al. (2020).

Source code in src/mors/miscellaneous.py
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
def ModelCluster():
    """Reads the model cluster used in Johnstone et al. (2020)."""

    # Get directory where package is installed
    packageDir = _GetPackageDirectory()

    # Set filename including path
    filename = packageDir + "ModelDistribution.dat"

    # Read lines of file
    with open(filename) as f:
        content = f.readlines()

    # Set number of header lines
    nHeader = 1

    # Get number of steps in file
    nStars = len(content) - nHeader

    # Make arrays
    Mstar = np.zeros(nStars)
    Omega = np.zeros(nStars)

    # Loop over lines and fill arrays
    iStar = 0
    for line in content[nHeader:len(content)]:
        data = line.split()
        Mstar[iStar] = data[0]
        Omega[iStar] = data[1]
        iStar += 1

    return Mstar , Omega

_GetPackageDirectory()

Gets path to main directory where the code is installed.

Source code in src/mors/miscellaneous.py
15
16
17
18
def _GetPackageDirectory():
    """Gets path to main directory where the code is installed."""

    return str(pathlib.Path(__file__).parent.absolute())+"/data/"

_convertFloatArray(Xin)

Takes a value and returns either as float or numpy.ndarray of floats.

Source code in src/mors/miscellaneous.py
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
def _convertFloatArray(Xin):
    """Takes a value and returns either as float or numpy.ndarray of floats."""

    # If input is float or int, return float version
    if isinstance(Xin,(float,int)):
        return float(Xin)

    # If input is a list, numpy array version (will only work if elements can be converted into floats)
    if isinstance(Xin,list):
        X = np.zeros(len(Xin))
        for i in range(0,len(Xin)):
            X[i] = float(Xin[i])
        return X

    # If input is a numpy object then do stuff
    if ( type(Xin).__module__ == 'numpy' ):

        # First see if it can be converted into a float (i.e. a 1-element array)
        isNumber = True
        try:
            X = float(Xin)
        except:
            isNumber = False

        # If it is just a single value, return float version
        if ( isNumber ):
            return float(X)

        # Otherwise, turn it into an array
        X = np.zeros(len(Xin))
        for i in range(0,len(Xin)):
            X[i] = float(Xin[i])
        return X

    return

_getIndexGT(Xarray, X)

Takes array of values and a value, returns index of closest element in array larger than value.

Source code in src/mors/miscellaneous.py
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
def _getIndexGT(Xarray,X):
    """Takes array of values and a value, returns index of closest element in array larger than value."""

    # It is assumed that X is less than the max of Xarray, but check this
    if ( X > np.max(Xarray) ):
        raise Exception("X is more than maximum of Xarray")

    # Get smaller value by taking difference of X and all Xarray elements
    # then removing all values smaller than 0.0 (i.e. those larger than X)
    deltaX = Xarray - X
    deltaX[np.where(deltaX<0.0)] = np.max(deltaX)*1.1+0.1

    # Get index
    index = np.argmin(deltaX)

    return index

_getIndexLT(Xarray, X)

Takes array of values and a value, returns index of closest element in array smaller than value.

Source code in src/mors/miscellaneous.py
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
def _getIndexLT(Xarray,X):
    """Takes array of values and a value, returns index of closest element in array smaller than value."""

    # It is assumed that X is greater than the min of Xarray, but check this
    if ( X < np.min(Xarray) ):
        raise Exception("X is less than minimum of Xarray")

    # Get smaller value by taking difference of X and all Xarray elements
    # then removing all values smaller than 0.0 (i.e. those larger than X)
    deltaX = X - Xarray
    deltaX[np.where(deltaX<0.0)] = np.max(deltaX)*1.1+0.1

    # Get index
    index = np.argmin(deltaX)

    return index

_getIndexLTordered(Xarray, X)

Takes min to max ordered array of values and a value, returns index of closest element in array smaller than value.

Source code in src/mors/miscellaneous.py
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
def _getIndexLTordered(Xarray,X):
    """Takes min to max ordered array of values and a value, returns index of closest element in array smaller than value."""

    # It is assumed that X is between the min and max of Xarray and it is assumed
    # that Xarray is in ascending order

    # Initial guesses for i
    i1 = 0
    i2 = len(Xarray)-1

    # Check if right value
    if ( Xarray[i1] == X ):
        return i1
    if ( Xarray[i2] == X ):
        return i2

    # Start iterating
    for iIter in range(0,len(Xarray)):

        # Get iMid
        iMid = int(0.5*(i1+i2))

        # Check if iMid is right value
        if ( ( Xarray[iMid] <= X ) and ( Xarray[iMid+1] > X ) ):
            return iMid

        # Work out if answer is between i1 and iMid or iMid and i2
        if ( Xarray[iMid] > X ):
            i2 = iMid
        else:
            i1 = iMid

    # It should not get here
    raise Exception("did not find index")

    return iMid