LSST Applications g02d81e74bb+86cf3d8bc9,g180d380827+7a4e862ed4,g2079a07aa2+86d27d4dc4,g2305ad1205+e1ca1c66fa,g29320951ab+012e1474a1,g295015adf3+341ea1ce94,g2bbee38e9b+0e5473021a,g337abbeb29+0e5473021a,g33d1c0ed96+0e5473021a,g3a166c0a6a+0e5473021a,g3ddfee87b4+c429d67c83,g48712c4677+f88676dd22,g487adcacf7+27e1e21933,g50ff169b8f+96c6868917,g52b1c1532d+585e252eca,g591dd9f2cf+b41db86c35,g5a732f18d5+53520f316c,g64a986408d+86cf3d8bc9,g858d7b2824+86cf3d8bc9,g8a8a8dda67+585e252eca,g99cad8db69+84912a7fdc,g9ddcbc5298+9a081db1e4,ga1e77700b3+15fc3df1f7,ga8c6da7877+a2b54eae19,gb0e22166c9+60f28cb32d,gba4ed39666+c2a2e4ac27,gbb8dafda3b+6681f309db,gc120e1dc64+f0fcc2f6d8,gc28159a63d+0e5473021a,gcf0d15dbbd+c429d67c83,gdaeeff99f8+f9a426f77a,ge6526c86ff+0433e6603d,ge79ae78c31+0e5473021a,gee10cc3b42+585e252eca,gff1a9f87cc+86cf3d8bc9,w.2024.17
LSST Data Management Base Package
Loading...
Searching...
No Matches
Public Member Functions | Public Attributes | Protected Member Functions | List of all members
lsst.jointcal.check_logged_chi2.LogParser Class Reference

Public Member Functions

 __init__ (self, plot=True, verbose=True)
 
 __call__ (self, logfile)
 

Public Attributes

 matcher
 
 plot
 
 verbose
 
 fig
 
 section_start
 
 section_end
 

Protected Member Functions

 _find_chi2_increase (self, chi2Data, title, label, threshold=1)
 
 _extract_chi2 (self, opened_log, section)
 
 _plot (self, astrometry, photometry, title)
 
 _plot_axes (self, ax0, ax1, chi2Data, palette, label="")
 

Detailed Description

Parse a jointcal logfile to extract chi2 values and plot them.

Call the instance with the path to a file to check it for anamolous chi2
and output plots to your current directory.

Parameters
----------
plot : `bool`
    Make plots for each file (saved to the current working directory)?
verbose : `bool`
    Print extra updates during processing?

Definition at line 76 of file check_logged_chi2.py.

Constructor & Destructor Documentation

◆ __init__()

lsst.jointcal.check_logged_chi2.LogParser.__init__ ( self,
plot = True,
verbose = True )

Definition at line 89 of file check_logged_chi2.py.

89 def __init__(self, plot=True, verbose=True):
90 # This regular expression extracts the chi2 values, and the "kind" of
91 # chi2 (e.g. "Initial", "Fit iteration").
92 # Chi2 values in the log look like this, for example:
93 # jointcal INFO: Initial chi2/ndof : 2.50373e+16/532674=4.7003e+10
94 chi2_re = "jointcal INFO: (?P<kind>.+) chi2/ndof : (?P<chi2>.+)/(?P<ndof>.+)=(?P<reduced_chi2>.+)"
95 self.matcher = re.compile(chi2_re)
96 self.plot = plot
97 self.verbose = verbose
98
99 # Reuse the Figure to speed up plotting and save memory.
100 self.fig = plt.figure(figsize=(15, 8))
101
102 # How to find the beginning and end of the relevant parts of the log
103 # to scan for chi2 values.
104 self.section_start = {"astrometry": "Starting astrometric fitting...",
105 "photometry": "Starting photometric fitting..."}
106 self.section_end = {"astrometry": "Updating WCS for visit:",
107 "photometry": "Updating PhotoCalib for visit:"}
108

Member Function Documentation

◆ __call__()

lsst.jointcal.check_logged_chi2.LogParser.__call__ ( self,
logfile )
Parse logfile to extract chi2 values and generate and save plots.

The plot output is written to the current directory, with the name
derived from the basename of ``logfile``.

Parameters
----------
logfile : `str`
    The filename of the jointcal log to process.

Definition at line 109 of file check_logged_chi2.py.

109 def __call__(self, logfile):
110 """Parse logfile to extract chi2 values and generate and save plots.
111
112 The plot output is written to the current directory, with the name
113 derived from the basename of ``logfile``.
114
115 Parameters
116 ----------
117 logfile : `str`
118 The filename of the jointcal log to process.
119 """
120 title = os.path.basename(logfile)
121 if self.verbose:
122 print("Processing:", title)
123
124 with open(logfile) as opened_log:
125 # Astrometry is always run first, so we can scan for that until the
126 # end of that section, and then continue scanning for photometry.
127 astrometry = self._extract_chi2(opened_log, "astrometry")
128 increased = self._find_chi2_increase(astrometry, title, "astrometry")
129 photometry = self._extract_chi2(opened_log, "photometry")
130 increased |= self._find_chi2_increase(photometry, title, "photometry")
131
132 if astrometry is None and photometry is None and self.verbose:
133 print(f"WARNING: No chi2 values found in {logfile}.")
134
135 if increased or self.plot:
136 self._plot(astrometry, photometry, title)
137 plotfile = f"{os.path.splitext(title)[0]}.png"
138 plt.savefig(plotfile, bbox_inches="tight")
139 print("Saved plot:", plotfile)
140

◆ _extract_chi2()

lsst.jointcal.check_logged_chi2.LogParser._extract_chi2 ( self,
opened_log,
section )
protected
Return the values extracted from the chi2 statements in the logfile.

Definition at line 158 of file check_logged_chi2.py.

158 def _extract_chi2(self, opened_log, section):
159 """Return the values extracted from the chi2 statements in the logfile.
160 """
161 start = self.section_start[section]
162 end = self.section_end[section]
163 kind = []
164 chi2 = []
165 ndof = []
166 reduced = []
167 # Skip over lines until we get to the section start line.
168 for line in opened_log:
169 if start in line:
170 break
171
172 for line in opened_log:
173 # Stop parsing at the section end line.
174 if end in line:
175 break
176 if "chi2" in line:
177 match = self.matcher.search(line)
178 if match is not None:
179 kind.append(match.group("kind"))
180 chi2.append(match.group("chi2"))
181 ndof.append(match.group("ndof"))
182 reduced.append(match.group("reduced_chi2"))
183
184 # No chi2 values were found (e.g., photometry wasn't run).
185 if len(kind) == 0:
186 return None
187
188 return Chi2Data(kind, np.array(chi2, dtype=np.float64),
189 np.array(ndof, dtype=int), np.array(reduced, dtype=np.float64))
190

◆ _find_chi2_increase()

lsst.jointcal.check_logged_chi2.LogParser._find_chi2_increase ( self,
chi2Data,
title,
label,
threshold = 1 )
protected
Return True and print a message if the raw chi2 increases
markedly.

Definition at line 141 of file check_logged_chi2.py.

141 def _find_chi2_increase(self, chi2Data, title, label, threshold=1):
142 """Return True and print a message if the raw chi2 increases
143 markedly.
144 """
145 if chi2Data is None:
146 return False
147 diff = np.diff(chi2Data.raw)
148 ratio = diff/chi2Data.raw[:-1]
149 if np.any(ratio > threshold):
150 increased = np.where(ratio > threshold)[0]
151 print(f"{title} has increasing {label} chi2:")
152 for x in zip(chi2Data.raw[increased], chi2Data.raw[increased + 1],
153 ratio[increased], diff[increased]):
154 print(f"{x[0]:.6} -> {x[1]:.6} (ratio: {x[2]:.6}, diff: {x[3]:.6})")
155 return True
156 return False
157

◆ _plot()

lsst.jointcal.check_logged_chi2.LogParser._plot ( self,
astrometry,
photometry,
title )
protected
Generate plots of chi2 values.

Parameters
----------
astrometry : `Chi2Data` or None
    The as-read astrometry data, or None if there is none to plot.
photometry : `Chi2Data` or None
    The as-read photometry data, or None if there is none to plot.
title : `str`
    Title for the whole plot.

Definition at line 191 of file check_logged_chi2.py.

191 def _plot(self, astrometry, photometry, title):
192 """Generate plots of chi2 values.
193
194 Parameters
195 ----------
196 astrometry : `Chi2Data` or None
197 The as-read astrometry data, or None if there is none to plot.
198 photometry : `Chi2Data` or None
199 The as-read photometry data, or None if there is none to plot.
200 title : `str`
201 Title for the whole plot.
202 """
203 palette = itertools.cycle(sns.color_palette())
204
205 self.fig.clf()
206 ax0, ax1 = self.fig.subplots(ncols=2, gridspec_kw={"wspace": 0.05})
207
208 self.fig.suptitle(title)
209 # Use a log scale if any of the chi2 values are very large.
210 if max(getattr(astrometry, "raw", [0])) > 100 or max(getattr(photometry, "raw", [0])) > 100:
211 ax0.set_yscale("log")
212 ax1.yaxis.set_label_position("right")
213 ax1.yaxis.tick_right()
214
215 if astrometry is not None:
216 patch1, patch2 = self._plot_axes(ax0, ax1, astrometry, palette, label="astrometry")
217
218 if photometry is not None:
219 patch3, patch4 = self._plot_axes(ax0, ax1, photometry, palette, label="photometry")
220
221 # Let matplotlib figure out the best legend location: if there is data
222 # in the "upper right", we definitely want to see it.
223 handles, labels = ax0.get_legend_handles_labels()
224 ax1.legend(handles, labels)
225
int max

◆ _plot_axes()

lsst.jointcal.check_logged_chi2.LogParser._plot_axes ( self,
ax0,
ax1,
chi2Data,
palette,
label = "" )
protected
Make the chi2 and degrees of freedom subplots.

Definition at line 226 of file check_logged_chi2.py.

226 def _plot_axes(self, ax0, ax1, chi2Data, palette, label=""):
227 """Make the chi2 and degrees of freedom subplots."""
228 xrange = np.arange(0, len(chi2Data.raw), dtype=float)
229
230 # mark chi2=1
231 ax0.axhline(1, color='grey', ls='--')
232 # mark the separation between initialization and iteration
233 ax0.axvline(chi2Data.init_count-0.5, color='grey', lw=0.9)
234 color = next(palette)
235 patch1 = ax0.plot(xrange[:chi2Data.init_count], chi2Data.raw[:chi2Data.init_count], '*', ms=10,
236 label=f"{label} pre-init", color=color)
237 patch2 = ax0.plot(xrange[chi2Data.init_count:], chi2Data.raw[chi2Data.init_count:], 'o', ms=10,
238 label=f"{label} post-init", color=color)
239 patch1 = ax0.plot(xrange[:chi2Data.init_count], chi2Data.reduced[:chi2Data.init_count], '*',
240 markerfacecolor="none", ms=10, color=color)
241 patch2 = ax0.plot(xrange[chi2Data.init_count:], chi2Data.reduced[chi2Data.init_count:], 'o',
242 markerfacecolor="none", ms=10, label=f"{label} reduced", color=color)
243
244 ax0.set_xlabel("Iteration #", fontsize=20)
245 ax0.set_ylabel(r"$\chi ^2$", fontsize=20)
246
247 # mark the separation between initialization and iteration
248 ax1.axvline(chi2Data.init_count-0.5, color='grey', lw=0.9)
249 ax1.plot(xrange[:chi2Data.init_count], chi2Data.ndof[:chi2Data.init_count], '*', ms=10,
250 label="pre-init", color=color)
251 ax1.plot(xrange[chi2Data.init_count:], chi2Data.ndof[chi2Data.init_count:], 'o', ms=10,
252 label="post-init", color=color)
253
254 ax1.set_xlabel("Iteration #", fontsize=20)
255 ax1.set_ylabel("# degrees of freedom", fontsize=20)
256
257 return patch1[0], patch2[0]
258
259

Member Data Documentation

◆ fig

lsst.jointcal.check_logged_chi2.LogParser.fig

Definition at line 100 of file check_logged_chi2.py.

◆ matcher

lsst.jointcal.check_logged_chi2.LogParser.matcher

Definition at line 95 of file check_logged_chi2.py.

◆ plot

lsst.jointcal.check_logged_chi2.LogParser.plot

Definition at line 96 of file check_logged_chi2.py.

◆ section_end

lsst.jointcal.check_logged_chi2.LogParser.section_end

Definition at line 106 of file check_logged_chi2.py.

◆ section_start

lsst.jointcal.check_logged_chi2.LogParser.section_start

Definition at line 104 of file check_logged_chi2.py.

◆ verbose

lsst.jointcal.check_logged_chi2.LogParser.verbose

Definition at line 97 of file check_logged_chi2.py.


The documentation for this class was generated from the following file: