Skip to content

Commit bd6601b

Browse files
committed
WIP red dwarf flares fitting
1 parent 64fafcd commit bd6601b

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

light-curve/light_curve/light_curve_py/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from .features.otsusplit import *
2424
from .features.pdiffmperc import *
2525
from .features.percampl import *
26+
from .features.red_dwarf_fit import *
2627
from .features.redchi2 import *
2728
from .features.skew import *
2829
from .features.stdev import *
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import numpy as np
2+
from scipy.special import erfc
3+
from scipy.stats import chisquare, sigmaclip
4+
5+
from ._base import BaseFeature
6+
7+
8+
class RedDwarfFit(BaseFeature):
9+
"""Red dwarf flares fitting function.
10+
11+
- Depends on: **time**, **magnitude**
12+
- Minimum number of observations: **2**
13+
- Number of features: **4**
14+
15+
Note, that the function is developed to be used with fluxes, not magnitudes.
16+
17+
Guadalupe Tovar Mendoza et al. 2022 [DOI:10.3847/1538-3881/ac6fe6](https://doi.org/10.3847/1538-3881/ac6fe6)
18+
"""
19+
20+
def _eval(self, t, m, sigma=None):
21+
amplitude, fwhm, tpeak = RedDwarfFit._flare_params(t, m)
22+
model = self.fit(t, amplitude, fwhm, tpeak)
23+
chi2 = np.sum((m - model) ** 2) / (len(m) - 1)
24+
25+
return np.array([amplitude, fwhm, tpeak, chi2])
26+
27+
@staticmethod
28+
def _flare_params(t, m):
29+
clipped = sigmaclip(m, low=3.0, high=3.0)[0]
30+
background = np.mean(clipped)
31+
clean_flux = m - background
32+
peak = np.argmax(clean_flux)
33+
amplitude = clean_flux[peak]
34+
tpeak = t[peak]
35+
36+
left_idx = np.where(clean_flux[:peak] < 0.5 * clean_flux[peak])[0][-1]
37+
left_t = t[left_idx] + (t[left_idx + 1] - t[left_idx]) * (0.5 * clean_flux[peak] - clean_flux[left_idx]) / (
38+
clean_flux[left_idx + 1] - clean_flux[left_idx]
39+
)
40+
41+
right_idx = (np.where(clean_flux[peak:] < 0.5 * clean_flux[peak]) + peak)[0][0]
42+
right_t = t[right_idx] + (t[right_idx + 1] - t[right_idx]) * (
43+
0.5 * clean_flux[peak] - clean_flux[right_idx]
44+
) / (clean_flux[right_idx + 1] - clean_flux[right_idx])
45+
46+
fwhm = right_t - left_t
47+
48+
return amplitude, fwhm, tpeak
49+
50+
@staticmethod
51+
def fit(t, amplitude, fwhm, tpeak):
52+
A, B, C, D1, D2, f1 = [
53+
0.9687734504375167,
54+
-0.251299705922117,
55+
0.22675974948468916,
56+
0.15551880775110513,
57+
1.2150539528490194,
58+
0.12695865022878844,
59+
]
60+
61+
t_new = (t - tpeak) / fwhm
62+
f2 = 1 - f1
63+
64+
eq = (
65+
(1 / 2)
66+
* np.sqrt(np.pi)
67+
* A
68+
* C
69+
* f1
70+
* np.exp(-D1 * t_new + ((B / C) + (D1 * C / 2)) ** 2)
71+
* erfc(((B - t_new) / C) + (C * D1 / 2))
72+
) + (
73+
(1 / 2)
74+
* np.sqrt(np.pi)
75+
* A
76+
* C
77+
* f2
78+
* np.exp(-D2 * t_new + ((B / C) + (D2 * C / 2)) ** 2)
79+
* erfc(((B - t_new) / C) + (C * D2 / 2))
80+
)
81+
82+
return eq * amplitude
83+
84+
@property
85+
def size(self):
86+
return 4
87+
88+
89+
__all__ = ("RedDwarfFit",)

0 commit comments

Comments
 (0)