corems.mass_spectrum.calc.MassSpectrumCalc

  1__author__ = "Yuri E. Corilo"
  2__date__ = "Jun 27, 2019"
  3
  4from numpy import power, multiply, sqrt, array, mean
  5from corems.mass_spectrum.calc.NoiseCalc import NoiseThresholdCalc
  6from corems.mass_spectrum.calc.PeakPicking import PeakPicking
  7
  8
  9class MassSpecCalc(PeakPicking, NoiseThresholdCalc):
 10    """Class for Mass Spectrum Calculations
 11
 12    Class including numerical calculations related to mass spectrum class
 13    Inherited PeakPicking and NoiseThresholdCalc ensuring its methods are
 14    available to the instantiated mass spectrum class object
 15
 16    Parameters
 17    -------
 18    mass_spectrum : MassSpectrum
 19        CoreMS mass spectrum object
 20
 21    Attributes
 22    --------
 23    All Attributes are derivative from the MassSpecBase Class
 24
 25    Methods
 26    --------
 27    * check_mspeaks().
 28        Check if the mspeaks attribute is populated
 29    * sort_by_abundance().
 30        Sort the mspeaks by abundance
 31    * percentile_assigned(report_error=False).
 32        Calculate the percentage of assigned peaks
 33    * resolving_power_calc(B, T).
 34        Calculate the resolving power
 35    * number_average_molecular_weight(profile=False).
 36        Calculate the number average molecular weight
 37    * weight_average_molecular_weight(profile=False).
 38        Calculate the weight average molecular weight
 39    """
 40
 41    def percentage_assigned(
 42        self, report_error: bool = False, mute_output: bool = False
 43    ):
 44        """Percentage of peaks which are assigned
 45
 46        Calculates the percentage and relative abundance of assigned peaks in the spectrum.
 47        Includes protection against division by zero with explicit handling of edge cases.
 48
 49        Parameters
 50        -----------
 51        report_error: bool, optional
 52            Report the RMS error of the assigned peaks. Default is False.
 53        mute_output: bool, optional
 54            Override the verbose setting. Default is False.
 55            If True, the function will silence results
 56
 57        Returns
 58        -------
 59        tuple
 60            If report_error is False:
 61                (assigned_count, unassigned_count, total_percent, total_relative_abundance)
 62            If report_error is True:
 63                (assigned_count, unassigned_count, total_percent, total_relative_abundance, rms_error)
 64                where rms_error is None if no assigned peaks exist
 65
 66        Notes
 67        -----
 68        Edge cases are handled with explicit reporting:
 69        - If no peaks detected: returns (0, 0, 0.0, 0.0[, None]) with message
 70        - If no abundance data: returns (i, j, 0.0, 0.0[, None]) with message
 71        - If no assigned peaks but peaks exist: returns with rms_error=None and explanatory message
 72        """
 73        verbose = self.parameters.mass_spectrum.verbose_processing
 74        assign_abun = 0
 75        not_assign_abun = 0
 76        i = 0
 77        j = 0
 78        if report_error:
 79            error = []
 80        for mspeak in self.sort_by_abundance():
 81            if mspeak.is_assigned:
 82                i += 1
 83                assign_abun += mspeak.abundance
 84                if report_error:
 85                    error.append(mspeak.best_molecular_formula_candidate.mz_error)
 86
 87            else:
 88                j += 1
 89                not_assign_abun += mspeak.abundance
 90
 91        # Protect against division by zero
 92        total_peaks = i + j
 93        total_abundance = assign_abun + not_assign_abun
 94
 95        # Handle edge cases
 96        if total_peaks == 0:
 97            if verbose and not mute_output:
 98                print("No peaks detected in spectrum")
 99            if report_error:
100                return i, j, 0.0, 0.0, None
101            else:
102                return i, j, 0.0, 0.0
103
104        if total_abundance == 0:
105            if verbose and not mute_output:
106                print("No abundance data detected in spectrum")
107            if report_error:
108                return i, j, 0.0, 0.0, None
109            else:
110                return i, j, 0.0, 0.0
111
112        total_percent = (i / total_peaks * 100) if total_peaks > 0 else 0.0
113        total_relative_abundance = (
114            (assign_abun / total_abundance * 100) if total_abundance > 0 else 0.0
115        )
116
117        if report_error:
118            rms_error = None
119            if i > 0:
120                rms_error = sqrt(mean(array(error) ** 2))
121            if verbose and not mute_output:
122                if i == 0:
123                    print(
124                        "No assigned peaks detected - cannot calculate RMS error. %i unassigned peaks, total = %.2f %%, relative abundance = %.2f %%"
125                        % (j, total_percent, total_relative_abundance)
126                    )
127                else:
128                    print(
129                        "%i assigned peaks and %i unassigned peaks, total  = %.2f %%, relative abundance = %.2f %%, RMS error (best candidate) (ppm) = %.3f"
130                        % (i, j, total_percent, total_relative_abundance, rms_error)
131                    )
132            return i, j, total_percent, total_relative_abundance, rms_error
133
134        else:
135            if verbose and not mute_output:
136                print(
137                    "%i assigned peaks and %i unassigned peaks , total  = %.2f %%, relative abundance = %.2f %%"
138                    % (
139                        i,
140                        j,
141                        total_percent,
142                        total_relative_abundance,
143                    )
144                )
145            return i, j, total_percent, total_relative_abundance
146
147    def percentile_assigned(
148        self, report_error: bool = False, mute_output: bool = False
149    ):
150        """Deprecated: Use percentage_assigned() instead.
151
152        This method is deprecated and will be removed in a future version.
153        The function returns a percentage, not a percentile, so the name has been corrected.
154
155        Parameters
156        -----------
157        report_error: bool, optional
158            Report the error of the assigned peaks. Default is False.
159        mute_output: bool, optional
160            Override the verbose setting. Default is False.
161
162        Returns
163        -------
164        tuple
165            Refer to percentage_assigned() for return value details.
166        """
167        import warnings
168
169        warnings.warn(
170            "percentile_assigned() is deprecated and will be removed in a future version. "
171            "Use percentage_assigned() instead, as the function returns a percentage, not a percentile.",
172            DeprecationWarning,
173            stacklevel=2,
174        )
175        return self.percentage_assigned(
176            report_error=report_error, mute_output=mute_output
177        )
178
179    def resolving_power_calc(self, B: float, T: float):
180        """Calculate the theoretical resolving power
181
182        Calls on the MSPeak object function to calculate the resolving power of a peak, this calcs for all peaks in a spectrum.
183
184        Parameters
185        -----------
186        T : float
187            transient time
188        B : float
189            Magnetic Filed Strength (Tesla)
190
191        References
192        ----------
193        1. Marshall et al. (Mass Spectrom Rev. 1998 Jan-Feb;17(1):1-35.)
194                DOI: 10.1002/(SICI)1098-2787(1998)17:1<1::AID-MAS1>3.0.CO;2-K
195
196        """
197
198        self.check_mspeaks()
199        return array([mspeak.resolving_power_calc(B, T) for mspeak in self.mspeaks])
200
201    def _f_to_mz(self):
202        """Ledford equation for converting frequency(Hz) to m/z
203
204        Returns
205        ----------
206        mz_domain : numpy array
207            m/z domain after conversion from frequency
208        """
209        Aterm, Bterm, Cterm = self.Aterm, self.Bterm, self.Cterm
210        # Check if the Bterm of Ledford equation scales with the ICR trap voltage or not then Bterm = Bterm*trap_voltage
211
212        if Cterm == 0:
213            if Bterm == 0:
214                # uncalibrated data
215                mz_domain = Aterm / self.freq_exp_profile
216
217            else:
218                mz_domain = (Aterm / (self.freq_exp_profile)) + (
219                    Bterm / power((self.freq_exp_profile), 2)
220                )
221
222        # @will I need you insight here, not sure what is the inverted ledford equation that Bruker refers to
223        else:
224            mz_domain = (
225                (Aterm / self.freq_exp_profile)
226                + (Bterm / power(self.freq_exp_profile, 2))
227                + Cterm
228            )
229
230        return mz_domain
231
232    def _f_to_mz_bruker(self):
233        """Frequency to m/z conversion (Bruker)
234        Bruker equations for converting frequency (Hz) to m/z,
235        nOmega acquisition is not yet implemented here.
236        However, nOmega should work for commerical Bruker 2xR systems as A Term is automatically defined for 2X or 1X by the instrument
237
238
239        Returns
240        ----------
241        numpy.array(float)
242            m/z domain after conversion from frequency
243        """
244        Aterm, Bterm, Cterm = self.Aterm, self.Bterm, self.Cterm
245        # Check if the Bterm of Ledford equation scales with the ICR trap voltage or not then Bterm = Bterm*trap_voltage
246        if Cterm == 0:
247            if Bterm == 0:
248                # uncalibrated data
249                return Aterm / self.freq_exp_profile
250
251            else:
252                # calc2
253                return Aterm / (self.freq_exp_profile + Bterm)
254
255        # @will I need you insight here, not sure what is the inverted ledford equation that Bruker refers to
256        else:
257            diff = Aterm * Aterm
258
259            # this sign(diff + 4) changes on older aquistion software
260            diff = diff + 4 * Cterm * (self.freq_exp_profile - Bterm)
261            diff = sqrt(diff)
262            diff = -Aterm + diff
263            # calc3
264            return (2 * Cterm) / diff
265            return diff / 2 * (self.freq_exp_profile - Bterm)
266
267    def number_average_molecular_weight(self, profile: bool = False):
268        """Average molecular weight calculation
269
270        Parameters
271        ----------
272        profile : bool, optional
273            is data profile or centroid mode. The default is False (e.g. Centroid data)
274
275        Returns
276        -------
277        float
278            The average molecular weight.
279
280        """
281        # mode is profile or centroid data
282        if profile:
283            a = multiply(self.mz_exp_profile, self.abundance_profile)
284            b = self.abundance_profile
285            return a.sum() / b.sum()
286
287        else:
288            return sum(self.mz_exp * self.abundance) / sum(self.abundance)
289
290    def weight_average_molecular_weight(self, profile: bool = False):
291        """
292        Weighted Average molecular weight calculation
293
294
295        Returns
296        -------
297        float
298            The weight average molecular weight.
299
300        """
301
302        # implement from MassSpectralPeaks objs
303
304        if profile:
305            a = multiply(power(self.mz_exp_profile, 2), self.abundance_profile)
306            b = self.mz_exp_profile * self.abundance_profile
307            return a.sum() / b.sum()
308
309        else:
310            return sum(power(self.mz_exp, 2) * self.abundance) / sum(
311                self.mz_exp * self.abundance
312            )
 10class MassSpecCalc(PeakPicking, NoiseThresholdCalc):
 11    """Class for Mass Spectrum Calculations
 12
 13    Class including numerical calculations related to mass spectrum class
 14    Inherited PeakPicking and NoiseThresholdCalc ensuring its methods are
 15    available to the instantiated mass spectrum class object
 16
 17    Parameters
 18    -------
 19    mass_spectrum : MassSpectrum
 20        CoreMS mass spectrum object
 21
 22    Attributes
 23    --------
 24    All Attributes are derivative from the MassSpecBase Class
 25
 26    Methods
 27    --------
 28    * check_mspeaks().
 29        Check if the mspeaks attribute is populated
 30    * sort_by_abundance().
 31        Sort the mspeaks by abundance
 32    * percentile_assigned(report_error=False).
 33        Calculate the percentage of assigned peaks
 34    * resolving_power_calc(B, T).
 35        Calculate the resolving power
 36    * number_average_molecular_weight(profile=False).
 37        Calculate the number average molecular weight
 38    * weight_average_molecular_weight(profile=False).
 39        Calculate the weight average molecular weight
 40    """
 41
 42    def percentage_assigned(
 43        self, report_error: bool = False, mute_output: bool = False
 44    ):
 45        """Percentage of peaks which are assigned
 46
 47        Calculates the percentage and relative abundance of assigned peaks in the spectrum.
 48        Includes protection against division by zero with explicit handling of edge cases.
 49
 50        Parameters
 51        -----------
 52        report_error: bool, optional
 53            Report the RMS error of the assigned peaks. Default is False.
 54        mute_output: bool, optional
 55            Override the verbose setting. Default is False.
 56            If True, the function will silence results
 57
 58        Returns
 59        -------
 60        tuple
 61            If report_error is False:
 62                (assigned_count, unassigned_count, total_percent, total_relative_abundance)
 63            If report_error is True:
 64                (assigned_count, unassigned_count, total_percent, total_relative_abundance, rms_error)
 65                where rms_error is None if no assigned peaks exist
 66
 67        Notes
 68        -----
 69        Edge cases are handled with explicit reporting:
 70        - If no peaks detected: returns (0, 0, 0.0, 0.0[, None]) with message
 71        - If no abundance data: returns (i, j, 0.0, 0.0[, None]) with message
 72        - If no assigned peaks but peaks exist: returns with rms_error=None and explanatory message
 73        """
 74        verbose = self.parameters.mass_spectrum.verbose_processing
 75        assign_abun = 0
 76        not_assign_abun = 0
 77        i = 0
 78        j = 0
 79        if report_error:
 80            error = []
 81        for mspeak in self.sort_by_abundance():
 82            if mspeak.is_assigned:
 83                i += 1
 84                assign_abun += mspeak.abundance
 85                if report_error:
 86                    error.append(mspeak.best_molecular_formula_candidate.mz_error)
 87
 88            else:
 89                j += 1
 90                not_assign_abun += mspeak.abundance
 91
 92        # Protect against division by zero
 93        total_peaks = i + j
 94        total_abundance = assign_abun + not_assign_abun
 95
 96        # Handle edge cases
 97        if total_peaks == 0:
 98            if verbose and not mute_output:
 99                print("No peaks detected in spectrum")
100            if report_error:
101                return i, j, 0.0, 0.0, None
102            else:
103                return i, j, 0.0, 0.0
104
105        if total_abundance == 0:
106            if verbose and not mute_output:
107                print("No abundance data detected in spectrum")
108            if report_error:
109                return i, j, 0.0, 0.0, None
110            else:
111                return i, j, 0.0, 0.0
112
113        total_percent = (i / total_peaks * 100) if total_peaks > 0 else 0.0
114        total_relative_abundance = (
115            (assign_abun / total_abundance * 100) if total_abundance > 0 else 0.0
116        )
117
118        if report_error:
119            rms_error = None
120            if i > 0:
121                rms_error = sqrt(mean(array(error) ** 2))
122            if verbose and not mute_output:
123                if i == 0:
124                    print(
125                        "No assigned peaks detected - cannot calculate RMS error. %i unassigned peaks, total = %.2f %%, relative abundance = %.2f %%"
126                        % (j, total_percent, total_relative_abundance)
127                    )
128                else:
129                    print(
130                        "%i assigned peaks and %i unassigned peaks, total  = %.2f %%, relative abundance = %.2f %%, RMS error (best candidate) (ppm) = %.3f"
131                        % (i, j, total_percent, total_relative_abundance, rms_error)
132                    )
133            return i, j, total_percent, total_relative_abundance, rms_error
134
135        else:
136            if verbose and not mute_output:
137                print(
138                    "%i assigned peaks and %i unassigned peaks , total  = %.2f %%, relative abundance = %.2f %%"
139                    % (
140                        i,
141                        j,
142                        total_percent,
143                        total_relative_abundance,
144                    )
145                )
146            return i, j, total_percent, total_relative_abundance
147
148    def percentile_assigned(
149        self, report_error: bool = False, mute_output: bool = False
150    ):
151        """Deprecated: Use percentage_assigned() instead.
152
153        This method is deprecated and will be removed in a future version.
154        The function returns a percentage, not a percentile, so the name has been corrected.
155
156        Parameters
157        -----------
158        report_error: bool, optional
159            Report the error of the assigned peaks. Default is False.
160        mute_output: bool, optional
161            Override the verbose setting. Default is False.
162
163        Returns
164        -------
165        tuple
166            Refer to percentage_assigned() for return value details.
167        """
168        import warnings
169
170        warnings.warn(
171            "percentile_assigned() is deprecated and will be removed in a future version. "
172            "Use percentage_assigned() instead, as the function returns a percentage, not a percentile.",
173            DeprecationWarning,
174            stacklevel=2,
175        )
176        return self.percentage_assigned(
177            report_error=report_error, mute_output=mute_output
178        )
179
180    def resolving_power_calc(self, B: float, T: float):
181        """Calculate the theoretical resolving power
182
183        Calls on the MSPeak object function to calculate the resolving power of a peak, this calcs for all peaks in a spectrum.
184
185        Parameters
186        -----------
187        T : float
188            transient time
189        B : float
190            Magnetic Filed Strength (Tesla)
191
192        References
193        ----------
194        1. Marshall et al. (Mass Spectrom Rev. 1998 Jan-Feb;17(1):1-35.)
195                DOI: 10.1002/(SICI)1098-2787(1998)17:1<1::AID-MAS1>3.0.CO;2-K
196
197        """
198
199        self.check_mspeaks()
200        return array([mspeak.resolving_power_calc(B, T) for mspeak in self.mspeaks])
201
202    def _f_to_mz(self):
203        """Ledford equation for converting frequency(Hz) to m/z
204
205        Returns
206        ----------
207        mz_domain : numpy array
208            m/z domain after conversion from frequency
209        """
210        Aterm, Bterm, Cterm = self.Aterm, self.Bterm, self.Cterm
211        # Check if the Bterm of Ledford equation scales with the ICR trap voltage or not then Bterm = Bterm*trap_voltage
212
213        if Cterm == 0:
214            if Bterm == 0:
215                # uncalibrated data
216                mz_domain = Aterm / self.freq_exp_profile
217
218            else:
219                mz_domain = (Aterm / (self.freq_exp_profile)) + (
220                    Bterm / power((self.freq_exp_profile), 2)
221                )
222
223        # @will I need you insight here, not sure what is the inverted ledford equation that Bruker refers to
224        else:
225            mz_domain = (
226                (Aterm / self.freq_exp_profile)
227                + (Bterm / power(self.freq_exp_profile, 2))
228                + Cterm
229            )
230
231        return mz_domain
232
233    def _f_to_mz_bruker(self):
234        """Frequency to m/z conversion (Bruker)
235        Bruker equations for converting frequency (Hz) to m/z,
236        nOmega acquisition is not yet implemented here.
237        However, nOmega should work for commerical Bruker 2xR systems as A Term is automatically defined for 2X or 1X by the instrument
238
239
240        Returns
241        ----------
242        numpy.array(float)
243            m/z domain after conversion from frequency
244        """
245        Aterm, Bterm, Cterm = self.Aterm, self.Bterm, self.Cterm
246        # Check if the Bterm of Ledford equation scales with the ICR trap voltage or not then Bterm = Bterm*trap_voltage
247        if Cterm == 0:
248            if Bterm == 0:
249                # uncalibrated data
250                return Aterm / self.freq_exp_profile
251
252            else:
253                # calc2
254                return Aterm / (self.freq_exp_profile + Bterm)
255
256        # @will I need you insight here, not sure what is the inverted ledford equation that Bruker refers to
257        else:
258            diff = Aterm * Aterm
259
260            # this sign(diff + 4) changes on older aquistion software
261            diff = diff + 4 * Cterm * (self.freq_exp_profile - Bterm)
262            diff = sqrt(diff)
263            diff = -Aterm + diff
264            # calc3
265            return (2 * Cterm) / diff
266            return diff / 2 * (self.freq_exp_profile - Bterm)
267
268    def number_average_molecular_weight(self, profile: bool = False):
269        """Average molecular weight calculation
270
271        Parameters
272        ----------
273        profile : bool, optional
274            is data profile or centroid mode. The default is False (e.g. Centroid data)
275
276        Returns
277        -------
278        float
279            The average molecular weight.
280
281        """
282        # mode is profile or centroid data
283        if profile:
284            a = multiply(self.mz_exp_profile, self.abundance_profile)
285            b = self.abundance_profile
286            return a.sum() / b.sum()
287
288        else:
289            return sum(self.mz_exp * self.abundance) / sum(self.abundance)
290
291    def weight_average_molecular_weight(self, profile: bool = False):
292        """
293        Weighted Average molecular weight calculation
294
295
296        Returns
297        -------
298        float
299            The weight average molecular weight.
300
301        """
302
303        # implement from MassSpectralPeaks objs
304
305        if profile:
306            a = multiply(power(self.mz_exp_profile, 2), self.abundance_profile)
307            b = self.mz_exp_profile * self.abundance_profile
308            return a.sum() / b.sum()
309
310        else:
311            return sum(power(self.mz_exp, 2) * self.abundance) / sum(
312                self.mz_exp * self.abundance
313            )

Class for Mass Spectrum Calculations

Class including numerical calculations related to mass spectrum class Inherited PeakPicking and NoiseThresholdCalc ensuring its methods are available to the instantiated mass spectrum class object

Parameters
  • mass_spectrum (MassSpectrum): CoreMS mass spectrum object
Attributes
  • All Attributes are derivative from the MassSpecBase Class
Methods
  • check_mspeaks(). Check if the mspeaks attribute is populated
  • sort_by_abundance(). Sort the mspeaks by abundance
  • percentile_assigned(report_error=False). Calculate the percentage of assigned peaks
  • resolving_power_calc(B, T). Calculate the resolving power
  • number_average_molecular_weight(profile=False). Calculate the number average molecular weight
  • weight_average_molecular_weight(profile=False). Calculate the weight average molecular weight
def percentage_assigned(self, report_error: bool = False, mute_output: bool = False):
 42    def percentage_assigned(
 43        self, report_error: bool = False, mute_output: bool = False
 44    ):
 45        """Percentage of peaks which are assigned
 46
 47        Calculates the percentage and relative abundance of assigned peaks in the spectrum.
 48        Includes protection against division by zero with explicit handling of edge cases.
 49
 50        Parameters
 51        -----------
 52        report_error: bool, optional
 53            Report the RMS error of the assigned peaks. Default is False.
 54        mute_output: bool, optional
 55            Override the verbose setting. Default is False.
 56            If True, the function will silence results
 57
 58        Returns
 59        -------
 60        tuple
 61            If report_error is False:
 62                (assigned_count, unassigned_count, total_percent, total_relative_abundance)
 63            If report_error is True:
 64                (assigned_count, unassigned_count, total_percent, total_relative_abundance, rms_error)
 65                where rms_error is None if no assigned peaks exist
 66
 67        Notes
 68        -----
 69        Edge cases are handled with explicit reporting:
 70        - If no peaks detected: returns (0, 0, 0.0, 0.0[, None]) with message
 71        - If no abundance data: returns (i, j, 0.0, 0.0[, None]) with message
 72        - If no assigned peaks but peaks exist: returns with rms_error=None and explanatory message
 73        """
 74        verbose = self.parameters.mass_spectrum.verbose_processing
 75        assign_abun = 0
 76        not_assign_abun = 0
 77        i = 0
 78        j = 0
 79        if report_error:
 80            error = []
 81        for mspeak in self.sort_by_abundance():
 82            if mspeak.is_assigned:
 83                i += 1
 84                assign_abun += mspeak.abundance
 85                if report_error:
 86                    error.append(mspeak.best_molecular_formula_candidate.mz_error)
 87
 88            else:
 89                j += 1
 90                not_assign_abun += mspeak.abundance
 91
 92        # Protect against division by zero
 93        total_peaks = i + j
 94        total_abundance = assign_abun + not_assign_abun
 95
 96        # Handle edge cases
 97        if total_peaks == 0:
 98            if verbose and not mute_output:
 99                print("No peaks detected in spectrum")
100            if report_error:
101                return i, j, 0.0, 0.0, None
102            else:
103                return i, j, 0.0, 0.0
104
105        if total_abundance == 0:
106            if verbose and not mute_output:
107                print("No abundance data detected in spectrum")
108            if report_error:
109                return i, j, 0.0, 0.0, None
110            else:
111                return i, j, 0.0, 0.0
112
113        total_percent = (i / total_peaks * 100) if total_peaks > 0 else 0.0
114        total_relative_abundance = (
115            (assign_abun / total_abundance * 100) if total_abundance > 0 else 0.0
116        )
117
118        if report_error:
119            rms_error = None
120            if i > 0:
121                rms_error = sqrt(mean(array(error) ** 2))
122            if verbose and not mute_output:
123                if i == 0:
124                    print(
125                        "No assigned peaks detected - cannot calculate RMS error. %i unassigned peaks, total = %.2f %%, relative abundance = %.2f %%"
126                        % (j, total_percent, total_relative_abundance)
127                    )
128                else:
129                    print(
130                        "%i assigned peaks and %i unassigned peaks, total  = %.2f %%, relative abundance = %.2f %%, RMS error (best candidate) (ppm) = %.3f"
131                        % (i, j, total_percent, total_relative_abundance, rms_error)
132                    )
133            return i, j, total_percent, total_relative_abundance, rms_error
134
135        else:
136            if verbose and not mute_output:
137                print(
138                    "%i assigned peaks and %i unassigned peaks , total  = %.2f %%, relative abundance = %.2f %%"
139                    % (
140                        i,
141                        j,
142                        total_percent,
143                        total_relative_abundance,
144                    )
145                )
146            return i, j, total_percent, total_relative_abundance

Percentage of peaks which are assigned

Calculates the percentage and relative abundance of assigned peaks in the spectrum. Includes protection against division by zero with explicit handling of edge cases.

Parameters
  • report_error (bool, optional): Report the RMS error of the assigned peaks. Default is False.
  • mute_output (bool, optional): Override the verbose setting. Default is False. If True, the function will silence results
Returns
  • tuple: If report_error is False: (assigned_count, unassigned_count, total_percent, total_relative_abundance) If report_error is True: (assigned_count, unassigned_count, total_percent, total_relative_abundance, rms_error) where rms_error is None if no assigned peaks exist
Notes

Edge cases are handled with explicit reporting:

  • If no peaks detected: returns (0, 0, 0.0, 0.0[, None]) with message
  • If no abundance data: returns (i, j, 0.0, 0.0[, None]) with message
  • If no assigned peaks but peaks exist: returns with rms_error=None and explanatory message
def percentile_assigned(self, report_error: bool = False, mute_output: bool = False):
148    def percentile_assigned(
149        self, report_error: bool = False, mute_output: bool = False
150    ):
151        """Deprecated: Use percentage_assigned() instead.
152
153        This method is deprecated and will be removed in a future version.
154        The function returns a percentage, not a percentile, so the name has been corrected.
155
156        Parameters
157        -----------
158        report_error: bool, optional
159            Report the error of the assigned peaks. Default is False.
160        mute_output: bool, optional
161            Override the verbose setting. Default is False.
162
163        Returns
164        -------
165        tuple
166            Refer to percentage_assigned() for return value details.
167        """
168        import warnings
169
170        warnings.warn(
171            "percentile_assigned() is deprecated and will be removed in a future version. "
172            "Use percentage_assigned() instead, as the function returns a percentage, not a percentile.",
173            DeprecationWarning,
174            stacklevel=2,
175        )
176        return self.percentage_assigned(
177            report_error=report_error, mute_output=mute_output
178        )

Deprecated: Use percentage_assigned() instead.

This method is deprecated and will be removed in a future version. The function returns a percentage, not a percentile, so the name has been corrected.

Parameters
  • report_error (bool, optional): Report the error of the assigned peaks. Default is False.
  • mute_output (bool, optional): Override the verbose setting. Default is False.
Returns
  • tuple: Refer to percentage_assigned() for return value details.
def resolving_power_calc(self, B: float, T: float):
180    def resolving_power_calc(self, B: float, T: float):
181        """Calculate the theoretical resolving power
182
183        Calls on the MSPeak object function to calculate the resolving power of a peak, this calcs for all peaks in a spectrum.
184
185        Parameters
186        -----------
187        T : float
188            transient time
189        B : float
190            Magnetic Filed Strength (Tesla)
191
192        References
193        ----------
194        1. Marshall et al. (Mass Spectrom Rev. 1998 Jan-Feb;17(1):1-35.)
195                DOI: 10.1002/(SICI)1098-2787(1998)17:1<1::AID-MAS1>3.0.CO;2-K
196
197        """
198
199        self.check_mspeaks()
200        return array([mspeak.resolving_power_calc(B, T) for mspeak in self.mspeaks])

Calculate the theoretical resolving power

Calls on the MSPeak object function to calculate the resolving power of a peak, this calcs for all peaks in a spectrum.

Parameters
  • T (float): transient time
  • B (float): Magnetic Filed Strength (Tesla)
References
  1. Marshall et al. (Mass Spectrom Rev. 1998 Jan-Feb;17(1):1-35.) DOI: 10.1002/(SICI)1098-2787(1998)17:1<1::AID-MAS1>3.0.CO;2-K
def number_average_molecular_weight(self, profile: bool = False):
268    def number_average_molecular_weight(self, profile: bool = False):
269        """Average molecular weight calculation
270
271        Parameters
272        ----------
273        profile : bool, optional
274            is data profile or centroid mode. The default is False (e.g. Centroid data)
275
276        Returns
277        -------
278        float
279            The average molecular weight.
280
281        """
282        # mode is profile or centroid data
283        if profile:
284            a = multiply(self.mz_exp_profile, self.abundance_profile)
285            b = self.abundance_profile
286            return a.sum() / b.sum()
287
288        else:
289            return sum(self.mz_exp * self.abundance) / sum(self.abundance)

Average molecular weight calculation

Parameters
  • profile (bool, optional): is data profile or centroid mode. The default is False (e.g. Centroid data)
Returns
  • float: The average molecular weight.
def weight_average_molecular_weight(self, profile: bool = False):
291    def weight_average_molecular_weight(self, profile: bool = False):
292        """
293        Weighted Average molecular weight calculation
294
295
296        Returns
297        -------
298        float
299            The weight average molecular weight.
300
301        """
302
303        # implement from MassSpectralPeaks objs
304
305        if profile:
306            a = multiply(power(self.mz_exp_profile, 2), self.abundance_profile)
307            b = self.mz_exp_profile * self.abundance_profile
308            return a.sum() / b.sum()
309
310        else:
311            return sum(power(self.mz_exp, 2) * self.abundance) / sum(
312                self.mz_exp * self.abundance
313            )

Weighted Average molecular weight calculation

Returns
  • float: The weight average molecular weight.