Ranging data
Where Roi is the central container for positional data, RangeCollection is the central container for mass/charge ranging data. This contains the range data in an accessible format for both the user and for APAV facilities that use mass ranging. The RangeCollection container manages many (or few) Range objects for each range.
A single mass/charge range
The Range object defines a single half-open interval on the mass spectrum, and assigns it an Ion.
Note
All ranging activities in APAV involving an interval on the mass spectrum, take the interval as a half-open interval. If the interval goes from mass m0 to mass m1, then the interval is [m0, m1) where m = m0 is included but m = m1 is not.
To create a range for O2 on the interval [31.5, 33):
>>> import apav as ap
>>> O2 = ap.Range("O2", (31.5, 33))
>>> print(O2)
Range: O2, Min: 31.5, Max: 33, Vol: 1, Color: (0, 0, 0)
The lower and upper limits can be modified:
>>> O2.lower = 31
>>> print(O2)
Range: O2, Min: 31, Max: 33, Vol: 1, Color: (0, 0, 0)
But the lower value cannot be set equal, or above the upper value and vice versa:
>>> O2.lower = 40
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-11-fdbbc8818585> in <module>
----> 1 o2.lower = 40
~\PycharmProjects\apav\apav\core\range.py in lower(self, new)
85 validate.positive_number(new)
86 if new >= self._upper:
---> 87 raise ValueError(f"Lower bound for {self.composition} ({new}) cannot be >= upper bound ({self.upper})")
88 self._lower = new
89
ValueError: Lower bound for O2 (40) cannot be >= upper bound (33)
The interval on the mass spectrum can be retrieved:
>>> O2.interval
(31, 33)
We can test whether or not 2 ranges intersect:
>>> O2 = ap.Range("O2", (31.5, 33)
>>> Cu = ap.Range("Cu", (30, 31))
>>> O2.intersects(Cu)
False
>>> Cu2 = ap.Range("Cu", (30, 32))
>>> O2.intersects(Cu2)
True
Remembering a Range interval is half-open:
>>> O2 = ap.Range("O2", (31.5, 33)
>>> Cu = ap.Range("Cu", (30, 31.5))
>>> O2.intersects(Cu)
False
Other properties can be found in the API reference.
Collections of ranges
The RangeCollection is responsible for containing and operating on a collection of Range instances. Typically, this class is constructed from a file via RangeCollection.from_rng() or RangeCollection.from_rrng() for loading data from common *.RNG or *.RRNG range files from IVAS or other software into a RangedCollection.
Note
The ranged mass spectrum can be visualized using apav.analysis.RangedMassSpectrum
The RangeCollection can be constructed without any Range, an empty RangeCollection can be initialized as simply:
>>> import apav as ap
>>> rng_col = ap.RangedCollection()
Then multiple Range objects can be added:
>>> rng_col.add(ap.Range("Cu", (30, 31.5)))
>>> rng_col.add(ap.Range("O2", (31.5, 32)))
>>> rng_col.add(ap.Range("Cu", (32, 33)))
>>> print(rng_col)
RangeCollection
Number of ranges: 3
Mass range: 30 - 33
Number of unique elements: 2
Elements: ('Cu', 'O')
Composition Min (Da) Max (Da) Volume Color (RGB 0-1)
------------- ---------- ---------- -------- -----------------
Cu 30 31.5 1 (0, 0, 0)
O2 31.5 32 1 (0, 0, 0)
Cu 32 33 1 (0, 0, 0)
Alternatively the Range objects can be passed into the constructor:
>>> rngs = [ap.Range("Cu", (30, 31.5)),
ap.Range("O2", (31.5, 32)),
ap.Range("Cu", (32, 33))]
>>> rng_col = ap.RangeCollection(rngs)
There cannot be overlapping ranges in a RangeCollection:
>>> rng_col.add(ap.Range("O2", (32.5, 34)))
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
<ipython-input-19-bc12e9d521c5> in <module>
----> 1 rng_col.add(ap.Range("O2", (32.5, 34)))
~\PycharmProjects\apav\apav\core\range.py in add(self, new)
315 for r in self.ranges:
316 if r.intersects(new):
--> 317 raise ValueError("Mass ranges cannot coincide")
318 self._ranges.append(new)
319
ValueError: Mass ranges cannot coincide
If a mass Range needs to be modified, it can be removed and a new range added. Modifying the first copper range to start at 28:
>>> rng_col.remove_by_mass(30)
>>> rng_col.add(ap.Range("Cu", (28, 31.5)))
RangeCollection
Number of ranges: 3
Mass range: 28 - 33
Number of unique elements: 2
Elements: O, Cu
Composition Min (Da) Max (Da) Volume Color (RGB 0-1)
------------- ---------- ---------- -------- -----------------
Cu 28 31.5 1 (0, 0, 0)
O2 31.5 32 1 (0, 0, 0)
Cu 32 33 1 (0, 0, 0)
Or see RangeCollection.replace().