def merge(self, d1, qmax=-1, qmin=-1, fix_scale=-1): """ combine the data in self and d1 scale d1 intensity to match self self and d1 should have the same qgrid if qmax or qmin <0 simply keep the WAXS data that is beyond qmax for the SAXS data this is useful for utilizing WAXS to normalize intensity but keep SAXS data only """ print("merging data: %s and %s ..." % (self.label, d1.label)) if not (d1.qgrid == self.qgrid).all(): print("merging data sets should have the same qgrid.") exit() # this gives the overlapping region idx = (self.data > 0) & (d1.data > 0) if len(self.qgrid[idx]) > 0: qmin0 = min(d1.qgrid[idx]) qmax0 = max(self.qgrid[idx]) # merge SAXS/WAXS based on intensity in the overlapping region if qmax0 < qmax: qmax = qmax0 if qmin0 > qmin: qmin = qmin0 idx = (self.qgrid > qmin) & (self.qgrid < qmax) # save the raw data in case needed, e.g. for ploting self.overlaps.append({'q_overlap': self.qgrid[idx], 'raw_data1': self.data[idx], 'raw_data2': d1.data[idx]}) else: # no overlap # simply stack WAXS data to the high q end of SAXS data qmin = qmax = max(self.qgrid[self.data > 0]) # idx = np.asarray([],dtype=int) if len(self.qgrid[idx]) < 2: print("data sets are not overlapping in the given q range.") if fix_scale < 0: fix_scale = 1 print("forcing fix_scale=1.") elif len(self.qgrid[idx]) < 10: print("too few overlapping points: %d" % len(self.qgrid[idx])) if fix_scale > 0: # For a given experimental configuration, the intensity normlization # factor between the SAXS and WAXS should be well-defined. This factor # can be determined using scattering data with siginificant intensity # in the overlapping q-range and applied to all data collected in the # same configuration. sc = fix_scale else: # idx = idx[1:-1] sc = np.linalg.lstsq(np.asmatrix(self.data[idx]).T, np.asmatrix(d1.data[idx]).T)[0] sc = np.trace(sc) d1.data /= sc d1.err /= sc if len(self.qgrid[idx]) > 0: self.overlaps[-1]['raw_data2'] /= sc self.label = common_name(self.label, d1.label) print("set2 scaled by 1/%f" % sc) print("merged set re-named %s." % self.label) if len(self.qgrid[idx]) > 0: self.data[idx] = (self.data[idx] + d1.data[idx]) / 2 # this won't work well if the merging data are mis-matched before bkg subtraction # but match well after bkg subtraction # self.err[idx] = (self.err[idx]+d1.err[idx])/2+np.fabs(self.data[idx]-d1.data[idx]) self.err[idx] = (self.err[idx] + d1.err[idx]) / 2 self.data[self.qgrid >= qmax] = d1.data[self.qgrid >= qmax] self.err[self.qgrid >= qmax] = d1.err[self.qgrid >= qmax] self.comments += "# merged with the following set by matching intensity within (%.4f, %.4f)," % (qmin, qmax) self.comments += " scaled by %f\n" % sc self.comments += d1.comments.replace("# ", "## ")
def avg(self, dsets, plot_data=False, ax=None): """ dset is a collection of Data1d ax is the Axes to plot the data in TODO: should calculate something like the cross-correlation between sets to evaluate the consistency between them """ print("averaging data with %s:" % self.label, end=' ') n = 1 if plot_data: if ax is None: plt.figure() plt.subplots_adjust(bottom=0.15) ax = plt.gca() ax.set_xlabel("$q (\AA^{-1})$", fontsize='x-large') ax.set_ylabel("$I$", fontsize='x-large') ax.set_xscale('log') ax.set_yscale('log') idx = (self.data > 0) ax.errorbar(self.qgrid[idx], self.data[idx], self.err[idx], label=self.label) for ov in self.overlaps: ax.plot(ov['q_overlap'], ov['raw_data1'], "v") ax.plot(ov['q_overlap'], ov['raw_data2'], "^") for d1 in dsets: print("%s " % d1.label, end=' ') if not (self.qgrid == d1.qgrid).all(): print("\n1D sets cannot be averaged: qgrid mismatch") exit() self.trans += d1.trans self.data += d1.data self.err += d1.err self.comments += "# averaged with \n%s" % d1.comments.replace("# ", "## ") if plot_data: idx = (d1.data > 0) # Remove Zeros on plot ax.errorbar(d1.qgrid[idx], d1.data[idx] * VOFFSET ** n, d1.err[idx] * VOFFSET ** n, label=d1.label) for ov in d1.overlaps: ax.plot(ov['q_overlap'], ov['raw_data1'] * VOFFSET ** n, "v") ax.plot(ov['q_overlap'], ov['raw_data2'] * VOFFSET ** n, "^") n += 1 self.label = common_name(self.label, d1.label) self.trans /= n self.data /= n self.err /= np.sqrt(n) print("\naveraged set re-named to %s." % self.label) if plot_data: # plot the averaged data over each individual curve for i in range(n): if i == 0: idx = (self.data > 0) # Remove Zeros on plot handles, labels = ax.get_legend_handles_labels() lbl = "averaged" if "averaged" not in labels else "" ax.plot(self.qgrid[idx], self.data[idx] * VOFFSET ** i, color="gray", lw=2, ls="--", label=lbl) else: idx = (self.data > 0) # Remove Zeros on plot ax.plot(self.qgrid[idx], self.data[idx] * VOFFSET ** i, color="gray", lw=2, ls="--") leg = ax.legend(loc='upper right', frameon=False) for t in leg.get_texts(): t.set_fontsize('small')