Repository: mosdef-hub/gmso

Issue:
Infer Element when converting from parmed
it might be nice to consider infering elements when converting from parmed.

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/mosdef-hub/gmso/pull/651?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub) Report
> Merging [#651](https://codecov.io/gh/mosdef-hub/gmso/pull/651?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub) (7b3873e) into [main](https://codecov.io/gh/mosdef-hub/gmso/commit/c78e2425ccb98ea952f024a569346d36045f6918?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub) (c78e242) will **decrease** coverage by `0.05%`.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff             @@
##             main     #651      +/-   ##
==========================================
- Coverage   90.78%   90.73%   -0.06%     
==========================================
  Files          56       56              
  Lines        4633     4629       -4     
==========================================
- Hits         4206     4200       -6     
- Misses        427      429       +2     
```


| [Impacted Files](https://codecov.io/gh/mosdef-hub/gmso/pull/651?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub) | Coverage Δ | |
|---|---|---|
| [gmso/external/convert\_parmed.py](https://codecov.io/gh/mosdef-hub/gmso/pull/651/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub#diff-Z21zby9leHRlcm5hbC9jb252ZXJ0X3Bhcm1lZC5weQ==) | `90.31% <100.00%> (+0.34%)` | :arrow_up: |
| [gmso/formats/mol2.py](https://codecov.io/gh/mosdef-hub/gmso/pull/651/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub#diff-Z21zby9mb3JtYXRzL21vbDIucHk=) | `95.94% <0.00%> (-4.06%)` | :arrow_down: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/mosdef-hub/gmso/pull/651?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/mosdef-hub/gmso/pull/651?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub). Last update [c78e242...7b3873e](https://codecov.io/gh/mosdef-hub/gmso/pull/651?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=mosdef-hub).


Patch:
diff --git a/gmso/external/convert_parmed.py b/gmso/external/convert_parmed.py
index 579d560..403fa4a 100644
--- a/gmso/external/convert_parmed.py
+++ b/gmso/external/convert_parmed.py
@@ -9,6 +9,7 @@ from sympy.parsing.sympy_parser import parse_expr
 import gmso
 from gmso.core.element import (
     element_by_atom_type,
+    element_by_atomic_number,
     element_by_name,
     element_by_symbol,
 )
@@ -82,6 +83,9 @@ def from_parmed(structure, refer_type=True):
         subtop_name = ("{}[{}]").format(residue.name, residue.idx)
         subtops.append(gmso.SubTopology(name=subtop_name, parent=top))
         for atom in residue.atoms:
+            element = (
+                element_by_atomic_number(atom.element) if atom.element else None
+            )
             if refer_type and isinstance(atom.atom_type, pmd.AtomType):
                 site = gmso.Atom(
                     name=atom.name,
@@ -92,6 +96,7 @@ def from_parmed(structure, refer_type=True):
                     atom_type=pmd_top_atomtypes[atom.atom_type],
                     residue_name=residue.name,
                     residue_number=residue.idx,
+                    element=element,
                 )
             else:
                 site = gmso.Atom(
@@ -103,6 +108,7 @@ def from_parmed(structure, refer_type=True):
                     atom_type=None,
                     residue_name=residue.name,
                     residue_number=residue.idx,
+                    element=element,
                 )
             site_map[atom] = site
             subtops[-1].add_site(site)
@@ -468,10 +474,8 @@ def to_parmed(top, refer_type=True):
     for site in top.sites:
         if site.element:
             atomic_number = site.element.atomic_number
-            charge = site.element.charge
         else:
             atomic_number = 0
-            charge = 0
         pmd_atom = pmd.Atom(
             atomic_number=atomic_number,
             name=site.name,


Test patch:
diff --git a/gmso/tests/base_test.py b/gmso/tests/base_test.py
index 3db264a..68faa73 100644
--- a/gmso/tests/base_test.py
+++ b/gmso/tests/base_test.py
@@ -500,3 +500,48 @@ class BaseTest:
         top.update_topology()
 
         return top
+
+    @pytest.fixture(scope="session")
+    def pentane_ua_mbuild(self):
+        class PentaneUA(mb.Compound):
+            """Create a united-atom pentane compound."""
+
+            def __init__(self):
+                super(PentaneUA, self).__init__()
+                # Calculate the angle between the two ports
+                angle = np.deg2rad(114)
+                x = 0
+                y = 0.077
+                z = 0
+                vec = [
+                    x,
+                    y * np.cos(angle) - z * np.sin(angle),
+                    y * np.sin(angle) + z * np.cos(angle),
+                ]
+                # Create the end group compound
+                ch3 = mb.Compound()
+                ch3.add(mb.Particle(name="_CH3"))
+                ch3.add(mb.Port(anchor=ch3[0]), "up")
+                ch3["up"].translate([x, y, z])
+                # Create the internal monomer
+                ch2 = mb.Compound()
+                ch2.add(mb.Particle(name="_CH2"))
+                ch2.add(mb.Port(anchor=ch2[0]), "up")
+                ch2["up"].translate([x, y, z])
+                ch2.add(mb.Port(anchor=ch2[0], orientation=vec), "down")
+                ch2["down"].translate(vec)
+                pentane = mb.recipes.Polymer(
+                    monomers=[ch2], end_groups=[ch3, mb.clone(ch3)]
+                )
+                pentane.build(n=3)
+                self.add(pentane, label="PNT")
+
+        return PentaneUA()
+
+    @pytest.fixture(scope="session")
+    def pentane_ua_parmed(self, pentane_ua_mbuild):
+        return mb.conversion.to_parmed(pentane_ua_mbuild)
+
+    @pytest.fixture(scope="session")
+    def pentane_ua_gmso(self, pentane_ua_mbuild):
+        return from_mbuild(pentane_ua_mbuild)
diff --git a/gmso/tests/test_convert_parmed.py b/gmso/tests/test_convert_parmed.py
index e367da8..e6fec88 100644
--- a/gmso/tests/test_convert_parmed.py
+++ b/gmso/tests/test_convert_parmed.py
@@ -323,3 +323,15 @@ class TestConvertParmEd(BaseTest):
         ]:
             for potential in potential_types:
                 assert potential.member_types
+
+    def test_parmed_element(self):
+        struc = pmd.load_file(get_fn("ethane.top"), xyz=get_fn("ethane.gro"))
+        top = from_parmed(struc)
+        for gmso_atom, pmd_atom in zip(top.sites, struc.atoms):
+            assert gmso_atom.element.atomic_number == pmd_atom.element
+
+    def test_parmed_element_non_atomistic(self, pentane_ua_parmed):
+        top = from_parmed(pentane_ua_parmed)
+        for gmso_atom, pmd_atom in zip(top.sites, pentane_ua_parmed.atoms):
+            assert gmso_atom.element is None
+            assert pmd_atom.element == 0