Repository: PlasmaPy/PlasmaPy

Issue:
Create classes to represent ionization state distributions
My plan for this PR is to create classes to represent the ionization state distributions of one or more elements.  I am going to add in a bunch of dunder methods like `__getitem__` and maybe `__call__` to help making access to the ionization states more straightfoward and intuitive.  Any suggestions on the naming convention will be helpful so that we can maximize readability. 

Eventually we'll need a way to calculate ionization state distributions assuming collisional ionization equilibrium, but that will be for a different PR.  The purpose of this PR is to set up how to store and access the ionization distributions.  This will be discussed in #352.

This will address some of #352.  It will probably be best to wait until after the `0.1.0` release to merge this, since this PR is only for a partial implementation anyway.




Discussion:
Hello @namurphy! Thanks for updating your pull request.







 - In the file [`plasmapy/atomic/ionization_states.py`](https://github.com/PlasmaPy/PlasmaPy/blob/e65e3b4fd9f61b1e17e90fbb0228566eacd54dc3/plasmapy/atomic/ionization_states.py), following are the PEP8 issues :

> [Line 458:27](https://github.com/PlasmaPy/PlasmaPy/blob/e65e3b4fd9f61b1e17e90fbb0228566eacd54dc3/plasmapy/atomic/ionization_states.py#L458): [E202](https://duckduckgo.com/?q=pep8%20E202) whitespace before ')'
> [Line 460:5](https://github.com/PlasmaPy/PlasmaPy/blob/e65e3b4fd9f61b1e17e90fbb0228566eacd54dc3/plasmapy/atomic/ionization_states.py#L460): [E112](https://duckduckgo.com/?q=pep8%20E112) expected an indented block













##### Comment last updated on August 07, 2018 at 18:59 Hours UTC
By the way, I've had a few opportunities at work to think about properly handling git trees and I think it may be time to revisit the idea of more consistently squash merging this kind of large exploratory PR... Or at least decreasing the number of commits going into master by rebasing and combining these changes into a few logical units. 

What do you think?
# [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=h1) Report
> Merging [#404](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=desc) into [master](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/c32c089c094b18d57824d6a1503708a8c504ad3e?src=pr&el=desc) will **decrease** coverage by `2.83%`.
> The diff coverage is `73.72%`.

[![Impacted file tree graph](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/graphs/tree.svg?token=LzZ5mnXVad&width=650&height=150&src=pr)](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #404      +/-   ##
==========================================
- Coverage   98.05%   95.22%   -2.84%     
==========================================
  Files          46       48       +2     
  Lines        3746     4227     +481     
==========================================
+ Hits         3673     4025     +352     
- Misses         73      202     +129
```


| [Impacted Files](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [plasmapy/atomic/atomic.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2F0b21pYy5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/\_\_init\_\_.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL19faW5pdF9fLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/particle\_input.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnRpY2xlX2lucHV0LnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/parsing.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnNpbmcucHk=) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/particle\_class.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnRpY2xlX2NsYXNzLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/ionization\_states.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGVzLnB5) | `67.52% <67.52%> (ø)` | |
| [plasmapy/atomic/ionization\_state.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGUucHk=) | `80.28% <80.28%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=footer). Last update [c32c089...e65e3b4](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Thanks for the code review, @StanczakDominik!  We've been using this and related functionality in a separate but related [project for non-equilibrium ionization (NEI) modeling](https://github.com/NEI-modeling/NEI) that we're still developing and refining, and that I'm hoping will get implemented into a different project.  

There are a few things I've been wondering about on larger scales.  In which project should the `IonizationStates` class (or something similar) go?  And also...where should NEI modeling functionality go?  The ionization state of a plasma is a really basic property, so I've been thinking that it should go in PlasmaPy, even though fiasco and SpectroscoPyx are also really good possibilities.  NEI modeling is a bit more specialized, but the data on recombination and ionization rates is pretty much the same data that's needed to calculate equilibrium ionization fractions, which is a really fundamental thing too so PlasmaPy might be the best place.  

I should probably create a separate issue to ask this question, but I'm going on vacation in three minutes so it'll have to wait! :bullettrain_front: :bridge_at_night: 

# [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=h1) Report
> Merging [#404](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=desc) into [master](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/0c6fa440cb8c8fea4c5ee70142c009525585e221?src=pr&el=desc) will **decrease** coverage by `2.2%`.
> The diff coverage is `79.03%`.

[![Impacted file tree graph](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/graphs/tree.svg?width=650&token=LzZ5mnXVad&height=150&src=pr)](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #404      +/-   ##
==========================================
- Coverage   98.07%   95.87%   -2.21%     
==========================================
  Files          46       48       +2     
  Lines        3796     4291     +495     
==========================================
+ Hits         3723     4114     +391     
- Misses         73      177     +104
```


| [Impacted Files](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [plasmapy/atomic/particle\_class.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnRpY2xlX2NsYXNzLnB5) | `100% <ø> (ø)` | :arrow_up: |
| [plasmapy/atomic/atomic.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2F0b21pYy5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/\_\_init\_\_.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL19faW5pdF9fLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/ionization\_states.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGVzLnB5) | `69.89% <69.89%> (ø)` | |
| [plasmapy/atomic/ionization\_state.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGUucHk=) | `90.69% <90.69%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=footer). Last update [0c6fa44...22dc045](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=h1) Report
> Merging [#404](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=desc) into [master](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/0c6fa440cb8c8fea4c5ee70142c009525585e221?src=pr&el=desc) will **decrease** coverage by `2.2%`.
> The diff coverage is `79.03%`.

[![Impacted file tree graph](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/graphs/tree.svg?width=650&token=LzZ5mnXVad&height=150&src=pr)](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #404      +/-   ##
==========================================
- Coverage   98.07%   95.87%   -2.21%     
==========================================
  Files          46       48       +2     
  Lines        3796     4291     +495     
==========================================
+ Hits         3723     4114     +391     
- Misses         73      177     +104
```


| [Impacted Files](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [plasmapy/atomic/particle\_class.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnRpY2xlX2NsYXNzLnB5) | `100% <ø> (ø)` | :arrow_up: |
| [plasmapy/atomic/atomic.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2F0b21pYy5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/\_\_init\_\_.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL19faW5pdF9fLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/ionization\_states.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGVzLnB5) | `69.89% <69.89%> (ø)` | |
| [plasmapy/atomic/ionization\_state.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGUucHk=) | `90.69% <90.69%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=footer). Last update [0c6fa44...913b204](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=h1) Report
> Merging [#404](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=desc) into [master](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/0c6fa440cb8c8fea4c5ee70142c009525585e221?src=pr&el=desc) will **decrease** coverage by `2.35%`.
> The diff coverage is `78.23%`.

[![Impacted file tree graph](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/graphs/tree.svg?width=650&token=LzZ5mnXVad&height=150&src=pr)](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #404      +/-   ##
==========================================
- Coverage   98.07%   95.72%   -2.36%     
==========================================
  Files          46       48       +2     
  Lines        3796     4305     +509     
==========================================
+ Hits         3723     4121     +398     
- Misses         73      184     +111
```


| [Impacted Files](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [plasmapy/atomic/particle\_class.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnRpY2xlX2NsYXNzLnB5) | `100% <ø> (ø)` | :arrow_up: |
| [plasmapy/atomic/atomic.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2F0b21pYy5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/\_\_init\_\_.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL19faW5pdF9fLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/ionization\_states.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGVzLnB5) | `69.89% <69.89%> (ø)` | |
| [plasmapy/atomic/ionization\_state.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGUucHk=) | `88.2% <88.2%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=footer). Last update [0c6fa44...913b204](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=h1) Report
> Merging [#404](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=desc) into [master](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/0c6fa440cb8c8fea4c5ee70142c009525585e221?src=pr&el=desc) will **decrease** coverage by `2.35%`.
> The diff coverage is `78.23%`.

[![Impacted file tree graph](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/graphs/tree.svg?width=650&token=LzZ5mnXVad&height=150&src=pr)](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #404      +/-   ##
==========================================
- Coverage   98.07%   95.72%   -2.36%     
==========================================
  Files          46       48       +2     
  Lines        3796     4305     +509     
==========================================
+ Hits         3723     4121     +398     
- Misses         73      184     +111
```


| [Impacted Files](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [plasmapy/atomic/particle\_class.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnRpY2xlX2NsYXNzLnB5) | `100% <ø> (ø)` | :arrow_up: |
| [plasmapy/atomic/atomic.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2F0b21pYy5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/\_\_init\_\_.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL19faW5pdF9fLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/ionization\_states.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGVzLnB5) | `69.89% <69.89%> (ø)` | |
| [plasmapy/atomic/ionization\_state.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGUucHk=) | `88.2% <88.2%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=footer). Last update [0c6fa44...913b204](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=h1) Report
> Merging [#404](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=desc) into [master](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/0c6fa440cb8c8fea4c5ee70142c009525585e221?src=pr&el=desc) will **decrease** coverage by `2.35%`.
> The diff coverage is `78.23%`.

[![Impacted file tree graph](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/graphs/tree.svg?width=650&token=LzZ5mnXVad&height=150&src=pr)](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #404      +/-   ##
==========================================
- Coverage   98.07%   95.72%   -2.36%     
==========================================
  Files          46       48       +2     
  Lines        3796     4305     +509     
==========================================
+ Hits         3723     4121     +398     
- Misses         73      184     +111
```


| [Impacted Files](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [plasmapy/atomic/particle\_class.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnRpY2xlX2NsYXNzLnB5) | `100% <ø> (ø)` | :arrow_up: |
| [plasmapy/atomic/atomic.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2F0b21pYy5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/\_\_init\_\_.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL19faW5pdF9fLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/ionization\_states.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGVzLnB5) | `69.89% <69.89%> (ø)` | |
| [plasmapy/atomic/ionization\_state.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGUucHk=) | `88.2% <88.2%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=footer). Last update [0c6fa44...913b204](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

# [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=h1) Report
> Merging [#404](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=desc) into [master](https://codecov.io/gh/PlasmaPy/PlasmaPy/commit/15a77592b6b5ba8ea3ed8b1dadd3e4e3f71bc631?src=pr&el=desc) will **decrease** coverage by `0.86%`.
> The diff coverage is `91.95%`.

[![Impacted file tree graph](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/graphs/tree.svg?width=650&token=LzZ5mnXVad&height=150&src=pr)](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #404      +/-   ##
==========================================
- Coverage   97.44%   96.58%   -0.87%     
==========================================
  Files          46       48       +2     
  Lines        3841     4503     +662     
==========================================
+ Hits         3743     4349     +606     
- Misses         98      154      +56
```


| [Impacted Files](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [plasmapy/atomic/atomic.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2F0b21pYy5weQ==) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/particle\_input.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnRpY2xlX2lucHV0LnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/\_\_init\_\_.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL19faW5pdF9fLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [plasmapy/atomic/particle\_class.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL3BhcnRpY2xlX2NsYXNzLnB5) | `96.63% <100%> (+0.03%)` | :arrow_up: |
| [plasmapy/atomic/ionization\_states.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGVzLnB5) | `90.66% <90.66%> (ø)` | |
| [plasmapy/atomic/ionization\_state.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvYXRvbWljL2lvbml6YXRpb25fc3RhdGUucHk=) | `92.88% <92.88%> (ø)` | |
| [plasmapy/classes/species.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvY2xhc3Nlcy9zcGVjaWVzLnB5) | `98.27% <0%> (-1.73%)` | :arrow_down: |
| [plasmapy/physics/magnetostatics.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvcGh5c2ljcy9tYWduZXRvc3RhdGljcy5weQ==) | `99.2% <0%> (-0.8%)` | :arrow_down: |
| [plasmapy/classes/sources/plasmablob.py](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree#diff-cGxhc21hcHkvY2xhc3Nlcy9zb3VyY2VzL3BsYXNtYWJsb2IucHk=) | `100% <0%> (ø)` | :arrow_up: |
| ... and [2 more](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=footer). Last update [15a7759...1bff7e6](https://codecov.io/gh/PlasmaPy/PlasmaPy/pull/404?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

Also, to make sure this doesn't get lost in GitHub's review interface, [this comment discusses the test failure](https://github.com/PlasmaPy/PlasmaPy/pull/404#discussion_r224181200).
> **Transport PR Incident**

:joy_cat: 

I still have more tests and docstrings to put in, but I don't have to finish all of them in this PR.  I was planning on working on this for one more day when I can take some time away from Fortran, and then start working on #521.  This is the last of my backlog of PRs to finish up, so I'm eager to get it done soon!
The Travis builds are only failing because I messed up a few git remote magic tricks; they're passing [over here](https://travis-ci.org/PlasmaPy/PlasmaPy/builds/441512524).
The downside of having `__repr__` return multiple lines of diagnostic data is that we can end up with messy error messages with `'\n'` showing up a bunch of times.
```
___________ Test_IonizationStates.test_inequality[number densities -> inputs] ___________
plasmapy/atomic/tests/test_ionization_states.py:159: in test_inequality
    assert original_instance != altered_instance
E   assert IonizationStates instance for: H, He\n\n  H  0+: 0.400\n  H  1+: 0.600\n\n  He  0+: 0.217\n  He  1+: 0.304\n  He  2+: 0.478\n\n != IonizationStates instance for: H, He\n\n  H  0+: 0.400\n  H  1+: 0.600\n\n  He  0+: 0.217\n  He  1+: 0.304\n  He  2+: 0.478\n\n
```
I'm still wondering if being able to easily print out really useful diagnostic data like this is worth it.  Hm...
```Python
In [1]: IonizationStates({'H': [0.1, 0.9], 'He': [0.9, 0.099, 0.001]})
Out[1]: 
IonizationStates instance for: H, He

  H  0+: 0.100
  H  1+: 0.900

  He  0+: 0.900
  He  1+: 0.099
```
Re: repr, could that perhaps be put into another custom method? Sure, it'd be less standard than putting a string description in a repr - but standard reprs are shorter anyway so we are already breaking that convention.
> Re: repr, could that perhaps be put into another custom method?

Yeah, that's what I was starting to think too, so let's go with this approach.  Thanks!
The docstrings still need to describe the consequences of dunder methods and it'd be good to fill in a few more gaps in text coverage, but I am ready for this to be merged.  After then, I can create separate issues for the remaining tasks.
I'd just do one final round of review and likely merge this today - but what of the commit messages? I could try to trim some of it down to something more manageable. Is that okay?
I was thinking that it'd be easiest if I did the squash merge after you approve it or I make any final changes.  That way I can remove commits that are now extraneous and maybe add some context to the remaining commits.  Does that sound good?
Thank you, @StanczakDominik!  I am very ready for this to be merged. :joy_cat:  I am working on the summary commit message now.  

A final thought is that some of the tests could likely be refactored into fixtures.  I did not do this because I do not yet know how to write fixtures, but that is fine to leave for the future.


That sounds like a possible future low priority issue. :laughing: 
:tada: 

Resolving patch:
diff --git a/plasmapy/classes/sources/plasma3d.py b/plasmapy/classes/sources/plasma3d.py
--- a/plasmapy/classes/sources/plasma3d.py
+++ b/plasmapy/classes/sources/plasma3d.py
@@ -110,9 +110,10 @@ def is_datasource_for(cls, **kwargs):
 
     def add_magnetostatic(self, *mstats: MagnetoStatics):
         # for each MagnetoStatic argument
+        prod = itertools.product(*[list(range(n)) for n in self.domain_shape])
         for mstat in mstats:
             # loop over 3D-index (ix,iy,iz)
-            for point_index in itertools.product(*[list(range(n)) for n in self.domain_shape]):
+            for point_index in prod:
                 # get coordinate
                 p = self.grid[(slice(None),)+point_index]  # function as [:, *index]
                 # calculate magnetic field at this point and add back


Test patch: