1 """
2 Simulation of a solarlike oscillations
3
4 Author: Joris De Ridder
5
6 Error messages are written to the logger "solarosc".
7
8 Notes:
9
10 Suppose Delta is the peak FWHM linewidth (muHz) and eta is the damping rate (muHz), then::
11
12 Delta = eta/pi
13 """
14
15 import numpy as np
16 from numpy.random import uniform, normal
17 from math import sin,cos, floor, pi
18 import logging
19
20
21
22
23
24
25
27 - def emit(self, record):
29
30 logger = logging.getLogger("solarosc")
31 nullHandler = NullHandler()
32 logger.addHandler(nullHandler)
33
34
35
36
38
39 """
40 Compute time series of stochastically excited damped modes
41
42 See also De Ridder et al., 2006, MNRAS 365, pp. 595-605.
43
44 Example:
45
46 >>> time = np.linspace(0, 40, 100) # in Ms
47 >>> freq = np.array([23.0, 23.5]) # in microHz
48 >>> ampl = np.array([100.0, 110.0]) # in ppm
49 >>> eta = np.array([1.e-6, 3.e-6]) # in 1/Ms
50 >>> oscsignal = solarosc(time, freq, ampl, eta)
51 >>> flux = 1000000.0 # average flux level
52 >>> signal = flux * (1.0 + oscsignal)
53 >>> # The same with a logger
54 >>> import sys, logging, logging.handlers
55 >>> myLogger = logging.getLogger("solarosc")
56 >>> myLogger.addHandler(logging.StreamHandler(sys.stdout))
57 >>> myLogger.setLevel(logging.INFO)
58 >>> oscsignal = solarosc(time, freq, ampl, eta, myLogger)
59 Simulating 2 modes
60 Oscillation kicktimestep: 3333.333333
61 300 kicks for warm up for oscillation signal
62 Simulating stochastic oscillations
63
64 @param time: time points [0..Ntime-1] (unit: e.g. Ms)
65 @type time: ndarray
66 @param freq: oscillation freqs [0..Nmodes-1] (unit: e.g. microHz)
67 @type freq: ndarray
68 @param ampl: amplitude of each oscillation mode
69 rms amplitude = ampl / sqrt(2.)
70 @type ampl: ndarray
71 @param eta: damping rates (unit: e.g. (Ms)^{-1})
72 @type eta: ndarray
73 @return: signal[0..Ntime-1]
74 @rtype: ndarray
75 """
76
77 Ntime = len(time)
78 Nmode = len(freq)
79
80 logger.info("Simulating %d modes" % Nmode)
81
82
83
84
85 kicktimestep = (1.0 / max(eta)) / 100.0
86
87 logger.info("Oscillation kicktimestep: %f" % kicktimestep)
88
89
90
91
92
93 amplcos = 0.0
94 amplsin = 0.0
95 kick_amplitude = ampl * np.sqrt(kicktimestep * eta)
96
97
98
99
100
101
102 damp = np.exp(-eta * kicktimestep)
103 Nwarmup = min(20000, int(floor(1.0 / min(eta) / kicktimestep)))
104
105 logger.info("%d kicks for warm up for oscillation signal" % Nwarmup)
106
107 for i in range(Nwarmup):
108 amplsin = damp * amplsin + normal(np.zeros(Nmode), kick_amplitude)
109 amplcos = damp * amplcos + normal(np.zeros(Nmode), kick_amplitude)
110
111
112
113
114
115
116 last_kicktime = uniform(time[0] - kicktimestep, time[0], Nmode)
117 next_kicktime = last_kicktime + kicktimestep
118
119
120
121
122 logger.info("Simulating stochastic oscillations")
123
124 signal = np.zeros(Ntime)
125
126 for j in range(Ntime):
127
128
129
130 for i in range(Nmode):
131
132
133
134 while (next_kicktime[i] <= time[j]):
135
136 deltatime = next_kicktime[i] - last_kicktime[i]
137 damp = np.exp(-eta[i] * deltatime)
138 amplsin[i] = damp * amplsin[i] + kick_amplitude[i] * normal(0.,1.)
139 amplcos[i] = damp * amplcos[i] + kick_amplitude[i] * normal(0.,1.)
140 last_kicktime[i] = next_kicktime[i]
141 next_kicktime[i] = next_kicktime[i] + kicktimestep
142
143
144
145 deltatime = time[j] - last_kicktime[i]
146 damp = np.exp(-eta[i] * deltatime)
147 signal[j] = signal[j] + damp * (amplsin[i] * sin(2*pi*freq[i]*time[j]) \
148 + amplcos[i] * cos(2*pi*freq[i]*time[j]))
149
150
151
152 return(signal)
153