teareduce 0.5.9__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -15,12 +15,30 @@ from tkinter import ttk
15
15
 
16
16
  from .centerchildparent import center_on_parent
17
17
  from .definitions import VALID_CLEANING_METHODS
18
+ from .definitions import MASKFILL_OPERATOR_VALUES
18
19
 
19
20
 
20
21
  class InterpolationEditor:
21
22
  """Dialog to select interpolation cleaning parameters."""
22
23
 
23
- def __init__(self, root, last_dilation, last_npoints, last_degree, auxdata, xmin, xmax, ymin, ymax, imgshape):
24
+ def __init__(
25
+ self,
26
+ root,
27
+ last_dilation,
28
+ last_npoints,
29
+ last_degree,
30
+ last_maskfill_size,
31
+ last_maskfill_operator,
32
+ last_maskfill_smooth,
33
+ last_maskfill_verbose,
34
+ auxdata,
35
+ cleandata_lacosmic,
36
+ xmin,
37
+ xmax,
38
+ ymin,
39
+ ymax,
40
+ imgshape,
41
+ ):
24
42
  """Initialize the interpolation editor dialog.
25
43
 
26
44
  Parameters
@@ -33,8 +51,18 @@ class InterpolationEditor:
33
51
  The last used number of points for interpolation.
34
52
  last_degree : int
35
53
  The last used degree for interpolation.
54
+ last_maskfill_size : int
55
+ The last used maskfill size parameter.
56
+ last_maskfill_operator : str
57
+ The last used maskfill operator parameter.
58
+ last_maskfill_smooth : bool
59
+ The last used maskfill smooth parameter.
60
+ last_maskfill_verbose : bool
61
+ The last used maskfill verbose parameter.
36
62
  auxdata : array-like or None
37
63
  Auxiliary data for cleaning, if available.
64
+ cleandata_lacosmic : array-like or None
65
+ Cleaned data from L.A.Cosmic, if available.
38
66
  xmin : float
39
67
  Minimum x value of the data. From 1 to NAXIS1.
40
68
  xmax : float
@@ -56,8 +84,6 @@ class InterpolationEditor:
56
84
  Handle the Cancel button click event.
57
85
  action_on_method_change()
58
86
  Handle changes in the selected cleaning method.
59
- check_interp_methods()
60
- Check that all interpolation methods are valid.
61
87
 
62
88
  Attributes
63
89
  ----------
@@ -67,6 +93,8 @@ class InterpolationEditor:
67
93
  The last used dilation parameter.
68
94
  auxdata : array-like or None
69
95
  Auxiliary data for cleaning, if available.
96
+ cleandata_lacosmic : array-like or None
97
+ Cleaned data from L.A.Cosmic, if available.
70
98
  dict_interp_methods : dict
71
99
  Mapping of interpolation method names to their codes.
72
100
  cleaning_method : str or None
@@ -75,6 +103,12 @@ class InterpolationEditor:
75
103
  The number of points for interpolation.
76
104
  degree : int
77
105
  The degree for interpolation.
106
+ maskfill_size : int
107
+ The size parameter for maskfill.
108
+ maskfill_operator : str
109
+ The operator parameter for maskfill.
110
+ maskfill_smooth : bool
111
+ The smooth parameter for maskfill.
78
112
  xmin : float
79
113
  Minimum x value of the data. From 1 to NAXIS1.
80
114
  xmax : float
@@ -90,21 +124,15 @@ class InterpolationEditor:
90
124
  self.root.title("Cleaning Parameters")
91
125
  self.last_dilation = last_dilation
92
126
  self.auxdata = auxdata
93
- self.dict_interp_methods = {
94
- "x interp.": "x",
95
- "y interp.": "y",
96
- "surface interp.": "a-plane",
97
- "median": "a-median",
98
- "mean": "a-mean",
99
- "lacosmic": "lacosmic",
100
- "maskfill": "maskfill",
101
- "auxdata": "auxdata",
102
- }
103
- self.check_interp_methods()
127
+ self.cleandata_lacosmic = cleandata_lacosmic
104
128
  # Initialize parameters
105
129
  self.cleaning_method = None
106
130
  self.npoints = last_npoints
107
131
  self.degree = last_degree
132
+ self.maskfill_size = last_maskfill_size
133
+ self.maskfill_operator = last_maskfill_operator
134
+ self.maskfill_smooth = last_maskfill_smooth
135
+ self.maskfill_verbose = last_maskfill_verbose
108
136
  self.xmin = xmin
109
137
  self.xmax = xmax
110
138
  self.ymin = ymin
@@ -129,38 +157,48 @@ class InterpolationEditor:
129
157
  bold_font = default_font.copy()
130
158
  bold_font.configure(weight="bold", size=default_font.cget("size") + 2)
131
159
  subtitle_label = tk.Label(main_frame, text="Select Cleaning Method", font=bold_font)
132
- subtitle_label.grid(row=row, column=0, columnspan=3, pady=(0, 15))
160
+ subtitle_label.grid(row=row, column=0, columnspan=7, pady=(0, 15))
133
161
  row += 1
134
162
 
135
163
  # Create labels and entry fields for each cleaning method
136
164
  row = 1
165
+ column = 0
137
166
  self.cleaning_method_var = tk.StringVar(value="surface interp.")
138
- for interp_method in self.dict_interp_methods.keys():
139
- valid_method = True
167
+ for interp_method in VALID_CLEANING_METHODS.keys():
168
+ state = "normal"
140
169
  # Skip replace by L.A.Cosmic values if last dilation is not zero
141
- if interp_method == "lacosmic" and self.last_dilation != 0:
142
- valid_method = False
170
+ if interp_method == "lacosmic":
171
+ if self.last_dilation != 0:
172
+ state = "disabled"
173
+ if self.cleandata_lacosmic is None:
174
+ state = "disabled"
143
175
  # Skip auxdata method if auxdata is not available
144
176
  if interp_method == "auxdata" and self.auxdata is None:
145
- valid_method = False
146
- if valid_method:
147
- tk.Radiobutton(
148
- main_frame,
149
- text=interp_method,
150
- variable=self.cleaning_method_var,
151
- value=interp_method,
152
- command=self.action_on_method_change,
153
- ).grid(row=row, column=1, sticky="w")
177
+ state = "disabled"
178
+ tk.Radiobutton(
179
+ main_frame,
180
+ text=interp_method,
181
+ variable=self.cleaning_method_var,
182
+ value=interp_method,
183
+ command=self.action_on_method_change,
184
+ state=state,
185
+ ).grid(row=row, column=column, sticky="w", padx=5, pady=5)
186
+ column += 1
187
+ if column > 6:
188
+ column = 0
154
189
  row += 1
190
+ row += 1
155
191
 
156
192
  # Separator
157
193
  separator1 = ttk.Separator(main_frame, orient="horizontal")
158
- separator1.grid(row=row, column=0, columnspan=3, sticky="ew", pady=(10, 10))
194
+ separator1.grid(row=row, column=0, columnspan=7, sticky="ew", pady=(10, 10))
159
195
  row += 1
160
196
 
161
197
  # Subtitle for additional parameters
162
- subtitle_label = tk.Label(main_frame, text="Additional Parameters", font=bold_font)
163
- subtitle_label.grid(row=row, column=0, columnspan=3, pady=(0, 15))
198
+ subtitle_label1 = tk.Label(main_frame, text="Fitting Parameters", font=bold_font)
199
+ subtitle_label1.grid(row=row, column=0, columnspan=3, pady=(0, 15))
200
+ subtitle_label2 = tk.Label(main_frame, text="Maskfill Parameters", font=bold_font)
201
+ subtitle_label2.grid(row=row, column=3, columnspan=3, pady=(0, 15))
164
202
  row += 1
165
203
 
166
204
  # Create labels and entry fields for each additional parameter
@@ -175,27 +213,61 @@ class InterpolationEditor:
175
213
  self.entry_degree = tk.Entry(main_frame, width=10)
176
214
  self.entry_degree.insert(0, self.degree)
177
215
  self.entry_degree.grid(row=row, column=1, sticky="w")
216
+ row -= 1
217
+ label = tk.Label(main_frame, text="Size:")
218
+ label.grid(row=row, column=3, sticky="e", padx=(0, 10))
219
+ self.entry_maskfill_size = tk.Entry(main_frame, width=10)
220
+ self.entry_maskfill_size.insert(0, self.maskfill_size)
221
+ self.entry_maskfill_size.grid(row=row, column=4, sticky="w")
222
+ label = tk.Label(main_frame, text="Operator:")
223
+ label.grid(row=row, column=5, sticky="e", padx=(0, 10))
224
+ self.entry_maskfill_operator = ttk.Combobox(
225
+ main_frame, width=10, values=MASKFILL_OPERATOR_VALUES, state="readonly"
226
+ )
227
+ self.entry_maskfill_operator.set(self.maskfill_operator)
228
+ # self.entry_maskfill_operator = tk.Entry(main_frame, width=10)
229
+ # self.entry_maskfill_operator.insert(0, self.maskfill_operator)
230
+ self.entry_maskfill_operator.grid(row=row, column=6, sticky="w")
231
+ row += 1
232
+ label = tk.Label(main_frame, text="Smooth:")
233
+ label.grid(row=row, column=3, sticky="e", padx=(0, 10))
234
+ self.entry_maskfill_smooth = tk.Entry(main_frame, width=10)
235
+ self.entry_maskfill_smooth.insert(0, str(self.maskfill_smooth))
236
+ self.entry_maskfill_smooth.grid(row=row, column=4, sticky="w")
237
+ label = tk.Label(main_frame, text="Verbose:")
238
+ label.grid(row=row, column=5, sticky="e", padx=(0, 10))
239
+ self.entry_maskfill_verbose = tk.Entry(main_frame, width=10)
240
+ self.entry_maskfill_verbose.insert(0, str(self.maskfill_verbose))
241
+ self.entry_maskfill_verbose.grid(row=row, column=6, sticky="w")
178
242
  row += 1
179
243
 
244
+ # Vertical separator
245
+ separatorv1 = ttk.Separator(main_frame, orient="vertical")
246
+ separatorv1.grid(row=row - 3, column=2, rowspan=3, sticky="ns", padx=5)
247
+
180
248
  # Separator
181
249
  separator2 = ttk.Separator(main_frame, orient="horizontal")
182
- separator2.grid(row=row, column=0, columnspan=3, sticky="ew", pady=(10, 10))
250
+ separator2.grid(row=row, column=0, columnspan=7, sticky="ew", pady=(10, 10))
183
251
  row += 1
184
252
 
185
253
  # Subtitle for region to be examined
186
254
  subtitle_label = tk.Label(main_frame, text="Region to be Examined", font=bold_font)
187
- subtitle_label.grid(row=row, column=0, columnspan=3, pady=(0, 15))
255
+ subtitle_label.grid(row=row, column=0, columnspan=7, pady=(0, 15))
188
256
  row += 1
189
257
 
190
258
  # Region to be examined label and entries
191
259
  for key in ["xmin", "xmax", "ymin", "ymax"]:
192
260
  # Parameter name label
193
- label = tk.Label(main_frame, text=f"{key}:", anchor="e", width=15)
194
- label.grid(row=row, column=0, sticky="w", pady=5)
261
+ label = tk.Label(main_frame, text=f"{key}:", anchor="e")
262
+ if key in ["xmin", "xmax"]:
263
+ coloff = 0
264
+ else:
265
+ coloff = 4
266
+ label.grid(row=row, column=coloff, sticky="e", pady=5)
195
267
  # Entry field
196
268
  entry = tk.Entry(main_frame, width=10)
197
269
  entry.insert(0, str(self.__dict__[key]))
198
- entry.grid(row=row, column=1, padx=10, pady=5)
270
+ entry.grid(row=row, column=coloff + 1, padx=10, pady=5)
199
271
  self.entries[key] = entry # dictionary to hold entry widgets
200
272
  # Type label
201
273
  dumtext = "(int)"
@@ -204,32 +276,42 @@ class InterpolationEditor:
204
276
  else:
205
277
  dumtext += f" --> [1, {self.imgshape[0]}]"
206
278
  type_label = tk.Label(main_frame, text=dumtext, fg="gray", anchor="w", width=15)
207
- type_label.grid(row=row, column=2, sticky="w", pady=5)
208
- row += 1
279
+ type_label.grid(row=row, column=coloff + 2, sticky="w", pady=5)
280
+ if key == "xmax":
281
+ row -= 1
282
+ else:
283
+ row += 1
284
+
285
+ # Vertical separator
286
+ separatorv2 = ttk.Separator(main_frame, orient="vertical")
287
+ separatorv2.grid(row=row - 2, column=3, rowspan=2, sticky="ns", padx=5)
209
288
 
210
289
  # Separator
211
290
  separator3 = ttk.Separator(main_frame, orient="horizontal")
212
- separator3.grid(row=row, column=0, columnspan=3, sticky="ew", pady=(10, 10))
291
+ separator3.grid(row=row, column=0, columnspan=7, sticky="ew", pady=(10, 10))
213
292
  row += 1
214
293
 
215
294
  # Button frame
216
295
  self.button_frame = tk.Frame(main_frame)
217
- self.button_frame.grid(row=row, column=0, columnspan=3, pady=(15, 0))
296
+ self.button_frame.grid(row=row, column=0, columnspan=7, pady=(5, 0))
218
297
 
219
298
  # OK button
220
- self.ok_button = tk.Button(self.button_frame, text="OK", width=5, command=self.on_ok)
299
+ self.ok_button = ttk.Button(self.button_frame, text="OK", command=self.on_ok)
221
300
  self.ok_button.pack(side="left", padx=5)
222
301
 
223
302
  # Cancel button
224
- self.cancel_button = tk.Button(self.button_frame, text="Cancel", width=5, command=self.on_cancel)
303
+ self.cancel_button = ttk.Button(self.button_frame, text="Cancel", command=self.on_cancel)
225
304
  self.cancel_button.pack(side="left", padx=5)
226
305
 
306
+ # Initial focus on OK button
307
+ self.ok_button.focus_set()
308
+
227
309
  # Initial action depending on the default method
228
310
  self.action_on_method_change()
229
311
 
230
312
  def on_ok(self):
231
313
  """Handle the OK button click event."""
232
- self.cleaning_method = self.dict_interp_methods[self.cleaning_method_var.get()]
314
+ self.cleaning_method = VALID_CLEANING_METHODS[self.cleaning_method_var.get()]
233
315
  try:
234
316
  self.npoints = int(self.entry_npoints.get())
235
317
  except ValueError:
@@ -252,6 +334,44 @@ class InterpolationEditor:
252
334
  messagebox.showerror("Input Error", "2*Npoints must be greater than Degree for x and y interpolation.")
253
335
  return
254
336
 
337
+ try:
338
+ self.maskfill_size = int(self.entry_maskfill_size.get())
339
+ except ValueError:
340
+ messagebox.showerror("Input Error", "Maskfill size must be an integer.")
341
+ return
342
+ if self.maskfill_size < 1:
343
+ messagebox.showerror("Input Error", "Maskfill size must be at least 1.")
344
+ return
345
+ if self.maskfill_size % 2 == 0:
346
+ messagebox.showerror("Input Error", "Maskfill size must be an odd integer.")
347
+ return
348
+
349
+ self.maskfill_operator = self.entry_maskfill_operator.get().strip()
350
+ if not self.maskfill_operator:
351
+ messagebox.showerror("Input Error", "Maskfill operator cannot be empty.")
352
+ return
353
+ if self.maskfill_operator not in ["median", "mean"]:
354
+ messagebox.showerror("Input Error", "Maskfill operator must be 'median' or 'mean'.")
355
+ return
356
+
357
+ smooth_str = self.entry_maskfill_smooth.get().strip().lower()
358
+ if smooth_str == "true":
359
+ self.maskfill_smooth = True
360
+ elif smooth_str == "false":
361
+ self.maskfill_smooth = False
362
+ else:
363
+ messagebox.showerror("Input Error", "Maskfill smooth must be True or False.")
364
+ return
365
+
366
+ verbose_str = self.entry_maskfill_verbose.get().strip().lower()
367
+ if verbose_str == "true":
368
+ self.maskfill_verbose = True
369
+ elif verbose_str == "false":
370
+ self.maskfill_verbose = False
371
+ else:
372
+ messagebox.showerror("Input Error", "Maskfill verbose must be True or False.")
373
+ return
374
+
255
375
  # Retrieve and validate region parameters
256
376
  try:
257
377
  xmin = int(self.entries["xmin"].get())
@@ -307,27 +427,51 @@ class InterpolationEditor:
307
427
  if selected_method in ["x interp.", "y interp."]:
308
428
  self.entry_npoints.config(state="normal")
309
429
  self.entry_degree.config(state="normal")
430
+ self.entry_maskfill_size.config(state="disabled")
431
+ self.entry_maskfill_operator.config(state="disabled")
432
+ self.entry_maskfill_smooth.config(state="disabled")
433
+ self.entry_maskfill_verbose.config(state="disabled")
310
434
  elif selected_method == "surface interp.":
311
435
  self.entry_npoints.config(state="normal")
312
436
  self.entry_degree.config(state="disabled")
437
+ self.entry_maskfill_size.config(state="disabled")
438
+ self.entry_maskfill_operator.config(state="disabled")
439
+ self.entry_maskfill_smooth.config(state="disabled")
440
+ self.entry_maskfill_verbose.config(state="disabled")
313
441
  elif selected_method == "median":
314
442
  self.entry_npoints.config(state="normal")
315
443
  self.entry_degree.config(state="disabled")
444
+ self.entry_maskfill_size.config(state="disabled")
445
+ self.entry_maskfill_operator.config(state="disabled")
446
+ self.entry_maskfill_smooth.config(state="disabled")
447
+ self.entry_maskfill_verbose.config(state="disabled")
316
448
  elif selected_method == "mean":
317
449
  self.entry_npoints.config(state="normal")
318
450
  self.entry_degree.config(state="disabled")
451
+ self.entry_maskfill_size.config(state="disabled")
452
+ self.entry_maskfill_operator.config(state="disabled")
453
+ self.entry_maskfill_smooth.config(state="disabled")
454
+ self.entry_maskfill_verbose.config(state="disabled")
319
455
  elif selected_method == "lacosmic":
320
456
  self.entry_npoints.config(state="disabled")
321
457
  self.entry_degree.config(state="disabled")
458
+ self.entry_maskfill_size.config(state="disabled")
459
+ self.entry_maskfill_operator.config(state="disabled")
460
+ self.entry_maskfill_smooth.config(state="disabled")
461
+ self.entry_maskfill_verbose.config(state="disabled")
322
462
  elif selected_method == "auxdata":
323
463
  self.entry_npoints.config(state="disabled")
324
464
  self.entry_degree.config(state="disabled")
325
-
326
- def check_interp_methods(self):
327
- """Check that all interpolation methods are valid."""
328
- for method in self.dict_interp_methods.keys():
329
- if method not in VALID_CLEANING_METHODS:
330
- raise ValueError(f"Invalid interpolation method: {method}")
331
- for method in VALID_CLEANING_METHODS:
332
- if method not in self.dict_interp_methods.keys():
333
- raise ValueError(f"Interpolation method not mapped: {method}")
465
+ self.entry_maskfill_size.config(state="disabled")
466
+ self.entry_maskfill_operator.config(state="disabled")
467
+ self.entry_maskfill_smooth.config(state="disabled")
468
+ self.entry_maskfill_verbose.config(state="disabled")
469
+ elif selected_method == "maskfill":
470
+ self.entry_npoints.config(state="disabled")
471
+ self.entry_degree.config(state="disabled")
472
+ self.entry_maskfill_size.config(state="normal")
473
+ self.entry_maskfill_operator.config(state="normal")
474
+ self.entry_maskfill_smooth.config(state="normal")
475
+ self.entry_maskfill_verbose.config(state="normal")
476
+ else:
477
+ messagebox.showerror("Error", f"Unknown cleaning method selected: {selected_method}")
@@ -19,8 +19,11 @@ except ModuleNotFoundError as e:
19
19
  ) from e
20
20
  import numpy as np
21
21
 
22
+ from .definitions import VALID_LACOSMIC_PSFMODEL_VALUES
23
+ from .gausskernel2d_elliptical import gausskernel2d_elliptical
22
24
 
23
- def lacosmicpad(pad_width, **kwargs):
25
+
26
+ def lacosmicpad(pad_width, show_arguments=False, **kwargs):
24
27
  """Execute LACosmic algorithm on a padded array.
25
28
 
26
29
  This function pads the input image array before applying the LACosmic
@@ -39,6 +42,8 @@ def lacosmicpad(pad_width, **kwargs):
39
42
  pad_width : int
40
43
  Width of the padding to be applied to the image before executing
41
44
  the LACosmic algorithm.
45
+ show_arguments : bool
46
+ If True, display LACosmic arguments being employed.
42
47
  **kwargs : dict
43
48
  Keyword arguments to be passed to the `cosmicray_lacosmic` function.
44
49
 
@@ -49,6 +54,7 @@ def lacosmicpad(pad_width, **kwargs):
49
54
  mask_array : 2D numpy.ndarray of bool
50
55
  The mask array indicating detected cosmic rays.
51
56
  """
57
+ # Check for required 'ccd' argument
52
58
  if "ccd" not in kwargs:
53
59
  raise ValueError("The 'ccd' keyword argument must be provided.")
54
60
  array = kwargs.pop("ccd")
@@ -56,6 +62,91 @@ def lacosmicpad(pad_width, **kwargs):
56
62
  raise TypeError("The 'ccd' keyword argument must be a numpy ndarray.")
57
63
  # Pad the array
58
64
  padded_array = np.pad(array, pad_width, mode="reflect")
65
+
66
+ # Pad inbkg if provided
67
+ if "inbkg" in kwargs:
68
+ if kwargs["inbkg"] is not None:
69
+ inbkg = kwargs["inbkg"]
70
+ if not isinstance(inbkg, np.ndarray):
71
+ raise TypeError("The 'inbkg' keyword argument must be a numpy ndarray.")
72
+ kwargs["inbkg"] = np.pad(inbkg, pad_width, mode="reflect")
73
+ else:
74
+ kwargs["inbkg"] = None
75
+
76
+ # Pad invar if provided
77
+ if "invar" in kwargs:
78
+ if kwargs["invar"] is not None:
79
+ invar = kwargs["invar"]
80
+ if not isinstance(invar, np.ndarray):
81
+ raise TypeError("The 'invar' keyword argument must be a numpy ndarray.")
82
+ kwargs["invar"] = np.pad(invar, pad_width, mode="reflect")
83
+ else:
84
+ kwargs["invar"] = None
85
+
86
+ # check for fsmode
87
+ if "fsmode" not in kwargs:
88
+ raise ValueError("The 'fsmode' keyword argument must be provided.")
89
+ else:
90
+ fsmode = kwargs["fsmode"]
91
+ if fsmode == "convolve":
92
+ if "psfmodel" not in kwargs:
93
+ raise ValueError("The 'psfmodel' keyword argument must be provided when fsmode is 'convolve'.")
94
+ psfmodel = kwargs["psfmodel"]
95
+ if psfmodel not in VALID_LACOSMIC_PSFMODEL_VALUES:
96
+ raise ValueError(f"The 'psfmodel' keyword argument must be one of {VALID_LACOSMIC_PSFMODEL_VALUES}.")
97
+ if "psffwhm" in kwargs:
98
+ raise ValueError(
99
+ "When 'fsmode' is 'convolve', 'psffwhm' should not be provided; use 'psffwhm_x' and 'psffwhm_y' instead."
100
+ )
101
+ if "psffwhm_x" not in kwargs or "psffwhm_y" not in kwargs:
102
+ raise ValueError("When 'fsmode' is 'convolve', both 'psffwhm_x' and 'psffwhm_y' must be provided.")
103
+ fwhm_x = kwargs["psffwhm_x"]
104
+ fwhm_y = kwargs["psffwhm_y"]
105
+ if "psfsize" not in kwargs:
106
+ raise ValueError("When 'fsmode' is 'convolve', 'psfsize' must be provided.")
107
+ psfsize = kwargs["psfsize"]
108
+ if kwargs["psfmodel"] == "gaussxy":
109
+ if "psfk" in kwargs:
110
+ raise ValueError(
111
+ "When 'fsmode' is 'convolve' and 'psfmodel' is 'gaussxy', 'psfk' should not be provided; it will be generated from 'psffwhm_x' and 'psffwhm_y'."
112
+ )
113
+ kwargs["psfk"] = gausskernel2d_elliptical(fwhm_x, fwhm_y, psfsize)
114
+ if show_arguments:
115
+ print(
116
+ f"Generated elliptical Gaussian kernel with fwhm_x={fwhm_x}, fwhm_y={fwhm_y}, size={psfsize}."
117
+ )
118
+ elif kwargs["psfmodel"] in ["gauss", "moffat"]:
119
+ kwargs["psffwhm"] = (fwhm_x + fwhm_y) / 2.0 # average for circular psf
120
+ if show_arguments:
121
+ print(f"Set psffwhm to average of fwhm_x and fwhm_y: {kwargs['psffwhm']}.")
122
+ elif kwargs["psfmodel"] == "gaussx":
123
+ kwargs["psffwhm"] = fwhm_x
124
+ if show_arguments:
125
+ print(f"Set psffwhm to fwhm_x: {fwhm_x}.")
126
+ elif kwargs["psfmodel"] == "gaussy":
127
+ kwargs["psffwhm"] = fwhm_y
128
+ if show_arguments:
129
+ print(f"Set psffwhm to fwhm_y: {fwhm_y}.")
130
+ else:
131
+ raise ValueError(f"Unsupported psfmodel: {kwargs['psfmodel']}")
132
+ if show_arguments:
133
+ print("Deleting 'psffwhm_x' and 'psffwhm_y' from kwargs.")
134
+ del kwargs["psffwhm_x"]
135
+ del kwargs["psffwhm_y"]
136
+ elif fsmode == "median":
137
+ # Remove unnecessary parameters for median fsmode
138
+ for param in ["psfmodel", "psfsize", "psffwhm", "psffwhm_x", "psffwhm_y"]:
139
+ if param in kwargs:
140
+ if show_arguments:
141
+ print(f"Removing '{param}' argument since fsmode is 'median'.")
142
+ del kwargs[param]
143
+ else:
144
+ raise ValueError("The 'fsmode' keyword argument must be either 'convolve' or 'median'.")
145
+
146
+ # Show LACosmic arguments if requested
147
+ if show_arguments:
148
+ for key, value in kwargs.items():
149
+ print(f"LACosmic parameter: {key} = {value}")
59
150
  # Apply LACosmic algorithm to the padded array
60
151
  cleaned_padded_array, mask_padded_array = cosmicray_lacosmic(ccd=padded_array, **kwargs)
61
152
  # Remove padding