diff --git a/docs/api.md b/docs/api.md index f9870bf..c6cc141 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,9 +1,9 @@ ::: qcmanybody.ManyBodyCalculator -::: qcmanybody.qcng_computer.ManyBodyComputerQCNG +::: qcmanybody.qcng_computer.ManyBodyComputer options: show_root_heading: true inherited_members: true members: true -$pydantic: qcmanybody.qcng_computer.ManyBodyComputerQCNG +$pydantic: qcmanybody.qcng_computer.ManyBodyComputer diff --git a/docs/changelog.md b/docs/changelog.md index fd4c927..7462e9c 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -19,6 +19,14 @@ --> +## v0.2.1 / 2024-05-14 + +#### Enhancements + +* [\#27](https://github.com/MolSSI/QCManyBody/pull/27) Intf -- move high-level interface from + `qcmb.qcng_computer.ManyBodyComputerQCNG` to `qcmb.computer.ManyBodyComputer`. Suppressed remaining printing. @loriab + + ## v0.2.0 / 2024-05-13 #### New Features diff --git a/docs/extensions/mdantic_v1/mdantic.py b/docs/extensions/mdantic_v1/mdantic.py index 6406476..6a34358 100644 --- a/docs/extensions/mdantic_v1/mdantic.py +++ b/docs/extensions/mdantic_v1/mdantic.py @@ -6,7 +6,10 @@ from typing import List, Dict, Optional import tabulate -from pydantic.v1 import BaseModel +try: + from pydantic.v1 import BaseModel +except ModuleNotFoundError: + from pydantic import BaseModel from markdown import Markdown from markdown.extensions import Extension from markdown.preprocessors import Preprocessor diff --git a/mkdocs.yml b/mkdocs.yml index 1671605..1498774 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -34,6 +34,7 @@ extra_css: plugins: - search +- autorefs - mkdocstrings: default_handler: python enable_inventory: true diff --git a/qcmanybody/qcng_computer.py b/qcmanybody/computer.py similarity index 96% rename from qcmanybody/qcng_computer.py rename to qcmanybody/computer.py index 2fcfb20..01ffe19 100644 --- a/qcmanybody/qcng_computer.py +++ b/qcmanybody/computer.py @@ -51,7 +51,7 @@ class Config: allow_mutation = True -class AtomicComputerQCNG(BaseComputerQCNG): +class AtomicComputer(BaseComputerQCNG): """Computer for analytic single-geometry computations.""" molecule: Molecule = Field(..., description="The molecule to use in the computation.") @@ -130,7 +130,7 @@ def get_results(self, client: Optional["qcportal.FractalClient"] = None) -> Atom return self.result -class ManyBodyComputerQCNG(BaseComputerQCNG): +class ManyBodyComputer(BaseComputerQCNG): input_data: ManyBodyInput = Field( ..., @@ -221,13 +221,13 @@ def set_bsse_type(cls, v: Any) -> List[BsseEnum]: @classmethod # v2: def set_embedding_charges(cls, v: Any, info: FieldValidationInfo) -> Dict[int, List[float]]: def set_embedding_charges(cls, v, values): # -> Dict[int, List[float]]: - print(f"hit embedding_charges validator with {v}", end="") + # print(f"hit embedding_charges validator with {v}", end="") nfr = len(values["molecule"].fragments) # v2: if len(v) != info.data["nfragments"]: if v and len(v) != nfr: raise ValueError(f"embedding_charges dict should have entries for each 1-indexed fragment ({nfr})") - print(f" ... setting embedding_charges={v}") + # print(f" ... setting embedding_charges={v}") return v # v2: @field_validator("return_total_data") @@ -235,7 +235,7 @@ def set_embedding_charges(cls, v, values): # -> Dict[int, List[float]]: @classmethod # v2: def set_return_total_data(cls, v: Optional[bool], info: FieldValidationInfo) -> bool: def set_return_total_data(cls, v: Optional[bool], values) -> bool: - print(f"hit return_total_data validator with {v}", end="") + # print(f"hit return_total_data validator with {v}", end="") if v is not None: rtd = v # v2: elif info.data["driver"] in ["gradient", "hessian"]: @@ -248,7 +248,7 @@ def set_return_total_data(cls, v: Optional[bool], values) -> bool: if values.get("embedding_charges", False) and rtd is False: raise ValueError("Cannot return interaction data when using embedding scheme.") - print(f" ... setting rtd={rtd}") + # print(f" ... setting rtd={rtd}") return rtd # v2: @field_validator("levels") @@ -256,7 +256,7 @@ def set_return_total_data(cls, v: Optional[bool], values) -> bool: @classmethod # v2: def set_levels(cls, v: Any, info: FieldValidationInfo) -> Dict[Union[int, Literal["supersystem"]], str]: def set_levels(cls, v: Any, values) -> Dict[Union[int, Literal["supersystem"]], str]: - print(f"hit levels validator with {v}", end="") + # print(f"hit levels validator with {v}", end="") if v is None: pass @@ -269,7 +269,7 @@ def set_levels(cls, v: Any, values) -> Dict[Union[int, Literal["supersystem"]], # rearrange bodies in order with supersystem last lest body count fail in organization loop below v = dict(sorted(v.items(), key=lambda item: 1000 if item[0] == "supersystem" else item[0])) - print(f" ... setting levels={v}") + # print(f" ... setting levels={v}") return v # TODO @computed_field( @@ -285,7 +285,7 @@ def set_levels(cls, v: Any, values) -> Dict[Union[int, Literal["supersystem"]], #}, @property def nbodies_per_mc_level(self) -> List[List[Union[int, Literal["supersystem"]]]]: - print(f"hit nbodies_per_mc_level", end="") + # print(f"hit nbodies_per_mc_level", end="") # Organize nbody calculations into modelchem levels # * expand keys of `levels` into full lists of nbodies covered. save to plan, resetting max_nbody accordingly @@ -304,7 +304,7 @@ def nbodies_per_mc_level(self) -> List[List[Union[int, Literal["supersystem"]]]] nbodies_per_mc_level.append(nbodies) prev_body = nb # formerly buggy `+= 1` - print(f" ... setting nbodies_per_mc_level={nbodies_per_mc_level}") + # print(f" ... setting nbodies_per_mc_level={nbodies_per_mc_level}") return nbodies_per_mc_level # v2: @field_validator("max_nbody") @@ -312,12 +312,12 @@ def nbodies_per_mc_level(self) -> List[List[Union[int, Literal["supersystem"]]]] @classmethod # v2: def set_max_nbody(cls, v: Any, info: FieldValidationInfo) -> int: def set_max_nbody(cls, v: Any, values) -> int: - print(f"hit max_nbody validator with {v}", end="") + # print(f"hit max_nbody validator with {v}", end="") # v2: levels_max_nbody = max(nb for nb in info.data["levels"] if nb != "supersystem") # v2: nfr = len(info.data["molecule"].fragments) levels_max_nbody = max(nb for nb in values["levels"] if nb != "supersystem") nfr = len(values["molecule"].fragments) - print(f" {levels_max_nbody=} {nfr=}", end="") + # print(f" {levels_max_nbody=} {nfr=}", end="") #ALT if v == -1: if v is None: @@ -333,7 +333,7 @@ def set_max_nbody(cls, v: Any, values) -> int: pass # TODO once was return min(v, nfragments) - print(f" ... setting max_nbody={v}") + # print(f" ... setting max_nbody={v}") return v # levels max_nbody F-levels F-max_nbody result @@ -350,7 +350,7 @@ def set_max_nbody(cls, v: Any, values) -> int: @classmethod # v2: def set_supersystem_ie_only(cls, v: Optional[bool], info: FieldValidationInfo) -> bool: def set_supersystem_ie_only(cls, v: Optional[bool], values) -> bool: - print(f"hit supersystem_ie_only validator with {v}", end="") + # print(f"hit supersystem_ie_only validator with {v}", end="") sio = v # v2: _nfr = len(info.data["molecule"].fragments) _nfr = len(values["molecule"].fragments) @@ -364,7 +364,7 @@ def set_supersystem_ie_only(cls, v: Optional[bool], values) -> bool: if (sio is True) and ("vmfc" in values["bsse_type"]): raise ValueError(f"Cannot skip intermediate n-body jobs when VMFC in bsse_type={values['bsse_type']}. Use CP instead.") - print(f" ... setting {sio=}") + # print(f" ... setting {sio=}") return sio @classmethod @@ -432,7 +432,7 @@ def from_manybodyinput(cls, input_model: ManyBodyInput, build_tasks: bool = True component_results[label] = result if not result.success: - print(result.error.error_message) + # print(result.error.error_message) raise RuntimeError("Calculation did not succeed! Error:\n" + result.error.error_message) # pull out stuff diff --git a/qcmanybody/models/manybody_input_pydv1.py b/qcmanybody/models/manybody_input_pydv1.py index 3bce1d3..4a5cb05 100644 --- a/qcmanybody/models/manybody_input_pydv1.py +++ b/qcmanybody/models/manybody_input_pydv1.py @@ -171,14 +171,14 @@ class ManyBodyKeywords(ProtoModel): # definitive description description="Target the supersystem total/interaction energy (IE) data over the many-body expansion (MBE) " "analysis, thereby omitting intermediate-body calculations. When False (default), compute each n-body level " - "in the MBE up through ``max_nbody``. When True (only allowed for ``max_nbody = nfragments``), only compute " + "in the MBE up through ``max_nbody``. When True (only allowed for ``max_nbody = nfragments`` ), only compute " "enough for the overall interaction/total energy: max_nbody-body and 1-body. When True, properties " - "``INTERACTION {driver} THROUGH {max_nbody}-BODY`` will always be available; ``TOTAL {driver} THROUGH " - "{max_nbody}-BODY`` will be available depending on ``return_total_data``; and ``{max_nbody}-BODY " - "CONTRIBUTION TO {driver}`` won't be available (except for dimers). This keyword produces no savings for a " - "two-fragment molecule. But for the interaction energy of a three-fragment molecule, for example, 2-body " - "subsystems can be skipped with ``supersystem_ie_only=True`` Do not use with ``vmfc`` in ``bsse_type``" - "as it cannot produce savings." + "``INTERACTION {driver} THROUGH {max_nbody}-BODY`` will always be available; " + "``TOTAL {driver} THROUGH {max_nbody}-BODY`` will be available depending on ``return_total_data`` ; and " + "``{max_nbody}-BODY CONTRIBUTION TO {driver}`` won't be available (except for dimers). This keyword produces " + "no savings for a two-fragment molecule. But for the interaction energy of a three-fragment molecule, for " + "example, 2-body subsystems can be skipped with ``supersystem_ie_only=True``. Do not use with ``vmfc`` in " + "``bsse_type`` as it cannot produce savings.", ) # v2: @field_validator("bsse_type", mode="before") @@ -201,7 +201,7 @@ class ManyBodySpecification(ProtoModel): schema_name: Literal["qcschema_manybodyspecification"] = "qcschema_manybodyspecification" #provenance: Provenance = Field(Provenance(**provenance_stamp(__name__)), description=Provenance.__doc__) keywords: ManyBodyKeywords = Field(..., description=ManyBodyKeywords.__doc__) - #program: str = Field(..., description="The program for which the Specification is intended.") + #program: str = Field(..., description="The program for which the Specification is intended.") # TODO is qcmanybody protocols: ManyBodyProtocols = Field(ManyBodyProtocols(), description=str(ManyBodyProtocols.__doc__)) driver: DriverEnum = Field( ..., diff --git a/qcmanybody/tests/test_mbe_he4_multilevel.py b/qcmanybody/tests/test_mbe_he4_multilevel.py index 3d123a4..9999c8a 100644 --- a/qcmanybody/tests/test_mbe_he4_multilevel.py +++ b/qcmanybody/tests/test_mbe_he4_multilevel.py @@ -10,9 +10,8 @@ from qcelemental.testing import compare_values, compare_recursive from qcmanybody.models import AtomicSpecification, ManyBodyKeywords, ManyBodyInput -from qcmanybody.qcng_computer import ManyBodyComputerQCNG, qcvars_to_manybodyproperties +from qcmanybody.computer import ManyBodyComputer, qcvars_to_manybodyproperties -import qcengine as qcng from .addons import using from .test_mbe_he4_singlelevel import sumdict as sumdict_single @@ -726,7 +725,7 @@ def test_nbody_he4_multi(levels, mbe_keywords, anskey, bodykeys, outstrs, calcin mbe_model = ManyBodyInput(**mbe_data_multilevel_631g) # qcng: ret = qcng.compute_procedure(mbe_model, "manybody", raise_error=True) - ret = ManyBodyComputerQCNG.from_manybodyinput(mbe_model) + ret = ManyBodyComputer.from_manybodyinput(mbe_model) print(f"MMMMMMM {request.node.name}") pprint.pprint(ret.dict(), width=200) @@ -819,7 +818,7 @@ def test_nbody_he4_supersys(levels, mbe_keywords, anskey, bodykeys, outstrs, cal mbe_model = ManyBodyInput(**mbe_data_multilevel_631g) # qcng: ret = qcng.compute_procedure(mbe_model, "manybody", raise_error=True) - ret = ManyBodyComputerQCNG.from_manybodyinput(mbe_model) + ret = ManyBodyComputer.from_manybodyinput(mbe_model) print(f"MMMMMMM {request.node.name}") pprint.pprint(ret.dict(), width=200) @@ -896,7 +895,7 @@ def test_count_he4_multi(mbe_keywords, ref_count, he_tetramer, request): atomic_spec = AtomicSpecification(model={"method": "mp2", "basis": "mybas"}, program="myqc", driver="energy") mbe_model = ManyBodyInput(specification={"specification": atomic_spec, "keywords": mbe_keywords, "driver": "energy"}, molecule=he_tetramer) - ret = ManyBodyComputerQCNG.from_manybodyinput(mbe_model, build_tasks=False) + ret = ManyBodyComputer.from_manybodyinput(mbe_model, build_tasks=False) ret = ret.qcmb_calculator text, dcount = ret.format_calc_plan() diff --git a/qcmanybody/tests/test_mbe_he4_singlelevel.py b/qcmanybody/tests/test_mbe_he4_singlelevel.py index 4e0b653..a74c8a3 100644 --- a/qcmanybody/tests/test_mbe_he4_singlelevel.py +++ b/qcmanybody/tests/test_mbe_he4_singlelevel.py @@ -9,9 +9,8 @@ from qcelemental.testing import compare_values, compare_recursive from qcmanybody.models import AtomicSpecification, ManyBodyKeywords, ManyBodyInput -from qcmanybody.qcng_computer import ManyBodyComputerQCNG, qcvars_to_manybodyproperties +from qcmanybody.computer import ManyBodyComputer, qcvars_to_manybodyproperties -import qcengine as qcng from .addons import using def skprop(qcvar): @@ -625,7 +624,7 @@ def test_nbody_he4_single(program, basis, keywords, mbe_keywords, anskey, bodyke mbe_model = ManyBodyInput(specification={"specification": atomic_spec, "keywords": mbe_keywords, "driver": "energy", "protocols": {"component_results": "all"}}, molecule=he_tetramer) # qcng: ret = qcng.compute_procedure(mbe_model, "manybody", raise_error=True) - ret = ManyBodyComputerQCNG.from_manybodyinput(mbe_model) + ret = ManyBodyComputer.from_manybodyinput(mbe_model) print(f"SSSSSSS {request.node.name}") # v2: pprint.pprint(ret.model_dump(), width=200) pprint.pprint(ret.dict(), width=200) @@ -712,7 +711,7 @@ def test_count_he4_single(mbe_keywords, ref_count, he_tetramer): atomic_spec = AtomicSpecification(model={"method": "mp2", "basis": "mybas"}, program="myqc", driver="energy") mbe_model = ManyBodyInput(specification={"specification": atomic_spec, "keywords": mbe_keywords, "driver": "energy"}, molecule=he_tetramer) - ret = ManyBodyComputerQCNG.from_manybodyinput(mbe_model, build_tasks=False) + ret = ManyBodyComputer.from_manybodyinput(mbe_model, build_tasks=False) ret = ret.qcmb_calculator text, dcount = ret.format_calc_plan() diff --git a/qcmanybody/tests/test_mbe_het4_grad.py b/qcmanybody/tests/test_mbe_het4_grad.py index 94dc543..76917be 100644 --- a/qcmanybody/tests/test_mbe_het4_grad.py +++ b/qcmanybody/tests/test_mbe_het4_grad.py @@ -8,7 +8,7 @@ from qcelemental.testing import compare_values from qcmanybody.models import ManyBodyKeywords, ManyBodyInput -from qcmanybody.qcng_computer import ManyBodyComputerQCNG, qcvars_to_manybodyproperties +from qcmanybody.computer import ManyBodyComputer, qcvars_to_manybodyproperties from .addons import uusing @@ -258,7 +258,7 @@ def test_nbody_het4_grad(mbe_keywords, anskeyE, anskeyG, bodykeys, outstrs, calc mbe_model = ManyBodyInput(**mbe_data_grad_dtz) # qcng: ret = qcng.compute_procedure(mbe_model, "manybody", raise_error=True) - ret = ManyBodyComputerQCNG.from_manybodyinput(mbe_model) + ret = ManyBodyComputer.from_manybodyinput(mbe_model) print(f"MMMMMMM {request.node.name}") pprint.pprint(ret.dict(), width=200) diff --git a/qcmanybody/tests/test_mbe_keywords.py b/qcmanybody/tests/test_mbe_keywords.py index 184ab9f..33011de 100644 --- a/qcmanybody/tests/test_mbe_keywords.py +++ b/qcmanybody/tests/test_mbe_keywords.py @@ -12,10 +12,8 @@ from qcelemental.models import DriverEnum, Molecule from qcmanybody.models import BsseEnum, ManyBodyInput -import qcengine as qcng - -# qcng: from qcengine.procedures.manybody import ManyBodyComputerQCNG -from qcmanybody.qcng_computer import ManyBodyComputerQCNG +# qcng: from qcengine.procedures.manybody import ManyBodyComputer +from qcmanybody.computer import ManyBodyComputer from qcmanybody import ManyBodyCalculator @@ -103,7 +101,7 @@ def test_mbe_rtd(mbe_data, driver, kws, ans): mbe_data["specification"]["keywords"] = kws input_model = ManyBodyInput(**mbe_data) - comp_model = ManyBodyComputerQCNG.from_manybodyinput(input_model, build_tasks=False) + comp_model = ManyBodyComputer.from_manybodyinput(input_model, build_tasks=False) assert comp_model.driver == driver assert comp_model.return_total_data == ans @@ -150,7 +148,7 @@ def test_mbe_level_bodies(mbe_data, kws, ans): mbe_data["specification"]["keywords"] = kws input_model = ManyBodyInput(**mbe_data) - comp_model = ManyBodyComputerQCNG.from_manybodyinput(input_model, build_tasks=False) + comp_model = ManyBodyComputer.from_manybodyinput(input_model, build_tasks=False) assert comp_model.nfragments == 3 assert comp_model.max_nbody == ans[0] @@ -178,7 +176,7 @@ def test_mbe_level_5mer(mbe_data, kws, ans): mbe_data["specification"]["keywords"] = kws input_model = ManyBodyInput(**mbe_data) - comp_model = ManyBodyComputerQCNG.from_manybodyinput(input_model, build_tasks=False) + comp_model = ManyBodyComputer.from_manybodyinput(input_model, build_tasks=False) assert comp_model.nfragments == 5 assert comp_model.max_nbody == ans[0] @@ -200,7 +198,7 @@ def test_mbe_level_fails(mbe_data, kws, errmsg): # v2: with pytest.raises(Exception): with pytest.raises(ValidationError) as e: input_model = ManyBodyInput(**mbe_data) - ManyBodyComputerQCNG.from_manybodyinput(input_model, build_tasks=False) + ManyBodyComputer.from_manybodyinput(input_model, build_tasks=False) assert errmsg in str(e.value), e.value @@ -230,7 +228,7 @@ def test_mbe_bsse_type(mbe_data, kws, ans): return input_model = ManyBodyInput(**mbe_data) - comp_model = ManyBodyComputerQCNG.from_manybodyinput(input_model, build_tasks=False) + comp_model = ManyBodyComputer.from_manybodyinput(input_model, build_tasks=False) assert comp_model.bsse_type == ans, f"{comp_model=} != {ans}" @@ -252,13 +250,13 @@ def test_mbe_sie(mbe_data, kws, ans): if isinstance(ans, str): input_model = ManyBodyInput(**mbe_data) with pytest.raises(ValidationError) as e: - ManyBodyComputerQCNG.from_manybodyinput(input_model, build_tasks=False) + ManyBodyComputer.from_manybodyinput(input_model, build_tasks=False) assert ans in str(e.value) return input_model = ManyBodyInput(**mbe_data) - comp_model = ManyBodyComputerQCNG.from_manybodyinput(input_model, build_tasks=False) + comp_model = ManyBodyComputer.from_manybodyinput(input_model, build_tasks=False) assert comp_model.supersystem_ie_only == ans