Skip to content

Commit

Permalink
Merge branch 'main' into add-types-module
Browse files Browse the repository at this point in the history
  • Loading branch information
alinelena authored Mar 5, 2024
2 parents 1ff009c + f77883f commit f32befc
Show file tree
Hide file tree
Showing 13 changed files with 380 additions and 165 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
with:
parallel: true
flag-name: run-${{ matrix.python-version }}
file: coverage.xml
base-path: janus_core

coverage:
needs: tests
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
*.pyc
*.swo
*.swp
*.xml
~*
*~
.project
Expand Down
2 changes: 1 addition & 1 deletion docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ customdefault:
all: html

clean:
rm -r $(BUILDDIR)
rm -rf $(BUILDDIR)

html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
Expand Down
30 changes: 20 additions & 10 deletions docs/source/apidoc/janus_core.rst
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
janus\_core package
===================

Module contents
---------------

.. automodule:: janus_core
:members:
:special-members:
:private-members:
:undoc-members:
:show-inheritance:

Submodules
----------

janus\_core.cli module
----------------------

.. automodule:: janus_core.cli
:members:
:special-members:
:private-members:
:undoc-members:
:show-inheritance:

janus\_core.geom\_opt module
----------------------------

Expand Down Expand Up @@ -43,13 +63,3 @@ janus\_core.single\_point module
:private-members:
:undoc-members:
:show-inheritance:

Module contents
---------------

.. automodule:: janus_core
:members:
:special-members:
:private-members:
:undoc-members:
:show-inheritance:
49 changes: 3 additions & 46 deletions docs/source/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,49 +187,6 @@

# Warnings to ignore when using the -n (nitpicky) option
# We should ignore any python built-in exception, for instance
nitpick_ignore = [("py:class", "Logger"), ("py:class", "numpy.float64")]


def run_apidoc(_):
"""Runs sphinx-apidoc when building the documentation.
Needs to be done in conf.py in order to include the APIdoc in the
build on readthedocs.
See also https://github.com/rtfd/readthedocs.org/issues/1139
"""
source_dir = os.path.abspath(os.path.dirname(__file__))
apidoc_dir = os.path.join(source_dir, "apidoc")
package_dir = os.path.join(source_dir, os.pardir, os.pardir, "janus_core")

# In #1139, they suggest the route below, but this ended up
# calling sphinx-build, not sphinx-apidoc
# from sphinx.apidoc import main
# main([None, '-e', '-o', apidoc_dir, package_dir, '--force'])

import subprocess

cmd_path = "sphinx-apidoc"
if hasattr(sys, "real_prefix"): # Check to see if we are in a virtualenv
# If we are, assemble the path manually
cmd_path = os.path.abspath(os.path.join(sys.prefix, "bin", "sphinx-apidoc"))

options = [
"-o",
apidoc_dir,
package_dir,
"--private",
"--force",
"--no-toc",
]

# See https://stackoverflow.com/a/30144019
env = os.environ.copy()
env["SPHINX_APIDOC_OPTIONS"] = (
"members,special-members,private-members,undoc-members,show-inheritance"
)
subprocess.check_call([cmd_path] + options, env=env)


def setup(app):
app.connect("builder-inited", run_apidoc)
nitpick_ignore = [
("py:class", "Logger"),
]
144 changes: 144 additions & 0 deletions janus_core/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
"""Set up commandline interface."""

import ast
from typing import Annotated

import typer

from janus_core.single_point import SinglePoint

app = typer.Typer()


class TyperDict: # pylint: disable=too-few-public-methods
"""
Custom dictionary for typer.
Parameters
----------
value : str
Value of string representing a dictionary.
"""

def __init__(self, value: str):
"""
Initialise class.
Parameters
----------
value : str
Value of string representing a dictionary.
"""
self.value = value

def __str__(self):
"""
String representation of class.
Returns
-------
str
Class name and value of string representing a dictionary.
"""
return f"<TyperDict: value={self.value}>"


def parse_dict_class(value: str):
"""
Convert string input into a dictionary.
Parameters
----------
value : str
String representing dictionary to be parsed.
Returns
-------
TyperDict
Parsed string as a dictionary.
"""
return TyperDict(ast.literal_eval(value))


@app.command()
def singlepoint(
structure: Annotated[
str, typer.Option(help="Path to structure to perform calculations")
],
architecture: Annotated[
str, typer.Option("--arch", help="MLIP architecture to use for calculations")
] = "mace_mp",
device: Annotated[str, typer.Option(help="Device to run calculations on")] = "cpu",
properties: Annotated[
list[str],
typer.Option(
"--property",
help="Properties to calculate. If not specified, 'energy', 'forces', \
and 'stress' will be returned.",
),
] = None,
read_kwargs: Annotated[
TyperDict,
typer.Option(
parser=parse_dict_class,
help="Keyword arguments to pass to ase.io.read [default: {}]",
metavar="DICT",
),
] = None,
calc_kwargs: Annotated[
TyperDict,
typer.Option(
parser=parse_dict_class,
help="Keyword arguments to pass to selected calculator [default: {}]",
metavar="DICT",
),
] = None,
):
"""
Perform single point calculations.
Parameters
----------
structure : str
Structure to simulate.
architecture : Optional[str]
MLIP architecture to use for single point calculations.
Default is "mace_mp".
device : Optional[str]
Device to run model on. Default is "cpu".
properties : Optional[str]
Physical properties to calculate. Default is "energy".
read_kwargs : Optional[dict[str, Any]]
Keyword arguments to pass to ase.io.read. Default is {}.
calc_kwargs : Optional[dict[str, Any]]
Keyword arguments to pass to the selected calculator. Default is {}.
"""
read_kwargs = read_kwargs.value if read_kwargs else {}
calc_kwargs = calc_kwargs.value if calc_kwargs else {}

if not isinstance(read_kwargs, dict):
raise ValueError("read_kwargs must be a dictionary")
if not isinstance(calc_kwargs, dict):
raise ValueError("calc_kwargs must be a dictionary")

s_point = SinglePoint(
structure=structure,
architecture=architecture,
device=device,
read_kwargs=read_kwargs,
calc_kwargs=calc_kwargs,
)
print(s_point.run_single_point(properties=properties))


@app.command()
def test(name: str):
"""
Dummy alternative CLI command.
Parameters
----------
name : str
Name of person.
"""
print(f"Hello, {name}!")
4 changes: 2 additions & 2 deletions janus_core/mlip_calculators.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,15 @@ def choose_calculator(
from mace.calculators import mace_mp

kwargs.setdefault("default_dtype", "float64")
kwargs.setdefault("model", "small")
kwargs["model"] = kwargs.pop("model_paths", "small")
calculator = mace_mp(**kwargs)

elif architecture == "mace_off":
from mace import __version__
from mace.calculators import mace_off

kwargs.setdefault("default_dtype", "float64")
kwargs.setdefault("model", "small")
kwargs["model"] = kwargs.pop("model_paths", "small")
calculator = mace_off(**kwargs)

elif architecture == "m3gnet":
Expand Down
Loading

0 comments on commit f32befc

Please sign in to comment.