diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index a4bfdf0..2405f72 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -51,3 +51,18 @@ jobs: - name: Show Coverage run: | coverage report -m + + # This allows us to have a branch protection rule for tests and deploys with matrix + # + # taken from https://github.com/orgs/community/discussions/4324#discussioncomment-3477871 + ci-report-status: + runs-on: ubuntu-latest + needs: build + if: always() + steps: + - name: Successful CI + if: ${{ !(contains(needs.build.result, 'failure')) }} + run: exit 0 + - name: Failing CI + if: ${{ contains(needs.build.result, 'failure') }} + run: exit 1 diff --git a/README.md b/README.md index 91a3fb0..2679e32 100644 --- a/README.md +++ b/README.md @@ -22,12 +22,12 @@ pip install py2sambvca ``` -`py2sambvca` has __zero__ external depdencies. +`py2sambvca` has __zero__ external dependencies. -### Downloading and Compiling `Sambvca` -`py2sambvca` can read and write input and output files for `Sambvca` without the actual program in place, but in order to run input files you must have an executable `sambvca21.exe` (or similar) somewhere on your machine. +### Downloading and Compiling `SambVca` +`py2sambvca` can read and write input and output files for `SambVca` without the actual program in place, but in order to run input files you must have an executable `sambvca21.exe` (or similar) somewhere on your machine. -You can download the source code [on the `Sambvca` webserver](https://www.molnac.unisa.it/OMtools/sambvca2.1/download/download.html) and compile it using [`gfortran`](https://gcc.gnu.org/wiki/GFortranBinaries). +You can download the source code [on the `SambVca` webserver](https://www.molnac.unisa.it/OMtools/sambvca2.1/download/download.html) and compile it using [`gfortran`](https://gcc.gnu.org/wiki/GFortranBinaries). By default, `py2sambvca` expects the executable to be present in the `cwd` and named `sambvca21.exe` on Windows or `sambvca21.x` on Unix-based systems. optionally, the filepath to your executable can be specified as shown below. @@ -62,6 +62,7 @@ The following parameters are optional and will be filled with default values if - `path_to_sambvcax` (str): Path to the SambVca executable. Only needed to use py2sambvca.calc()(default "sambvca.exe") - `working_dir` (path): Path to the working directory where the output and input files are generated (default os.getcwd()) - `verbose` (int): 0 for no output, 1 for some output, 2 for the most output (default 1) + - `radii_table` (dict or str): a dictionary of atomic symbols and their radii (angstroms), or "default" for the radii used in the original implementation From here, running can be done stepwise or with a single function: diff --git a/py2sambvca/__init__.py b/py2sambvca/__init__.py index 54ec9b2..715e0d2 100644 --- a/py2sambvca/__init__.py +++ b/py2sambvca/__init__.py @@ -2,4 +2,4 @@ __all__ = ["p2s"] -__version__ = "1.3.4" +__version__ = "1.4.0" diff --git a/py2sambvca/py2sambvca.py b/py2sambvca/py2sambvca.py index af11d46..fdc7bb1 100644 --- a/py2sambvca/py2sambvca.py +++ b/py2sambvca/py2sambvca.py @@ -2,9 +2,11 @@ import re import glob import os -from typing import List +from typing import List, Union from warnings import warn +from py2sambvca.radii_tables import table_lookup, format_radii_table + class py2sambvca: """ @@ -28,6 +30,7 @@ class py2sambvca: path_to_sambvcax (str): Path to the SambVca executable. Only needed to use py2sambvca.calc()( default "/path/to/executable/sambvca.x") working_dir (path): Path to the working directory where the output and input files are generated (default os.getcwd()) verbose (int): 0 for no output, 1 for some output, 2 for the most output + radii_table (dict or str): atomic symbols (ie. H, LI) and radii (Angstrom), "default" (bondii radii*1.17), or "vdw" for van Der Waals """ def __init__( @@ -46,6 +49,7 @@ def __init__( path_to_sambvcax: str = "sambvca.exe", working_dir: str = os.getcwd(), verbose: int = 1, + radii_table: Union[str, dict] = "default", ): """ Wrapper class for py2sambvca functions. @@ -68,6 +72,7 @@ def __init__( path_to_sambvcax (str): Path to the SambVca executable. Only needed to use py2sambvca.calc()( default "/path/to/executable/sambvca.x") working_dir (path): Path to the working directory where the output and input files are generated (default os.getcwd()) verbose (int): 0 for no output, 1 for some output, 2 for the most output + radii_table (dict or str): atomic symbols (ie. H, LI) and radii (Angstrom), "default" (bondii radii*1.17), or "vdw" for van Der Waals """ # if atoms are requested to be deleted, assign them and the number of them if atoms_to_delete_ids is not None: @@ -114,6 +119,11 @@ def __init__( self.quadrant_results = None self.octant_results = None + # data table + self.__radii_table = format_radii_table( + table_lookup[radii_table] if type(radii_table) is str else radii_table + ) + def write_input(self): """ Write input for the Sambvca buried-volume Fortran calculator based on the data entered @@ -167,7 +177,7 @@ def write_input(self): ] ) # write radii - file.writelines(radii_table) + file.writelines(self.__radii_table) # write the atom coordinates file.writelines(self.xyz_data) @@ -511,110 +521,3 @@ def run(self): self.parse_output() self.clean_files() return self.total_results, self.quadrant_results, self.octant_results - - -radii_table = [ - "H 1.28\n", - "HE 1.64\n", - "LI 2.13\n", - "BE 1.79\n", - "B 2.25\n", - "C 1.99\n", - "N 1.81\n", - "O 1.78\n", - "F 1.72\n", - "NE 1.80\n", - "NA 2.66\n", - "MG 2.02\n", - "AL 2.15\n", - "SI 2.46\n", - "P 2.11\n", - "S 2.11\n", - "CL 2.05\n", - "AR 2.20\n", - "K 3.22\n", - "CA 2.70\n", - "SC 2.52\n", - "TI 2.47\n", - "V 2.42\n", - "CR 2.41\n", - "MN 2.40\n", - "FE 2.39\n", - "CO 2.34\n", - "NI 1.91\n", - "CU 1.64\n", - "ZN 1.63\n", - "GA 2.19\n", - "GE 2.47\n", - "AS 2.16\n", - "SE 2.22\n", - "BR 2.16\n", - "KR 2.36\n", - "RB 3.55\n", - "SR 2.91\n", - "Y 2.71\n", - "ZR 2.61\n", - "NB 2.55\n", - "MO 2.54\n", - "TC 2.53\n", - "RU 2.49\n", - "RH 2.46\n", - "PD 1.91\n", - "AG 2.01\n", - "CD 1.85\n", - "IN 2.26\n", - "SN 2.54\n", - "SB 2.41\n", - "TE 2.41\n", - "I 2.32\n", - "XE 2.53\n", - "CS 4.01\n", - "BA 3.14\n", - "LA 2.84\n", - "CE 2.83\n", - "PR 2.81\n", - "ND 2.80\n", - "PM 2.78\n", - "SM 2.76\n", - "EU 2.75\n", - "GD 2.74\n", - "TB 2.73\n", - "DY 2.70\n", - "HO 2.69\n", - "ER 2.68\n", - "TM 2.66\n", - "YB 2.64\n", - "LU 2.62\n", - "HF 2.61\n", - "TA 2.60\n", - "W 2.55\n", - "RE 2.53\n", - "OS 2.53\n", - "IR 2.49\n", - "PT 2.01\n", - "AU 1.94\n", - "HG 1.81\n", - "TL 2.29\n", - "PB 2.36\n", - "BI 2.42\n", - "PO 2.30\n", - "AT 2.36\n", - "RN 2.57\n", - "FR 4.07\n", - "RA 3.31\n", - "AC 2.89\n", - "TH 2.87\n", - "PA 2.84\n", - "U 2.18\n", - "NP 2.80\n", - "PU 2.84\n", - "AM 2.85\n", - "CM 2.87\n", - "BK 2.85\n", - "CF 2.87\n", - "ES 2.87\n", - "FM 2.87\n", - "M 2.88\n", - "NO 2.88\n", - "LR 2.88\n", -] diff --git a/py2sambvca/radii_tables/__init__.py b/py2sambvca/radii_tables/__init__.py new file mode 100644 index 0000000..b0c6c34 --- /dev/null +++ b/py2sambvca/radii_tables/__init__.py @@ -0,0 +1,10 @@ +from py2sambvca.radii_tables.default import default_radii_table +from py2sambvca.radii_tables.vanDerWaals import vdw_radii_table +from py2sambvca.radii_tables.format_table import format_radii_table + +table_lookup = { + "default": default_radii_table, + "vdw": vdw_radii_table, +} + +__all__ = ["format_radii_table", "table_lookup"] diff --git a/py2sambvca/radii_tables/default.py b/py2sambvca/radii_tables/default.py new file mode 100644 index 0000000..2906a58 --- /dev/null +++ b/py2sambvca/radii_tables/default.py @@ -0,0 +1,107 @@ +# These are the radii used in the original Cavallo paper, which are just the vDW +# radii multiplied by 1.17 +default_radii_table = { + "H": 1.28, + "HE": 1.64, + "LI": 2.13, + "BE": 1.79, + "B": 2.25, + "C": 1.99, + "N": 1.81, + "O": 1.78, + "F": 1.72, + "NE": 1.80, + "NA": 2.66, + "MG": 2.02, + "AL": 2.15, + "SI": 2.46, + "P": 2.11, + "S": 2.11, + "CL": 2.05, + "AR": 2.20, + "K": 3.22, + "CA": 2.70, + "SC": 2.52, + "TI": 2.47, + "V": 2.42, + "CR": 2.41, + "MN": 2.40, + "FE": 2.39, + "CO": 2.34, + "NI": 1.91, + "CU": 1.64, + "ZN": 1.63, + "GA": 2.19, + "GE": 2.47, + "AS": 2.16, + "SE": 2.22, + "BR": 2.16, + "KR": 2.36, + "RB": 3.55, + "SR": 2.91, + "Y": 2.71, + "ZR": 2.61, + "NB": 2.55, + "MO": 2.54, + "TC": 2.53, + "RU": 2.49, + "RH": 2.46, + "PD": 1.91, + "AG": 2.01, + "CD": 1.85, + "IN": 2.26, + "SN": 2.54, + "SB": 2.41, + "TE": 2.41, + "I": 2.32, + "XE": 2.53, + "CS": 4.01, + "BA": 3.14, + "LA": 2.84, + "CE": 2.83, + "PR": 2.81, + "ND": 2.80, + "PM": 2.78, + "SM": 2.76, + "EU": 2.75, + "GD": 2.74, + "TB": 2.73, + "DY": 2.70, + "HO": 2.69, + "ER": 2.68, + "TM": 2.66, + "YB": 2.64, + "LU": 2.62, + "HF": 2.61, + "TA": 2.60, + "W": 2.55, + "RE": 2.53, + "OS": 2.53, + "IR": 2.49, + "PT": 2.01, + "AU": 1.94, + "HG": 1.81, + "TL": 2.29, + "PB": 2.36, + "BI": 2.42, + "PO": 2.30, + "AT": 2.36, + "RN": 2.57, + "FR": 4.07, + "RA": 3.31, + "AC": 2.89, + "TH": 2.87, + "PA": 2.84, + "U": 2.18, + "NP": 2.80, + "PU": 2.84, + "AM": 2.85, + "CM": 2.87, + "BK": 2.85, + "CF": 2.87, + "ES": 2.87, + "FM": 2.87, + "M": 2.88, + "NO": 2.88, + "LR": 2.88, +} diff --git a/py2sambvca/radii_tables/format_table.py b/py2sambvca/radii_tables/format_table.py new file mode 100644 index 0000000..b95c34a --- /dev/null +++ b/py2sambvca/radii_tables/format_table.py @@ -0,0 +1,20 @@ +def format_radii_table(radii_table: dict): + """Formats a dictionary of atomic symbol: radii to a list of strings for sambvca + + Args: + radii_table (dict): Mapping of atomic symbols to radii, i.e. {'H':1.0,'LI':1.1} + """ + output_list = [] + for element, radius in radii_table.items(): + # sambvca expects each row in the radii table to look like this: + # "C 1.11" with _exactly_ six spaces for elements with two letter + # abbreviations and _exactly_ seven for elements with one letter + # abbreviations, and then three digits for the radius + output_list.append( + element + + (" " if len(element) == 1 else "") + + " " + + str(round(radius, 2)) + + "\n" + ) + return output_list diff --git a/py2sambvca/radii_tables/vanDerWaals.py b/py2sambvca/radii_tables/vanDerWaals.py new file mode 100644 index 0000000..fc9b065 --- /dev/null +++ b/py2sambvca/radii_tables/vanDerWaals.py @@ -0,0 +1,8 @@ +# this radius table just returns to the plain old van Der Waals radii, +# which are the radii reported in the original Cavallo paper divided by +# 1.17 +from py2sambvca.radii_tables.default import default_radii_table + +vdw_radii_table = { + element: radius / 1.17 for element, radius in default_radii_table.items() +} diff --git a/test/test_py2sambvca.py b/test/test_py2sambvca.py index 757a2ef..c977a6d 100644 --- a/test/test_py2sambvca.py +++ b/test/test_py2sambvca.py @@ -108,6 +108,7 @@ def test_full_init(self): self.orient_Z, self.write_surf_files, self.exe_path, + "default", ) self.assertEqual( self.sphere_ids,