Repository: PlasmaPy/PlasmaPy

Issue:
Allow Roman numeral spectroscopic notation to represent ions
In astronomy it is common to use Roman numerals to represent the ion species responsible for the emission from a particular spectral line.  The Roman numeral is the charge state of the ion plus one (e.g., Fe I corresponds to Fe<sup>0+</sup> and Fe X corresponds to Fe<sup>9+</sup>).  

Some examples:
```Python
>>> from plasmapy.atomic import *
>>> integer_charge('Fe X')
9
>>> Particle('O VI').ion
'O 5+'
```
It would be worth looking for already existing packages that parse Roman numerals so that we do not need to reinvent this functionality.

I personally dislike this notation because the off-by-one difference is confusing and using Roman numerals greatly decreases readability for high charge states, but it is used commonly enough that we should allow it.




Discussion:
I'll give this a go. The [roman](https://pypi.python.org/pypi/roman) package looks good enough to me.
```python
>>> roman.fromRoman('LXI')
61
```
There are also other packages like [numeral](https://pypi.python.org/pypi/numeral) but I think they are a bit of overkill. What do you think?
> The Roman numeral is the charge state of the ion plus one (e.g., Fe I corresponds to Fe⁰⁺ and Fe X corresponds to Fe⁹⁺).

By the way, is there a reason for doing this? Why can't Fe I correspond to Fe¹⁺? (Fe without any charge specified could just correspond to Fe⁰⁺)
```python
>>> integer_charge('Fe II')
2
>>> integer_charge('Fe')
0
```
I completely agree that it would make much more sense to have Fe I correspond to Fe¹⁺ and so on, but the Roman numeral notation has been a standard notation for spectroscopy that has been used like this for the better part of a century (e.g., [this abstract from ~1930](http://adsabs.harvard.edu/abs/1931ApJ....74..225S)).  I've been trying to use notation like Fe¹⁺ when describing spectra since that's much clearer.

I wonder if the source of the problem was that the roman numeral system doesn't have a symbol that represents zero.


Resolving patch:
diff --git a/plasmapy/atomic/parsing.py b/plasmapy/atomic/parsing.py
--- a/plasmapy/atomic/parsing.py
+++ b/plasmapy/atomic/parsing.py
@@ -1,5 +1,6 @@
 """Functionality to parse representations of particles into standard form."""
 
+import roman
 import numpy as np
 import re
 import warnings
@@ -205,13 +206,19 @@ def _extract_charge(arg: str):
             if not sign_indicator_only_on_one_end and just_one_sign_indicator:
                 raise InvalidParticleError(invalid_charge_errmsg) from None
 
-            if '-' in charge_info:
-                sign = -1
-            elif '+' in charge_info:
-                sign = 1
-
             charge_str = charge_info.strip('+-')
-            Z_from_arg = sign * int(charge_str)
+
+            try:
+                if roman.romanNumeralPattern.match(charge_info):
+                    Z_from_arg = roman.fromRoman(charge_info) - 1
+                elif '-' in charge_info:
+                    Z_from_arg = - int(charge_str)
+                elif '+' in charge_info:
+                    Z_from_arg = int(charge_str)
+                else:
+                    raise InvalidParticleError(invalid_charge_errmsg) from None
+            except ValueError:
+                raise InvalidParticleError(invalid_charge_errmsg) from None
 
         elif arg.endswith(('-', '+')):  # Cases like 'H-' and 'Pb-209+++'
             char = arg[-1]


Test patch:
diff --git a/plasmapy/atomic/tests/test_parsing.py b/plasmapy/atomic/tests/test_parsing.py
--- a/plasmapy/atomic/tests/test_parsing.py
+++ b/plasmapy/atomic/tests/test_parsing.py
@@ -242,6 +242,10 @@ def test_parse_and_check_atomic_input(arg, kwargs, expected):
     ('He-99', {}),
     ('H-2+', {'Z': 0}),
     ('H-', {'Z': 1}),
+    ('C VX', {}),
+    ('Rh XXXX', {}),
+    ('Li -II', {}),
+    ('B +IV', {}),
 ]