Repository: choderalab/perses
Issue: `RelativeFEPSetup` cannot handle list of smiles as input ligands

According to the documentation, `RelativeFEPSetup` should be able to handle a list of SMILES strings as input ligands but it makes the interpreter to freeze giving the following warnings:

```
Warning: Unable to set unknown read format (UNDEFINED) in input stream, using existing format (Canonical stereo SMILES)
Warning: Unable to open "Oc1ccccc1" for reading molecules.

Warning: Error reading molecule "" in Canonical stereo SMILES format.
```

And example code to reproduce the issue is as follows (Warning, this kinda kills the python interpreter, use at your own risk):

```python
from perses.app.relative_setup import RelativeFEPSetup
from openmm import unit
phenol_smiles = "Oc1ccccc1"
paracetamol_smiles = "CC(=O)Nc1ccc(O)cc1"
input_smiles = [phenol_smiles, paracetamol_smiles]
fe_setup = RelativeFEPSetup(
                ligand_input=input_smiles,
                old_ligand_index=0,
                new_ligand_index=1,
                forcefield_files=["amber14/tip3p.xml"],
                small_molecule_forcefield="gaff-2.11",
                phases=["solvent"],
                solvent_padding=1.1 * unit.nanometers)
```

Changed files:
perses/tests/test_relative_setup.py, perses/app/relative_setup.py

diff --git a/perses/app/relative_setup.py b/perses/app/relative_setup.py
index b36f9243..bba96656 100644
--- a/perses/app/relative_setup.py
+++ b/perses/app/relative_setup.py
@@ -293,15 +293,22 @@ class RelativeFEPSetup(object):
                 self._ligand_topology_old = forcefield_generators.generateTopologyFromOEMol(self._ligand_oemol_old)
                 self._ligand_topology_new = forcefield_generators.generateTopologyFromOEMol(self._ligand_oemol_new)
                 _logger.info(f"\\tsuccessfully generated topologies for both OEMOLs.")
-        else:
-            self._ligand_oemol_old = createOEMolFromSDF(self._ligand_input[self._old_ligand_index])
-            self._ligand_oemol_new = createOEMolFromSDF(self._ligand_input[self._new_ligand_index])
+        else:  # Input is a list of files or smiles
+            # Try reading the string as smiles
+            from openff.toolkit.topology import Molecule
+            from openff.toolkit.utils.exceptions import SMILESParseError
+            try:
+                off_old_mol = Molecule.from_smiles(str(self._ligand_input[self._old_ligand_index]))
+                off_new_mol = Molecule.from_smiles(str(self._ligand_input[self._new_ligand_index]))
+                self._ligand_oemol_old = off_old_mol.to_openeye()
+                self._ligand_oemol_new = off_new_mol.to_openeye()
+            except SMILESParseError:
+                # Assume the input is a list of sdf file paths
+                self._ligand_oemol_old = createOEMolFromSDF(self._ligand_input[self._old_ligand_index])
+                self._ligand_oemol_new = createOEMolFromSDF(self._ligand_input[self._new_ligand_index])
             self._ligand_oemol_old = generate_unique_atom_names(self._ligand_oemol_old)
             self._ligand_oemol_new = generate_unique_atom_names(self._ligand_oemol_new)
 
-            self._ligand_oemol_old.SetTitle("OLD")
-            self._ligand_oemol_new.SetTitle("NEW")
-
             # forcefield_generators needs to be able to distinguish between the two ligands
             # while topology_proposal needs them to have the same residue name
             self._ligand_oemol_old.SetTitle("MOL")
diff --git a/perses/tests/test_relative_setup.py b/perses/tests/test_relative_setup.py
index b1029bed..dfe965d5 100644
--- a/perses/tests/test_relative_setup.py
+++ b/perses/tests/test_relative_setup.py
@@ -7,7 +7,7 @@ from perses.dispersed import feptasks
 from perses.app import setup_relative_calculation
 import mdtraj as md
 from openmmtools import states, alchemy, testsystems, cache
-from unittest import skipIf
+
 import pytest
 
 from perses.tests.utils import enter_temp_directory
@@ -410,5 +410,34 @@ def test_relative_setup_list_ligand_input():
                                                      f"receiving {ligand_input_size} files."
 
 
+def test_relative_setup_list_smiles_input():
+    """Test RelativeFEPSetup can handle a list of smiles strings as input ligands
+    """
+    from perses.app.relative_setup import RelativeFEPSetup
+    from openff.toolkit.topology import Molecule
+    from openmm import unit
+
+    benzene_smiles = "c1ccccc1"
+    phenol_smiles = "Oc1ccccc1"
+    input_smiles = [benzene_smiles, phenol_smiles]
+
+    fe_setup = RelativeFEPSetup(
+        ligand_input=input_smiles,
+        old_ligand_index=0,
+        new_ligand_index=1,
+        forcefield_files=["amber14/tip3p.xml"],
+        small_molecule_forcefield="gaff-2.11",
+        phases=["solvent"],
+        solvent_padding=1.1 * unit.nanometers)
+
+    assert isinstance(fe_setup._ligand_input, list)
+    # Assert the molecules are the expected one
+    original_mol_a = Molecule.from_smiles(benzene_smiles)
+    original_mol_b = Molecule.from_smiles(phenol_smiles)
+    fe_setup_old = Molecule.from_openeye(fe_setup._ligand_oemol_old)
+    fe_setup_new = Molecule.from_openeye(fe_setup._ligand_oemol_new)
+    assert original_mol_a == fe_setup_old, "Old input ligand is not the same after FE setup."
+    assert original_mol_b == fe_setup_new, "New input ligand is not the same after FE setup."
+
 # if __name__=="__main__":
 #     test_run_cdk2_iterations_repex()