move to wsl

This commit is contained in:
liuyihui 2022-11-22 17:29:48 +08:00
parent 5385cef9dc
commit 893507e340
9 changed files with 905 additions and 911 deletions

46
.gitignore vendored
View File

@ -1,26 +1,20 @@
# data file # data file
*.root *.root
*.log *.log
*.csv *.csv
*.json *.json
*.png *.png
*.txt *.txt
2016Q3D/ data/
result/ result/
!requirements.txt !requirements.txt
# env # build cache
venv/ __pycache__
# build cache # config
__pycache__ .vscode
# config # dev
.vscode *.ipynb
.vs test*
# dev
*.ipynb
test*
*.code-workspace

View File

@ -1,3 +1,3 @@
from .Bind import Bind from .Bind import Bind
from .process import Process from .process import Process
from .calibration import Calibration from .calibration import Calibration

View File

@ -1,296 +1,296 @@
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from .utils import get_hist, GMM_clip from .utils import get_hist, GMM_clip
from .model import Linear1D, FixedSlopeLine, pXLine from .model import Linear1D, FixedSlopeLine, pXLine
from .fit import fit_line, fit_hist_gaussian from .fit import fit_line, fit_hist_gaussian
class Bind(object): class Bind(object):
"""Bind of a Block, using data under two energy conditions for fitting. """Bind of a Block, using data under two energy conditions for fitting.
The energy of an ADC device can be expressed as: $E = kx + b$. The energy of an ADC device can be expressed as: $E = kx + b$.
So the complete energy is represented by $E(x,y) = k_1x + b_1 + k_2y + b_2$. So the complete energy is represented by $E(x,y) = k_1x + b_1 + k_2y + b_2$.
This formula can be converted to: $y = -\\frac{k_1}{k_2}x + \\frac{E-b_1-b_2}{k_2}$. This formula can be converted to: $y = -\\frac{k_1}{k_2}x + \\frac{E-b_1-b_2}{k_2}$.
Plotting the data in a 2D plane for linear regression, we can get $\\frac{k_1}{k_2}$ and $C_i$ Plotting the data in a 2D plane for linear regression, we can get $\\frac{k_1}{k_2}$ and $C_i$
Using data of $E_1$ and $E_2$, now $k_2 = \\frac{E_1 - E_2}{C_1 - C_2}$. Using data of $E_1$ and $E_2$, now $k_2 = \\frac{E_1 - E_2}{C_1 - C_2}$.
The incident position produces different responses in the left and right detectors, which can be expressed as: The incident position produces different responses in the left and right detectors, which can be expressed as:
$Px = \\frac{k_2y - k_1x}{E}L+CL$. $Px = \\frac{k_2y - k_1x}{E}L+CL$.
Attributes Attributes
---------- ----------
L/C : float L/C : float
parameters in $Px = \\frac{k_2y - k_1x}{E}L+CL$. parameters in $Px = \\frac{k_2y - k_1x}{E}L+CL$.
k1, k2: float k1, k2: float
parameters in $Px = \\frac{k_2y - k_1x}{E}L+CL$. parameters in $Px = \\frac{k_2y - k_1x}{E}L+CL$.
b : float b : float
$b = b_1 + b_2$ $b = b_1 + b_2$
K1/K2/C1/C2: float K1/K2/C1/C2: float
$K_i = -\\frac{k_1}{k_2}$ $K_i = -\\frac{k_1}{k_2}$
$C_i = \\frac{E_i-b}{k_2}$ $C_i = \\frac{E_i-b}{k_2}$
""" """
def __init__(self, n, m): def __init__(self, n, m):
self.n, self.m = n, m self.n, self.m = n, m
self.px = [None, None] self.px = [None, None]
self.x, self.y = [None, None], [None, None] self.x, self.y = [None, None], [None, None]
self.L, self.C = 40, 0 self.L, self.C = 40, 0
self.k1, self.k2, self.b = 0, 0, 0 self.k1, self.k2, self.b = 0, 0, 0
self.K1, self.C1, self.K2, self.C2 = 0, 0, 0, 0 self.K1, self.C1, self.K2, self.C2 = 0, 0, 0, 0
def add_data(self, k, x, y, px): def add_data(self, k, x, y, px):
"""k-th energy data """k-th energy data
Parameters Parameters
---------- ----------
k : int k : int
k-th energy k-th energy
x : array x : array
left data left data
y : array y : array
right data right data
px : int px : int
px (set value) px (set value)
""" """
self.x[k] = np.concatenate((self.x[k], x)) if self.x[k] is not None else x self.x[k] = np.concatenate((self.x[k], x)) if self.x[k] is not None else x
self.y[k] = np.concatenate((self.y[k], y)) if self.y[k] is not None else y self.y[k] = np.concatenate((self.y[k], y)) if self.y[k] is not None else y
self.px[k] = ( self.px[k] = (
np.concatenate((self.px[k], np.full(len(x), px))) np.concatenate((self.px[k], np.full(len(x), px)))
if self.px[k] is not None if self.px[k] is not None
else np.full(len(x), px) else np.full(len(x), px)
) )
def clip(self): def clip(self):
"""Using Gaussian Mixture Method (GMM) to decompose the data into noise and available data""" """Using Gaussian Mixture Method (GMM) to decompose the data into noise and available data"""
data = GMM_clip( data = GMM_clip(
np.array(list(zip(self.x[0], self.y[0], self.px[0])), dtype=object) np.array(list(zip(self.x[0], self.y[0], self.px[0])), dtype=object)
) )
self.x[0] = data[:, 0] self.x[0] = data[:, 0]
self.y[0] = data[:, 1] self.y[0] = data[:, 1]
self.px[0] = data[:, 2] self.px[0] = data[:, 2]
data = GMM_clip( data = GMM_clip(
np.array(list(zip(self.x[1], self.y[1], self.px[1])), dtype=object) np.array(list(zip(self.x[1], self.y[1], self.px[1])), dtype=object)
) )
self.x[1] = data[:, 0] self.x[1] = data[:, 0]
self.y[1] = data[:, 1] self.y[1] = data[:, 1]
self.px[1] = data[:, 2] self.px[1] = data[:, 2]
def get_line(self): def get_line(self):
"""Fit data with $y = -\\frac{k_1}{k_2}x + \\frac{E-b_1-b_2}{k_2}$.""" """Fit data with $y = -\\frac{k_1}{k_2}x + \\frac{E-b_1-b_2}{k_2}$."""
model = Linear1D() model = Linear1D()
reg = fit_line(model, self.x[0], self.y[0]) reg = fit_line(model, self.x[0], self.y[0])
self.K1 = reg.slope.value self.K1 = reg.slope.value
self.C1 = reg.intercept.value self.C1 = reg.intercept.value
reg = fit_line(model, self.x[1], self.y[1]) reg = fit_line(model, self.x[1], self.y[1])
self.K2 = reg.slope.value self.K2 = reg.slope.value
self.C2 = reg.intercept.value self.C2 = reg.intercept.value
def get_kb(self, bias, deltaE=4): def get_kb(self, bias, deltaE=4):
"""Get $k_2$, $k_2$, $b$ from $K_i$, $C_i$ """Get $k_2$, $k_2$, $b$ from $K_i$, $C_i$
Set slope equal average of $K_i$. Set slope equal average of $K_i$.
Parameters Parameters
---------- ----------
bias : float bias : float
bias $b = b_1 + b_2$ bias $b = b_1 + b_2$
deltaE : float, optional deltaE : float, optional
delta energy between two beams delta energy between two beams
""" """
K = (self.K1 + self.K2) / 2 K = (self.K1 + self.K2) / 2
self.K1 = self.K2 = K self.K1 = self.K2 = K
model = FixedSlopeLine(slope=K, intercept=self.C1) model = FixedSlopeLine(slope=K, intercept=self.C1)
fitted_model = fit_line(model, self.x[0], self.y[0]) fitted_model = fit_line(model, self.x[0], self.y[0])
self.C1 = fitted_model.intercept.value self.C1 = fitted_model.intercept.value
model = FixedSlopeLine(slope=K, intercept=self.C2) model = FixedSlopeLine(slope=K, intercept=self.C2)
fitted_model = fit_line(model, self.x[1], self.y[1]) fitted_model = fit_line(model, self.x[1], self.y[1])
self.C2 = fitted_model.intercept.value self.C2 = fitted_model.intercept.value
self.k2 = deltaE / abs(self.C1 - self.C2) self.k2 = deltaE / abs(self.C1 - self.C2)
self.k1 = -self.k2 * K self.k1 = -self.k2 * K
eng = self.k1 * self.x[0] + self.k2 * self.y[0] eng = self.k1 * self.x[0] + self.k2 * self.y[0]
fitted_model = fit_hist_gaussian(eng, step=0.01) fitted_model = fit_hist_gaussian(eng, step=0.01)
self.E1 = fitted_model.mean.value self.E1 = fitted_model.mean.value
eng = self.k1 * self.x[1] + self.k2 * self.y[1] eng = self.k1 * self.x[1] + self.k2 * self.y[1]
fitted_model = fit_hist_gaussian(eng, step=0.01) fitted_model = fit_hist_gaussian(eng, step=0.01)
self.E2 = fitted_model.mean.value self.E2 = fitted_model.mean.value
self.b = bias - self.C1 * self.k2 self.b = bias - self.C1 * self.k2
self.E1 += self.b self.E1 += self.b
self.E2 += self.b self.E2 += self.b
def get_peak_center(self): def get_peak_center(self):
"""Get peak center (in channel) using Gaussian Model""" """Get peak center (in channel) using Gaussian Model"""
self.fx, self.fy, self.fz = [], [], [] self.fx, self.fy, self.fz = [], [], []
peaks = np.unique(self.px[0]) peaks = np.unique(self.px[0])
for px in peaks: for px in peaks:
idx = np.where(self.px[0] == px)[0] idx = np.where(self.px[0] == px)[0]
x, y = self.x[0][idx], self.y[0][idx] x, y = self.x[0][idx], self.y[0][idx]
if len(idx) < 400: if len(idx) < 400:
continue continue
fitted_model = fit_hist_gaussian(x) fitted_model = fit_hist_gaussian(x)
self.fx.append(fitted_model.mean.value) self.fx.append(fitted_model.mean.value)
fitted_model = fit_hist_gaussian(y) fitted_model = fit_hist_gaussian(y)
self.fy.append(fitted_model.mean.value) self.fy.append(fitted_model.mean.value)
self.fz.append(px) self.fz.append(px)
self.fx = np.array(self.fx) self.fx = np.array(self.fx)
self.fy = np.array(self.fy) self.fy = np.array(self.fy)
self.fz = np.array(self.fz) self.fz = np.array(self.fz)
def fit_px(self): def fit_px(self):
"""Fit using $Px = \\frac{k_2y - k_1x}{E}L+CL$.""" """Fit using $Px = \\frac{k_2y - k_1x}{E}L+CL$."""
model = Linear1D() model = Linear1D()
reg = fit_line(model, self.fx, self.fz) reg = fit_line(model, self.fx, self.fz)
E = np.mean(self.k1 * self.fx + self.k2 * self.fy + self.b) E = np.mean(self.k1 * self.fx + self.k2 * self.fy + self.b)
L = reg.slope.value * E / (self.k2 * self.K1 - self.k1) L = reg.slope.value * E / (self.k2 * self.K1 - self.k1)
C = (reg.intercept.value - self.k2 * self.C1 * L / E) / L C = (reg.intercept.value - self.k2 * self.C1 * L / E) / L
model = pXLine(L=L, C=C, k1=self.k1, k2=self.k2, b=self.b) model = pXLine(L=L, C=C, k1=self.k1, k2=self.k2, b=self.b)
reg = fit_line( reg = fit_line(
model, np.array(list(zip(self.fx, self.fy)), dtype=object), self.fz model, np.array(list(zip(self.fx, self.fy)), dtype=object), self.fz
) )
self.L = reg.L.value self.L = reg.L.value
self.C = reg.C.value self.C = reg.C.value
def predict_energy(self, x, y): def predict_energy(self, x, y):
"""Use $E(x,y) = k_1x + b_1 + k_2y + b_2$. to calculate energy. """Use $E(x,y) = k_1x + b_1 + k_2y + b_2$. to calculate energy.
Parameters Parameters
---------- ----------
x/y : array x/y : array
data data
""" """
return self.k1 * x + self.k2 * y + self.b return self.k1 * x + self.k2 * y + self.b
def predict_px(self, x, y): def predict_px(self, x, y):
"""Use $Px = \\frac{k_2y - k_1x}{E}L+CL$ to calculate pX. """Use $Px = \\frac{k_2y - k_1x}{E}L+CL$ to calculate pX.
Parameters Parameters
---------- ----------
x/y : array x/y : array
data data
""" """
eng = self.predict_energy(x, y) eng = self.predict_energy(x, y)
return (self.k2 * y - self.k1 * x) / eng * self.L + self.C * self.L return (self.k2 * y - self.k1 * x) / eng * self.L + self.C * self.L
def draw_fit_line(self, title): def draw_fit_line(self, title):
fig = plt.figure(figsize=(8, 8)) fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1) ax = fig.add_subplot(1, 1, 1)
ax.scatter(self.x[0], self.y[0], s=0.1, c="black", label=r"$E_1$") ax.scatter(self.x[0], self.y[0], s=0.1, c="black", label=r"$E_1$")
ax.scatter(self.x[1], self.y[1], s=0.1, c="dimgray", label=r"$E_2$") ax.scatter(self.x[1], self.y[1], s=0.1, c="dimgray", label=r"$E_2$")
ax.plot( ax.plot(
self.x[0], self.x[0],
self.K1 * self.x[0] + self.C1, self.K1 * self.x[0] + self.C1,
c="red", c="red",
label=r"$x_2={:.4f}x_1+{:.4f},\ R^2={:.5f}$".format( label=r"$x_2={:.4f}x_1+{:.4f},\ R^2={:.5f}$".format(
self.K1, self.C1, self.RSquare1 self.K1, self.C1, self.RSquare1
), ),
) )
ax.plot( ax.plot(
self.x[1], self.x[1],
self.K2 * self.x[1] + self.C2, self.K2 * self.x[1] + self.C2,
c="orangered", c="orangered",
label=r"$x_2={:.4f}x_1+{:.4f},\ R^2={:.5f}$".format( label=r"$x_2={:.4f}x_1+{:.4f},\ R^2={:.5f}$".format(
self.K2, self.C2, self.RSquare2 self.K2, self.C2, self.RSquare2
), ),
) )
plt.title("Y - X Line") plt.title("Y - X Line")
plt.xlabel("Output - Left (X) / (channel)") plt.xlabel("Output - Left (X) / (channel)")
plt.ylabel("Output - Right (Y) / (channel)") plt.ylabel("Output - Right (Y) / (channel)")
ax.legend() ax.legend()
fig.savefig(title, facecolor="w", transparent=False, bbox_inches='tight') fig.savefig(title, facecolor="w", transparent=False, bbox_inches="tight")
plt.close() plt.close()
def draw_peak(self, title): def draw_peak(self, title):
fig = plt.figure(figsize=(8, 8)) fig = plt.figure(figsize=(8, 8))
peaks = np.unique(self.px[0]) peaks = np.unique(self.px[0])
n, k = len(peaks), 1 n, k = len(peaks), 1
for px in peaks: for px in peaks:
ax = fig.add_subplot(n, 1, k) ax = fig.add_subplot(n, 1, k)
ax.set_title("pX = {:.2f}".format(px)) ax.set_title("pX = {:.2f}".format(px))
idx = np.where(self.px[0] == px)[0] idx = np.where(self.px[0] == px)[0]
x, y = self.x[0][idx], self.y[0][idx] x, y = self.x[0][idx], self.y[0][idx]
count1, center1 = get_hist(x) count1, center1 = get_hist(x)
count2, center2 = get_hist(y) count2, center2 = get_hist(y)
ax.scatter(center1, count1, s=0.5) ax.scatter(center1, count1, s=0.5)
ax.scatter(center2, count2, s=0.5) ax.scatter(center2, count2, s=0.5)
ax.set_xlabel("Channel") ax.set_xlabel("Channel")
ax.set_ylabel("Counts per Channel") ax.set_ylabel("Counts per Channel")
k += 1 k += 1
fig.suptitle("Counts Curve") fig.suptitle("Counts Curve")
plt.tight_layout() plt.tight_layout()
fig.savefig(title, facecolor="w", transparent=False) fig.savefig(title, facecolor="w", transparent=False)
plt.close() plt.close()
def draw_cluster(self, title): def draw_cluster(self, title):
fig = plt.figure(figsize=(8, 8)) fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1) ax = fig.add_subplot(1, 1, 1)
peaks = np.unique(self.px[0]) peaks = np.unique(self.px[0])
for px in peaks: for px in peaks:
idx = np.where(self.px[0] == px)[0] idx = np.where(self.px[0] == px)[0]
x, y = self.x[0][idx], self.y[0][idx] x, y = self.x[0][idx], self.y[0][idx]
ax.scatter(x, y, s=0.1, label="pX={:.0f}".format(px)) ax.scatter(x, y, s=0.1, label="pX={:.0f}".format(px))
plt.title("Y - X Line") plt.title("Y - X Line")
plt.xlabel("Output - Left (X) / (channel)") plt.xlabel("Output - Left (X) / (channel)")
plt.ylabel("Output - Right (Y) / (channel)") plt.ylabel("Output - Right (Y) / (channel)")
plt.legend() plt.legend()
plt.tight_layout() plt.tight_layout()
fig.savefig(title, facecolor="w", transparent=False) fig.savefig(title, facecolor="w", transparent=False)
plt.close() plt.close()
@property @property
def name(self): def name(self):
return "{:d}-{:d}-{:.2f}-{:.2f}".format(self.n, self.m, self.E1, self.E2) return "{:d}-{:d}-{:.2f}-{:.2f}".format(self.n, self.m, self.E1, self.E2)
def _r_square(self, y, yp): def _r_square(self, y, yp):
mean = np.mean(y) mean = np.mean(y)
SST = np.sum((y - mean) ** 2) SST = np.sum((y - mean) ** 2)
SSE = np.sum((y - yp) ** 2) SSE = np.sum((y - yp) ** 2)
return 1 - SSE / SST return 1 - SSE / SST
@property @property
def RSquare1(self): def RSquare1(self):
return self._r_square(self.y[0], self.K1 * self.x[0] + self.C1) return self._r_square(self.y[0], self.K1 * self.x[0] + self.C1)
@property @property
def RSquare2(self): def RSquare2(self):
return self._r_square(self.y[1], self.K2 * self.x[1] + self.C2) return self._r_square(self.y[1], self.K2 * self.x[1] + self.C2)
def __call__(self, data): def __call__(self, data):
"""Data is read to complete initialization""" """Data is read to complete initialization"""
self.k1 = data[0] self.k1 = data[0]
self.k2 = data[1] self.k2 = data[1]
self.b = data[2] self.b = data[2]
self.L = data[3] self.L = data[3]
self.C = data[4] self.C = data[4]

View File

@ -1,172 +1,172 @@
import os import os
import csv import csv
import numpy as np import numpy as np
from tqdm import tqdm from tqdm import tqdm
from matplotlib import pyplot as plt from matplotlib import pyplot as plt
from .Bind import Bind from .bind import Bind
from .utils import readBlockData, get_hist from .utils import readBlockData, get_hist
class Calibration(object): class Calibration(object):
"""Calibrate the detector according to the calibration data""" """Calibrate the detector according to the calibration data"""
def __init__(self): def __init__(self):
pass pass
def __call__(self, file1, file2, bias_b, delta_e, n=6, m=8): def __call__(self, file1, file2, bias_b, delta_e, n=6, m=8):
"""Calibration """Calibration
Parameters Parameters
---------- ----------
file1/2 : str file1/2 : str
data file path of energy 1/2 data file path of energy 1/2
bias_b : float bias_b : float
bias $b = b_1 + b_2$, in MeV bias $b = b_1 + b_2$, in MeV
delta_e : float delta_e : float
delta energy between two beams, in MeV delta energy between two beams, in MeV
n : int, optional n : int, optional
number of blocks, default 6 number of blocks, default 6
m : int, optional m : int, optional
number of binds, default 8 number of binds, default 8
""" """
# Initialization # Initialization
self.n, self.m = n, m self.n, self.m = n, m
self.binds = [[Bind(i, j) for j in range(m)] for i in range(n)] self.binds = [[Bind(i, j) for j in range(m)] for i in range(n)]
# Read Data # Read Data
file_list = csv.reader(open(file1, "r")) file_list = csv.reader(open(file1, "r"))
pbar = tqdm(desc="Read Data E1", total=len(open(file1, "r").readlines())) pbar = tqdm(desc="Read Data E1", total=len(open(file1, "r").readlines()))
for row in file_list: for row in file_list:
pn = int(row[1]) pn = int(row[1])
ldata, rdata = readBlockData(row[0], int(row[5]), pn, m) ldata, rdata = readBlockData(row[0], int(row[3]), pn, m)
for i in range(m): for i in range(m):
bind = self.binds[pn][i] bind = self.binds[pn][i]
bind.add_data(0, ldata[i], rdata[i], float(row[4])) bind.add_data(0, ldata[i], rdata[i], float(row[2]))
pbar.update(1) pbar.update(1)
pbar.close() pbar.close()
file_list = csv.reader(open(file2, "r")) file_list = csv.reader(open(file2, "r"))
pbar = tqdm(desc="Read Data E2", total=len(open(file2, "r").readlines())) pbar = tqdm(desc="Read Data E2", total=len(open(file2, "r").readlines()))
for row in file_list: for row in file_list:
pn = int(row[1]) pn = int(row[1])
ldata, rdata = readBlockData(row[0], int(row[5]), pn, m) ldata, rdata = readBlockData(row[0], int(row[3]), pn, m)
for i in range(m): for i in range(m):
bind = self.binds[pn][i] bind = self.binds[pn][i]
bind.add_data(1, ldata[i], rdata[i], float(row[4])) bind.add_data(1, ldata[i], rdata[i], float(row[2]))
pbar.update(1) pbar.update(1)
pbar.close() pbar.close()
# Data preprocessing # Data preprocessing
pbar = tqdm(desc="Bind Process", total=n * m) pbar = tqdm(desc="Bind Process", total=n * m)
for i in range(n): for i in range(n):
for j in range(m): for j in range(m):
bind: Bind = self.binds[i][j] bind: Bind = self.binds[i][j]
bind.clip() bind.clip()
bind.get_line() bind.get_line()
bind.get_kb(bias_b, delta_e) bind.get_kb(bias_b, delta_e)
pbar.update(1) pbar.update(1)
pbar.close() pbar.close()
# Fit # Fit
pbar = tqdm(desc="Bind Fit", total=n * m) pbar = tqdm(desc="Bind Fit", total=n * m)
for i in range(n): for i in range(n):
for j in range(m): for j in range(m):
bind: Bind = self.binds[i][j] bind: Bind = self.binds[i][j]
bind.get_peak_center() bind.get_peak_center()
bind.fit_px() bind.fit_px()
pbar.update(1) pbar.update(1)
pbar.close() pbar.close()
def draw_fit(self, path): def draw_fit(self, path):
"""Draw fit result """Draw fit result
Parameters Parameters
---------- ----------
path : str path : str
save folder, there must be `FIT-LINE`, `GMM`, and `PEAK` 3 subfolders. save folder, there must be `FIT-LINE`, `GMM`, and `PEAK` 3 subfolders.
""" """
pbar = tqdm(desc="Draw Fit Figure", total=self.n * self.m) pbar = tqdm(desc="Draw Fit Figure", total=self.n * self.m)
for i in range(self.n): for i in range(self.n):
for j in range(self.m): for j in range(self.m):
bind: Bind = self.binds[i][j] bind: Bind = self.binds[i][j]
bind.draw_fit_line(os.path.join(path, "FIT-LINE", bind.name + ".png")) bind.draw_fit_line(os.path.join(path, "FIT-LINE", bind.name + ".png"))
bind.draw_cluster(os.path.join(path, "GMM", bind.name + ".png")) bind.draw_cluster(os.path.join(path, "GMM", bind.name + ".png"))
bind.draw_peak(os.path.join(path, "PEAK", bind.name + ".png")) bind.draw_peak(os.path.join(path, "PEAK", bind.name + ".png"))
pbar.update(1) pbar.update(1)
pbar.close() pbar.close()
def draw_check(self, path="Check.png"): def draw_check(self, path="Check.png"):
"""Draw check figure """Draw check figure
Parameters Parameters
---------- ----------
path : str, optional path : str, optional
save path save path
""" """
pbar = tqdm(desc="Draw Check Figure", total=self.n * self.m) pbar = tqdm(desc="Draw Check Figure", total=self.n * self.m)
fig = plt.figure(figsize=(24, 24), dpi=200) fig = plt.figure(figsize=(24, 24), dpi=200)
ax1 = fig.add_subplot(3, 1, 1) ax1 = fig.add_subplot(3, 1, 1)
ax2 = fig.add_subplot(3, 1, 2) ax2 = fig.add_subplot(3, 1, 2)
ax3 = fig.add_subplot(3, 1, 3) ax3 = fig.add_subplot(3, 1, 3)
peaks = np.array([]) peaks = np.array([])
for i in range(self.n): for i in range(self.n):
engs = np.array([]) engs = np.array([])
for j in range(self.m): for j in range(self.m):
bind = self.binds[i][j] bind = self.binds[i][j]
peaks = np.hstack((np.unique(bind.px[0]), peaks)) peaks = np.hstack((np.unique(bind.px[0]), peaks))
eng = bind.predict_energy(bind.x[0], bind.y[0]) eng = bind.predict_energy(bind.x[0], bind.y[0])
pX = bind.predict_px(bind.x[0], bind.y[0]) pX = bind.predict_px(bind.x[0], bind.y[0])
count, center = get_hist(pX, step=0.5) count, center = get_hist(pX, step=0.5)
engs = np.hstack((engs, eng)) engs = np.hstack((engs, eng))
ax2.scatter(pX, eng, s=0.1, color="k") ax2.scatter(pX, eng, s=0.1, color="k")
ax3.scatter(center, count + 3000 * (7 - j), s=0.5, color="k") ax3.scatter(center, count + 3000 * (7 - j), s=0.5, color="k")
pbar.update(1) pbar.update(1)
count, center = get_hist(engs, step=0.01) count, center = get_hist(engs, step=0.01)
ax1.plot(center, count) ax1.plot(center, count)
peaks = np.unique(peaks) peaks = np.unique(peaks)
for x in peaks: for x in peaks:
ax3.vlines(x, 0, 3000 * self.m, color="gray", linestyles="dashed") ax3.vlines(x, 0, 3000 * self.m, color="gray", linestyles="dashed")
for j in range(self.m): for j in range(self.m):
ax3.hlines( ax3.hlines(
3000 * j, 3000 * j,
(np.min(peaks) // 50) * 50, (np.min(peaks) // 50) * 50,
(np.max(peaks) // 50 + 1) * 50, (np.max(peaks) // 50 + 1) * 50,
color="r", color="r",
linestyles="dashdot", linestyles="dashdot",
) )
ax1.set_xlabel("Energy (MeV)") ax1.set_xlabel("Energy (MeV)")
ax1.set_ylabel("Count per bin") ax1.set_ylabel("Count per bin")
ax2.set_xlabel("x (mm)") ax2.set_xlabel("x (mm)")
ax2.set_ylabel("Energy (MeV)") ax2.set_ylabel("Energy (MeV)")
ax3.set_xlabel("x (mm)") ax3.set_xlabel("x (mm)")
ax3.set_ylabel("Count per bin") ax3.set_ylabel("Count per bin")
fig.savefig(path, facecolor="w", transparent=False) fig.savefig(path, facecolor="w", transparent=False)
plt.close() plt.close()
pbar.close() pbar.close()
def save(self, path="coef.csv"): def save(self, path="coef.csv"):
"""Save coefficient to file """Save coefficient to file
Parameters Parameters
---------- ----------
path : str, optional path : str, optional
save path save path
""" """
f = open(path, "w") f = open(path, "w")
for i in range(self.n): for i in range(self.n):
for j in range(self.m): for j in range(self.m):
bind = self.binds[i][j] bind = self.binds[i][j]
f.writelines( f.writelines(
"{:d},{:d},{:.9f},{:.9f},{:.9f},{:.9f},{:.9f}\n".format( "{:d},{:d},{:.9f},{:.9f},{:.9f},{:.9f},{:.9f}\n".format(
i, j, bind.k1, bind.k2, bind.b, bind.L, bind.C i, j, bind.k1, bind.k2, bind.b, bind.L, bind.C
) )
) )

View File

@ -1,56 +1,56 @@
import numpy as np import numpy as np
from astropy.modeling import models, fitting from astropy.modeling import models, fitting
from .utils import get_hist from .utils import get_hist
def fit_line(model, x, y): def fit_line(model, x, y):
""" """
Line fitting kx+b Line fitting kx+b
Parameters Parameters
---------- ----------
model : astropy.modeling.Model model : astropy.modeling.Model
fit model fit model
x : array x : array
x data, can have two columns representing two independent variables x data, can have two columns representing two independent variables
y : array y : array
y data y data
Returns Returns
------- -------
fitted_model : astropy fitting model fitted_model : astropy fitting model
fitting gaussian model fitting gaussian model
""" """
fitter = fitting.LevMarLSQFitter() fitter = fitting.LevMarLSQFitter()
if np.ndim(x) == 1: if np.ndim(x) == 1:
fitted_model = fitter(model, x, y) fitted_model = fitter(model, x, y)
else: else:
fitted_model = fitter(model, x[:, 0], x[:, 1], y) fitted_model = fitter(model, x[:, 0], x[:, 1], y)
return fitted_model return fitted_model
def fit_hist_gaussian(x, step=1): def fit_hist_gaussian(x, step=1):
""" """
Gaussian fitting is performed on the histogram Gaussian fitting is performed on the histogram
Parameters Parameters
---------- ----------
x : array x : array
data point data point
step : int, optional step : int, optional
Minimum bin width. The bin width is an integer multiple of step. Minimum bin width. The bin width is an integer multiple of step.
Returns Returns
------- -------
fitted_model : astropy fitting model fitted_model : astropy fitting model
fitting gaussian model fitting gaussian model
""" """
fitter = fitting.LMLSQFitter() fitter = fitting.LMLSQFitter()
count, center = get_hist(x, step=step) count, center = get_hist(x, step=step)
model = models.Gaussian1D(amplitude=count.max(), mean=x.mean(), stddev=x.std()) model = models.Gaussian1D(amplitude=count.max(), mean=x.mean(), stddev=x.std())
fitted_model = fitter(model, center, count) fitted_model = fitter(model, center, count)
return fitted_model return fitted_model

View File

@ -1,86 +1,86 @@
import numpy as np import numpy as np
from astropy.modeling import Fittable1DModel, Fittable2DModel, Parameter from astropy.modeling import Fittable1DModel, Fittable2DModel, Parameter
class Linear1D(Fittable1DModel): class Linear1D(Fittable1DModel):
""" """
One dimensional Line model. One dimensional Line model.
Parameters Parameters
---------- ----------
slope : float slope : float
Slope of the straight line Slope of the straight line
intercept : float intercept : float
Intercept of the straight line Intercept of the straight line
""" """
slope = Parameter(default=1, description="Slope of the straight line") slope = Parameter(default=1, description="Slope of the straight line")
intercept = Parameter(default=0, description="Intercept of the straight line") intercept = Parameter(default=0, description="Intercept of the straight line")
@staticmethod @staticmethod
def evaluate(x, slope, intercept): def evaluate(x, slope, intercept):
return slope * x + intercept return slope * x + intercept
@staticmethod @staticmethod
def fit_deriv(x, slope, intercept): def fit_deriv(x, slope, intercept):
d_slope = x d_slope = x
d_intercept = np.ones_like(x) d_intercept = np.ones_like(x)
return [d_slope, d_intercept] return [d_slope, d_intercept]
class FixedSlopeLine(Fittable1DModel): class FixedSlopeLine(Fittable1DModel):
""" """
Linear model, but fix the slope Linear model, but fix the slope
Parameters Parameters
---------- ----------
slope : float slope : float
Slope of the line Slope of the line
intercept : float intercept : float
Intercept of the line Intercept of the line
""" """
slope = Parameter() slope = Parameter()
intercept = Parameter() intercept = Parameter()
@staticmethod @staticmethod
def evaluate(x, slope, intercept): def evaluate(x, slope, intercept):
return slope * x + intercept return slope * x + intercept
@staticmethod @staticmethod
def fit_deriv(x, slope, intercept): def fit_deriv(x, slope, intercept):
d_slope = np.zeros_like(x) d_slope = np.zeros_like(x)
d_intercept = np.ones_like(x) d_intercept = np.ones_like(x)
return [d_slope, d_intercept] return [d_slope, d_intercept]
class pXLine(Fittable2DModel): class pXLine(Fittable2DModel):
""" """
pX linear model. pX linear model.
$Px = \\frac{k_2y - k_1x}{E}L+CL$. $Px = \\frac{k_2y - k_1x}{E}L+CL$.
Parameters Parameters
---------- ----------
L : float L : float
Slope of the straight line Slope of the straight line
C : float C : float
Intercept / Slope of the straight line Intercept / Slope of the straight line
""" """
linear = True linear = True
L, C = Parameter(default=40), Parameter(default=0) L, C = Parameter(default=40), Parameter(default=0)
k1, k2, b = Parameter(), Parameter(), Parameter() k1, k2, b = Parameter(), Parameter(), Parameter()
@staticmethod @staticmethod
def evaluate(x, y, L, C, k1, k2, b): def evaluate(x, y, L, C, k1, k2, b):
E = k1 * x + k2 * y + b E = k1 * x + k2 * y + b
return (k2 * y - k1 * x) / E * L + C * L return (k2 * y - k1 * x) / E * L + C * L
@staticmethod @staticmethod
def fit_deriv(x, y, L, C, k1, k2, b): def fit_deriv(x, y, L, C, k1, k2, b):
E = k1 * x + k2 * y + b E = k1 * x + k2 * y + b
d_L = (k2 * y - k1 * x) / E + C d_L = (k2 * y - k1 * x) / E + C
d_C = np.full(x.shape, L) d_C = np.full(x.shape, L)
d_k1, d_k2, d_b = np.zeros_like(x), np.zeros_like(x), np.zeros_like(x) d_k1, d_k2, d_b = np.zeros_like(x), np.zeros_like(x), np.zeros_like(x)
return [d_L, d_C, d_k1, d_k2, d_b] return [d_L, d_C, d_k1, d_k2, d_b]

View File

@ -1,131 +1,131 @@
import csv import csv
import numpy as np import numpy as np
from tqdm import tqdm from tqdm import tqdm
from matplotlib import pyplot as plt from matplotlib import pyplot as plt
from .Bind import Bind from .bind import Bind
from .fit import fit_line from .fit import fit_line
from .model import Linear1D from .model import Linear1D
from .utils import readFileData, get_hist from .utils import readFileData, get_hist
class Process(object): class Process(object):
"""Process the experimental data according to the calibration results.""" """Process the experimental data according to the calibration results."""
def __init__(self) -> None: def __init__(self) -> None:
pass pass
def __call__(self, coef, task, n=6, m=8): def __call__(self, coef, task, n=6, m=8):
"""Read Process Data """Read Process Data
coef : str coef : str
coefficient file coefficient file
task : str task : str
task file task file
n : int, optional n : int, optional
number of blocks, default 6 number of blocks, default 6
m : int, optional m : int, optional
number of binds, default 8 number of binds, default 8
""" """
# Initialization # Initialization
self.n, self.m = n, m self.n, self.m = n, m
self.binds = [[Bind(i, j) for j in range(m)] for i in range(n)] self.binds = [[Bind(i, j) for j in range(m)] for i in range(n)]
# Read Calibration Data # Read Calibration Data
pbar = tqdm(desc="Bind Initialization", total=n * m) pbar = tqdm(desc="Bind Initialization", total=n * m)
data = list(csv.reader(open(coef, "r"))) data = list(csv.reader(open(coef, "r")))
data = np.array(data, dtype=np.float64) data = np.array(data, dtype=np.float64)
for i in range(n): for i in range(n):
for j in range(m): for j in range(m):
bind = self.binds[i][j] bind = self.binds[i][j]
bind(data[j + i * m][2:]) bind(data[j + i * m][2:])
pbar.update(1) pbar.update(1)
pbar.close() pbar.close()
# Read Data # Read Data
total = len(open(task, "r").readlines()) * n * m total = len(open(task, "r").readlines()) * n * m
file_list = csv.reader(open(task, "r")) file_list = csv.reader(open(task, "r"))
self.pX = np.array([]) self.pX = np.array([])
self.eng = np.array([]) self.eng = np.array([])
pbar = tqdm(desc="Read Data", total=total) pbar = tqdm(desc="Read Data", total=total)
for row in file_list: for row in file_list:
ldata, rdata = readFileData(row[0], n, m) ldata, rdata = readFileData(row[0], n, m)
for i in range(n): for i in range(n):
for j in range(m): for j in range(m):
bind = self.binds[i][j] bind = self.binds[i][j]
x = bind.predict_px(ldata[j + i * m], rdata[j + i * m]) + float( x = bind.predict_px(ldata[j + i * m], rdata[j + i * m]) + float(
row[1] row[1]
) )
e = bind.predict_energy(ldata[j + i * m], rdata[j + i * m]) e = bind.predict_energy(ldata[j + i * m], rdata[j + i * m])
edge_l = 5 + 130 * i + float(row[1]) - 35 edge_l = 5 + 130 * i + float(row[1]) - 35
edge_r = edge_l + 65 edge_r = edge_l + 65
idx = np.where((x >= edge_l) & (x <= edge_r))[0] idx = np.where((x >= edge_l) & (x <= edge_r))[0]
self.pX = np.hstack((self.pX, x[idx])) self.pX = np.hstack((self.pX, x[idx]))
self.eng = np.hstack((self.eng, e[idx])) self.eng = np.hstack((self.eng, e[idx]))
pbar.update(1) pbar.update(1)
pbar.close() pbar.close()
def energy_filter(self, lower, upper, sigma=5.0, maxiters=5): def energy_filter(self, lower, upper, sigma=5.0, maxiters=5):
"""Fit px - E line and do sigma clip iteratively. """Fit px - E line and do sigma clip iteratively.
Parameters Parameters
---------- ----------
lower/upper : float lower/upper : float
Upper and lower bounds on the initial filter Upper and lower bounds on the initial filter
sigma: float, optional sigma: float, optional
The number of standard deviations to use for both the lower and upper clipping limit. The number of standard deviations to use for both the lower and upper clipping limit.
maxiters: int or None, optional maxiters: int or None, optional
The maximum number of sigma-clipping iterations to perform or None to clip until convergence is achieved. The maximum number of sigma-clipping iterations to perform or None to clip until convergence is achieved.
If convergence is achieved prior to maxiters iterations, the clipping iterations will stop. If convergence is achieved prior to maxiters iterations, the clipping iterations will stop.
""" """
model = Linear1D() model = Linear1D()
idx = np.where((self.eng >= lower) & (self.eng <= upper))[0] idx = np.where((self.eng >= lower) & (self.eng <= upper))[0]
x, y = self.pX[idx], self.eng[idx] x, y = self.pX[idx], self.eng[idx]
for i in range(maxiters): for i in range(maxiters):
reg = fit_line(model, x, y) reg = fit_line(model, x, y)
err = np.abs(y - reg(x)) err = np.abs(y - reg(x))
idx = np.where(err <= sigma * np.std(err))[0] idx = np.where(err <= sigma * np.std(err))[0]
if len(idx) == len(x): if len(idx) == len(x):
break break
x, y = x[idx], y[idx] x, y = x[idx], y[idx]
self.pX_n = x self.pX_n = x
self.eng_n = y self.eng_n = y
self.reg = reg self.reg = reg
def draw_result(self, path="result.png"): def draw_result(self, path="result.png"):
"""Draw the processing result """Draw the processing result
Parameters Parameters
---------- ----------
path : str, optional path : str, optional
save path save path
""" """
fig = plt.figure(figsize=(24, 12), dpi=200) fig = plt.figure(figsize=(24, 12), dpi=200)
ax1 = fig.add_subplot(2, 1, 1) ax1 = fig.add_subplot(2, 1, 1)
ax2 = fig.add_subplot(2, 1, 2) ax2 = fig.add_subplot(2, 1, 2)
count, center = get_hist(self.pX_n, step=0.1) count, center = get_hist(self.pX_n, step=0.1)
ax1.scatter(self.pX, self.eng, s=0.01, color="black") ax1.scatter(self.pX, self.eng, s=0.01, color="black")
ax1.scatter(self.pX_n, self.eng_n, s=0.01, color="orange") ax1.scatter(self.pX_n, self.eng_n, s=0.01, color="orange")
ax2.step(center, count, where="post", color="k") ax2.step(center, count, where="post", color="k")
px_min = (np.min(self.pX_n) // 50) * 50 px_min = (np.min(self.pX_n) // 50) * 50
px_max = (np.max(self.pX_n) // 50 + 1) * 50 px_max = (np.max(self.pX_n) // 50 + 1) * 50
px_x = np.linspace(px_min, px_max, int(px_max - px_min)) px_x = np.linspace(px_min, px_max, int(px_max - px_min))
ax1.plot(px_x, self.reg(px_x)) ax1.plot(px_x, self.reg(px_x))
ax1.set_xticks(np.arange(px_min, px_max, 50)) ax1.set_xticks(np.arange(px_min, px_max, 50))
ax2.set_xticks(np.arange(px_min, px_max, 50)) ax2.set_xticks(np.arange(px_min, px_max, 50))
ax1.set_xlabel("x (mm)") ax1.set_xlabel("x (mm)")
ax1.set_ylabel("Energy (MeV)") ax1.set_ylabel("Energy (MeV)")
ax2.set_xlabel("x (mm)") ax2.set_xlabel("x (mm)")
ax2.set_ylabel("Count per bin") ax2.set_ylabel("Count per bin")
fig.savefig(path, facecolor="w", transparent=False) fig.savefig(path, facecolor="w", transparent=False)
plt.close() plt.close()

View File

@ -1,141 +1,141 @@
import uproot import uproot
import numpy as np import numpy as np
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
from sklearn.mixture import GaussianMixture from sklearn.mixture import GaussianMixture
def readFileData(file, count, n=6, m=8, minT=800, maxT=4000): def readFileData(file, count, n=6, m=8, minT=800, maxT=4000):
"""Read whole data from root file """Read whole data from root file
Parameters Parameters
---------- ----------
file : str file : str
root file path root file path
count : int count : int
count that normalized by counts of Faraday cylinder count that normalized by counts of Faraday cylinder
n : int, optional n : int, optional
number of blocks, default 6 number of blocks, default 6
m : int, optional m : int, optional
number of binds, default 8 number of binds, default 8
minT/maxT : int, optional minT/maxT : int, optional
Filtering data, the sum of the left and right sides needs to be in the interval [minT, maxT] Filtering data, the sum of the left and right sides needs to be in the interval [minT, maxT]
min / max threshold min / max threshold
""" """
data = uproot.open(file)["Tree1"] data = uproot.open(file)["Tree1"]
ldata, rdata = [], [] ldata, rdata = [], []
for i in range(n): for i in range(n):
for j in range(m): for j in range(m):
na = i // 2 na = i // 2
nc = j + 2 * m * (i % 2) nc = j + 2 * m * (i % 2)
x = data["adc{:d}ch{:d}".format(na, nc)].array(library="np")[:count] x = data["adc{:d}ch{:d}".format(na, nc)].array(library="np")[:count]
y = data["adc{:d}ch{:d}".format(na, nc + m)].array(library="np")[:count] y = data["adc{:d}ch{:d}".format(na, nc + m)].array(library="np")[:count]
idx = np.where((x + y >= minT) & (x + y <= maxT))[0] idx = np.where((x + y >= minT) & (x + y <= maxT))[0]
ldata.append(x[idx]) ldata.append(x[idx])
rdata.append(y[idx]) rdata.append(y[idx])
return ldata, rdata return ldata, rdata
def readBlockData(file, count, n, m=8, minT=800, maxT=4000): def readBlockData(file, count, n, m=8, minT=800, maxT=4000):
"""Read block data from root file """Read block data from root file
Parameters Parameters
---------- ----------
file : str file : str
root file path root file path
count : int count : int
count that normalized by counts of Faraday cylinder count that normalized by counts of Faraday cylinder
n : int n : int
No.n block No.n block
m : int, optional m : int, optional
number of binds, default 8 number of binds, default 8
minT/maxT : int, optional minT/maxT : int, optional
Filtering data, the sum of the left and right sides needs to be in the interval [minT, maxT] Filtering data, the sum of the left and right sides needs to be in the interval [minT, maxT]
min / max threshold min / max threshold
""" """
data = uproot.open(file)["Tree1"] data = uproot.open(file)["Tree1"]
ldata, rdata = [], [] ldata, rdata = [], []
for j in range(m): for j in range(m):
na = n // 2 na = n // 2
nc = j + 2 * m * (n % 2) nc = j + 2 * m * (n % 2)
x = data["adc{:d}ch{:d}".format(na, nc)].array(library="np")[:count] x = data["adc{:d}ch{:d}".format(na, nc)].array(library="np")[:count]
y = data["adc{:d}ch{:d}".format(na, nc + m)].array(library="np")[:count] y = data["adc{:d}ch{:d}".format(na, nc + m)].array(library="np")[:count]
idx = np.where((x + y >= minT) & (x + y <= maxT))[0] idx = np.where((x + y >= minT) & (x + y <= maxT))[0]
ldata.append(x[idx]) ldata.append(x[idx])
rdata.append(y[idx]) rdata.append(y[idx])
return ldata, rdata return ldata, rdata
def draw_scatter(data, title, s=0.1): def draw_scatter(data, title, s=0.1):
"""Draw points using scatter """Draw points using scatter
Parameters Parameters
---------- ----------
s : float, optional s : float, optional
size of scatter point, default 0.1 size of scatter point, default 0.1
""" """
fig = plt.figure(figsize=(8, 8)) fig = plt.figure(figsize=(8, 8))
ax = fig.add_subplot(1, 1, 1) ax = fig.add_subplot(1, 1, 1)
for cluster in data: for cluster in data:
ax.scatter(cluster[:, 0], cluster[:, 1], s=s) ax.scatter(cluster[:, 0], cluster[:, 1], s=s)
fig.savefig(title, facecolor="w", transparent=False) fig.savefig(title, facecolor="w", transparent=False)
plt.close() plt.close()
def get_hist(data, step=1, maxN=50, return_edge=False): def get_hist(data, step=1, maxN=50, return_edge=False):
"""Gets the boundary of histogram that the maximum count is bigger than threshold """Gets the boundary of histogram that the maximum count is bigger than threshold
Parameters Parameters
---------- ----------
step : int, optional step : int, optional
Minimum bin width. The bin width is an integer multiple of step. Minimum bin width. The bin width is an integer multiple of step.
maxN : int, optional maxN : int, optional
Maximum count threshold Maximum count threshold
return_edge: bool, optional return_edge: bool, optional
If True, then the bin edges are also returned. If True, then the bin edges are also returned.
""" """
delta = step delta = step
edge = np.arange(data.min(), data.max() + 1, delta) edge = np.arange(data.min(), data.max() + 1, delta)
count, _ = np.histogram(data, bins=edge) count, _ = np.histogram(data, bins=edge)
try: try:
while count.max() <= maxN: while count.max() <= maxN:
delta += step delta += step
edge = np.arange(data.min(), data.max() + 1, delta) edge = np.arange(data.min(), data.max() + 1, delta)
count, _ = np.histogram(data, bins=edge) count, _ = np.histogram(data, bins=edge)
except: except:
edge = np.arange(data.min(), data.max() + 1, step) edge = np.arange(data.min(), data.max() + 1, step)
count, _ = np.histogram(data, bins=edge) count, _ = np.histogram(data, bins=edge)
if return_edge: if return_edge:
return count / delta, (edge[1:] + edge[:-1]) / 2, edge return count / delta, (edge[1:] + edge[:-1]) / 2, edge
else: else:
return count / delta, (edge[1:] + edge[:-1]) / 2 return count / delta, (edge[1:] + edge[:-1]) / 2
def GMM_clip(data, return_all=False): def GMM_clip(data, return_all=False):
"""Using Gaussian Mixture Method (GMM) to decompose the data into noise and available data """Using Gaussian Mixture Method (GMM) to decompose the data into noise and available data
Parameters Parameters
---------- ----------
data : numpy.ndarray data : numpy.ndarray
Data to be clipped Data to be clipped
return_all: bool, optional return_all: bool, optional
If True, then all data will be returned. If True, then all data will be returned.
""" """
fit_data = np.array([]) fit_data = np.array([])
model = GaussianMixture(n_components=2) model = GaussianMixture(n_components=2)
model.fit(data[:, :2]) model.fit(data[:, :2])
ny = model.predict(data[:, :2]) ny = model.predict(data[:, :2])
for i in np.unique(ny): for i in np.unique(ny):
idx = np.where(ny == i)[0] idx = np.where(ny == i)[0]
fit_data = idx if len(idx) > len(fit_data) else fit_data fit_data = idx if len(idx) > len(fit_data) else fit_data
if return_all: if return_all:
return ny return ny
else: else:
return data[fit_data] return data[fit_data]

Binary file not shown.