Skip to content

Commit f340d66

Browse files
authored
#19 Merge pull request from deshima-dev/ana2025
Add KID flagging scripts based on FitSweep
2 parents 2e28503 + 6d8d630 commit f340d66

20 files changed

+2375
-29
lines changed

.devcontainer/devcontainer.json

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,13 @@
11
{
22
"name": "kidanalysis-delft",
33
"image": "python:3.11",
4-
"features": {
5-
"ghcr.io/devcontainers-contrib/features/poetry:2": {
6-
"version": "1.8.3"
7-
}
8-
},
94
"containerEnv": {
105
"POETRY_VIRTUALENVS_CREATE": "false"
116
},
127
"runArgs": [
138
"--name=kidanalysis-delft"
149
],
15-
"postCreateCommand": "poetry install",
10+
"postCreateCommand": "pip install poetry && poetry install",
1611
"customizations": {
1712
"vscode": {
1813
"extensions": [

.github/workflows/tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ jobs:
2626
with:
2727
python-version: ${{ matrix.python }}
2828
- run: pip install setuptools==70.0.0 # temporary
29-
- run: pip install poetry==1.8.3 && poetry install
29+
- run: pip install poetry && poetry install
3030
- run: deshima-rawdata download 20231117042946 -e
3131
- run: python scripts/aste/Configure.py cosmos_20231117042946 out
3232
- run: python scripts/aste/FitSweep.py

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ version = "2024.7.0"
44
description = "KID analysis scripts made in Delft"
55
authors = ["Kenichi Karatsu", "Shinji Fujita"]
66
maintainers = ["Akio Taniguchi <taniguchi@a.phys.nagoya-u.ac.jp>"]
7+
package-mode = false
78
readme = "README.md"
89

910
[tool.poetry.dependencies]

scripts/aste/current_outdir.conf

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/home/deshima/data/fujita_analysis/work_in_Kitami202508/analysis/cosmos_20241020224554/out_test_5
Lines changed: 304 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,304 @@
1+
#!/usr/bin/env python
2+
# -*- coding:utf-8 -*-
3+
4+
import os
5+
import sys
6+
import shutil
7+
8+
from collections import OrderedDict
9+
10+
import matplotlib.pyplot as plt
11+
#import mkid_data as md
12+
import numpy as np
13+
from glob import glob
14+
15+
def main(argv=None):
16+
parser = argparse.ArgumentParser(formatter_class=myHelpFormatter, description=__doc__)
17+
parser.add_argument('--threshold_fr_diff', type=float, default=1.0e-4,
18+
help='Threshold of difference between fr with neighboring KID. If it is less than this, one of them will be deleted.')
19+
parser.add_argument('--threshold_chi2', type=float, default=5.0e-8,
20+
help='threshold of chi2 to be deleted.')
21+
parser.add_argument('--frac_FWHM', type=float, default=2.0,
22+
help='calculation range of chi2 (+-FWHM*?)')
23+
parser.add_argument('--frac_fr', type=float, default=0.2,
24+
help='check to see if fr is too far apart.')
25+
parser.add_argument('--del_1st_or_2nd', type=str, default="2nd",
26+
help='If there are overlapping KIDs, which one should be deleted.')
27+
#parser.add_argument('--terahertzsweep_or_aste', type=str, default="obs",
28+
# help='for THzsweep [terahertzsweep] or observations (COSMOS dir) [aste].')
29+
30+
args = parser.parse_args(argv)
31+
threshold_fr_diff = args.threshold_fr_diff
32+
threshold_chi2 = args.threshold_chi2
33+
frac_FWHM = args.frac_FWHM
34+
frac_fr = args.frac_fr
35+
del_1st_or_2nd = args.del_1st_or_2nd
36+
#terahertzsweep_or_aste = args.terahertzsweep_or_aste
37+
38+
#if toptica_or_obs=="terahertzsweep":
39+
# fit_res_dir = os.path.join(outdir, "THzsweep")
40+
#elif toptica_or_obs=="aste":
41+
# fit_res_dir = os.path.join(outdir, "aste")
42+
#else:
43+
# print('"terahertzsweep_or_aste" should be terahertzsweep or aste')
44+
# sys.exit()
45+
46+
#dir_list = sorted(glob(os.path.join(fit_res_dir, "[0-9]*[0-9]")))
47+
48+
##### save original disabled_kids.dat
49+
reftxtlist = outdir + '/disabled_kids.dat'
50+
os.system(f"cp -n {reftxtlist} {os.path.join(outdir, 'disabled_kids_ori.dat')}")
51+
52+
#####
53+
def main_2(sky_or_room):
54+
if sky_or_room=="sky":
55+
rs = 'raw_sweep'
56+
fit_name = "fit"
57+
elif sky_or_room=="room":
58+
rs = 'raw_sweep_roomchopper'
59+
fit_name = "fit_roomchopper"
60+
raw_sweep_list = []
61+
fit_list = []
62+
for i, kid in kids.items():
63+
if kid.enabled:
64+
raw_sweep_list.append( kid.get_cache(rs) )
65+
fit_list.append( kid.get_cache(fit_name) )
66+
else:
67+
raw_sweep_list.append(np.nan)
68+
fit_list.append(np.nan)
69+
70+
#residual_pmFrac, good_list, bad_list = pmFrac(Frac, threshold, fr_offset_frac)
71+
residual_pmFrac, good_list, bad_list = pmFrac(fit_list, raw_sweep_list, frac_FWHM, threshold_chi2, frac_fr)
72+
print(f"bad_list from chi2 ({sky_or_room})", bad_list)
73+
74+
reftxtlist = outdir + f'/disabled_kids.dat'
75+
os.system(f"cp {os.path.join(outdir, 'disabled_kids_ori.dat')} {reftxtlist}")
76+
77+
with open(reftxtlist, 'a') as f:
78+
print( '# below are append due to bad chi2', file=f )
79+
for i in bad_list:
80+
print( i, file=f )
81+
82+
bad_list = np.array(my_loadtxt(reftxtlist, unpack=True, skiprows=1)[0])
83+
good_list = np.setdiff1d(good_list, bad_list)
84+
bad_list = np.sort(bad_list)
85+
86+
kid_ids = []
87+
frs = []
88+
for i in range(len(fit_list)):
89+
kid_ids.append(i)
90+
try:
91+
fr = fit_list[i]._result.params["fr"].value
92+
frs.append(fr)
93+
except:
94+
frs.append(np.nan)
95+
kid_ids = np.array(kid_ids)
96+
frs = np.array(frs)
97+
np.save(os.path.join(outdir,f"frs_{sky_or_room}.npy"), frs)
98+
99+
#diff_next = np.abs(np.diff(frs))
100+
#ids_next = kid_ids[:-1]
101+
102+
#threshold_fr_diff = 1e-4 #########
103+
mask_good = ~np.isin(kid_ids, bad_list)
104+
kid_ids_good = kid_ids[mask_good]
105+
frs_good = frs[mask_good]
106+
107+
sorted_indices = np.argsort(kid_ids_good)
108+
kid_ids_good = kid_ids_good[sorted_indices]
109+
frs_good = frs_good[sorted_indices]
110+
111+
fr_diffs = np.abs(np.diff(frs_good))
112+
adjacent_pairs = [(kid_ids_good[i], kid_ids_good[i+1])
113+
for i in range(len(frs_good) - 1)
114+
if fr_diffs[i] <= threshold_fr_diff]
115+
np.save(os.path.join(outdir,f"kid_ids_good_{sky_or_room}.npy"), kid_ids_good)
116+
np.save(os.path.join(outdir,f"fr_diffs_{sky_or_room}.npy"), fr_diffs)
117+
print(f"adjacent_pairs ({sky_or_room}) =", adjacent_pairs)
118+
119+
bad_list_fr_diff = []
120+
for a, b in adjacent_pairs:
121+
if del_1st_or_2nd=="1st":
122+
bad_list_fr_diff.append(a)
123+
elif del_1st_or_2nd=="2nd":
124+
bad_list_fr_diff.append(b)
125+
else:
126+
print('"del_1st_or_2nd" should be 1st or 2nd')
127+
sys.exit()
128+
129+
print(f"bad_list_fr_diff ({sky_or_room})", bad_list_fr_diff)
130+
with open(reftxtlist, 'a') as f:
131+
print( '# below are append due to overlap %s' %del_1st_or_2nd, file=f )
132+
for i in bad_list_fr_diff:
133+
print( i, file=f )
134+
135+
bad_candidates = np.array([i for i in bad_list_fr_diff if i in good_list]).astype("int")
136+
bad_list = np.union1d(bad_list, bad_candidates).astype("int")
137+
good_list = np.setdiff1d(good_list, bad_list).astype("int")
138+
bad_list = np.sort(bad_list).astype("int")
139+
print(f"bad_list ({sky_or_room})", bad_list)
140+
141+
#kid_ids = np.array([i for i in range(len(raw_sweep_list))])
142+
143+
plt.figure(figsize=(16, 8))
144+
plt.scatter(kid_ids[good_list], residual_pmFrac[good_list], marker="o", c="b", label="Good")
145+
plt.scatter(kid_ids[bad_list], residual_pmFrac[bad_list], marker="x", c="r", label="Bad")
146+
plt.grid()
147+
plt.xlabel("KID ID", size=20)
148+
plt.ylabel(r"$\chi^2$", size=20)
149+
plt.yscale("log")
150+
plt.legend()
151+
for i in bad_list:
152+
x = kid_ids[i]
153+
y = residual_pmFrac[i]
154+
if not np.isfinite(y):
155+
continue
156+
plt.text(x, y, str(int(x)), color="magenta", fontsize=10, ha="center", va="bottom")
157+
158+
plt.savefig(os.path.join(outdir, f"flag_delete_{del_1st_or_2nd}_{sky_or_room}.png"))
159+
160+
161+
np.save(os.path.join(outdir,f"kid_ids_{sky_or_room}.npy"), kid_ids)
162+
np.save(os.path.join(outdir,f"residual_pmFrac_{sky_or_room}.npy"), residual_pmFrac)
163+
164+
reftxtlist_new = outdir + f'/disabled_kids_{sky_or_room}.dat'
165+
com = f"mv {reftxtlist} {reftxtlist_new}"
166+
os.system(com)
167+
168+
return bad_list, bad_list_fr_diff
169+
170+
bad_list_sky, bad_list_fr_diff_sky = main_2("sky")
171+
bad_list_room, bad_list_fr_diff_room = main_2("room")
172+
173+
bad_list_concat = np.concatenate([bad_list_sky, bad_list_room])
174+
bad_list_fr_diff_concat = np.concatenate([bad_list_fr_diff_sky, bad_list_fr_diff_room])
175+
176+
reftxtlist = outdir + f'/disabled_kids.dat'
177+
os.system(f"cp {os.path.join(outdir, 'disabled_kids_ori.dat')} {reftxtlist}")
178+
179+
unique_vals, counts = np.unique(bad_list_concat, return_counts=True)
180+
once_only = unique_vals[counts == 1]
181+
print(f"bad KID ID from chi2 (appeared once): {once_only}")
182+
unique_vals, counts = np.unique(bad_list_fr_diff_concat, return_counts=True)
183+
once_only = unique_vals[counts == 1]
184+
print(f"bad KID ID from fr (appeared once): {once_only}")
185+
186+
with open(reftxtlist, 'a') as f:
187+
print( '# below are append due to bad chi2', file=f )
188+
for i in np.unique(bad_list_concat):
189+
print( i, file=f )
190+
with open(reftxtlist, 'a') as f:
191+
print( '# below are append due to overlap %s' %del_1st_or_2nd, file=f )
192+
for i in np.unique(bad_list_fr_diff_concat):
193+
print( i, file=f )
194+
195+
196+
197+
"""
198+
f = open(os.path.join(outdir, "flag_delete_%s.dat"%del_1st_or_2nd), "w")
199+
f.write("# flag\n")
200+
for i in bad_list:
201+
f.write("%i\n"%i)
202+
f.close()
203+
"""
204+
205+
def gao_model(f, params):
206+
arga = params['arga'].value
207+
absa = params['absa'].value
208+
tau = params['tau'].value
209+
fr = params['fr'].value
210+
Qr = params['Qr'].value
211+
Qc = params['Qc'].value
212+
phi0 = params['phi0'].value
213+
c = params['c'].value
214+
215+
df = f - fr
216+
background = c * df + 1
217+
resonance = Qr * np.exp(1j * phi0) / (Qc * (1 + 2j * Qr * df / fr))
218+
system_phase = np.exp(1j * (arga - 2 * np.pi * tau * f))
219+
220+
return absa * (background - resonance) * system_phase
221+
222+
def residual(params, f, data):
223+
model = gao_model(f, params)
224+
return np.concatenate([(np.real(model) - np.real(data)), (np.imag(model) - np.imag(data))])**2
225+
226+
def pmFrac(fit_list, raw_sweep_list, Frac, threshold, fr_offset_frac):
227+
residual_sum_pmFrac_list = []
228+
good_list, bad_list = [], []
229+
is_first = True
230+
for i in range(len(raw_sweep_list)):
231+
try:
232+
params_test = fit_list[i]._result.params
233+
f_test = raw_sweep_list[i].f
234+
data_test = raw_sweep_list[i].iq
235+
236+
residual_test = residual(params_test, f_test, data_test)
237+
238+
fr = fit_list[i]._result.params["fr"].value
239+
Qr = fit_list[i]._result.params["Qr"].value
240+
FWHM = fr/Qr
241+
242+
len_f = len(f_test)
243+
ind_fr = np.argmin(np.abs(f_test - fr))
244+
245+
if is_first:
246+
# print(i)
247+
print("fr = ", fr, "GHz")
248+
print("Qr = ", Qr)
249+
print("FWHM = ", FWHM*1e3, "MHz")
250+
print("pmFrac = ", FWHM*Frac*1e3, "MHz")
251+
is_first = False
252+
253+
ind_start = np.argmin(np.abs(f_test - (fr - FWHM*Frac)))
254+
ind_end = np.argmin(np.abs(f_test - (fr + FWHM*Frac)))
255+
residual_sum = float(np.sum(residual_test[ind_start:ind_end]))/(ind_end - ind_start)
256+
257+
if ind_fr<0 or ind_fr>len_f-1:
258+
residual_sum_pmFrac_list.append(residual_sum)
259+
bad_list.append(i)
260+
continue
261+
262+
if FWHM*1e3<0 or FWHM*1e3>1.0:
263+
residual_sum_pmFrac_list.append(residual_sum)
264+
bad_list.append(i)
265+
continue
266+
267+
f_cen = np.nanmedian(f_test)
268+
ind_f_cen = np.argmin(np.abs(f_test - f_cen))
269+
if abs(ind_fr-ind_f_cen) > len_f*fr_offset_frac:
270+
residual_sum_pmFrac_list.append(residual_sum)
271+
bad_list.append(i)
272+
continue
273+
274+
residual_sum_pmFrac_list.append(residual_sum)
275+
if residual_sum <= threshold:
276+
good_list.append(i)
277+
else:
278+
bad_list.append(i)
279+
except:
280+
residual_sum_pmFrac_list.append(np.nan)
281+
bad_list.append(i)
282+
continue
283+
return np.array(residual_sum_pmFrac_list), np.array(good_list), np.array(bad_list)
284+
285+
286+
287+
if __name__ == '__main__':
288+
script_dir = os.path.dirname(os.path.abspath(__file__))
289+
libpath = os.path.join(os.path.dirname(script_dir), 'libs')
290+
sys.path.append(libpath)
291+
292+
current_outdir = './current_outdir.conf'
293+
with open(current_outdir) as f:
294+
outdir = f.readline().strip()
295+
reftxtlist = outdir + '/disabled_kids.dat'
296+
if os.path.exists(os.path.join(outdir, 'disabled_kids_ori.dat')):
297+
com = f"cp {os.path.join(outdir, 'disabled_kids_ori.dat')} {reftxtlist}"
298+
print(com)
299+
os.system(com)
300+
301+
from common import *
302+
main()
303+
304+
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/bin/sh
2+
NCPU=`python -c "import multiprocessing as m; print(m.cpu_count() - 1);"`
3+
4+
echo NCPU = $NCPU
5+
6+
file_dir=$1
7+
out_dir=$2
8+
9+
last_dir=$(basename "$file_dir")
10+
#second_last_dir=$(basename "$(dirname "$file_dir")")
11+
12+
echo ====Configure.py====
13+
echo -e "${file_dir}\n/home/deshima/data/fujita_analysis/work_in_Kitami202508/analysis/${last_dir}/${out_dir}" | python Configure.py
14+
15+
echo ====FitSweep.py====
16+
#python FitSweep.py
17+
echo ====FitSweep.py --mode plot --ncpu $NCPU====
18+
#python FitSweep.py --mode plot --ncpu $NCPU
19+
20+
echo ====SaveFits.py====
21+
#python SaveFits.py
22+
echo ====SaveFits.py --mode plot --ncpu $NCPU====
23+
#python SaveFits.py --mode plot --ncpu $NCPU
24+
25+
echo ====flag_KIDs_based_on_FitSweep.py====
26+
python flag_KIDs_based_on_FitSweep.py --threshold_fr_diff 1.0e-4 --threshold_chi2 5.0e-8 --frac_FWHM 2.0 --frac_fr 0.2 --del_1st_or_2nd 2nd
27+
28+
29+
echo ====FINISHED====

scripts/terahertzsweep/FitSweep.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ def Plot(kids, force, test, NCPU):
354354

355355
def plot_multi(params):
356356
import mkid_data as md
357-
357+
358358
i = params["i"]
359359
kid = params["kid"]
360360
plotdir = params["plotdir"]

0 commit comments

Comments
 (0)