From c5f747b59c353bc62b4ed90e5a2b571089d0428e Mon Sep 17 00:00:00 2001 From: Ivan Kondov <ivan.kondov@kit.edu> Date: Sat, 18 Jan 2025 14:27:06 +0100 Subject: [PATCH 1/3] add a second parameter to "view structure" to display constraints --- src/virtmat/language/constraints/amml.py | 27 +++++++++++++++++++ .../language/constraints/processors.py | 2 ++ src/virtmat/language/constraints/view.py | 17 ++++++++++++ src/virtmat/language/utilities/ase_viewers.py | 7 ++++- 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 src/virtmat/language/constraints/view.py diff --git a/src/virtmat/language/constraints/amml.py b/src/virtmat/language/constraints/amml.py index d0f96ba8..9bb89d57 100644 --- a/src/virtmat/language/constraints/amml.py +++ b/src/virtmat/language/constraints/amml.py @@ -1,7 +1,9 @@ """checks / constraints for AMML objects""" from textx import get_children_of_type +from virtmat.language.utilities.errors import StaticTypeError from virtmat.language.utilities.errors import raise_exception, StaticValueError from virtmat.language.utilities.textx import get_reference +from virtmat.language.utilities.typemap import typemap from virtmat.language.utilities.ase_params import spec task_properties = { @@ -44,3 +46,28 @@ def check_amml_property_processor(model, _): if not algo and calc_task and name not in task_properties[calc_task]: msg = f'property \"{name}\" not available in task \"{calc_task}\"' raise_exception(obj, StaticValueError, msg) + + +def check_view_amml_structure_processor(model, _): + """check the parameters of view structure statements""" + for obj in get_children_of_type('View', model): + if obj.mode != 'structure': + continue + if len(obj.params) > 2: + msg = f'view structure has maximum 2 parameters but {len(obj.params)} given' + raise_exception(obj, StaticTypeError, msg) + if obj.params[0].type_: + if not issubclass(obj.params[0].type_, typemap['AMMLStructure']): + msg = (f'parameter must be type {typemap["AMMLStructure"].__name__}' + f' but is type {obj.params[0].type_.__name__}') + raise_exception(obj.params[0], StaticTypeError, msg) + if len(obj.params) == 2: + if obj.params[1].type_: + if not issubclass(obj.params[1].type_, typemap['Tuple']): + msg = 'parameter must be Tuple of constraints' + raise_exception(obj.params[1], StaticTypeError, msg) + for type_ in obj.params[1].type_.datatype: + if type_ and not issubclass(type_, typemap['AMMLConstraint']): + msg = (f'parameter must be type {typemap["AMMLConstraint"].__name__}' + f' but is type {type_.__name__}') + raise_exception(obj.params[1], StaticTypeError, msg) diff --git a/src/virtmat/language/constraints/processors.py b/src/virtmat/language/constraints/processors.py index c5f5c85a..ae2931b2 100644 --- a/src/virtmat/language/constraints/processors.py +++ b/src/virtmat/language/constraints/processors.py @@ -20,6 +20,7 @@ from .functions import check_functions_processor from .imports import check_imports_processor from .units import check_units_processor from .parallel import check_parallelizable_processor +from .view import check_view_processor from .amml import check_amml_property_processor from .chem import check_chem_reaction_processor @@ -122,5 +123,6 @@ def add_constraints_processors(metamodel): metamodel.register_model_processor(check_parallelizable_processor) metamodel.register_model_processor(check_vary_processor) metamodel.register_model_processor(check_tag_processor) + metamodel.register_model_processor(check_view_processor) metamodel.register_model_processor(check_amml_property_processor) metamodel.register_model_processor(check_chem_reaction_processor) diff --git a/src/virtmat/language/constraints/view.py b/src/virtmat/language/constraints/view.py new file mode 100644 index 00000000..7844cb96 --- /dev/null +++ b/src/virtmat/language/constraints/view.py @@ -0,0 +1,17 @@ +"""apply constraints for all view statements""" +from virtmat.language.utilities.errors import textxerror_wrap +from .amml import check_view_amml_structure_processor + + +@textxerror_wrap +def check_view_processor(model, metamodel): + """apply constraints for all view statements""" + # check_view_lineplot_processor(model, metamodel) + # check_view_scatterplot_processor(model, metamodel) + check_view_amml_structure_processor(model, metamodel) + # check_view_amml_trajectory_processor(model, metamodel) + # check_view_amml_vibration_processor(model, metamodel) + # check_view_amml_neb_processor(model, metamodel) + # check_view_amml_bs_processor(model, metamodel) + # check_view_amml_eos_processor(model, metamodel) + # check_view_amml_waterfall_processor(model, metamodel) diff --git a/src/virtmat/language/utilities/ase_viewers.py b/src/virtmat/language/utilities/ase_viewers.py index f4d288b6..253bb9f1 100644 --- a/src/virtmat/language/utilities/ase_viewers.py +++ b/src/virtmat/language/utilities/ase_viewers.py @@ -24,7 +24,12 @@ def show_atoms(atoms, show=True): def display_amml_structure(obj, show=True): """display an atomic structure using ASE""" - show_atoms(obj.params[0].value.to_ase(), show=show) + atoms_lst = obj.params[0].value.to_ase() + if len(obj.params) == 2: + constraints = [c for cs in obj.params[1].value for c in cs.to_ase()] + for atoms_obj in atoms_lst: + atoms_obj.constraints = constraints + show_atoms(atoms_lst, show=show) def display_amml_trajectory(obj, show=True): -- GitLab From 95e0657eeeb2155d0f769db19dd101fada8b5b85 Mon Sep 17 00:00:00 2001 From: Ivan Kondov <ivan.kondov@kit.edu> Date: Sat, 18 Jan 2025 16:52:12 +0100 Subject: [PATCH 2/3] add tests for view structure type checks --- tests/test_amml.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/test_amml.py b/tests/test_amml.py index f0aef064..27e97488 100644 --- a/tests/test_amml.py +++ b/tests/test_amml.py @@ -754,6 +754,52 @@ def test_view_amml_structure(meta_model, model_kwargs_no_display): assert meta_model.model_from_str(inp, **model_kwargs_no_display).value == '' +def test_view_amml_structure_with_constraints(meta_model, model_kwargs_no_display): + """test view atomic structure with constraints""" + inp = ("h = Structure H ((atoms: ((symbols: 'H'), (x: 0.) [angstrom]," + " (y: 0.) [angstrom], (z: 0.) [angstrom])));" + "view structure (h, (FixedAtoms where (fixed: true),))") + assert meta_model.model_from_str(inp, **model_kwargs_no_display).value == '' + + +def test_view_amml_structure_wrong_par_len(meta_model, model_kwargs_no_display): + """test view atomic structure with wrong number of parameters""" + inp = 'view structure (1, 2, 3)' + msg = 'view structure has maximum 2 parameters but 3 given' + with pytest.raises(TextXError, match=msg) as err: + meta_model.model_from_str(inp, **model_kwargs_no_display) + assert isinstance(err.value.__cause__, StaticTypeError) + + +def test_view_amml_structure_wrong_first_par(meta_model, model_kwargs_no_display): + """test view atomic structure with wrong first parameter""" + inp = 'view structure (1, )' + msg = 'parameter must be type AMMLStructure but is type Quantity' + with pytest.raises(TextXError, match=msg) as err: + meta_model.model_from_str(inp, **model_kwargs_no_display) + assert isinstance(err.value.__cause__, StaticTypeError) + + +def test_view_amml_structure_wrong_second_par(meta_model, model_kwargs_no_display): + """test view atomic structure with wrong type of second parameter""" + inp = ("h = Structure H ((atoms: ((symbols: 'H'), (x: 0.) [angstrom]," + " (y: 0.) [angstrom], (z: 0.) [angstrom]))); view structure (h, 1)") + msg = 'parameter must be Tuple of constraints' + with pytest.raises(TextXError, match=msg) as err: + meta_model.model_from_str(inp, **model_kwargs_no_display) + assert isinstance(err.value.__cause__, StaticTypeError) + + +def test_view_amml_structure_wrong_second_par_type(meta_model, model_kwargs_no_display): + """test view atomic structure with a wrong type in second parameter""" + inp = ("h = Structure H ((atoms: ((symbols: 'H'), (x: 0.) [angstrom]," + " (y: 0.) [angstrom], (z: 0.) [angstrom]))); view structure (h, (1,))") + msg = 'parameter must be type Constraint but is type Quantity' + with pytest.raises(TextXError, match=msg) as err: + meta_model.model_from_str(inp, **model_kwargs_no_display) + assert isinstance(err.value.__cause__, StaticTypeError) + + def test_view_equation_of_state(meta_model, model_kwargs_no_display): """test view equation of state""" inp = ("atoms = ((symbols: 'Ag'), (x: 0.) [angstrom], (y: 0.) [angstrom]," -- GitLab From fa88433b78dbe34a49eb6da4da276af584d80510 Mon Sep 17 00:00:00 2001 From: Ivan Kondov <ivan.kondov@kit.edu> Date: Sat, 18 Jan 2025 16:42:19 +0000 Subject: [PATCH 3/3] add the optional constraints to view structure docs --- docs/amml.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/amml.md b/docs/amml.md index 21864c05..9ea6a7f6 100644 --- a/docs/amml.md +++ b/docs/amml.md @@ -517,10 +517,10 @@ The [`view` statement](scl.md#the-view-statement) can be used to visualize and a ### Visualize / analyze atomic structures -Parameters of type [AMML Structure](amml.md#structure) can be viewed using this simple syntax: +Parameters of type [AMML Structure](amml.md#structure) with optional geometry constraints can be viewed using this syntax: ``` -view structure (struct) +view structure (struct, [(constr1, [[constr2], ...])]) ``` ### Visualize a trajectory -- GitLab