From b49991a1d5d3dd0e895b14549593e8c2581c0f85 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 19 Jun 2022 21:35:46 +0200 Subject: [PATCH 01/36] Add short descriptions to setter functions --- masci_tools/io/fleurxmlmodifier.py | 322 ++++++++++----------- masci_tools/util/xml/xml_setters_basic.py | 18 +- masci_tools/util/xml/xml_setters_names.py | 112 +++---- utils/write_fleurxmlmodifier_docstrings.py | 10 +- 4 files changed, 211 insertions(+), 251 deletions(-) diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index a973ce7dd..ed4436b57 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -412,11 +412,7 @@ def modify_xmlfile(self, return new_xmltree, additional_files def set_inpchanges(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_inpchanges()` to - the list of tasks that will be done on the xmltree. - - This method sets all the attribute and texts provided in the change_dict. + """Set the value of attributes/text occurring once in the XML tree The first occurrence of the attribute/tag is set @@ -431,6 +427,9 @@ def set_inpchanges(self, *args: Any, **kwargs: Any) -> None: 'ctail': False, 'l_ss': True } + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_inpchanges()` to + the list of tasks that will be done on the xmltree. """ if 'change_dict' in kwargs: warnings.warn('The argument change_dict is deprecated. Use changes instead', DeprecationWarning) @@ -439,11 +438,7 @@ def set_inpchanges(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('set_inpchanges', args, kwargs)) def shift_value(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value()` to - the list of tasks that will be done on the xmltree. - - Shifts numerical values of attributes directly in the inp.xml file. + """Add/Multiply values of attributes occurring once in the XML tree The first occurrence of the attribute is shifted @@ -457,6 +452,9 @@ def shift_value(self, *args: Any, **kwargs: Any) -> None: An example of changes:: changes = {'itmax' : 1, 'dVac': -0.123} + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value()` to + the list of tasks that will be done on the xmltree. """ if 'change_dict' in kwargs: warnings.warn('The argument change_dict is deprecated. Use changes instead', DeprecationWarning) @@ -465,11 +463,7 @@ def shift_value(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('shift_value', args, kwargs)) def set_species(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_species()` to - the list of tasks that will be done on the xmltree. - - Method to set parameters of a species tag of the fleur inp.xml file. + """Set the attributes of a species, specified by name position, etc. :param species_name: string, name of the specie you want to change Can be name of the species, 'all' or 'all-' (sets species with the string in the species name) @@ -497,6 +491,9 @@ def set_species(self, *args: Any, **kwargs: Any) -> None: ``energyParameters``, ``lo``, ``electronConfig``, ``nocoParams``, ``ldaU`` and ``special`` keys are supported. To find possible keys of the inner dictionary please refer to the FLEUR documentation flapw.de + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_species()` to + the list of tasks that will be done on the xmltree. """ if 'attributedict' in kwargs: warnings.warn('The argument attributedict is deprecated. Use changes instead', DeprecationWarning) @@ -505,9 +502,7 @@ def set_species(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('set_species', args, kwargs)) def set_species_label(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_species_label()` to - the list of tasks that will be done on the xmltree. + """Set the attributes of a species, given by an atom label occurring in it's atom type This method calls :func:`~masci_tools.util.xml.xml_setters_names.set_species()` method for a certain atom species that corresponds to an atom with a given label @@ -515,6 +510,9 @@ def set_species_label(self, *args: Any, **kwargs: Any) -> None: :param atom_label: string, a label of the atom which specie will be changed. 'all' to change all the species :param changes: a python dict specifying what you want to change. :param create: bool, if species does not exist create it and all subtags? + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_species_label()` to + the list of tasks that will be done on the xmltree. """ if 'attributedict' in kwargs: warnings.warn('The argument attributedict is deprecated. Use changes instead', DeprecationWarning) @@ -523,11 +521,7 @@ def set_species_label(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('set_species_label', args, kwargs)) def clone_species(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.clone_species()` to - the list of tasks that will be done on the xmltree. - - Method to create a new species from an existing one with evtl. modifications + """Clone (and possibly change) a species in the XML tree For reference of the changes dictionary look at :py:func:`set_species()` @@ -535,16 +529,15 @@ def clone_species(self, *args: Any, **kwargs: Any) -> None: Has to correspond to one single species (no 'all'/'all-') :param new_name: new name of the cloned species :param changes: a optional python dict specifying what you want to change. + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.clone_species()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('clone_species', args, kwargs) self._tasks.append(ModifierTask('clone_species', args, kwargs)) def switch_species(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species()` to - the list of tasks that will be done on the xmltree. - - Method to switch the species of an atom group of the fleur inp.xml file. + """Change the species of an atom group, identified by species name, position, etc. :param new_species_name: name of the species to switch to :param position: position of an atom group to be changed. If equals to 'all', all species will be changed @@ -554,32 +547,30 @@ def switch_species(self, *args: Any, **kwargs: Any) -> None: :param changes: changes to do if the species is cloned :param filters: Dict specifying constraints to apply on the xpath. See :py:class:`~masci_tools.util.xml.xpathbuilder.XPathBuilder` for details + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('switch_species', args, kwargs) self._tasks.append(ModifierTask('switch_species', args, kwargs)) def switch_species_label(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species_label()` to - the list of tasks that will be done on the xmltree. - - Method to switch the species of an atom group of the fleur inp.xml file based on a label - of a contained atom + """Change the species of an atom group, identified by the lable of an atom in it's group :param atom_label: string, a label of the atom which group will be changed. 'all' to change all the groups :param new_species_name: name of the species to switch to :param clone: if True and the new species name does not exist and it corresponds to changing from one species the species will be cloned with :py:func:`clone_species()` :param changes: changes to do if the species is cloned + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species_label()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('switch_species_label', args, kwargs) self._tasks.append(ModifierTask('switch_species_label', args, kwargs)) def shift_value_species_label(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value_species_label()` to - the list of tasks that will be done on the xmltree. - + """Add/Multiply numeric attributes in a or multiple atom species Shifts the value of an attribute on a species by label if atom_label contains 'all' then applies to all species @@ -593,6 +584,9 @@ def shift_value_species_label(self, *args: Any, **kwargs: Any) -> None: Kwargs if the attribute_name does not correspond to a unique path: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value_species_label()` to + the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: warnings.warn('The argument attributename is deprecated. Use attribute_name instead', DeprecationWarning) @@ -604,11 +598,7 @@ def shift_value_species_label(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('shift_value_species_label', args, kwargs)) def set_atomgroup(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` to - the list of tasks that will be done on the xmltree. - - Method to set parameters of an atom group of the fleur inp.xml file. + """Set the attributes of a atom group, specified by species name, position, etc. :param changes: a python dict specifying what you want to change. :param position: position of an atom group to be changed. If equals to 'all', all species will be changed @@ -622,6 +612,9 @@ def set_atomgroup(self, *args: Any, **kwargs: Any) -> None: can be done via:: 'changes': {'nocoParams': {'beta': val}} + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` to + the list of tasks that will be done on the xmltree. """ if 'attributedict' in kwargs: warnings.warn('The argument attributedict is deprecated. Use changes instead', DeprecationWarning) @@ -633,11 +626,9 @@ def set_atomgroup(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('set_atomgroup', args, kwargs)) def set_atomgroup_label(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup_label()` to - the list of tasks that will be done on the xmltree. + """Set the attributes of a atom group, given by an atom label occuring in it's definition - This method calls :func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` + This method calls :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` method for a certain atom species that corresponds to an atom with a given label. :param atom_label: string, a label of the atom which specie will be changed. 'all' to change all the species @@ -649,6 +640,9 @@ def set_atomgroup_label(self, *args: Any, **kwargs: Any) -> None: can be done via:: 'changes': {'nocoParams': {'beta': val}} + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup_label()` to + the list of tasks that will be done on the xmltree. """ if 'attributedict' in kwargs: warnings.warn('The argument attributedict is deprecated. Use changes instead', DeprecationWarning) @@ -660,15 +654,16 @@ def set_atomgroup_label(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('set_atomgroup_label', args, kwargs)) def create_tag(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.create_tag()` to - the list of tasks that will be done on the xmltree. - + """Create a tag with a given name in the XML tree This method creates a tag with a uniquely identified xpath under the nodes of its parent. If there are no nodes evaluated the subtags can be created with `create_parents=True` The tag is always inserted in the correct place if a order is enforced by the schema + .. usage-example:: + + fm.create_tag('greensFunction') + :param tag: str of the tag to create or etree Element or string representing the XML element with the same name to insert :param complex_xpath: an optional xpath to use instead of the simple xpath for the evaluation :param filters: Dict specifying constraints to apply on the xpath. @@ -681,16 +676,15 @@ def create_tag(self, *args: Any, **kwargs: Any) -> None: Kwargs: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.create_tag()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('create_tag', args, kwargs) self._tasks.append(ModifierTask('create_tag', args, kwargs)) def delete_tag(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.delete_tag()` to - the list of tasks that will be done on the xmltree. - - This method deletes a tag with a uniquely identified xpath. + """Delete a tag with a given name from the XML tree :param tag: str of the tag to delete :param complex_xpath: an optional xpath to use instead of the simple xpath for the evaluation @@ -702,16 +696,15 @@ def delete_tag(self, *args: Any, **kwargs: Any) -> None: Kwargs: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.delete_tag()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('delete_tag', args, kwargs) self._tasks.append(ModifierTask('delete_tag', args, kwargs)) def delete_att(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.delete_att()` to - the list of tasks that will be done on the xmltree. - - This method deletes a attribute with a uniquely identified xpath. + """Delete an attribute with a given name from the XML tree :param name: str of the attribute to delete :param complex_xpath: an optional xpath to use instead of the simple xpath for the evaluation @@ -726,6 +719,9 @@ def delete_att(self, *args: Any, **kwargs: Any) -> None: :param not_contains: str, this string has to NOT be in the final path :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.delete_att()` to + the list of tasks that will be done on the xmltree. """ if 'attrib_name' in kwargs: warnings.warn('The argument attrib_name is deprecated. Use name instead', DeprecationWarning) @@ -734,11 +730,7 @@ def delete_att(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('delete_att', args, kwargs)) def replace_tag(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.replace_tag()` to - the list of tasks that will be done on the xmltree. - - This method deletes a tag with a uniquely identified xpath. + """Replace a tag with a given name with a different XML element :param tag: str of the tag to replace :param element: etree Element or string representing the XML element to replace the tag @@ -751,6 +743,9 @@ def replace_tag(self, *args: Any, **kwargs: Any) -> None: Kwargs: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.replace_tag()` to + the list of tasks that will be done on the xmltree. """ if 'newelement' in kwargs: warnings.warn('The argument newelement is deprecated. Use element instead', DeprecationWarning) @@ -759,9 +754,7 @@ def replace_tag(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('replace_tag', args, kwargs)) def set_complex_tag(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_complex_tag()` to - the list of tasks that will be done on the xmltree. + """Setattributes, text and subtags of a given tag in the XML tree Function to correctly set tags/attributes for a given tag. Goes through the attributedict and decides based on the schema_dict, how the corresponding @@ -787,16 +780,17 @@ def set_complex_tag(self, *args: Any, **kwargs: Any) -> None: Kwargs: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_complex_tag()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_complex_tag', args, kwargs) self._tasks.append(ModifierTask('set_complex_tag', args, kwargs)) def set_simple_tag(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_simple_tag()` to - the list of tasks that will be done on the xmltree. + """Sets one or multiple ``simple`` tag(s) (no subtags/text) in an xmltree. - Sets one or multiple `simple` tag(s) in an xmltree. A simple tag can only hold attributes and has no + A simple tag can only hold attributes and has no subtags. The tag is specified by its name and further specification If the tag can occur multiple times all existing tags are DELETED and new ones are written. If the tag only occurs once it will automatically be created if its missing. @@ -813,17 +807,17 @@ def set_simple_tag(self, *args: Any, **kwargs: Any) -> None: Kwargs: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_simple_tag()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_simple_tag', args, kwargs) self._tasks.append(ModifierTask('set_simple_tag', args, kwargs)) def set_text(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_text()` to - the list of tasks that will be done on the xmltree. + """Set the value of text of tags in the XML tree possibly occurring mutliple times - Sets the text on tags in a xmltree to a given value, specified by the name of the tag and - further specifications. By default the text will be set on all nodes returned for the specified xpath. + By default the text will be set on all nodes returned for the specified xpath. If there are no nodes under the specified xpath a tag can be created with `create=True`. The text values are converted automatically according to the types with :py:func:`~masci_tools.util.xml.converters.convert_to_xml()` if they @@ -840,17 +834,17 @@ def set_text(self, *args: Any, **kwargs: Any) -> None: Kwargs: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_text()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_text', args, kwargs) self._tasks.append(ModifierTask('set_text', args, kwargs)) def set_first_text(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_text()` to - the list of tasks that will be done on the xmltree. + """Set the value of text of the first occurrence of a tag in the XML tree - Sets the text the first occurrence of a tag in a xmltree to a given value, specified by the name of the tag and - further specifications. By default the text will be set on all nodes returned for the specified xpath. + By default the text will be set on all nodes returned for the specified xpath. If there are no nodes under the specified xpath a tag can be created with `create=True`. The text values are converted automatically according to the types with :py:func:`~masci_tools.util.xml.converters.convert_to_xml()` if they @@ -866,17 +860,16 @@ def set_first_text(self, *args: Any, **kwargs: Any) -> None: Kwargs: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_text()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_first_text', args, kwargs) self._tasks.append(ModifierTask('set_first_text', args, kwargs)) def set_attrib_value(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_attrib_value()` to - the list of tasks that will be done on the xmltree. + """Set the value of an attribute possibly occurring multiple times - Sets an attribute in a xmltree to a given value, specified by its name and further - specifications. If there are no nodes under the specified xpath a tag can be created with `create=True`. The attribute values are converted automatically according to the types of the attribute with :py:func:`~masci_tools.util.xml.converters.convert_to_xml()` if they @@ -896,6 +889,9 @@ def set_attrib_value(self, *args: Any, **kwargs: Any) -> None: :param not_contains: str, this string has to NOT be in the final path :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_attrib_value()` to + the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: warnings.warn('The argument attributename is deprecated. Use name instead', DeprecationWarning) @@ -907,12 +903,8 @@ def set_attrib_value(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('set_attrib_value', args, kwargs)) def set_first_attrib_value(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_attrib_value()` to - the list of tasks that will be done on the xmltree. + """Set the value of the first occurrence of an attribute - Sets the first occurrence of an attribute in a xmltree to a given value, specified by its name and further - specifications. If there are no nodes under the specified xpath a tag can be created with `create=True`. The attribute values are converted automatically according to the types of the attribute with :py:func:`~masci_tools.util.xml.converters.convert_to_xml()` if they @@ -931,6 +923,9 @@ def set_first_attrib_value(self, *args: Any, **kwargs: Any) -> None: :param not_contains: str, this string has to NOT be in the final path :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_attrib_value()` to + the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: warnings.warn('The argument attributename is deprecated. Use name instead', DeprecationWarning) @@ -942,13 +937,7 @@ def set_first_attrib_value(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('set_first_attrib_value', args, kwargs)) def add_number_to_attrib(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_attrib()` to - the list of tasks that will be done on the xmltree. - - Adds a given number to the attribute value in a xmltree specified by the name of the attribute - and optional further specification - If there are no nodes under the specified xpath an error is raised + """Add/Multiply values for multiple occurrences in the XML tree :param name: the attribute name to change :param number_to_add: number to add/multiply with the old attribute value @@ -966,6 +955,9 @@ def add_number_to_attrib(self, *args: Any, **kwargs: Any) -> None: :param not_contains: str, this string has to NOT be in the final path :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_attrib()` to + the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: warnings.warn('The argument attributename is deprecated. Use name instead', DeprecationWarning) @@ -977,13 +969,7 @@ def add_number_to_attrib(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('add_number_to_attrib', args, kwargs)) def add_number_to_first_attrib(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_first_attrib()` to - the list of tasks that will be done on the xmltree. - - Adds a given number to the first occurrence of an attribute value in a xmltree specified by the name of the attribute - and optional further specification - If there are no nodes under the specified xpath an error is raised + """Add/Multiply value for the first occurrences of an attribute in the XML tree :param name: the attribute name to change :param number_to_add: number to add/multiply with the old attribute value @@ -1000,6 +986,9 @@ def add_number_to_first_attrib(self, *args: Any, **kwargs: Any) -> None: :param not_contains: str, this string has to NOT be in the final path :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_first_attrib()` to + the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: warnings.warn('The argument attributename is deprecated. Use name instead', DeprecationWarning) @@ -1011,10 +1000,7 @@ def add_number_to_first_attrib(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('add_number_to_first_attrib', args, kwargs)) def xml_create_tag(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_create_tag()` to - the list of tasks that will be done on the xmltree. - + """Creates a tag under the given XPath This method evaluates an xpath expression and creates a tag in a xmltree under the returned nodes. If there are no nodes under the specified xpath an error is raised. @@ -1034,21 +1020,23 @@ def xml_create_tag(self, *args: Any, **kwargs: Any) -> None: :param several: bool, if True multiple tags od the given name are allowed :raises ValueError: If the insertion failed in any way (tag_order does not match, failed to insert, ...) + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_create_tag()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('xml_create_tag', args, kwargs) self._tasks.append(ModifierTask('xml_create_tag', args, kwargs)) def xml_replace_tag(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_replace_tag()` to - the list of tasks that will be done on the xmltree. - - Replace XML tags by a given tag on the given XML tree + """Replace XML tags under the XPath by a given tag :param xpath: a path to the tag to be replaced :param element: an Element or string representing the Element to replace the found tags with :param occurrences: int or list of int. Which occurrence of the parent nodes to create a tag. By default all nodes are used. + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_replace_tag()` to + the list of tasks that will be done on the xmltree. """ if 'newelement' in kwargs: warnings.warn('The argument newelement is deprecated. Use element instead', DeprecationWarning) @@ -1058,30 +1046,28 @@ def xml_replace_tag(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('xml_replace_tag', args, kwargs)) def xml_delete_tag(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_delete_tag()` to - the list of tasks that will be done on the xmltree. - - Deletes a tag in the XML tree. + """Deletes a tag under the XPath in the XML tree. :param xpath: a path to the tag to be deleted :param occurrences: int or list of int. Which occurrence of the parent nodes to create a tag. By default all nodes are used. + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_delete_tag()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('xml_delete_tag', args, kwargs) self._tasks.append(ModifierTask('xml_delete_tag', args, kwargs)) def xml_delete_att(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_delete_att()` to - the list of tasks that will be done on the xmltree. - - Deletes an attribute in the XML tree + """Deletes an attribute on the tags of the given XPath in the XML tree :param xpath: a path to the attribute to be deleted :param name: the name of an attribute to delete :param occurrences: int or list of int. Which occurrence of the parent nodes to create a tag. By default all nodes are used. + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_delete_att()` to + the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: warnings.warn('The argument attributename is deprecated. Use name instead', DeprecationWarning) @@ -1090,11 +1076,8 @@ def xml_delete_att(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('xml_delete_att', args, kwargs)) def xml_set_attrib_value_no_create(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_set_attrib_value_no_create()` to - the list of tasks that will be done on the xmltree. - - Sets an attribute in a xmltree to a given value. By default the attribute will be set + """Sets the value of an attribute under the XPath + By default the attribute will be set on all nodes returned for the specified xpath. :param xpath: a path where to set the attributes @@ -1103,6 +1086,9 @@ def xml_set_attrib_value_no_create(self, *args: Any, **kwargs: Any) -> None: :param occurrences: int or list of int. Which occurrence of the node to set. By default all are set. :raises ValueError: If the lengths of attribv or occurrences do not match number of nodes + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_set_attrib_value_no_create()` to + the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: warnings.warn('The argument attributename is deprecated. Use name instead', DeprecationWarning) @@ -1114,11 +1100,7 @@ def xml_set_attrib_value_no_create(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('xml_set_attrib_value_no_create', args, kwargs)) def xml_set_text_no_create(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_set_text_no_create()` to - the list of tasks that will be done on the xmltree. - - Sets the text of a tag in a xmltree to a given value. + """Sets the text of a tag under the XPath By default the text will be set on all nodes returned for the specified xpath. :param xpath: a path where to set the text @@ -1126,16 +1108,15 @@ def xml_set_text_no_create(self, *args: Any, **kwargs: Any) -> None: :param occurrences: int or list of int. Which occurrence of the node to set. By default all are set. :raises ValueError: If the lengths of text or occurrences do not match number of nodes + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_set_text_no_create()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('xml_set_text_no_create', args, kwargs) self._tasks.append(ModifierTask('xml_set_text_no_create', args, kwargs)) def set_nmmpmat(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.set_nmmpmat()` to - the list of tasks that will be done on the xmltree. - - Routine sets the block in the n_mmp_mat file specified by species_name, orbital and spin + """Routine sets the block in the n_mmp_mat file specified by species_name, orbital and spin to the desired density matrix :param species_name: string, name of the species you want to change @@ -1151,16 +1132,15 @@ def set_nmmpmat(self, *args: Any, **kwargs: Any) -> None: :raises ValueError: If something in the input is wrong :raises KeyError: If no LDA+U procedure is found on a species + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.set_nmmpmat()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_nmmpmat', args, kwargs) self._tasks.append(ModifierTask('set_nmmpmat', args, kwargs)) def rotate_nmmpmat(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.rotate_nmmpmat()` to - the list of tasks that will be done on the xmltree. - - Rotate the density matrix with the given angles phi and theta + """Rotate the density matrix with the given angles phi and theta :param species_name: string, name of the species you want to change :param orbital: integer or string ('all'), orbital quantum number of the LDA+U procedure to be modified @@ -1171,16 +1151,15 @@ def rotate_nmmpmat(self, *args: Any, **kwargs: Any) -> None: :raises ValueError: If something in the input is wrong :raises KeyError: If no LDA+U procedure is found on a species + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.rotate_nmmpmat()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('rotate_nmmpmat', args, kwargs) self._tasks.append(ModifierTask('rotate_nmmpmat', args, kwargs)) def align_nmmpmat_to_sqa(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.align_nmmpmat_to_sqa()` to - the list of tasks that will be done on the xmltree. - - Align the density matrix with the given SQA of the associated species + """Align the density matrix with the given SQA of the associated species :param species_name: string, name of the species you want to change :param orbital: integer or string ('all'), orbital quantum number of the LDA+U procedure to be modified @@ -1193,17 +1172,18 @@ def align_nmmpmat_to_sqa(self, *args: Any, **kwargs: Any) -> None: :raises ValueError: If something in the input is wrong :raises KeyError: If no LDA+U procedure is found on a species + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.align_nmmpmat_to_sqa()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('align_nmmpmat_to_sqa', args, kwargs) self._tasks.append(ModifierTask('align_nmmpmat_to_sqa', args, kwargs)) def set_kpointlist(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointlist()` to - the list of tasks that will be done on the xmltree. + """Create a k-point list with the given points and weights - Explicitly create a kPointList from the given kpoints and weights. This routine will add the - specified kPointList with the given name. + .. note:: + If no name is given, a name of the form ``default-`` is generated .. warning:: For input versions Max4 and older **all** keyword arguments are not valid (`name`, `kpoint_type`, @@ -1217,31 +1197,29 @@ def set_kpointlist(self, *args: Any, **kwargs: Any) -> None: corresponding to the given index :param switch: bool, if True the kPointlist will be used by Fleur when starting the next calculation :param overwrite: bool, if True and a kPointlist with the given name already exists it will be overwritten + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointlist()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_kpointlist', args, kwargs) self._tasks.append(ModifierTask('set_kpointlist', args, kwargs)) def switch_kpointset(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.switch_kpointset()` to - the list of tasks that will be done on the xmltree. - - Switch the used k-point set + """Switch the used k-point set .. warning:: This method is only supported for input versions after the Max5 release :param list_name: name of the kPoint set to use + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.switch_kpointset()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('switch_kpointset', args, kwargs) self._tasks.append(ModifierTask('switch_kpointset', args, kwargs)) def set_nkpts(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_nkpts()` to - the list of tasks that will be done on the xmltree. - - Sets a k-point mesh directly into inp.xml + """Sets a k-point mesh directly specific for inputs of version Max4 .. warning:: This method is only supported for input versions before the Max5 release @@ -1249,16 +1227,15 @@ def set_nkpts(self, *args: Any, **kwargs: Any) -> None: :param count: number of k-points :param gamma: bool that controls if the gamma-point should be included in the k-point mesh + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_nkpts()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_nkpts', args, kwargs) self._tasks.append(ModifierTask('set_nkpts', args, kwargs)) def set_kpath(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpath()` to - the list of tasks that will be done on the xmltree. - - Sets a k-path directly into inp.xml as a alternative kpoint set with purpose 'bands' + """Sets a k-path directly as an alternative kpoint set with purpose 'bands' .. warning:: This method is only supported for input versions before the Max5 release @@ -1267,6 +1244,9 @@ def set_kpath(self, *args: Any, **kwargs: Any) -> None: :param count: number of k-points :param gamma: bool that controls if the gamma-point should be included in the k-point mesh + + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpath()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_kpath', args, kwargs) self._tasks.append(ModifierTask('set_kpath', args, kwargs)) diff --git a/masci_tools/util/xml/xml_setters_basic.py b/masci_tools/util/xml/xml_setters_basic.py index 33c9660eb..17159e80b 100644 --- a/masci_tools/util/xml/xml_setters_basic.py +++ b/masci_tools/util/xml/xml_setters_basic.py @@ -29,8 +29,7 @@ def xml_replace_tag(xmltree: XMLLike, xpath: XPathLike, element: str | etree._Element, occurrences: int | Iterable[int] | None = None) -> XMLLike: - """ - Replace XML tags by a given tag on the given XML tree + """Replace XML tags under the XPath by a given tag :param xmltree: an xmltree that represents inp.xml :param xpath: a path to the tag to be replaced @@ -79,8 +78,7 @@ def xml_delete_att(xmltree: XMLLike, xpath: XPathLike, name: str, occurrences: int | Iterable[int] | None = None) -> XMLLike: - """ - Deletes an attribute in the XML tree + """Deletes an attribute on the tags of the given XPath in the XML tree :param xmltree: an xmltree that represents inp.xml :param xpath: a path to the attribute to be deleted @@ -116,8 +114,7 @@ def xml_delete_att(xmltree: XMLLike, def xml_delete_tag(xmltree: XMLLike, xpath: XPathLike, occurrences: int | Iterable[int] | None = None) -> XMLLike: - """ - Deletes a tag in the XML tree. + """Deletes a tag under the XPath in the XML tree. :param xmltree: an xmltree that represents inp.xml :param xpath: a path to the tag to be deleted @@ -198,7 +195,7 @@ def xml_create_tag(xmltree: XMLLike, occurrences: int | Iterable[int] | None = None, correct_order: bool = True, several: bool = True) -> XMLLike: - """ + """Creates a tag under the given XPath This method evaluates an xpath expression and creates a tag in a xmltree under the returned nodes. If there are no nodes under the specified xpath an error is raised. @@ -329,8 +326,8 @@ def xml_set_attrib_value_no_create(xmltree: XMLLike, name: str, value: Any, occurrences: int | Iterable[int] | None = None) -> XMLLike: - """ - Sets an attribute in a xmltree to a given value. By default the attribute will be set + """Sets the value of an attribute under the XPath + By default the attribute will be set on all nodes returned for the specified xpath. :param xmltree: an xmltree that represents inp.xml @@ -382,8 +379,7 @@ def xml_set_text_no_create(xmltree: XMLLike, xpath: XPathLike, text: Any, occurrences: int | Iterable[int] | None = None) -> XMLLike: - """ - Sets the text of a tag in a xmltree to a given value. + """Sets the text of a tag under the XPath By default the text will be set on all nodes returned for the specified xpath. :param xmltree: an xmltree that represents inp.xml diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 6a628f1ed..3f06f428d 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -40,12 +40,16 @@ def create_tag(xmltree: XMLLike, create_parents: bool = False, occurrences: int | Iterable[int] | None = None, **kwargs: Any) -> XMLLike: - """ + """Create a tag with a given name in the XML tree This method creates a tag with a uniquely identified xpath under the nodes of its parent. If there are no nodes evaluated the subtags can be created with `create_parents=True` The tag is always inserted in the correct place if a order is enforced by the schema + .. usage-example:: + + fm.create_tag('greensFunction') + :param xmltree: an xmltree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input :param tag: str of the tag to create or etree Element or string representing the XML element with the same name to insert @@ -100,8 +104,7 @@ def delete_tag(xmltree: XMLLike, filters: FilterType | None = None, occurrences: int | Iterable[int] | None = None, **kwargs: Any) -> XMLLike: - """ - This method deletes a tag with a uniquely identified xpath. + """Delete a tag with a given name from the XML tree :param xmltree: an xmltree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -136,8 +139,7 @@ def delete_att(xmltree: XMLLike, filters: FilterType | None = None, occurrences: int | Iterable[int] | None = None, **kwargs: Any) -> XMLLike: - """ - This method deletes a attribute with a uniquely identified xpath. + """Delete an attribute with a given name from the XML tree :param xmltree: an xmltree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -177,8 +179,7 @@ def replace_tag(xmltree: XMLLike, filters: FilterType | None = None, occurrences: int | Iterable[int] | None = None, **kwargs: Any) -> XMLLike: - """ - This method deletes a tag with a uniquely identified xpath. + """Replace a tag with a given name with a different XML element :param xmltree: an xmltree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -216,10 +217,7 @@ def add_number_to_attrib(xmltree: XMLLike, mode: Literal['abs', 'absolute', 'rel', 'relative'] = 'absolute', occurrences: int | Iterable[int] | None = None, **kwargs: Any) -> XMLLike: - """ - Adds a given number to the attribute value in a xmltree specified by the name of the attribute - and optional further specification - If there are no nodes under the specified xpath an error is raised + """Add/Multiply values for multiple occurrences in the XML tree :param xmltree: an xmltree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -267,10 +265,7 @@ def add_number_to_first_attrib(xmltree: XMLLike, filters: FilterType | None = None, mode: Literal['abs', 'absolute', 'rel', 'relative'] = 'absolute', **kwargs: Any) -> XMLLike: - """ - Adds a given number to the first occurrence of an attribute value in a xmltree specified by the name of the attribute - and optional further specification - If there are no nodes under the specified xpath an error is raised + """Add/Multiply value for the first occurrences of an attribute in the XML tree :param xmltree: an xmltree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -312,9 +307,8 @@ def set_attrib_value(xmltree: XMLLike, occurrences: int | Iterable[int] | None = None, create: bool = False, **kwargs: Any) -> XMLLike: - """ - Sets an attribute in a xmltree to a given value, specified by its name and further - specifications. + """Set the value of an attribute possibly occurring multiple times + If there are no nodes under the specified xpath a tag can be created with `create=True`. The attribute values are converted automatically according to the types of the attribute with :py:func:`~masci_tools.util.xml.converters.convert_to_xml()` if they @@ -369,9 +363,8 @@ def set_first_attrib_value(xmltree: XMLLike, filters: FilterType | None = None, create: bool = False, **kwargs: Any) -> XMLLike: - """ - Sets the first occurrence of an attribute in a xmltree to a given value, specified by its name and further - specifications. + """Set the value of the first occurrence of an attribute + If there are no nodes under the specified xpath a tag can be created with `create=True`. The attribute values are converted automatically according to the types of the attribute with :py:func:`~masci_tools.util.xml.converters.convert_to_xml()` if they @@ -415,9 +408,9 @@ def set_text(xmltree: XMLLike, occurrences: int | Iterable[int] | None = None, create: bool = False, **kwargs: Any) -> XMLLike: - """ - Sets the text on tags in a xmltree to a given value, specified by the name of the tag and - further specifications. By default the text will be set on all nodes returned for the specified xpath. + """Set the value of text of tags in the XML tree possibly occurring mutliple times + + By default the text will be set on all nodes returned for the specified xpath. If there are no nodes under the specified xpath a tag can be created with `create=True`. The text values are converted automatically according to the types with :py:func:`~masci_tools.util.xml.converters.convert_to_xml()` if they @@ -455,9 +448,9 @@ def set_first_text(xmltree: XMLLike, filters: FilterType | None = None, create: bool = False, **kwargs: Any) -> XMLLike: - """ - Sets the text the first occurrence of a tag in a xmltree to a given value, specified by the name of the tag and - further specifications. By default the text will be set on all nodes returned for the specified xpath. + """Set the value of text of the first occurrence of a tag in the XML tree + + By default the text will be set on all nodes returned for the specified xpath. If there are no nodes under the specified xpath a tag can be created with `create=True`. The text values are converted automatically according to the types with :py:func:`~masci_tools.util.xml.converters.convert_to_xml()` if they @@ -497,8 +490,9 @@ def set_simple_tag(xmltree: XMLLike, filters: FilterType | None = None, create_parents: bool = False, **kwargs: Any) -> XMLLike: - """ - Sets one or multiple `simple` tag(s) in an xmltree. A simple tag can only hold attributes and has no + """Sets one or multiple ``simple`` tag(s) (no subtags/text) in an xmltree. + + A simple tag can only hold attributes and has no subtags. The tag is specified by its name and further specification If the tag can occur multiple times all existing tags are DELETED and new ones are written. If the tag only occurs once it will automatically be created if its missing. @@ -549,7 +543,8 @@ def set_complex_tag(xmltree: XMLLike, filters: FilterType | None = None, create: bool = False, **kwargs: Any) -> XMLLike: - """ + """Setattributes, text and subtags of a given tag in the XML tree + Function to correctly set tags/attributes for a given tag. Goes through the attributedict and decides based on the schema_dict, how the corresponding key has to be handled. @@ -592,7 +587,8 @@ def set_species_label(xmltree: XMLLike, atom_label: str, changes: dict[str, Any], create: bool = False) -> XMLLike: - """ + """Set the attributes of a species, given by an atom label occurring in it's atom type + This method calls :func:`~masci_tools.util.xml.xml_setters_names.set_species()` method for a certain atom species that corresponds to an atom with a given label @@ -633,8 +629,7 @@ def set_species(xmltree: XMLLike, changes: dict[str, Any], filters: FilterType | None = None, create: bool = False) -> XMLLike: - """ - Method to set parameters of a species tag of the fleur inp.xml file. + """Set the attributes of a species, specified by name position, etc. :param xmltree: xml etree of the inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -686,8 +681,7 @@ def clone_species(xmltree: XMLLike, species_name: str, new_name: str, changes: dict[str, Any] | None = None) -> XMLLike: - """ - Method to create a new species from an existing one with evtl. modifications + """Clone (and possibly change) a species in the XML tree For reference of the changes dictionary look at :py:func:`set_species()` @@ -736,7 +730,7 @@ def shift_value_species_label(xmltree: XMLLike, number_to_add: Any, mode: Literal['abs', 'absolute', 'rel', 'relative'] = 'absolute', **kwargs: Any) -> XMLLike: - """ + """Add/Multiply numeric attributes in a or multiple atom species Shifts the value of an attribute on a species by label if atom_label contains 'all' then applies to all species @@ -793,8 +787,9 @@ def shift_value_species_label(xmltree: XMLLike, def set_atomgroup_label(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, atom_label: str, changes: dict[str, Any]) -> XMLLike: - """ - This method calls :func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` + """Set the attributes of a atom group, given by an atom label occuring in it's definition + + This method calls :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` method for a certain atom species that corresponds to an atom with a given label. :param xmltree: xml etree of the inp.xml @@ -839,8 +834,7 @@ def set_atomgroup(xmltree: XMLLike, position: int | Literal['all'] | None = None, species: str | None = None, filters: FilterType | None = None) -> XMLLike: - """ - Method to set parameters of an atom group of the fleur inp.xml file. + """Set the attributes of a atom group, specified by species name, position, etc. :param xmltree: xml etree of the inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -889,9 +883,7 @@ def switch_species_label(xmltree: XMLLike, new_species_name: str, clone: bool = False, changes: dict[str, Any] | None = None) -> XMLLike: - """ - Method to switch the species of an atom group of the fleur inp.xml file based on a label - of a contained atom + """Change the species of an atom group, identified by the lable of an atom in it's group :param xmltree: xml etree of the inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -926,8 +918,7 @@ def switch_species(xmltree: XMLLike, filters: FilterType | None = None, clone: bool = False, changes: dict[str, Any] | None = None) -> XMLLike: - """ - Method to switch the species of an atom group of the fleur inp.xml file. + """Change the species of an atom group, identified by species name, position, etc. :param xmltree: xml etree of the inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -989,8 +980,7 @@ def shift_value(xmltree: XMLLike, changes: dict[str, Any], mode: Literal['abs', 'absolute', 'rel', 'relative'] = 'absolute', path_spec: dict[str, Any] | None = None) -> XMLLike: - """ - Shifts numerical values of attributes directly in the inp.xml file. + """Add/Multiply values of attributes occurring once in the XML tree The first occurrence of the attribute is shifted @@ -1028,8 +1018,7 @@ def set_inpchanges(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, changes: dict[str, Any], path_spec: dict[str, Any] | None = None) -> XMLLike: - """ - This method sets all the attribute and texts provided in the change_dict. + """Set the value of attributes/text occurring once in the XML tree The first occurrence of the attribute/tag is set @@ -1143,10 +1132,11 @@ def set_kpointlist(xmltree: XMLLike, switch: bool = False, overwrite: bool = False, additional_attributes: dict[str, Any] | None = None) -> XMLLike: - """ - Explicitly create a kPointList from the given kpoints and weights. This routine will add the - specified kPointList with the given name. + """Create a k-point list with the given points and weights + .. note:: + If no name is given, a name of the form ``default-`` is generated + .. warning:: For input versions Max4 and older **all** keyword arguments are not valid (`name`, `kpoint_type`, `special_labels`, `switch` and `overwrite`) @@ -1271,8 +1261,7 @@ def set_kpointlist_max4(xmltree: XMLLike, @schema_dict_version_dispatch(output_schema=False) def switch_kpointset(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, list_name: str) -> XMLLike: - """ - Switch the used k-point set + """Switch the used k-point set .. warning:: This method is only supported for input versions after the Max5 release @@ -1296,8 +1285,7 @@ def switch_kpointset(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, lis @switch_kpointset.register(max_version='0.31') def switch_kpointset_max4(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, list_name: str) -> XMLLike: - """ - Sets a k-point mesh directly into inp.xml specific for inputs of version Max4 + """Switch the used k-point set .. warning:: This method is only supported for input versions after the Max5 release @@ -1314,8 +1302,7 @@ def switch_kpointset_max4(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict @schema_dict_version_dispatch(output_schema=False) def set_nkpts(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, count: int, gamma: bool = False) -> XMLLike: - """ - Sets a k-point mesh directly into inp.xml + """Sets a k-point mesh directly specific for inputs of version Max4 .. warning:: This method is only supported for input versions before the Max5 release @@ -1334,8 +1321,7 @@ def set_nkpts(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, count: int @set_nkpts.register(max_version='0.31') def set_nkpts_max4(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, count: int, gamma: bool = False) -> XMLLike: - """ - Sets a k-point mesh directly into inp.xml specific for inputs of version Max4 + """Sets a k-point mesh directly specific for inputs of version Max4 :param xmltree: xml tree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input @@ -1368,8 +1354,7 @@ def set_kpath(xmltree: XMLLike, kpath: dict[str, Iterable[float]], count: int, gamma: bool = False) -> XMLLike: - """ - Sets a k-path directly into inp.xml as a alternative kpoint set with purpose 'bands' + """Sets a k-path directly as an alternative kpoint set with purpose 'bands' .. warning:: This method is only supported for input versions before the Max5 release @@ -1395,8 +1380,7 @@ def set_kpath_max4(xmltree: XMLLike, kpath: dict[str, Iterable[float]], count: int, gamma: bool = False) -> XMLLike: - """ - Sets a k-path directly into inp.xml as a alternative kpoint set with purpose 'bands' + """Sets a k-path directly as an alternative kpoint set with purpose 'bands' :param xmltree: xml tree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input diff --git a/utils/write_fleurxmlmodifier_docstrings.py b/utils/write_fleurxmlmodifier_docstrings.py index 24982a876..c738d5922 100644 --- a/utils/write_fleurxmlmodifier_docstrings.py +++ b/utils/write_fleurxmlmodifier_docstrings.py @@ -26,21 +26,21 @@ def get_method_docstring(name, docstring, module): if all(x not in line for x in (':param xmltree:', ':param schema_dict:', ':param nmmplines:', ':returns'))] additional_lines = [ - f'Appends a :py:func:`~masci_tools.util.xml.{module}.{name}()` to', + 'This registration method does not modify the file immediately ' + f'but only appendsa :py:func:`~masci_tools.util.xml.{module}.{name}()` to', 'the list of tasks that will be done on the xmltree.', '' ] - if lines[0]: - lines.insert(0, '') if lines[-1]: lines.append('') - for line in reversed(additional_lines): - lines.insert(1, line) + for line in additional_lines: + lines.append(line) while all(not line.strip() for line in lines[-2:]): lines.pop() lines = [2 * INDENT * ' ' + line if line.strip() else line.lstrip() for line in lines] lines[-1] = 2 * INDENT * ' ' + lines[0] = lines[0].lstrip() #Two levels of indentation have to be added since the docstrings go into methods return '\n'.join(lines) From 9cf1f656d498bb1264a98e2d91db7f67f17019ce Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 20 Jun 2022 11:03:32 +0200 Subject: [PATCH 02/36] WIP: Autogenerate Usage examples in the documentation --- .gitignore | 1 + docs/source/conf.py | 7 +- .../config.yml | 12 + .../files/inp.xml | 106 ++++++ .../template.md.jinja | 58 ++++ docs/source/user_guide/index.rst | 13 + masci_tools/io/fleurxmlmodifier.py | 53 ++- masci_tools/util/sphinxext.py | 318 ++++++++++++++++++ masci_tools/util/xml/xml_setters_names.py | 61 +++- 9 files changed, 614 insertions(+), 15 deletions(-) create mode 100644 docs/source/user_guide/fleurxmlmodifier_usage_examples/config.yml create mode 100644 docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp.xml create mode 100644 docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja create mode 100644 docs/source/user_guide/index.rst create mode 100644 masci_tools/util/sphinxext.py diff --git a/.gitignore b/.gitignore index 3144e5fa1..d13cf1e1d 100644 --- a/.gitignore +++ b/.gitignore @@ -92,6 +92,7 @@ instance/ # Sphinx documentation docs/_build/ docs/source/_build/ +docs/source/user_guide/fleurxmlmodifier_usage_examples/examples # PyBuilder target/ diff --git a/docs/source/conf.py b/docs/source/conf.py index a63b428a7..f3bc960ff 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -38,7 +38,8 @@ 'sphinx.ext.intersphinx', 'sphinx_autodoc_typehints', 'sphinx_copybutton', - 'sphinx_click'] + 'sphinx_click', + 'masci_tools.util.sphinxext'] intersphinx_mapping = {'numpy': ('https://numpy.org/doc/stable/', None), 'python': ('https://docs.python.org/3', None), @@ -57,6 +58,10 @@ # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] +usage_examples_conf = { + 'template_dirs': ['user_guide/fleurxmlmodifier_usage_examples'] +} + # The encoding of source files. #source_encoding = 'utf-8-sig' diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/config.yml b/docs/source/user_guide/fleurxmlmodifier_usage_examples/config.yml new file mode 100644 index 000000000..2859f67e2 --- /dev/null +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/config.yml @@ -0,0 +1,12 @@ +module-file: ../../../../masci_tools/io/fleurxmlmodifier.py +class-name: FleurXMLModifier +output-folder: examples +exclude-methods: + - fromList + - add_task_list + - task_list + - apply_modifications + - get_avail_actions + - undo + - changes + - modify_xmlfile diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp.xml b/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp.xml new file mode 100644 index 000000000..e7cbe481d --- /dev/null +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp.xml @@ -0,0 +1,106 @@ + + + + A Fleur input generator calculation with aiida + + + + + + + + .0000000000 .0000000000 .0000000000 + + + + + + + + + + + + + -0.250000 0.250000 0.000000 + 0.250000 0.250000 0.000000 + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + + + 5.301179702900000 .000000000000000 .000000000000000 + .000000000000000 7.497000033000000 .000000000000000 + .000000000000000 .000000000000000 7.992850008800000 + + + + + + + + + + + [Ne] + (3s1/2) (3p1/2) (3p3/2) (4s1/2) (3d3/2) (3d5/2) + + + + + + + + + + + + [Kr] (5s1/2) (4d3/2) (4d5/2) (4f5/2) (4f7/2) + (5p1/2) (5p3/2) (6s1/2) (5d3/2) (5d5/2) + + + + + + + + + + .0000000000 .0000000000 -.9964250044 + + + + + 1.000/2.000 1.000/2.000 .9964250044 + + + + + + + + + + + + + + 0.0 0.0 0.0 + 0.2 0.0 0.0 + + + + + diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja new file mode 100644 index 000000000..aa9a6d6f2 --- /dev/null +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -0,0 +1,58 @@ +--- +jupytext: + text_representation: + extension: .md + format_name: myst + format_version: 0.13 + jupytext_version: 1.11.4 +kernelspec: + display_name: Python 3 + language: python + name: python3 +--- + + +```{code-cell} ipython3 +:tags: [remove-cell] +%xmode Minimal +%load_ext masci_tools +``` + +{% for example in examples %} +# {{ example.title }} + +{{ example.description }} + +```{code-cell} ipython3 +:tags: [hide-output] + +from masci_tools.io.fleur_xml import load_inpxml +from lxml import etree + +xmltree, schema_dict = load_inpxml('../files/{{ example.inputfile }}') +xmltree +``` + +```{code-cell} ipython3 +{% if example.error %}:tags: [raises-exception]{% endif %} + +from masci_tools.io.fleurxmlmodifier import FleurXMLModifier + +fm = FleurXMLModifier() +{{ example.code }} +new_xmltree = fm.modify_xmlfile(xmltree, validate_changes=False) +``` + +{% if not example.error %} +```{code-cell} ipython3 +:tags: [remove-input, hide-output] +from masci_tools.util.ipython import xml_diff +xml_diff(xmltree, new_xmltree) +``` + +```{code-cell} ipython3 +:tags: [remove-input, hide-output] +new_xmltree +``` +{% endif %} +{% endfor %} diff --git a/docs/source/user_guide/index.rst b/docs/source/user_guide/index.rst new file mode 100644 index 000000000..3c0e6b49c --- /dev/null +++ b/docs/source/user_guide/index.rst @@ -0,0 +1,13 @@ +User guide +============= + +This is the masci-tools user’s guide. + +.. toctree:: + :maxdepth: 2 + + fleur_parser + fleurxmlmodifier + hdf5_parser + fleur_plots + plotting diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index ed4436b57..2ede92451 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -660,10 +660,6 @@ def create_tag(self, *args: Any, **kwargs: Any) -> None: The tag is always inserted in the correct place if a order is enforced by the schema - .. usage-example:: - - fm.create_tag('greensFunction') - :param tag: str of the tag to create or etree Element or string representing the XML element with the same name to insert :param complex_xpath: an optional xpath to use instead of the simple xpath for the evaluation :param filters: Dict specifying constraints to apply on the xpath. @@ -677,6 +673,53 @@ def create_tag(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.create_tag('mtnocoparams') + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.create_tag('lo') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.create_tag('lo', contains='species') + + .. usage-example:: + :title: Nested creation + :description: With ``create_parents=True`` evtl. missing parent tags are also created + + fm.create_tag('diagElements', + create_parents=True, + contains='species', + not_contains='torque') + + .. usage-example:: + :title: Creation of pre-created XML element + :description: Passing a XML element instead of a name will insert this element at the correct position + + fm.create_tag(etree.Element('lo', n='5', l='0', type='SCLO'), + contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.create_tag(etree.Element('lo', n='5', l='0', type='SCLO'), + contains='species', + filters={ + 'species': { + 'name': {'contains': 'Fe'} + } + }) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.create_tag()` to the list of tasks that will be done on the xmltree. """ @@ -1183,7 +1226,7 @@ def set_kpointlist(self, *args: Any, **kwargs: Any) -> None: """Create a k-point list with the given points and weights .. note:: - If no name is given, a name of the form ``default-`` is generated + If no name is given, a name of the form ``default-`` is generated .. warning:: For input versions Max4 and older **all** keyword arguments are not valid (`name`, `kpoint_type`, diff --git a/masci_tools/util/sphinxext.py b/masci_tools/util/sphinxext.py new file mode 100644 index 000000000..52a96177c --- /dev/null +++ b/masci_tools/util/sphinxext.py @@ -0,0 +1,318 @@ +""" +Spinx extension for masci-tools + +This adds the ability for giving usage examples atm specific +to the FleurXMLModifier. A template can be given, which is filled +in with the options and content from `usage-example` directives in +the docstrings of the specified methods +""" +import os +from pathlib import Path +import copy +import ast +from contextlib import redirect_stderr, contextmanager +import yaml +import io + +from sphinx.util.logging import getLogger +from sphinx.errors import ConfigError, ExtensionError +from sphinx.util.docutils import register_directive +from sphinx.util.docutils import SphinxDirective + +from docutils.core import publish_doctree +from docutils.parsers.rst.directives.body import CodeBlock +from docutils.parsers.rst import directives +from docutils import nodes +from docutils.parsers.rst.roles import set_classes +from docutils.utils.code_analyzer import Lexer, LexerError + +from jinja2 import Environment, FileSystemLoader + +logger = getLogger('masci-tools-sphinxext') + +DEFAULT_CONF = {'template_dirs': os.path.join('..', 'usage_examples'), 'template_file': 'template.md.jinja'} + +TEMPLATE_CONFIG_FILE = 'config.yml' +DEFAULT_TEMPLATE_CONFIG = { + 'module-file': None, # Required + 'class-name': None, # Required (TODO: Could be made optional if there's only one class definition) + 'exclude-methods': None, + 'include-private-methods': False, + 'output-folder': 'examples' +} + + +@contextmanager +def patch_directive(name, directive): + """ + Temporarily replace the directive of the given name + with a different one + """ + #pylint: disable=protected-access + + before = directives._directives.get(name, None) + try: + register_directive(name, directive) + yield + finally: + directives._directives.pop(name) + if before is not None: + directives._directives[name] = before + + +def generate_usage_example_files(app): + """ + Generate the markdown files for the specified usage examples + """ + logger.info('Generating usage examples ...') + + config = copy.deepcopy(DEFAULT_CONF) + config.update(app.config.usage_examples_conf) + + for template_folder in config['template_dirs']: + template_folder, template_conf = _load_template_conf(template_folder, app.builder.srcdir) + usage_examples = _gather_usage_examples(**template_conf) + _render_templates(template_folder, usage_examples, config, template_conf) + + +def _load_template_conf(template_folder, srcdir): + """ + Load the configuration for the current template folder + + :param template_folder: Filepath to the folder containing the template + :param srcdir: directory containing the conf.py + """ + template_folder = Path(srcdir) / template_folder + + config = copy.deepcopy(DEFAULT_TEMPLATE_CONFIG) + with open(template_folder / TEMPLATE_CONFIG_FILE, encoding='utf-8') as file: + config.update(yaml.safe_load(file)) + + if config['exclude-methods'] is not None: + config['exclude-methods'] = set(config['exclude-methods']) + + if config['module-file'] is None: + raise ConfigError(f'The template in {template_folder} does not define a module') + config['module-file'] = template_folder / config['module-file'] + + if config['class-name'] is None: + raise ConfigError(f'The template in {template_folder} does not define a class') + + config = {k.replace('-', '_'): v for k, v in config.items()} + return template_folder, config + + +def _render_templates(template_folder, usage_examples, config, template_config): + """ + Render all usage-example with the specified jinja template + + :param template_folder: Filepath to the folder containing the template + :param usage_examples: Dict of all usage examples + :param config: global configuration of the extension + :param template_config: configuration specific to the current template + """ + template_env = Environment( + loader=FileSystemLoader(template_folder), + keep_trailing_newline=True, + lstrip_blocks=True, + trim_blocks=True, + ) + + for name, examples in usage_examples.items(): + if not examples: + continue + template = template_env.get_template(config['template_file']) + + output_folder = template_folder / template_config['output_folder'] + if not output_folder.exists(): + output_folder.mkdir() + + with open(output_folder / f'{name}.md', 'w', encoding='utf-8') as file: + file.write(template.render(examples=examples)) + logger.info('Rendered Usage example to "%s".', os.fspath(template_folder / f'{name}.md')) + + +def _gather_usage_examples(module_file, class_name, exclude_methods=None, include_private_methods=False, **kwargs): + """ + Gather all usage-example blocks for the specified methods + + :param module_file: Filepath to the module to analyze + :param class_name: Name of the class to analyze + :param exclude_methods: set of str, these methods will not be analyzed + :param include_private_methods: bool, if True methods starting with `_` will be analyzed + + :returns: dict mapping method names to the list of usage examples defined in it's docstring + """ + + class UsageExampleTemplateBlock(CodeBlock): + """ + Dummy directive which extract the information + of usage-example directives + and collects them in a class variable for later use + """ + + #This directive should contain the template rendering logic + #In conf.py another one will be defined, which creates a admonition + # with code block + option_spec = { + 'title': directives.unchanged, + 'description': directives.unchanged, + 'result': directives.unchanged, + 'inputfile': directives.unchanged, + } + has_content = True + collected_examples = [] + + def run(self): + self.assert_has_content() + + self.options.setdefault('classes', []).append( + 'usage-example') #For checking after the fact if there were usage examples provided + + example = { + 'title': self.options.get('title', ''), + 'error': self.options.get('result', 'success').lower() == 'error', + 'inputfile': self.options.get('inputfile', 'inp.xml'), + 'code': '\n'.join(self.content) + } + if 'description' in self.options: + example['description'] = self.options['description'] + self.collected_examples.append(example) + return super().run() + + @classmethod + def reset(cls): + cls.collected_examples = [] + + if exclude_methods is None: + exclude_methods = set() + + with open(module_file, encoding='utf-8') as file: + module = ast.parse(file.read()) + + usage_examples = {} + with patch_directive('usage-example', UsageExampleTemplateBlock): + + class_definitions = [node for node in module.body if isinstance(node, ast.ClassDef)] + + for class_def in class_definitions: + if class_def.name == class_name: + method_definition = [node for node in class_def.body if isinstance(node, ast.FunctionDef)] + for method in method_definition: + if method.name in exclude_methods: + continue + if method.name.startswith('_') and not include_private_methods: + continue + + docstring = ast.get_docstring(method, clean=True) + short_desc = ast.get_docstring(method, clean=False).split('\n')[0] + + #Ignore unknown directive errors + with redirect_stderr(io.StringIO()): + doctree = publish_doctree(docstring) + + def is_code_block(node): + return (node.tagname == 'literal_block' and 'usage-example' in node.attributes['classes']) + + code_blocks = doctree.traverse(condition=is_code_block) + if len(code_blocks) == 0: + logger.warning(f'Method {method.name} of class {class_name} has no usage-example') + + examples = UsageExampleTemplateBlock.collected_examples + for entry in examples: + entry['title'] = f"``{method.name}``: {entry['title']}" + if not 'description' in entry and short_desc: + entry['description'] = short_desc + + usage_examples[method.name] = UsageExampleTemplateBlock.collected_examples + UsageExampleTemplateBlock.reset() + + return usage_examples + + +class UsageExampleBlock(SphinxDirective): + """ + Directive for usage examples + + These are rendered as admonitions containing the + optional desciption and title and the content in the + form of a python code-block + """ + + final_argument_whitespace = True + option_spec = { + 'class': directives.class_option, + 'name': directives.unchanged, + 'title': directives.unchanged, + 'description': directives.unchanged, + 'result': directives.unchanged, + 'inputfile': directives.unchanged, + } + has_content = True + + node_class = nodes.admonition + """Subclasses must set this to the appropriate admonition node class.""" + + def run(self): + set_classes(self.options) + self.assert_has_content() + + description = self.options.pop('description', '') + title_text = self.options.pop('title', 'Default') + for key in ('result', 'inputfile'): + self.options.pop(key, None) + + admonition_node = self.node_class(description, **self.options) + self.add_name(admonition_node) + + textnodes, messages = self.state.inline_text(title_text, self.lineno) + title = nodes.title(title_text, '', *textnodes) + title.source, title.line = (self.state_machine.get_source_and_line(self.lineno)) + admonition_node += title + admonition_node += messages + text_nodes, messages = self.state.inline_text(description.strip(), self.lineno) + line = nodes.line(description, '', *text_nodes) + admonition_node += line + if not 'classes' in self.options: + admonition_node['classes'] += ['admonition-' + nodes.make_id(title_text)] + + classes = ['code', 'python'] + + # set up lexical analyzer + try: + tokens = Lexer('\n'.join(self.content), 'python', self.state.document.settings.syntax_highlight) + except LexerError as error: + raise self.warning(error) + + code_node = nodes.literal_block('\n'.join(self.content), classes=classes) + self.add_name(code_node) + + # analyze content and add nodes for every token + for classes, value in tokens: + if classes: + code_node += nodes.inline(value, value, classes=classes) + else: + # insert as Text to decrease the verbosity of the output + code_node += nodes.Text(value) + + admonition_node += code_node + + return [admonition_node] + + +#Panel of cards for referencing the usage-examples +# class UsageExampleGallery(): + +# def run(self): +# pass + + +def setup(app): + """Setup sphinx extension""" + + app.add_config_value('usage_examples_conf', DEFAULT_CONF, 'html') + + app.add_directive('usage-example', UsageExampleBlock) + # app.add_directive('usage-example-gallery', UsageExampleGallery) + + app.connect('builder-inited', generate_usage_example_files) diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 3f06f428d..e44ea9a25 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -46,10 +46,6 @@ def create_tag(xmltree: XMLLike, The tag is always inserted in the correct place if a order is enforced by the schema - .. usage-example:: - - fm.create_tag('greensFunction') - :param xmltree: an xmltree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input :param tag: str of the tag to create or etree Element or string representing the XML element with the same name to insert @@ -65,6 +61,53 @@ def create_tag(xmltree: XMLLike, :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.create_tag('mtnocoparams') + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.create_tag('lo') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.create_tag('lo', contains='species') + + .. usage-example:: + :title: Nested creation + :description: With ``create_parents=True`` evtl. missing parent tags are also created + + fm.create_tag('diagElements', + create_parents=True, + contains='species', + not_contains='torque') + + .. usage-example:: + :title: Creation of pre-created XML element + :description: Passing a XML element instead of a name will insert this element at the correct position + + fm.create_tag(etree.Element('lo', n='5', l='0', type='SCLO'), + contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.create_tag(etree.Element('lo', n='5', l='0', type='SCLO'), + contains='species', + filters={ + 'species': { + 'name': {'contains': 'Fe'} + } + }) + :returns: xmltree with created tags """ from masci_tools.util.xml.xml_setters_xpaths import xml_create_tag_schema_dict @@ -409,7 +452,7 @@ def set_text(xmltree: XMLLike, create: bool = False, **kwargs: Any) -> XMLLike: """Set the value of text of tags in the XML tree possibly occurring mutliple times - + By default the text will be set on all nodes returned for the specified xpath. If there are no nodes under the specified xpath a tag can be created with `create=True`. The text values are converted automatically according to the types @@ -491,7 +534,7 @@ def set_simple_tag(xmltree: XMLLike, create_parents: bool = False, **kwargs: Any) -> XMLLike: """Sets one or multiple ``simple`` tag(s) (no subtags/text) in an xmltree. - + A simple tag can only hold attributes and has no subtags. The tag is specified by its name and further specification If the tag can occur multiple times all existing tags are DELETED and new ones are written. @@ -588,7 +631,7 @@ def set_species_label(xmltree: XMLLike, changes: dict[str, Any], create: bool = False) -> XMLLike: """Set the attributes of a species, given by an atom label occurring in it's atom type - + This method calls :func:`~masci_tools.util.xml.xml_setters_names.set_species()` method for a certain atom species that corresponds to an atom with a given label @@ -1135,8 +1178,8 @@ def set_kpointlist(xmltree: XMLLike, """Create a k-point list with the given points and weights .. note:: - If no name is given, a name of the form ``default-`` is generated - + If no name is given, a name of the form ``default-`` is generated + .. warning:: For input versions Max4 and older **all** keyword arguments are not valid (`name`, `kpoint_type`, `special_labels`, `switch` and `overwrite`) From e8b91706ac1c9c21c885fb321e97ceae8a1abd12 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 20 Jun 2022 11:42:54 +0200 Subject: [PATCH 03/36] Add more usage examples and add them to the toctree temporarily --- .../fleurxmlmodifier_usage_examples/index.rst | 8 ++ .../template.md.jinja | 2 + docs/source/user_guide/index.rst | 1 + masci_tools/io/fleurxmlmodifier.py | 93 +++++++++++++++++++ masci_tools/util/xml/xml_setters_names.py | 93 +++++++++++++++++++ 5 files changed, 197 insertions(+) create mode 100644 docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst b/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst new file mode 100644 index 000000000..f1d1f9158 --- /dev/null +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst @@ -0,0 +1,8 @@ + +Usage Examples ++++++++++++++++ + +.. toctree:: + :glob: + + examples/* \ No newline at end of file diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja index aa9a6d6f2..a7a30274f 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -18,6 +18,8 @@ kernelspec: %load_ext masci_tools ``` +.. contents:: + {% for example in examples %} # {{ example.title }} diff --git a/docs/source/user_guide/index.rst b/docs/source/user_guide/index.rst index 3c0e6b49c..f293f0c3e 100644 --- a/docs/source/user_guide/index.rst +++ b/docs/source/user_guide/index.rst @@ -8,6 +8,7 @@ This is the masci-tools user’s guide. fleur_parser fleurxmlmodifier + fleurxmlmodifier_usage_examples/index hdf5_parser fleur_plots plotting diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 2ede92451..ee79016ac 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -740,6 +740,37 @@ def delete_tag(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.delete_tag('expertModes') + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.delete_tag('lo') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.delete_tag('lo', contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.delete_tag('lo', + contains='species', + filters={ + 'species': { + 'name': {'contains': 'Fe'} + } + }) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.delete_tag()` to the list of tasks that will be done on the xmltree. """ @@ -763,6 +794,37 @@ def delete_att(self, *args: Any, **kwargs: Any) -> None: :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.delete_att('mixparam') + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.delete_att('alpha') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.delete_att('alpha', contains='nocoParams') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.delete_att('alpha', + contains='nocoParams', + filters={ + 'atomGroup': { + 'species': {'not-contains': 'Fe'} + } + }) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.delete_att()` to the list of tasks that will be done on the xmltree. """ @@ -787,6 +849,37 @@ def replace_tag(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.replace_tag('expertmodes', etree.Element('greensFunction')) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.replace_tag('lo', etree.Element('ldaU', l='3')) + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.replace_tag('lo', etree.Element('ldaU', l='3'), contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.replace_tag('lo', + etree.Element('ldaU', l='3'), + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.replace_tag()` to the list of tasks that will be done on the xmltree. """ diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index e44ea9a25..476bcc5c3 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -162,6 +162,37 @@ def delete_tag(xmltree: XMLLike, :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.delete_tag('expertModes') + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.delete_tag('lo') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.delete_tag('lo', contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.delete_tag('lo', + contains='species', + filters={ + 'species': { + 'name': {'contains': 'Fe'} + } + }) + :returns: xmltree with deleted tags """ from masci_tools.util.xml.xml_setters_basic import xml_delete_tag @@ -200,6 +231,37 @@ def delete_att(xmltree: XMLLike, :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.delete_att('mixparam') + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.delete_att('alpha') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.delete_att('alpha', contains='nocoParams') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.delete_att('alpha', + contains='nocoParams', + filters={ + 'atomGroup': { + 'species': {'not-contains': 'Fe'} + } + }) + :returns: xmltree with deleted attributes """ from masci_tools.util.xml.xml_setters_basic import xml_delete_att @@ -238,6 +300,37 @@ def replace_tag(xmltree: XMLLike, :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.replace_tag('expertmodes', etree.Element('greensFunction')) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.replace_tag('lo', etree.Element('ldaU', l='3')) + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.replace_tag('lo', etree.Element('ldaU', l='3'), contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.replace_tag('lo', + etree.Element('ldaU', l='3'), + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + :returns: xmltree with replaced tags """ from masci_tools.util.xml.xml_setters_basic import xml_replace_tag From 099f562af66a1a2163919cc5a195e1827a3a18c6 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 20 Jun 2022 13:44:05 +0200 Subject: [PATCH 04/36] Even more usage-examples --- masci_tools/io/fleurxmlmodifier.py | 67 ++++++++++++++++++++++- masci_tools/util/xml/xml_setters_names.py | 65 +++++++++++++++++++++- 2 files changed, 129 insertions(+), 3 deletions(-) diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index ee79016ac..73f3b2673 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -811,7 +811,7 @@ def delete_att(self, *args: Any, **kwargs: Any) -> None: :title: Tag selection :description: Selection can be done by adding conditions on what the XPath should(n't) contain - fm.delete_att('alpha', contains='nocoParams') + fm.delete_att('alpha', contains='nocoParams', not_contains='species') .. usage-example:: :title: Added filters @@ -819,6 +819,7 @@ def delete_att(self, *args: Any, **kwargs: Any) -> None: fm.delete_att('alpha', contains='nocoParams', + not_contains='species' filters={ 'atomGroup': { 'species': {'not-contains': 'Fe'} @@ -849,7 +850,7 @@ def replace_tag(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path - Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) .. usage-example:: @@ -1092,6 +1093,37 @@ def add_number_to_attrib(self, *args: Any, **kwargs: Any) -> None: :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.add_number_to_attrib('itmax', 10) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.add_number_to_attrib('radius', 1.05, mode='rel') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.add_number_to_attrib('radius', 1.05, mode='rel', contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.add_number_to_attrib('spinUp', + -1, + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_attrib()` to the list of tasks that will be done on the xmltree. """ @@ -1123,6 +1155,37 @@ def add_number_to_first_attrib(self, *args: Any, **kwargs: Any) -> None: :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.add_number_to_first_attrib('itmax', 10) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.add_number_to_first_attrib('radius', 1.05, mode='rel') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.add_number_to_first_attrib('radius', 1.05, mode='rel', contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.add_number_to_first_attrib('spinUp', + -1, + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_first_attrib()` to the list of tasks that will be done on the xmltree. """ diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 476bcc5c3..20ee1efe2 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -248,7 +248,7 @@ def delete_att(xmltree: XMLLike, :title: Tag selection :description: Selection can be done by adding conditions on what the XPath should(n't) contain - fm.delete_att('alpha', contains='nocoParams') + fm.delete_att('alpha', contains='nocoParams', not_contains='species') .. usage-example:: :title: Added filters @@ -256,6 +256,7 @@ def delete_att(xmltree: XMLLike, fm.delete_att('alpha', contains='nocoParams', + not_contains='species' filters={ 'atomGroup': { 'species': {'not-contains': 'Fe'} @@ -374,6 +375,37 @@ def add_number_to_attrib(xmltree: XMLLike, :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.add_number_to_attrib('itmax', 10) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.add_number_to_attrib('radius', 1.05, mode='rel') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.add_number_to_attrib('radius', 1.05, mode='rel', contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.add_number_to_attrib('spinUp', + -1, + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + :returns: xmltree with shifted attribute """ from masci_tools.util.xml.xml_setters_xpaths import xml_add_number_to_attrib @@ -421,6 +453,37 @@ def add_number_to_first_attrib(xmltree: XMLLike, :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.add_number_to_first_attrib('itmax', 10) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.add_number_to_first_attrib('radius', 1.05, mode='rel') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.add_number_to_first_attrib('radius', 1.05, mode='rel', contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.add_number_to_first_attrib('spinUp', + -1, + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + :returns: xmltree with shifted attribute """ return add_number_to_attrib(xmltree, From c1dd362f0ec85478234460d3a5d33e5429d31ec5 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Wed, 22 Jun 2022 14:27:40 +0200 Subject: [PATCH 05/36] Improve template with contents and nested heading --- .../fleurxmlmodifier_usage_examples/template.md.jinja | 8 ++++++-- masci_tools/util/sphinxext.py | 7 +++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja index a7a30274f..4a868bbc3 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -18,10 +18,14 @@ kernelspec: %load_ext masci_tools ``` -.. contents:: +```{contents} + +``` + +# {{ title }} {% for example in examples %} -# {{ example.title }} +## {{ example.title }} {{ example.description }} diff --git a/masci_tools/util/sphinxext.py b/masci_tools/util/sphinxext.py index 52a96177c..8326650b4 100644 --- a/masci_tools/util/sphinxext.py +++ b/masci_tools/util/sphinxext.py @@ -128,7 +128,7 @@ def _render_templates(template_folder, usage_examples, config, template_config): output_folder.mkdir() with open(output_folder / f'{name}.md', 'w', encoding='utf-8') as file: - file.write(template.render(examples=examples)) + file.write(template.render(examples=examples, title=f"``{name}``")) logger.info('Rendered Usage example to "%s".', os.fspath(template_folder / f'{name}.md')) @@ -170,7 +170,7 @@ def run(self): 'usage-example') #For checking after the fact if there were usage examples provided example = { - 'title': self.options.get('title', ''), + 'title': self.options.get('title', 'Simple Usage'), 'error': self.options.get('result', 'success').lower() == 'error', 'inputfile': self.options.get('inputfile', 'inp.xml'), 'code': '\n'.join(self.content) @@ -220,7 +220,6 @@ def is_code_block(node): examples = UsageExampleTemplateBlock.collected_examples for entry in examples: - entry['title'] = f"``{method.name}``: {entry['title']}" if not 'description' in entry and short_desc: entry['description'] = short_desc @@ -258,7 +257,7 @@ def run(self): self.assert_has_content() description = self.options.pop('description', '') - title_text = self.options.pop('title', 'Default') + title_text = self.options.pop('title', 'Simple Usage') for key in ('result', 'inputfile'): self.options.pop(key, None) From 3bbd689c8a9a1436ed0d1dee9c62d4f946b533b7 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Wed, 22 Jun 2022 16:26:50 +0200 Subject: [PATCH 06/36] Adjust colors in XML diff function --- masci_tools/util/ipython.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/masci_tools/util/ipython.py b/masci_tools/util/ipython.py index c8b0dd028..b1355c921 100644 --- a/masci_tools/util/ipython.py +++ b/masci_tools/util/ipython.py @@ -38,10 +38,10 @@ def xml_diff(old: XMLLike, new: XMLLike, indent: bool = True) -> HTML: STYLES = { 'control': 'font-weight: bold', - 'delete': 'background-color: hsla(0, 100%, 74%, 0.5); color: #000000;', - 'delete-detail': 'background-color: hsla(0, 100%, 74%, 0.5); color: #000000;', - 'insert': 'background-color: hsla(102, 100%, 74%, 0.5); color: #000000;', - 'insert-detail': 'background-color: hsla(102, 100%, 74%, 0.5); color: #000000;', + 'delete': 'background-color: hsla(0, 100%, 74%, 0.5);', + 'delete-detail': 'background-color: hsla(0, 100%, 60%, 0.5);', + 'insert': 'background-color: hsla(102, 100%, 74%, 0.5);', + 'insert-detail': 'background-color: hsla(102, 100%, 60%, 0.5);', } if indent: From 2c78269da87a68418411245d2703313f213f1c9b Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Wed, 22 Jun 2022 17:43:23 +0200 Subject: [PATCH 07/36] Move the sphinx extension stuff into a subfolder for nicer organization --- docs/source/reference/module_guide/index.rst | 9 + .../reference/module_guide/sphinxext.rst | 5 + masci_tools/util/sphinxext/__init__.py | 32 +++ .../usage_examples.py} | 199 ++++++++---------- 4 files changed, 137 insertions(+), 108 deletions(-) create mode 100644 docs/source/reference/module_guide/index.rst create mode 100644 docs/source/reference/module_guide/sphinxext.rst create mode 100644 masci_tools/util/sphinxext/__init__.py rename masci_tools/util/{sphinxext.py => sphinxext/usage_examples.py} (89%) diff --git a/docs/source/reference/module_guide/index.rst b/docs/source/reference/module_guide/index.rst new file mode 100644 index 000000000..16ccd1588 --- /dev/null +++ b/docs/source/reference/module_guide/index.rst @@ -0,0 +1,9 @@ +Source code documentation +========================= + +.. toctree:: + :maxdepth: 3 + + code + tools + sphinxext diff --git a/docs/source/reference/module_guide/sphinxext.rst b/docs/source/reference/module_guide/sphinxext.rst new file mode 100644 index 000000000..73fbe373b --- /dev/null +++ b/docs/source/reference/module_guide/sphinxext.rst @@ -0,0 +1,5 @@ +Extensions to Sphinx +++++++++++++++++++++++++++ + +.. automodule:: masci_tools.util.sphinxext + :members: \ No newline at end of file diff --git a/masci_tools/util/sphinxext/__init__.py b/masci_tools/util/sphinxext/__init__.py new file mode 100644 index 000000000..63a39675a --- /dev/null +++ b/masci_tools/util/sphinxext/__init__.py @@ -0,0 +1,32 @@ +""" +Spinx extension for masci-tools + +This adds the ability for giving usage examples atm specific +to the FleurXMLModifier. A template can be given, which is filled +in with the options and content from `usage-example` directives in +the docstrings of the specified methods + +Example of the usage-example directive without a connected template. + +.. usage-example:: + :title: This is how it's done + :description: Simply do the stuff + + print('Hello World') + +""" +from .usage_examples import UsageExampleBlock, generate_usage_example_files, DEFAULT_CONF + + +def setup(app): + """ + This function sets up the Sphinx extension. It is called, when + ``masci_tools.util.sphinxext`` is added to the extensions in a conf.py file + """ + + app.add_config_value('usage_examples_conf', DEFAULT_CONF, 'html') + + app.add_directive('usage-example', UsageExampleBlock) + # app.add_directive('usage-example-gallery', UsageExampleGallery) + + app.connect('builder-inited', generate_usage_example_files) diff --git a/masci_tools/util/sphinxext.py b/masci_tools/util/sphinxext/usage_examples.py similarity index 89% rename from masci_tools/util/sphinxext.py rename to masci_tools/util/sphinxext/usage_examples.py index 8326650b4..2c7b4d5b5 100644 --- a/masci_tools/util/sphinxext.py +++ b/masci_tools/util/sphinxext/usage_examples.py @@ -28,9 +28,14 @@ from jinja2 import Environment, FileSystemLoader -logger = getLogger('masci-tools-sphinxext') +logger = getLogger('masci-tools-usage-examples') -DEFAULT_CONF = {'template_dirs': os.path.join('..', 'usage_examples'), 'template_file': 'template.md.jinja'} +# yapf: disable +DEFAULT_CONF = { + 'template_dirs': os.path.join('..', 'usage_examples'), + 'template_file': 'template.md.jinja' +} +# yapf: enable TEMPLATE_CONFIG_FILE = 'config.yml' DEFAULT_TEMPLATE_CONFIG = { @@ -42,22 +47,74 @@ } -@contextmanager -def patch_directive(name, directive): +class UsageExampleBlock(SphinxDirective): """ - Temporarily replace the directive of the given name - with a different one + Directive for usage examples + + These are rendered as admonitions containing the + optional description and title and the content in the + form of a python code-block """ - #pylint: disable=protected-access - before = directives._directives.get(name, None) - try: - register_directive(name, directive) - yield - finally: - directives._directives.pop(name) - if before is not None: - directives._directives[name] = before + final_argument_whitespace = True + option_spec = { + 'class': directives.class_option, + 'name': directives.unchanged, + 'title': directives.unchanged, + 'description': directives.unchanged, + 'result': directives.unchanged, + 'inputfile': directives.unchanged, + } + has_content = True + + node_class = nodes.admonition + """Subclasses must set this to the appropriate admonition node class.""" + + def run(self): + set_classes(self.options) + self.assert_has_content() + + description = self.options.pop('description', '') + title_text = self.options.pop('title', 'Simple Usage') + for key in ('result', 'inputfile'): + self.options.pop(key, None) + + admonition_node = self.node_class(description, **self.options) + self.add_name(admonition_node) + + textnodes, messages = self.state.inline_text(title_text, self.lineno) + title = nodes.title(title_text, '', *textnodes) + title.source, title.line = (self.state_machine.get_source_and_line(self.lineno)) + admonition_node += title + admonition_node += messages + text_nodes, messages = self.state.inline_text(description.strip(), self.lineno) + line = nodes.line(description, '', *text_nodes) + admonition_node += line + if not 'classes' in self.options: + admonition_node['classes'] += ['admonition-' + nodes.make_id(title_text)] + + classes = ['code', 'python'] + + # set up lexical analyzer + try: + tokens = Lexer('\n'.join(self.content), 'python', self.state.document.settings.syntax_highlight) + except LexerError as error: + raise self.warning(error) + + code_node = nodes.literal_block('\n'.join(self.content), classes=classes) + self.add_name(code_node) + + # analyze content and add nodes for every token + for classes, value in tokens: + if classes: + code_node += nodes.inline(value, value, classes=classes) + else: + # insert as Text to decrease the verbosity of the output + code_node += nodes.Text(value) + + admonition_node += code_node + + return [admonition_node] def generate_usage_example_files(app): @@ -128,7 +185,7 @@ def _render_templates(template_folder, usage_examples, config, template_config): output_folder.mkdir() with open(output_folder / f'{name}.md', 'w', encoding='utf-8') as file: - file.write(template.render(examples=examples, title=f"``{name}``")) + file.write(template.render(examples=examples, title=f'``{name}``')) logger.info('Rendered Usage example to "%s".', os.fspath(template_folder / f'{name}.md')) @@ -209,109 +266,35 @@ def reset(cls): #Ignore unknown directive errors with redirect_stderr(io.StringIO()): - doctree = publish_doctree(docstring) - - def is_code_block(node): - return (node.tagname == 'literal_block' and 'usage-example' in node.attributes['classes']) + publish_doctree(docstring) - code_blocks = doctree.traverse(condition=is_code_block) - if len(code_blocks) == 0: + method_examples = UsageExampleTemplateBlock.collected_examples + if len(method_examples) == 0: logger.warning(f'Method {method.name} of class {class_name} has no usage-example') - examples = UsageExampleTemplateBlock.collected_examples - for entry in examples: + for entry in method_examples: if not 'description' in entry and short_desc: entry['description'] = short_desc - usage_examples[method.name] = UsageExampleTemplateBlock.collected_examples + usage_examples[method.name] = method_examples UsageExampleTemplateBlock.reset() return usage_examples -class UsageExampleBlock(SphinxDirective): +@contextmanager +def patch_directive(name, directive): """ - Directive for usage examples - - These are rendered as admonitions containing the - optional desciption and title and the content in the - form of a python code-block + Temporarily replace the directive of the given name + with a different one """ + #pylint: disable=protected-access - final_argument_whitespace = True - option_spec = { - 'class': directives.class_option, - 'name': directives.unchanged, - 'title': directives.unchanged, - 'description': directives.unchanged, - 'result': directives.unchanged, - 'inputfile': directives.unchanged, - } - has_content = True - - node_class = nodes.admonition - """Subclasses must set this to the appropriate admonition node class.""" - - def run(self): - set_classes(self.options) - self.assert_has_content() - - description = self.options.pop('description', '') - title_text = self.options.pop('title', 'Simple Usage') - for key in ('result', 'inputfile'): - self.options.pop(key, None) - - admonition_node = self.node_class(description, **self.options) - self.add_name(admonition_node) - - textnodes, messages = self.state.inline_text(title_text, self.lineno) - title = nodes.title(title_text, '', *textnodes) - title.source, title.line = (self.state_machine.get_source_and_line(self.lineno)) - admonition_node += title - admonition_node += messages - text_nodes, messages = self.state.inline_text(description.strip(), self.lineno) - line = nodes.line(description, '', *text_nodes) - admonition_node += line - if not 'classes' in self.options: - admonition_node['classes'] += ['admonition-' + nodes.make_id(title_text)] - - classes = ['code', 'python'] - - # set up lexical analyzer - try: - tokens = Lexer('\n'.join(self.content), 'python', self.state.document.settings.syntax_highlight) - except LexerError as error: - raise self.warning(error) - - code_node = nodes.literal_block('\n'.join(self.content), classes=classes) - self.add_name(code_node) - - # analyze content and add nodes for every token - for classes, value in tokens: - if classes: - code_node += nodes.inline(value, value, classes=classes) - else: - # insert as Text to decrease the verbosity of the output - code_node += nodes.Text(value) - - admonition_node += code_node - - return [admonition_node] - - -#Panel of cards for referencing the usage-examples -# class UsageExampleGallery(): - -# def run(self): -# pass - - -def setup(app): - """Setup sphinx extension""" - - app.add_config_value('usage_examples_conf', DEFAULT_CONF, 'html') - - app.add_directive('usage-example', UsageExampleBlock) - # app.add_directive('usage-example-gallery', UsageExampleGallery) - - app.connect('builder-inited', generate_usage_example_files) + before = directives._directives.get(name, None) + try: + register_directive(name, directive) + yield + finally: + directives._directives.pop(name) + if before is not None: + directives._directives[name] = before From accf5728cb25c8e92f53c17fae2d9d170582c82c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 23 Jun 2022 13:19:32 +0000 Subject: [PATCH 08/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- docs/source/reference/module_guide/sphinxext.rst | 2 +- .../source/user_guide/fleurxmlmodifier_usage_examples/index.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/module_guide/sphinxext.rst b/docs/source/reference/module_guide/sphinxext.rst index 73fbe373b..c2ef1b3fc 100644 --- a/docs/source/reference/module_guide/sphinxext.rst +++ b/docs/source/reference/module_guide/sphinxext.rst @@ -2,4 +2,4 @@ Extensions to Sphinx ++++++++++++++++++++++++++ .. automodule:: masci_tools.util.sphinxext - :members: \ No newline at end of file + :members: diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst b/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst index f1d1f9158..7d605f0b8 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst @@ -5,4 +5,4 @@ Usage Examples .. toctree:: :glob: - examples/* \ No newline at end of file + examples/* From 2c6c39c3d7842bb2f0a7080a52a63c5fc1d4b969 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Thu, 23 Jun 2022 15:23:43 +0200 Subject: [PATCH 09/36] Fixes after rebase --- docs/source/reference/module_guide/index.md | 1 + docs/source/reference/module_guide/index.rst | 9 --------- docs/source/reference/module_guide/sphinxext.md | 6 ++++++ .../fleurxmlmodifier_usage_examples/index.md | 7 +++++++ docs/source/user_guide/index.md | 1 + docs/source/user_guide/index.rst | 14 -------------- 6 files changed, 15 insertions(+), 23 deletions(-) delete mode 100644 docs/source/reference/module_guide/index.rst create mode 100644 docs/source/reference/module_guide/sphinxext.md create mode 100644 docs/source/user_guide/fleurxmlmodifier_usage_examples/index.md delete mode 100644 docs/source/user_guide/index.rst diff --git a/docs/source/reference/module_guide/index.md b/docs/source/reference/module_guide/index.md index 019a03db9..23dd0b045 100644 --- a/docs/source/reference/module_guide/index.md +++ b/docs/source/reference/module_guide/index.md @@ -5,4 +5,5 @@ code tools +sphinxext ``` diff --git a/docs/source/reference/module_guide/index.rst b/docs/source/reference/module_guide/index.rst deleted file mode 100644 index 16ccd1588..000000000 --- a/docs/source/reference/module_guide/index.rst +++ /dev/null @@ -1,9 +0,0 @@ -Source code documentation -========================= - -.. toctree:: - :maxdepth: 3 - - code - tools - sphinxext diff --git a/docs/source/reference/module_guide/sphinxext.md b/docs/source/reference/module_guide/sphinxext.md new file mode 100644 index 000000000..75cffb70a --- /dev/null +++ b/docs/source/reference/module_guide/sphinxext.md @@ -0,0 +1,6 @@ +# Extensions to Sphinx + +```{eval-rst} +.. automodule:: masci_tools.util.sphinxext + :members: +``` diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.md b/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.md new file mode 100644 index 000000000..f2c81668f --- /dev/null +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.md @@ -0,0 +1,7 @@ +# Usage Examples + +```{toctree} +:glob: true + +examples/* +``` diff --git a/docs/source/user_guide/index.md b/docs/source/user_guide/index.md index 810d3f54b..50084781e 100644 --- a/docs/source/user_guide/index.md +++ b/docs/source/user_guide/index.md @@ -7,6 +7,7 @@ This is the masci-tools user’s guide. fleur_parser fleurxmlmodifier +fleurxmlmodifier_usage_examples/index hdf5_parser fleur_plots kkr_plots diff --git a/docs/source/user_guide/index.rst b/docs/source/user_guide/index.rst deleted file mode 100644 index f293f0c3e..000000000 --- a/docs/source/user_guide/index.rst +++ /dev/null @@ -1,14 +0,0 @@ -User guide -============= - -This is the masci-tools user’s guide. - -.. toctree:: - :maxdepth: 2 - - fleur_parser - fleurxmlmodifier - fleurxmlmodifier_usage_examples/index - hdf5_parser - fleur_plots - plotting From 311e34fad0bce1af1eec2b5acdc16c4a1d57e1ac Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 13:04:47 +0200 Subject: [PATCH 10/36] Improve template --- docs/source/reference/module_guide/sphinxext.rst | 5 ----- .../fleurxmlmodifier_usage_examples/index.rst | 8 -------- .../fleurxmlmodifier_usage_examples/template.md.jinja | 10 ++++++---- masci_tools/io/fleurxmlmodifier.py | 2 +- masci_tools/util/xml/xml_setters_names.py | 2 +- 5 files changed, 8 insertions(+), 19 deletions(-) delete mode 100644 docs/source/reference/module_guide/sphinxext.rst delete mode 100644 docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst diff --git a/docs/source/reference/module_guide/sphinxext.rst b/docs/source/reference/module_guide/sphinxext.rst deleted file mode 100644 index c2ef1b3fc..000000000 --- a/docs/source/reference/module_guide/sphinxext.rst +++ /dev/null @@ -1,5 +0,0 @@ -Extensions to Sphinx -++++++++++++++++++++++++++ - -.. automodule:: masci_tools.util.sphinxext - :members: diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst b/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst deleted file mode 100644 index 7d605f0b8..000000000 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/index.rst +++ /dev/null @@ -1,8 +0,0 @@ - -Usage Examples -+++++++++++++++ - -.. toctree:: - :glob: - - examples/* diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja index 4a868bbc3..c0d1b0ee3 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -18,12 +18,12 @@ kernelspec: %load_ext masci_tools ``` -```{contents} +# {{ title }} +```{contents} Examples +:local: ``` -# {{ title }} - {% for example in examples %} ## {{ example.title }} @@ -46,16 +46,18 @@ from masci_tools.io.fleurxmlmodifier import FleurXMLModifier fm = FleurXMLModifier() {{ example.code }} -new_xmltree = fm.modify_xmlfile(xmltree, validate_changes=False) +new_xmltree, additional_files = fm.modify_xmlfile(xmltree, validate_changes=False) ``` {% if not example.error %} +Changes in the ``inp.xml`` file ```{code-cell} ipython3 :tags: [remove-input, hide-output] from masci_tools.util.ipython import xml_diff xml_diff(xmltree, new_xmltree) ``` +Conplete Modified ``inp.xml`` file ```{code-cell} ipython3 :tags: [remove-input, hide-output] new_xmltree diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 73f3b2673..fe8159be2 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -819,7 +819,7 @@ def delete_att(self, *args: Any, **kwargs: Any) -> None: fm.delete_att('alpha', contains='nocoParams', - not_contains='species' + not_contains='species', filters={ 'atomGroup': { 'species': {'not-contains': 'Fe'} diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 20ee1efe2..1ce604509 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -256,7 +256,7 @@ def delete_att(xmltree: XMLLike, fm.delete_att('alpha', contains='nocoParams', - not_contains='species' + not_contains='species', filters={ 'atomGroup': { 'species': {'not-contains': 'Fe'} From 98686c111ded1f9fb97ce0886ca87a29480dbcc3 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 13:13:05 +0200 Subject: [PATCH 11/36] Move error handling in schema_dict into function --- .../io/parsers/fleur_schema/schema_dict.py | 160 +++++++++--------- 1 file changed, 76 insertions(+), 84 deletions(-) diff --git a/masci_tools/io/parsers/fleur_schema/schema_dict.py b/masci_tools/io/parsers/fleur_schema/schema_dict.py index b5551ef0c..291318925 100644 --- a/masci_tools/io/parsers/fleur_schema/schema_dict.py +++ b/masci_tools/io/parsers/fleur_schema/schema_dict.py @@ -22,9 +22,8 @@ import copy from functools import update_wrapper, wraps from pathlib import Path +from collections.abc import Collection from typing import Callable, Iterable, TypeVar, Any, cast - -from .fleur_schema_parser_functions import TagInfo, convert_str_version_number try: from typing import Literal, Protocol except ImportError: @@ -39,6 +38,7 @@ from masci_tools.util.xml.common_functions import abs_to_rel_xpath, clear_xml, split_off_tag, contains_tag, validate_xml from .inpschema_todict import create_inpschema_dict, InputSchemaData from .outschema_todict import create_outschema_dict, merge_schema_dicts +from .fleur_schema_parser_functions import TagInfo, convert_str_version_number PACKAGE_DIRECTORY = Path(__file__).parent.resolve() @@ -123,7 +123,7 @@ def dispatch(version: tuple[int, int]) -> F: matches.append(default_match) if len(matches) > 2: - raise ValueError('Ambiguous possibilities for schema_dict_version_dispatch for version {version}') + raise ValueError(f'Ambiguous possibilities for schema_dict_version_dispatch for version {version}') return matches[0] @@ -225,6 +225,34 @@ def _add_condition(specification: str | Iterable[str] | None, condition: str) -> return specification +def _ensure_path_uniqueness(paths: Collection[str], + description: str, + path_type: str | None = None, + **specifications: Any) -> str: + """ + Ensure that the given iterable of paths consists of only one path + Otherwise an error is raised that either no or more than one path was found + + :param paths: sized iterable of paths to check + :param description: str for the kind of endpoint (tag name, etc.) that was searched (for errors) + :param path_type: optional str for the kind of path that was searched (for errors) + + Kwargs are entered in a formatted string in one line of the error messages + """ + if len(paths) == 1: + return next(iter(paths)) + + path_type = path_type + ' ' if path_type else path_type + specification_str = ', '.join([f'{key}: {value}' for key, value in specifications.items()]) + if len(paths) == 0: + raise NoPathFound(f'The {description} has no possible {path_type}paths with the current specification.\n' + + specification_str) + raise NoUniquePathFound( + f'The {description} has multiple possible {path_type}paths with the current specification.\n' + f'{specification_str}\n' + f'The following are possible:\n' + '\n'.join([f' - {path}' for path in paths])) + + class SchemaDict(LockableDict): """ Base class for schema dictionaries. Is locked on initialization with :py:meth:`~masci_tools.util.lockable_containers.LockableDict.freeze()`. @@ -339,15 +367,7 @@ def tag_xpath(self, ' since no tag entries are defined') paths = self._find_paths(name, self._tag_entries, contains=contains, not_contains=not_contains) - - if len(paths) == 1: - return paths[0] - if len(paths) == 0: - raise NoPathFound(f'The tag {name} has no possible paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}') - raise NoUniquePathFound(f'The tag {name} has multiple possible paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains} \n' - f'These are possible: {paths}') + return _ensure_path_uniqueness(paths, f'tag {name}', contains=contains, not_contains=not_contains) def relative_tag_xpath(self, name: str, @@ -382,15 +402,12 @@ def relative_tag_xpath(self, paths = [path for path in paths if contains_tag(path, root_tag)] relative_paths = {abs_to_rel_xpath(xpath, root_tag) for xpath in paths} - - if len(relative_paths) == 1: - return relative_paths.pop() - if len(relative_paths) == 0: - raise NoPathFound(f'The tag {name} has no possible relative paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, root_tag {root_tag}') - raise NoUniquePathFound(f'The tag {name} has multiple possible relative paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, root_tag {root_tag} \n' - f'These are possible: {relative_paths}') + return _ensure_path_uniqueness(relative_paths, + f'tag {name}', + path_type='relative', + contains=contains, + not_contains=not_contains, + root_tag=root_tag) def attrib_xpath(self, name: str, @@ -439,15 +456,11 @@ def attrib_xpath(self, entries = [entry for entry in self._attrib_entries if all(f'{excl}_attribs' not in entry for excl in exclude)] paths = self._find_paths(name, entries, contains=contains, not_contains=not_contains) - - if len(paths) == 1: - return paths[0] - if len(paths) == 0: - raise NoPathFound(f'The attrib {name} has no possible paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, exclude {exclude}') - raise NoUniquePathFound(f'The attrib {name} has multiple possible paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, exclude {exclude}\n' - f'These are possible: {paths}') + return _ensure_path_uniqueness(paths, + f'attribute {name}', + contains=contains, + not_contains=not_contains, + exclude=exclude) def relative_attrib_xpath(self, name: str, @@ -508,16 +521,12 @@ def relative_attrib_xpath(self, #e.g. bravaisMatrix vs. bravaisMatrixFilm paths = [path for path in paths if contains_tag(path, root_tag)] relative_paths = {abs_to_rel_xpath(xpath, root_tag) for xpath in paths} - - if len(relative_paths) == 1: - return relative_paths.pop() - if len(relative_paths) == 0: - raise NoPathFound(f'The attrib {name} has no possible relative paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, root_tag {root_tag}') - raise NoUniquePathFound( - f'The attrib {name} has multiple possible relative paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, root_tag {root_tag} \n' - f'These are possible: {relative_paths}') + return _ensure_path_uniqueness(relative_paths, + f'attribute {name}', + path_type='relative', + contains=contains, + not_contains=not_contains, + exclude=exclude) def tag_info(self, name: str, @@ -556,8 +565,9 @@ def tag_info(self, if tag_info is not None and entry != tag_info: raise NoUniquePathFound(f'Differing tag_info for the found with the current specification\n' - f'contains: {contains}, not_contains: {not_contains}\n' - f'These are possible: {paths}') + f'contains: {contains}, not_contains: {not_contains}, parent: {parent}\n' + f'The following are possible:\n' + + '\n'.join([f' - {path}' for path in paths])) tag_info = entry if tag_info is None: @@ -899,16 +909,11 @@ def iteration_tag_xpath(self, paths = self._find_paths(name, ('iteration_tag_paths',), contains=contains, not_contains=not_contains) paths = [f"{iteration_path}{path.lstrip('.')}" for path in paths] - - if len(paths) == 1: - return paths[0] - if len(paths) == 0: - raise NoPathFound(f'The tag {name} has no possible iteration paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}') - raise NoUniquePathFound( - f'The tag {name} has multiple possible iteration paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains} \n' - f'These are possible: {paths}') + return _ensure_path_uniqueness(paths, + f'tag {name}', + path_type='iteration', + contains=contains, + not_contains=not_contains) def relative_iteration_tag_xpath(self, name: str, @@ -947,17 +952,12 @@ def relative_iteration_tag_xpath(self, paths = [path for path in paths if contains_tag(path, root_tag)] paths = [f"{iteration_path}{path.lstrip('.')}" for path in paths] relative_paths = {abs_to_rel_xpath(xpath, root_tag) for xpath in paths} - - if len(paths) == 1: - return relative_paths.pop() - if len(paths) == 0: - raise NoPathFound( - f'The tag {name} has no possible relative iteration paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, root_tag {root_tag}') - raise NoUniquePathFound( - f'The tag {name} has multiple possible relative iteration paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, root_tag {root_tag} \n' - f'These are possible: {relative_paths}') + return _ensure_path_uniqueness(relative_paths, + f'tag {name}', + path_type='relative iteration', + contains=contains, + not_contains=not_contains, + root_tag=root_tag) def iteration_attrib_xpath(self, name: str, @@ -1019,16 +1019,12 @@ def iteration_attrib_xpath(self, paths = self._find_paths(name, entries, contains=contains, not_contains=not_contains) paths = [f"{iteration_path}{path.lstrip('.')}" for path in paths] - - if len(paths) == 1: - return paths[0] - if len(paths) == 0: - raise NoPathFound(f'The attrib {name} has no possible iteration paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, exclude {exclude}') - raise NoUniquePathFound( - f'The attrib {name} has multiple possible iteration paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, exclude {exclude}\n' - f'These are possible: {paths}') + return _ensure_path_uniqueness(paths, + f'attribute {name}', + path_type='iteration', + contains=contains, + not_contains=not_contains, + exclude=exclude) def relative_iteration_attrib_xpath(self, name: str, @@ -1103,14 +1099,10 @@ def relative_iteration_attrib_xpath(self, paths = [path for path in paths if contains_tag(path, root_tag)] paths = [f"{iteration_path}{path.lstrip('.')}" for path in paths] relative_paths = {abs_to_rel_xpath(xpath, root_tag) for xpath in paths} - - if len(relative_paths) == 1: - return relative_paths.pop() - if len(relative_paths) == 0: - raise NoPathFound( - f'The attrib {name} has no possible relative iteration paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, root_tag {root_tag}') - raise NoUniquePathFound( - f'The attrib {name} has multiple possible relative iteration paths with the current specification.\n' - f'contains: {contains}, not_contains: {not_contains}, root_tag {root_tag} \n' - f'These are possible: {relative_paths}') + return _ensure_path_uniqueness(relative_paths, + f'attribute {name}', + path_type='relative iteration', + contains=contains, + not_contains=not_contains, + root_tag=root_tag, + exclude=exclude) From f6a74dcd311aa9aaa17d92aa1aebd14b4ed393ba Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 13:34:03 +0200 Subject: [PATCH 12/36] Move finding paths to attributes from tag names into separate method --- .../io/parsers/fleur_schema/schema_dict.py | 106 +++++++++--------- 1 file changed, 55 insertions(+), 51 deletions(-) diff --git a/masci_tools/io/parsers/fleur_schema/schema_dict.py b/masci_tools/io/parsers/fleur_schema/schema_dict.py index 291318925..3583d3885 100644 --- a/masci_tools/io/parsers/fleur_schema/schema_dict.py +++ b/masci_tools/io/parsers/fleur_schema/schema_dict.py @@ -344,6 +344,39 @@ def _find_paths(self, return path_list + def _find_attrib_via_tag_name(self, + attrib_name: str, + tag_name: str, + tag_func: Callable[..., str], + *args: Any, + contains: str | Iterable[str] | None = None, + not_contains: str | Iterable[str] | None = None, + **kwargs: Any) -> str: + """ + Find the path to an attribute by first finding the tag on which it sits + Then return the concatenated path + + :param attrib_name: name of the attribute + :param tag_name: name of the tag + :param tag_func: function to use to find the tag path (e.g. self.tag_xpath) + + Args and Kwargs are passed on to the ``tag_func``, ``contains`` and ``not_contains`` kwargs + are additionally passed to the :py:meth:`tag_info()` method + + :returns: path to the attribute on the given tag if the attribute is allowed to be on the tag + """ + + tag_xpath = tag_func(tag_name, *args, contains=contains, not_contains=not_contains, **kwargs) + + tag_info = self.tag_info(tag_name, contains=contains, not_contains=not_contains, **kwargs) + + if attrib_name not in tag_info['attribs']: + raise NoPathFound(f'No attribute {attrib_name} found at tag {tag_name}') + original_case = tag_info['attribs'].original_case[attrib_name] + if tag_xpath.endswith('/'): + return f'{tag_xpath}@{original_case}' + return f'{tag_xpath}/@{original_case}' + def tag_xpath(self, name: str, contains: str | Iterable[str] | None = None, @@ -440,18 +473,11 @@ def attrib_xpath(self, exclude = [] if tag_name is not None: - tag_xpath = self.tag_xpath(tag_name, contains=contains, not_contains=not_contains) - - tag_info = self.tag_info( - tag_name, - contains=contains, - not_contains=not_contains, - ) - - if name not in tag_info['attribs']: - raise NoPathFound(f'No attribute {name} found at tag {tag_name}') - original_case = tag_info['attribs'].original_case[name] - return f'{tag_xpath}/@{original_case}' + return self._find_attrib_via_tag_name(name, + tag_name, + self.tag_xpath, + contains=contains, + not_contains=not_contains) entries = [entry for entry in self._attrib_entries if all(f'{excl}_attribs' not in entry for excl in exclude)] @@ -498,18 +524,12 @@ def relative_attrib_xpath(self, exclude = [] if tag_name is not None: - tag_xpath = self.relative_tag_xpath(tag_name, root_tag, contains=contains, not_contains=not_contains) - - tag_info = self.tag_info(tag_name, contains=contains, not_contains=not_contains) - - if name not in tag_info['attribs']: - raise NoPathFound(f'No attribute {name} found at tag {tag_name}') - - original_case = tag_info['attribs'].original_case[name] - - if tag_xpath.endswith('/'): - return f'{tag_xpath}@{original_case}' - return f'{tag_xpath}/@{original_case}' + return self._find_attrib_via_tag_name(name, + tag_name, + self.relative_tag_xpath, + root_tag, + contains=contains, + not_contains=not_contains) entries = [entry for entry in self._attrib_entries if all(f'{excl}_attribs' not in entry for excl in exclude)] @@ -999,18 +1019,11 @@ def iteration_attrib_xpath(self, exclude = [] if tag_name is not None: - tag_xpath = self.iteration_tag_xpath(tag_name, contains=contains, not_contains=not_contains) - - tag_info = self.tag_info( - tag_name, - contains=contains, - not_contains=not_contains, - ) - - if name not in tag_info['attribs']: - raise NoPathFound(f'No attribute {name} found at tag {tag_name}') - original_case = tag_info['attribs'].original_case[name] - return f'{tag_xpath}/@{original_case}' + return self._find_attrib_via_tag_name(name, + tag_name, + self.iteration_tag_xpath, + contains=contains, + not_contains=not_contains) entries = [ entry for entry in self._attrib_entries @@ -1068,21 +1081,12 @@ def relative_iteration_attrib_xpath(self, exclude = [] if tag_name is not None: - tag_xpath = self.relative_iteration_tag_xpath(tag_name, - root_tag, - contains=contains, - not_contains=not_contains) - - tag_info = self.tag_info(tag_name, contains=contains, not_contains=not_contains) - - if name not in tag_info['attribs']: - raise NoPathFound(f'No attribute {name} found at tag {tag_name}') - - original_case = tag_info['attribs'].original_case[name] - - if tag_xpath.endswith('/'): - return f'{tag_xpath}@{original_case}' - return f'{tag_xpath}/@{original_case}' + return self._find_attrib_via_tag_name(name, + tag_name, + self.relative_iteration_tag_xpath, + root_tag, + contains=contains, + not_contains=not_contains) entries = [ entry for entry in self._attrib_entries From f204e98626f515315f8cf13c303d35628e44490c Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 13:52:50 +0200 Subject: [PATCH 13/36] Add make step to docs to run the fleurxmlmodfier docstring write script More direct feedback when changing the examples, since no additional pre-commit step is needed in between --- docs/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/Makefile b/docs/Makefile index d9c3654dd..e8ccf9e69 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -6,6 +6,7 @@ SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build +PYTHON3 ?= python3 # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 @@ -41,7 +42,10 @@ help: clean: -rm -r $(BUILDDIR) -html: +modifier-docstrings: + $(PYTHON3) ../utils/write_fleurxmlmodifier_docstrings.py + +html: modifier-docstrings $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." From 2329d0b2c6c396a0297534f65bf72997bed47af7 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 14:00:32 +0200 Subject: [PATCH 14/36] Delete comment from example file to reduce noise --- docs/Makefile | 2 +- .../user_guide/fleurxmlmodifier_usage_examples/files/inp.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index e8ccf9e69..3cc0be0e2 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -15,7 +15,7 @@ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) sou # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source -.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext +.PHONY: help clean modifier-docstrings html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp.xml b/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp.xml index e7cbe481d..6723e0d48 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp.xml +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp.xml @@ -101,6 +101,5 @@ 0.2 0.0 0.0 - From bcb920fee06e5d17536092bfdd0dbccad808dc89 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 14:01:40 +0200 Subject: [PATCH 15/36] More examples --- masci_tools/io/fleurxmlmodifier.py | 137 ++++++++++++++++++++++ masci_tools/util/xml/xml_setters_names.py | 137 ++++++++++++++++++++++ 2 files changed, 274 insertions(+) diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index fe8159be2..7117fe969 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -945,6 +945,12 @@ def set_simple_tag(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_simple_tag('soc', {'theta': 0.1, 'phi': 0.2, 'l_soc': True}) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_simple_tag()` to the list of tasks that will be done on the xmltree. """ @@ -972,6 +978,44 @@ def set_text(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_text('kpoint', [[1,2,3], [4,5,6]]) + + .. usage-example:: + :title: Setting one value + :description: If only one value for the text is given all elements are set ot the same value + in this case only one list of three coordinates is set + + fm.set_text('kpoint', [4,4,4]) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_text('q', '1 1 1') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_text('q', '1 1 1', contains='spinSpiral') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_text('valenceConfig', + '(1s1/2)', + contains='species', + filters={ + 'species': { + './lo/@n': {'>': 4} + }}) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_text()` to the list of tasks that will be done on the xmltree. """ @@ -998,6 +1042,37 @@ def set_first_text(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_first_text('kpoint', [1,2,3]) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_first_text('valenceConfig', '(1s1/2)') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_first_text('valenceConfig', '(1s1/2)', contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_first_text('valenceConfig', + '(1s1/2)', + contains='species', + filters={ + 'species': { + './lo/@n': {'>': 4} + }}) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_text()` to the list of tasks that will be done on the xmltree. """ @@ -1027,6 +1102,37 @@ def set_attrib_value(self, *args: Any, **kwargs: Any) -> None: :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_attrib_value('itmax', 180) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_attrib_value('radius', 1.05) + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_attrib_value('radius', 1.05, contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_attrib_value('spinUp', + 1, + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_attrib_value()` to the list of tasks that will be done on the xmltree. """ @@ -1061,6 +1167,37 @@ def set_first_attrib_value(self, *args: Any, **kwargs: Any) -> None: :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_first_attrib_value('itmax', 180) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_first_attrib_value('radius', 1.05) + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_first_attrib_value('radius', 1.05, contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_first_attrib_value('spinUp', + 1, + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_attrib_value()` to the list of tasks that will be done on the xmltree. """ diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 1ce604509..6b94e2ff9 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -530,6 +530,37 @@ def set_attrib_value(xmltree: XMLLike, :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_attrib_value('itmax', 180) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_attrib_value('radius', 1.05) + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_attrib_value('radius', 1.05, contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_attrib_value('spinUp', + 1, + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + :returns: xmltree with set attribute """ from masci_tools.util.xml.xml_setters_xpaths import xml_set_attrib_value @@ -585,6 +616,37 @@ def set_first_attrib_value(xmltree: XMLLike, :param exclude: list of str, here specific types of attributes can be excluded valid values are: settable, settable_contains, other + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_first_attrib_value('itmax', 180) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_first_attrib_value('radius', 1.05) + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_first_attrib_value('radius', 1.05, contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_first_attrib_value('spinUp', + 1, + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + :returns: xmltree with set attribute """ return set_attrib_value(xmltree, @@ -629,6 +691,44 @@ def set_text(xmltree: XMLLike, :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_text('kpoint', [[1,2,3], [4,5,6]]) + + .. usage-example:: + :title: Setting one value + :description: If only one value for the text is given all elements are set ot the same value + in this case only one list of three coordinates is set + + fm.set_text('kpoint', [4,4,4]) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_text('q', '1 1 1') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_text('q', '1 1 1', contains='spinSpiral') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_text('valenceConfig', + '(1s1/2)', + contains='species', + filters={ + 'species': { + './lo/@n': {'>': 4} + }}) + :returns: xmltree with set text """ from masci_tools.util.xml.xml_setters_xpaths import xml_set_text @@ -668,6 +768,37 @@ def set_first_text(xmltree: XMLLike, :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_first_text('kpoint', [1,2,3]) + + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_first_text('valenceConfig', '(1s1/2)') + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_first_text('valenceConfig', '(1s1/2)', contains='species') + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_first_text('valenceConfig', + '(1s1/2)', + contains='species', + filters={ + 'species': { + './lo/@n': {'>': 4} + }}) + :returns: xmltree with set text """ return set_text(xmltree, @@ -711,6 +842,12 @@ def set_simple_tag(xmltree: XMLLike, :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_simple_tag('soc', {'theta': 0.1, 'phi': 0.2, 'l_soc': True}) + :returns: xmltree with set simple tags """ from masci_tools.util.xml.xml_setters_xpaths import xml_set_simple_tag From 6181779fcd0fc5739c13a6bb0d497c9244007ab6 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 14:07:12 +0200 Subject: [PATCH 16/36] Clearer docstring --- masci_tools/util/sphinxext/usage_examples.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/masci_tools/util/sphinxext/usage_examples.py b/masci_tools/util/sphinxext/usage_examples.py index 2c7b4d5b5..76b22020c 100644 --- a/masci_tools/util/sphinxext/usage_examples.py +++ b/masci_tools/util/sphinxext/usage_examples.py @@ -120,6 +120,14 @@ def run(self): def generate_usage_example_files(app): """ Generate the markdown files for the specified usage examples + + The process consists of two steps: + 1. The module specified in the individual configurations (``config.yml`` files in the ``template_dirs`` + specified in the ``conf.py`` file) + is parsed to extract the + information specified in ``.. usage-example::`` directives. + 2. The information extracted is used to render the jinja template + in the ``template_dirs`` """ logger.info('Generating usage examples ...') From a246b563de449cb62a7919314ad0ab2664843c52 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 14:24:48 +0200 Subject: [PATCH 17/36] Cleanup conf.py --- docs/source/conf.py | 264 ++++---------------------------------------- 1 file changed, 19 insertions(+), 245 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index f3bc960ff..2ec0ad935 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -4,29 +4,13 @@ # # This file is execfile()d with the current directory set to its # containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. import masci_tools import os -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -#sys.path.insert(0, os.path.abspath('../aiida_fleur')) # -- General configuration ------------------------------------------------ -# If your documentation needs a minimal Sphinx version, state it here. -#needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. extensions = ['myst_nb', 'sphinx.ext.autodoc', 'sphinx.ext.doctest', @@ -62,8 +46,7 @@ 'template_dirs': ['user_guide/fleurxmlmodifier_usage_examples'] } -# The encoding of source files. -#source_encoding = 'utf-8-sig' +autodoc_mock_imports = ['bokeh', '_typeshed'] # The master toctree document. master_doc = 'index' @@ -72,189 +55,30 @@ project = 'Masci-tools' copyright = '2016-2021, Forschungszentrum Jülich GmbH, PGI-1/IAS-1 Quantum Theory of Materials' -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# - version = '.'.join(masci_tools.__version__.split('.')[:2]) # The full version, including alpha/beta/rc tags. release = masci_tools.__version__ author = 'The JuDFT team' - -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -#language = None - -# There are two options for replacing |today|: either, you set today to some -# non-false value, then it is used: -#today = '' -# Else, today_fmt is used as the format for a strftime call. -#today_fmt = '%B %d, %Y' - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. exclude_patterns = ['_build'] - -# The reST default role (used for this markup: `text`) to use for all -# documents. -#default_role = None - -# If true, '()' will be appended to :func: etc. cross-reference text. -#add_function_parentheses = True - -# If true, the current module name will be prepended to all description -# unit titles (such as .. function::). -#add_module_names = True - -# If true, sectionauthor and moduleauthor directives will be shown in the -# output. They are ignored by default. -#show_authors = False - -# The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' -# A list of ignored prefixes for module index sorting. -#modindex_common_prefix = [] - -# If true, keep warnings as "system message" paragraphs in the built documents. -#keep_warnings = False +# -- Options for HTML output --------------------------------------------- -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. html_theme = 'default' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -#html_theme_options = {} - -# Add any paths that contain custom themes here, relative to this directory. -#html_theme_path = [] - -# The name for this set of Sphinx documents. If None, it defaults to -# " v documentation". -#html_title = None - -# A shorter title for the navigation bar. Default is the same as html_title. -#html_short_title = None - -# The name of an image file (relative to this directory) to place at the top -# of the sidebar. -#html_logo = None - -# The name of an image file (within the static path) to use as favicon of the -# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 -# pixels large. -#html_favicon = None - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] - -# Add any extra paths that contain custom files (such as robots.txt or -# .htaccess) here, relative to this directory. These files are copied -# directly to the root of the documentation. -#html_extra_path = [] - -# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, -# using the given strftime format. -#html_last_updated_fmt = '%b %d, %Y' - -# If true, SmartyPants will be used to convert quotes and dashes to -# typographically correct entities. -#html_use_smartypants = True - -# Custom sidebar templates, maps document names to template names. -#html_sidebars = {} - -# Additional templates that should be rendered to pages, maps page names to -# template names. -#html_additional_pages = {} - -# If false, no module index is generated. -#html_domain_indices = True - -# If false, no index is generated. -#html_use_index = True - -# If true, the index is split into individual pages for each letter. -#html_split_index = False - -# If true, links to the reST sources are added to the pages. -#html_show_sourcelink = True - -# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. -#html_show_sphinx = True - -# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. -#html_show_copyright = True - -# If true, an OpenSearch description file will be output, and all pages will -# contain a tag referring to it. The value of this option must be the -# base URL from which the finished HTML is served. -#html_use_opensearch = '' - -# This is the file name suffix for HTML files (e.g. ".xhtml"). -#html_file_suffix = None - -# Output file base name for HTML help builder. htmlhelp_basename = 'masci-toolsdoc' +# These folders are copied to the documentation's HTML output +html_static_path = ['_static'] - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { -# The paper size ('letterpaper' or 'a4paper'). -#'papersize': 'letterpaper', - -# The font size ('10pt', '11pt' or '12pt'). -#'pointsize': '10pt', - -# Additional stuff for the LaTeX preamble. -#'preamble': '', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). -latex_documents = [ - ('index', 'masci-tools.tex', 'Masci-tools Documentation', - 'The JuDFT team', 'manual'), +# These paths are either relative to html_static_path +# or fully qualified paths (eg. https://...) +html_css_files = [ + 'theme_overrides.css', ] - -# The name of an image file (relative to this directory) to place at the top of -# the title page. -#latex_logo = None - -# For "manual" documents, if this is true, then toplevel headings are parts, -# not chapters. -#latex_use_parts = False - -# If true, show page references after internal links. -#latex_show_pagerefs = False - -# If true, show URL addresses after external links. -#latex_show_urls = False - -# Documents to append as an appendix to all manuals. -#latex_appendices = [] - -# If false, no module index is generated. -#latex_domain_indices = True - - # on_rtd is whether we are on readthedocs.org, this line of code grabbed # from docs.readthedocs.org -# NOTE: it is needed to have these lines before load_dbenv() -on_rtd = os.environ.get('READTHEDOCS', None) == 'True' # python 3 -#on_rtd = os.environ.read('READTHEDOCS', None) == 'True' # python 2 - +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' if not on_rtd: # only import and set the theme if we're building docs locally try: import sphinx_rtd_theme @@ -264,7 +88,16 @@ # No sphinx_rtd_theme installed pass -autodoc_mock_imports = ['bokeh', '_typeshed'] + +# -- Options for LaTeX output --------------------------------------------- + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'masci-tools.tex', 'Masci-tools Documentation', + 'The JuDFT team', 'manual'), +] # -- Options for manual page output --------------------------------------- @@ -276,10 +109,6 @@ ['The JuDFT team'], 1) ] -# If true, show URL addresses after external links. -#man_show_urls = False - - # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples @@ -291,18 +120,6 @@ 'Miscellaneous'), ] -# Documents to append as an appendix to all manuals. -#texinfo_appendices = [] - -# If false, no module index is generated. -#texinfo_domain_indices = True - -# How to display URL addresses: 'footnote', 'no', or 'inline'. -#texinfo_show_urls = 'footnote' - -# If true, do not generate a @detailmenu in the "Top" node's menu. -#texinfo_no_detailmenu = False - # -- Options for Epub output --------------------------------------------------- # Bibliographic Dublin Core info. @@ -311,39 +128,6 @@ epub_publisher = author epub_copyright = copyright -# The language of the text. It defaults to the language option -# or en if the language is not set. -#epub_language = '' - -# The scheme of the identifier. Typical schemes are ISBN or URL. -#epub_scheme = '' - -# The unique identifier of the text. This can be a ISBN number -# or the project homepage. -#epub_identifier = '' - -# A unique identification for the text. -#epub_uid = '' - -# A tuple containing the cover image and cover page html template filenames. -#epub_cover = () - -# HTML files that should be inserted before the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_pre_files = [] - -# HTML files shat should be inserted after the pages created by sphinx. -# The format is a list of tuples containing the path and title. -#epub_post_files = [] - -# A list of files that should not be packed into the epub file. -#epub_exclude_files = [] - -# The depth of the table of contents in toc.ncx. -#epub_tocdepth = 3 - - - # Warnings to ignore when using the -n (nitpicky) option # We should ignore any python built-in exception, for instance nitpick_ignore = [ @@ -411,13 +195,3 @@ ('py:data', 'masci_tools.io.parsers.fleur.fleur_outxml_parser.F'), ('py:class', 'np.ndarray') ] - - -# These folders are copied to the documentation's HTML output -html_static_path = ['_static'] - -# These paths are either relative to html_static_path -# or fully qualified paths (eg. https://...) -html_css_files = [ - 'theme_overrides.css', -] From 3aeebd09d3fd7b7d1f4c91b11dd219fa22e14614 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 14:47:56 +0200 Subject: [PATCH 18/36] typing --- .pre-commit-config.yaml | 1 + masci_tools/util/sphinxext/__init__.py | 3 +- masci_tools/util/sphinxext/usage_examples.py | 62 +++++++++++++------- 3 files changed, 45 insertions(+), 21 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 03428764d..d50f5c99a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -96,6 +96,7 @@ repos: masci_tools/io/fleurxmlmodifier.py| masci_tools/io/common_functions.py| masci_tools/util/xml/.*py| + masci_tools/util/sphinxext/.*py| masci_tools/util/lockable_containers.py| masci_tools/util/case_insensitive_dict.py| masci_tools/util/schema_dict_util.py| diff --git a/masci_tools/util/sphinxext/__init__.py b/masci_tools/util/sphinxext/__init__.py index 63a39675a..90e7299a8 100644 --- a/masci_tools/util/sphinxext/__init__.py +++ b/masci_tools/util/sphinxext/__init__.py @@ -16,9 +16,10 @@ """ from .usage_examples import UsageExampleBlock, generate_usage_example_files, DEFAULT_CONF +from sphinx.application import Sphinx -def setup(app): +def setup(app: Sphinx) -> None: """ This function sets up the Sphinx extension. It is called, when ``masci_tools.util.sphinxext`` is added to the extensions in a conf.py file diff --git a/masci_tools/util/sphinxext/usage_examples.py b/masci_tools/util/sphinxext/usage_examples.py index 76b22020c..c4b661491 100644 --- a/masci_tools/util/sphinxext/usage_examples.py +++ b/masci_tools/util/sphinxext/usage_examples.py @@ -6,14 +6,17 @@ in with the options and content from `usage-example` directives in the docstrings of the specified methods """ +from __future__ import annotations import os from pathlib import Path import copy import ast from contextlib import redirect_stderr, contextmanager +from typing import Any, TypedDict, Generator, cast import yaml import io +from sphinx.application import Sphinx from sphinx.util.logging import getLogger from sphinx.errors import ConfigError, ExtensionError from sphinx.util.docutils import register_directive @@ -21,7 +24,7 @@ from docutils.core import publish_doctree from docutils.parsers.rst.directives.body import CodeBlock -from docutils.parsers.rst import directives +from docutils.parsers.rst import directives, Directive from docutils import nodes from docutils.parsers.rst.roles import set_classes from docutils.utils.code_analyzer import Lexer, LexerError @@ -47,6 +50,17 @@ } +class UsageExample(TypedDict, total=False): + """ + Dict representing information from ``..usage-example`` directives + """ + title: str + error: bool + inputfile: str + code: str + description: str + + class UsageExampleBlock(SphinxDirective): """ Directive for usage examples @@ -117,7 +131,7 @@ def run(self): return [admonition_node] -def generate_usage_example_files(app): +def generate_usage_example_files(app: Sphinx) -> None: """ Generate the markdown files for the specified usage examples @@ -135,39 +149,41 @@ def generate_usage_example_files(app): config.update(app.config.usage_examples_conf) for template_folder in config['template_dirs']: - template_folder, template_conf = _load_template_conf(template_folder, app.builder.srcdir) + template_folder_path, template_conf = _load_template_conf(template_folder, + app.builder.srcdir) #type: ignore[union-attr] usage_examples = _gather_usage_examples(**template_conf) - _render_templates(template_folder, usage_examples, config, template_conf) + _render_templates(template_folder_path, usage_examples, config, template_conf) -def _load_template_conf(template_folder, srcdir): +def _load_template_conf(template_folder: str, srcdir: str) -> tuple[Path, dict[str, Any]]: """ Load the configuration for the current template folder :param template_folder: Filepath to the folder containing the template :param srcdir: directory containing the conf.py """ - template_folder = Path(srcdir) / template_folder + template_folder_path = Path(srcdir) / template_folder config = copy.deepcopy(DEFAULT_TEMPLATE_CONFIG) - with open(template_folder / TEMPLATE_CONFIG_FILE, encoding='utf-8') as file: + with open(template_folder_path / TEMPLATE_CONFIG_FILE, encoding='utf-8') as file: config.update(yaml.safe_load(file)) if config['exclude-methods'] is not None: - config['exclude-methods'] = set(config['exclude-methods']) + config['exclude-methods'] = set(config['exclude-methods']) #type: ignore[assignment,arg-type] if config['module-file'] is None: raise ConfigError(f'The template in {template_folder} does not define a module') - config['module-file'] = template_folder / config['module-file'] + config['module-file'] = template_folder_path / config['module-file'] #type: ignore[assignment,operator] if config['class-name'] is None: - raise ConfigError(f'The template in {template_folder} does not define a class') + raise ConfigError(f'The template in {template_folder_path} does not define a class') config = {k.replace('-', '_'): v for k, v in config.items()} - return template_folder, config + return template_folder_path, config -def _render_templates(template_folder, usage_examples, config, template_config): +def _render_templates(template_folder: Path, usage_examples: dict[str, list[UsageExample]], config: dict[str, Any], + template_config: dict[str, Any]) -> None: """ Render all usage-example with the specified jinja template @@ -197,7 +213,11 @@ def _render_templates(template_folder, usage_examples, config, template_config): logger.info('Rendered Usage example to "%s".', os.fspath(template_folder / f'{name}.md')) -def _gather_usage_examples(module_file, class_name, exclude_methods=None, include_private_methods=False, **kwargs): +def _gather_usage_examples(module_file: Path, + class_name: str, + exclude_methods: set[str] | None = None, + include_private_methods: bool = False, + **kwargs: Any) -> dict[str, list[UsageExample]]: """ Gather all usage-example blocks for the specified methods @@ -209,7 +229,7 @@ def _gather_usage_examples(module_file, class_name, exclude_methods=None, includ :returns: dict mapping method names to the list of usage examples defined in it's docstring """ - class UsageExampleTemplateBlock(CodeBlock): + class UsageExampleTemplateBlock(CodeBlock): #type: ignore[misc] """ Dummy directive which extract the information of usage-example directives @@ -226,7 +246,7 @@ class UsageExampleTemplateBlock(CodeBlock): 'inputfile': directives.unchanged, } has_content = True - collected_examples = [] + collected_examples: list[UsageExample] = [] def run(self): self.assert_has_content() @@ -234,12 +254,12 @@ def run(self): self.options.setdefault('classes', []).append( 'usage-example') #For checking after the fact if there were usage examples provided - example = { + example = UsageExample({ 'title': self.options.get('title', 'Simple Usage'), 'error': self.options.get('result', 'success').lower() == 'error', 'inputfile': self.options.get('inputfile', 'inp.xml'), 'code': '\n'.join(self.content) - } + }) if 'description' in self.options: example['description'] = self.options['description'] self.collected_examples.append(example) @@ -256,7 +276,7 @@ def reset(cls): module = ast.parse(file.read()) usage_examples = {} - with patch_directive('usage-example', UsageExampleTemplateBlock): + with patch_directive('usage-example', cast(type[Directive], UsageExampleTemplateBlock)): class_definitions = [node for node in module.body if isinstance(node, ast.ClassDef)] @@ -270,7 +290,9 @@ def reset(cls): continue docstring = ast.get_docstring(method, clean=True) - short_desc = ast.get_docstring(method, clean=False).split('\n')[0] + short_desc = ast.get_docstring(method, clean=False) + if short_desc is not None: + short_desc = short_desc.split('\n')[0] #Ignore unknown directive errors with redirect_stderr(io.StringIO()): @@ -291,7 +313,7 @@ def reset(cls): @contextmanager -def patch_directive(name, directive): +def patch_directive(name: str, directive: type[Directive]) -> Generator[None, None, None]: """ Temporarily replace the directive of the given name with a different one From 226ca9f30847b07c910050b262495d7d1b156edc Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 17:01:55 +0200 Subject: [PATCH 19/36] Start experimenting with some link layouts on the actual fleurxmlmodifier site --- docs/source/conf.py | 1 + docs/source/user_guide/fleurxmlmodifier.md | 276 ++++++++++++++++++ .../template.md.jinja | 2 +- masci_tools/util/sphinxext/usage_examples.py | 2 +- 4 files changed, 279 insertions(+), 2 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 2ec0ad935..6774f9576 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -21,6 +21,7 @@ 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx', 'sphinx_autodoc_typehints', + 'sphinx_design', 'sphinx_copybutton', 'sphinx_click', 'masci_tools.util.sphinxext'] diff --git a/docs/source/user_guide/fleurxmlmodifier.md b/docs/source/user_guide/fleurxmlmodifier.md index 72a556a64..50c641d9c 100644 --- a/docs/source/user_guide/fleurxmlmodifier.md +++ b/docs/source/user_guide/fleurxmlmodifier.md @@ -134,3 +134,279 @@ LDA+U procedure. They are read in the same order as they appear in the `inp.xml` file can become invalid if one adds/removes a LDA+U procedure to the `inp.xml` after the `n_mmp_mat` file was initialized. Therefore any modifications to the `n_mmp_mat` file should be done after adding/removing or modifying the LDA+U configuration. ::: + +## Modification methods + +::::::{dropdown} Simple changes +:open: +:color: info +:animate: fade-in-slide-down + +:::::{grid} 2 + +::::{grid-item-card} **set_inpchanges** +:text-align: center +Change the value of multiple text or attribute values at once. ++++ +:::{button-ref} set_inpchanges +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: +::::: +:::::: + +::::::{dropdown} Modifying atom species +:open: +:color: info +:animate: fade-in-slide-down + +:::::{grid} 2 + +::::{grid-item-card} **set_species** +:text-align: center +Change parameters or add new elements in `species` elements. ++++ +:::{button-ref} set_species +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: +::::: +:::::: + +::::::{dropdown} Modifying atom groups +:open: +:color: info +:animate: fade-in-slide-down + +:::::{grid} 2 + +::::{grid-item-card} **set_atomgroup** +:text-align: center +Change parameters or add new elements in `atomGroup` elements, +i.e. the elmements containing the symmetry equivalent atoms. ++++ +:::{button-ref} set_atomgroup +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: +::::: +:::::: + +::::::{dropdown} Modifying kpoint sets +:open: +:color: info +:animate: fade-in-slide-down + +:::::{grid} 2 + +::::{grid-item-card} **switch_kpointset** +:text-align: center +Switch the used kpoint set ++++ +:::{button-ref} switch_kpointset +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: +::::: +:::::: + +::::::{dropdown} Setting generic XML elements and attributes +:open: +:color: info +:animate: fade-in-slide-down + +:::::{grid} 2 + +::::{grid-item-card} **set_attrib_value** +:text-align: center +Set abitrary XML attribute values ++++ +:::{button-ref} set_attrib_value +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **set_first_attrib_value** +:text-align: center +Set abitrary XML attribute values for the +first occurrence of the given attribute in the XML tree ++++ +:::{button-ref} set_first_attrib_value +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + + +::::{grid-item-card} **set_text** +:text-align: center +Set the text of arbitrary XML elements ++++ +:::{button-ref} set_text +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **set_first_text** +:text-align: center +Set the text of arbitrary XML elements for the first +occurrence of the given element in the XML tree ++++ +:::{button-ref} set_first_text +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **add_number_to_attrib** +:text-align: center +Add to or multiply the values of arbitrary XML +attributes ++++ +:::{button-ref} add_number_to_attrib +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **add_number_to_first_attrib** +:text-align: center +Add to or multiply the values of arbitrary XML +attributes for the first occurrence of the given attribute +in the XML tree ++++ +:::{button-ref} add_number_to_first_attrib +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **set_simple_tag** +:text-align: center +Create or change arbitrary simple XML elements, i.e. elements +without child elements ++++ +:::{button-ref} set_simple_tag +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **set_complex_tag** +:text-align: center +Create or change an arbitrary complex XML element, i.e. an element +with child elements. ++++ +:::{button-ref} set_complex_tag +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::: +:::::: + +::::::{dropdown} Manipulating the DFT+U density matrix +:color: info +:animate: fade-in-slide-down + +:::::{grid} 2 + +::::{grid-item-card} **set_nmmpmat** +:text-align: center +Initialize the `n_mmp_mat` file with a given density matrix ++++ +:::{button-ref} set_nmmpmat +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: +::::: +:::::: + + +::::::{dropdown} Using explicit XPath expressions for modifications +:color: warning +:icon: Alert +:animate: fade-in-slide-down + +These routines should be used with a lot of care, since they have +much less checks than all other setting functions + +:::::{grid} 2 + +::::{grid-item-card} **xml_create_tag** +:text-align: center +Create a XML element with the given name as a child of the +results of the XPath expression ++++ +:::{button-ref} xml_create_tag +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::: +:::::: \ No newline at end of file diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja index c0d1b0ee3..92b5b4073 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -17,7 +17,7 @@ kernelspec: %xmode Minimal %load_ext masci_tools ``` - +({{ reference }})= # {{ title }} ```{contents} Examples diff --git a/masci_tools/util/sphinxext/usage_examples.py b/masci_tools/util/sphinxext/usage_examples.py index c4b661491..4a9c16846 100644 --- a/masci_tools/util/sphinxext/usage_examples.py +++ b/masci_tools/util/sphinxext/usage_examples.py @@ -209,7 +209,7 @@ def _render_templates(template_folder: Path, usage_examples: dict[str, list[Usag output_folder.mkdir() with open(output_folder / f'{name}.md', 'w', encoding='utf-8') as file: - file.write(template.render(examples=examples, title=f'``{name}``')) + file.write(template.render(examples=examples, title=f'``{name}``',reference=name)) logger.info('Rendered Usage example to "%s".', os.fspath(template_folder / f'{name}.md')) From cbc89e4f6c9d9e0bbc547eb0cddd6b33073870c4 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 17:10:11 +0200 Subject: [PATCH 20/36] Add references to API references --- .../user_guide/fleurxmlmodifier_usage_examples/template.md.jinja | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja index 92b5b4073..c34657f2b 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -20,6 +20,7 @@ kernelspec: ({{ reference }})= # {{ title }} +{py:meth}`Go to the API reference ` ```{contents} Examples :local: ``` From 18e8e271e47ffb5a81d5b9342c02496dbaebc3db Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 17:40:56 +0200 Subject: [PATCH 21/36] Add all missing links --- docs/source/user_guide/fleurxmlmodifier.md | 382 +++++++++++++++------ 1 file changed, 279 insertions(+), 103 deletions(-) diff --git a/docs/source/user_guide/fleurxmlmodifier.md b/docs/source/user_guide/fleurxmlmodifier.md index 50c641d9c..88d38770a 100644 --- a/docs/source/user_guide/fleurxmlmodifier.md +++ b/docs/source/user_guide/fleurxmlmodifier.md @@ -38,104 +38,7 @@ new_xmltree, _ = fm.modify_xmlfile('/path/to/original/inp.xml') #Apply last task or all tasks from the list of changes. (modify-methods)= - -### Modification registration methods - -The registration methods can be separated into two groups. First of all, -there are XML methods that require deeper knowledge about the structure of an `inp.xml` file. -All of them require an xpath input and start their method names start with `xml_`: - -- {py:meth}`FleurXMLModifier.xml_set_attrib_value_no_create()`: Set attributes on the result(s) of the given xpath -- {py:meth}`FleurXMLModifier.xml_set_text_no_create()`: Set text on the result(s) of the given xpath -- {py:meth}`FleurXMLModifier.xml_create_tag()`: Insert - an xml element in the xml tree on the result(s) of the given xpath. -- {py:meth}`FleurXMLModifier.xml_delete_tag()`: Delete - an xml element in the xml tree on the result(s) of the given xpath. -- {py:meth}`FleurXMLModifier.xml_delete_att()`: Delete - an attribute in the xml tree on the result(s) of the given xpath. -- {py:meth}`FleurXMLModifier.xml_replace_tag()`: Replace an xml element on the result(s) of the given xpath. - -On the other hand, there are shortcut methods that already know some paths: - -- {py:meth}`FleurXMLModifier.set_species()`: Specific - user-friendly method to change species parameters. -- {py:meth}`FleurXMLModifier.clone_species()`: Method to - create a clone of a given species with optional modifications -- {py:meth}`FleurXMLModifier.set_atomgroup()`: Specific - method to change atom group parameters. -- {py:meth}`FleurXMLModifier.set_species_label()`: Specific - user-friendly method to change a species of an atom with a certain label. -- {py:meth}`FleurXMLModifier.set_atomgroup_label()`: Specific - method to change atom group parameters of an atom with a certain label. -- {py:meth}`FleurXMLModifier.switch_species()`: user-friendly method for switching the atom species of a atom group -- {py:meth}`FleurXMLModifier.switch_species_label()`: user-friendly method for switching the atom species of a atom group with an atom with a certain label. -- {py:meth}`FleurXMLModifier.set_nkpts()`: user-friendly method for setting the `kPointCount` (**Only for MaX4 and older**) -- {py:meth}`FleurXMLModifier.set_kpath()`: user-friendly method for setting the path for a bandstructure calculations (**Only for MaX4 and older**) -- {py:meth}`FleurXMLModifier.set_kpointlist()`: user-friendly method for setting/creating a `kPointlist` from lists -- {py:meth}`FleurXMLModifier.switch_kpointset()`: user-friendly method for switching the used kpoint set in a calculation (**Only for MaX5 and newer**) -- {py:meth}`FleurXMLModifier.set_inpchanges()`: Specific - user-friendly method for easy changes of attribute key value type. -- {py:meth}`FleurXMLModifier.shift_value()`: Specific - user-friendly method to shift value of an attribute. -- {py:meth}`FleurXMLModifier.shift_value_species_label()`: Specific - user-friendly method to shift value of an attribute of an atom with a certain label. -- {py:meth}`FleurXMLModifier.set_attrib_value()`: user-friendly method for setting attributes in the xml file by specifying their name -- {py:meth}`FleurXMLModifier.set_first_attrib_value()`: user-friendly method for setting the first occurrence of an attribute in the xml file by specifying its name -- {py:meth}`FleurXMLModifier.add_number_to_attrib()`: user-friendly method for adding to or multiplying values of attributes in the xml file by specifying their name -- {py:meth}`FleurXMLModifier.add_number_to_first_attrib()`: user-friendly method for adding to or multiplying values of the first occurrence of the attribute in the xml file by specifying their name -- {py:meth}`FleurXMLModifier.set_text()`: user-friendly method for setting text on xml elements in the xml file by specifying their name -- {py:meth}`FleurXMLModifier.set_first_text()`: user-friendly method for setting the text on the first occurrence of an xml element in the xml file by specifying its name -- {py:meth}`FleurXMLModifier.set_simple_tag()`: user-friendly method for creating and setting attributes on simple xml elements (only attributes) in the xml file by specifying its name -- {py:meth}`FleurXMLModifier.set_complex_tag()`: user-friendly method for creating complex tags in the xml file by specifying its name -- {py:meth}`FleurXMLModifier.create_tag()`: User-friendly method for inserting a tag in the right place by specifying it's name -- {py:meth}`FleurXMLModifier.delete_tag()`: User-friendly method for delete a tag by specifying it's name -- {py:meth}`FleurXMLModifier.delete_att()`: User-friendly method for deleting an attribute from a tag by specifying it's name -- {py:meth}`FleurXMLModifier.replace_tag()`: User-friendly method for replacing a tag by another by specifying its name -- {py:meth}`FleurXMLModifier.set_nmmpmat()`: Specific - method for initializing or modifying the density matrix file for a LDA+U calculation (details see below) -- {py:meth}`FleurXMLModifier.rotate_nmmpmat()`: Specific - method for rotating a block/blocks of the density matrix file for a LDA+U calculation (details see below) in real space -- {py:meth}`FleurXMLModifier.align_nmmpmat_to_sqa()`: Specific - method for aligning a block/blocks of the density matrix file for a LDA+U calculation (details see below) in real space with the SQA already specified in the `inp.xml` - -% The figure below shows a comparison between the use of XML and shortcut methods. -% -% .. image:: images/registration_methods.png -% :width: 100% -% :align: center - -## Modifying the density matrix for LDA+U calculations - -The above mentioned {py:meth}`FleurXMLModifier.set_nmmpmat()`, {py:meth}`FleurXMLModifier.rotate_nmmpmat()` and -{py:meth}`FleurXMLModifier.align_nmmpmat_to_sqa()` take a special role in the modification registration methods, -as the modifications are not done on the `inp.xml` file but the density matrix file `n_mmp_mat` used by Fleur -for LDA+U calculations. The resulting new `n_mmp_mat` file is returned next to the new `inp.xml` by -the {py:meth}`FleurXMLModifier.modify_xmlfile()`. - -The code example below shows how to use this method to add a LDA+U procedure to an atom species and provide -an initial guess for the density matrix. - -```python -from masci_tools.io.fleurxmlmodifier import FleurXMLModifier - -fm = FleurXMLModifier() -# Add LDA+U procedure -fm.set_species('Nd-1', {'ldaU':{'l': 3, 'U': 6.76, 'J': 0.76, 'l_amf': 'F'}}) -# Initialize n_mmp_mat file with the states m = -3 to m = 0 occupied for spin up -# spin down is initialized with 0 by default, since no n_mmp_mat file is provided -fm.set_nmmpmat('Nd-1', orbital=3, spin=1, state_occupations=[1,1,1,1,0,0,0]) -new_xmltree, add_files = fm.modify_xmlfile('/path/to/original/inp.xml') -print(add_files['n_mmp_mat']) -``` - -:::{note} -The `n_mmp_mat` file is a simple text file with no knowledge of which density matrix block corresponds to which -LDA+U procedure. They are read in the same order as they appear in the `inp.xml`. For this reason the `n_mmp_mat` -file can become invalid if one adds/removes a LDA+U procedure to the `inp.xml` after the `n_mmp_mat` file was -initialized. Therefore any modifications to the `n_mmp_mat` file should be done after adding/removing or modifying the LDA+U configuration. -::: - -## Modification methods +### Modification methods ::::::{dropdown} Simple changes :open: @@ -157,7 +60,22 @@ Change the value of multiple text or attribute values at once. Show Examples ::: :::: + +::::{grid-item-card} **shift_value** +:text-align: center +Shift or multiply the value of multiple text or attribute values at once. ++++ +:::{button-ref} shift_value +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: ::::: + :::::: ::::::{dropdown} Modifying atom species @@ -169,7 +87,8 @@ Show Examples ::::{grid-item-card} **set_species** :text-align: center -Change parameters or add new elements in `species` elements. +Change parameters or add new tags in atomic `species` elements. +For example changing the MT radius or adding DFT+U. +++ :::{button-ref} set_species :ref-type: ref @@ -180,6 +99,35 @@ Change parameters or add new elements in `species` elements. Show Examples ::: :::: + +::::{grid-item-card} **set_species_label** +:text-align: center +Change parameters or add new tags in atomic `species` of a +specific atom. The atom is identified by it's label. ++++ +:::{button-ref} set_species_label +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **clone_species** +:text-align: center +Duplicate a given species element with a different name. ++++ +:::{button-ref} clone_species +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: ::::: :::::: @@ -193,7 +141,7 @@ Show Examples ::::{grid-item-card} **set_atomgroup** :text-align: center Change parameters or add new elements in `atomGroup` elements, -i.e. the elmements containing the symmetry equivalent atoms. +i.e. the elements containing the symmetry equivalent atoms. +++ :::{button-ref} set_atomgroup :ref-type: ref @@ -204,6 +152,51 @@ i.e. the elmements containing the symmetry equivalent atoms. Show Examples ::: :::: + +::::{grid-item-card} **set_atomgroup_label** +:text-align: center +Change parameters or add new elements in `atomGroup` elements, +i.e. the elements containing the symmetry equivalent atoms. +The group to modify is identified by a given label of an atom. ++++ +:::{button-ref} set_atomgroup_label +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **switch_species** +:text-align: center +Change the species of a given atom group. ++++ +:::{button-ref} switch_species +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **switch_species_label** +:text-align: center +Change the species of a atom group containing a given atom. ++++ +:::{button-ref} switch_species +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + ::::: :::::: @@ -216,9 +209,37 @@ Show Examples ::::{grid-item-card} **switch_kpointset** :text-align: center -Switch the used kpoint set +Switch the used kpoint set {bdg-success-line}`MaX 5.0 or newer` ++++ +:::{button-ref} switch_kpointset +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **set_kpointlist** +:text-align: center +Create a k-point list from a list of coordinates and weights. ++++ +:::{button-ref} set_kpointlist +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **set_nkpts** +:text-align: center +Set the number of kpts (`kpointCount`) {bdg-danger-line}`MaX 4.0 or older` +++ -:::{button-ref} switch_kpointset +:::{button-ref} set_nkpts :ref-type: ref :click-parent: :expand: @@ -227,6 +248,21 @@ Switch the used kpoint set Show Examples ::: :::: + +::::{grid-item-card} **set_kpath** +:text-align: center +Set a explicit path for bandstructure {bdg-danger-line}`MaX 4.0 or older` ++++ +:::{button-ref} set_kpath +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + ::::: :::::: @@ -379,6 +415,36 @@ Initialize the `n_mmp_mat` file with a given density matrix Show Examples ::: :::: + +::::{grid-item-card} **rotate_nmmpmat** +:text-align: center +Rotate one or multiple block(s) of the `n_mmp_mat` with euler angles ++++ +:::{button-ref} rotate_nmmpmat +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **align_nmmpmat_to_sqa** +:text-align: center +Rotate one or multiple blocks of the `n_mmp_mat` with euler angles to align +with the spin-quantization axis specified. ++++ +:::{button-ref} align_nmmpmat_to_sqa +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + ::::: :::::: @@ -408,5 +474,115 @@ Show Examples ::: :::: +::::{grid-item-card} **xml_delete_tag** +:text-align: center +Delete the results of the XPath expression. ++++ +:::{button-ref} xml_delete_tag +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **xml_delete_att** +:text-align: center +Delete a give XML attribute from the results of the XPath expression. ++++ +:::{button-ref} xml_delete_att +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **xml_replace_tag** +:text-align: center +Replace the results of the XPath expression with a given XML element. ++++ +:::{button-ref} xml_replace_tag +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **xml_set_attrib_value_no_create** +:text-align: center +Set XML attribute values on the results of the XPath expression. ++++ +:::{button-ref} xml_set_attrib_value_no_create +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + +::::{grid-item-card} **xml_set_text_no_create** +:text-align: center +Set text on the results of the XPath expression. ++++ +:::{button-ref} xml_set_text_no_create +:ref-type: ref +:click-parent: +:expand: +:color: primary +:outline: +Show Examples +::: +:::: + + + ::::: -:::::: \ No newline at end of file +:::::: + + +% The figure below shows a comparison between the use of XML and shortcut methods. +% +% .. image:: images/registration_methods.png +% :width: 100% +% :align: center + +## Modifying the density matrix for LDA+U calculations + +The above mentioned {py:meth}`FleurXMLModifier.set_nmmpmat()`, {py:meth}`FleurXMLModifier.rotate_nmmpmat()` and +{py:meth}`FleurXMLModifier.align_nmmpmat_to_sqa()` take a special role in the modification registration methods, +as the modifications are not done on the `inp.xml` file but the density matrix file `n_mmp_mat` used by Fleur +for LDA+U calculations. The resulting new `n_mmp_mat` file is returned next to the new `inp.xml` by +the {py:meth}`FleurXMLModifier.modify_xmlfile()`. + +The code example below shows how to use this method to add a LDA+U procedure to an atom species and provide +an initial guess for the density matrix. + +```python +from masci_tools.io.fleurxmlmodifier import FleurXMLModifier + +fm = FleurXMLModifier() +# Add LDA+U procedure +fm.set_species('Nd-1', {'ldaU':{'l': 3, 'U': 6.76, 'J': 0.76, 'l_amf': 'F'}}) +# Initialize n_mmp_mat file with the states m = -3 to m = 0 occupied for spin up +# spin down is initialized with 0 by default, since no n_mmp_mat file is provided +fm.set_nmmpmat('Nd-1', orbital=3, spin=1, state_occupations=[1,1,1,1,0,0,0]) +new_xmltree, add_files = fm.modify_xmlfile('/path/to/original/inp.xml') +print(add_files['n_mmp_mat']) +``` + +:::{note} +The `n_mmp_mat` file is a simple text file with no knowledge of which density matrix block corresponds to which +LDA+U procedure. They are read in the same order as they appear in the `inp.xml`. For this reason the `n_mmp_mat` +file can become invalid if one adds/removes a LDA+U procedure to the `inp.xml` after the `n_mmp_mat` file was +initialized. Therefore any modifications to the `n_mmp_mat` file should be done after adding/removing or modifying the LDA+U configuration. +::: \ No newline at end of file From f35ec03598baa6fdaee1620e72429f32e6a1eabe Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Sun, 17 Jul 2022 17:44:19 +0200 Subject: [PATCH 22/36] formatting --- docs/source/user_guide/fleurxmlmodifier.md | 2 +- masci_tools/util/sphinxext/usage_examples.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/source/user_guide/fleurxmlmodifier.md b/docs/source/user_guide/fleurxmlmodifier.md index 88d38770a..73ebfd2ef 100644 --- a/docs/source/user_guide/fleurxmlmodifier.md +++ b/docs/source/user_guide/fleurxmlmodifier.md @@ -585,4 +585,4 @@ The `n_mmp_mat` file is a simple text file with no knowledge of which density ma LDA+U procedure. They are read in the same order as they appear in the `inp.xml`. For this reason the `n_mmp_mat` file can become invalid if one adds/removes a LDA+U procedure to the `inp.xml` after the `n_mmp_mat` file was initialized. Therefore any modifications to the `n_mmp_mat` file should be done after adding/removing or modifying the LDA+U configuration. -::: \ No newline at end of file +::: diff --git a/masci_tools/util/sphinxext/usage_examples.py b/masci_tools/util/sphinxext/usage_examples.py index 4a9c16846..716e21426 100644 --- a/masci_tools/util/sphinxext/usage_examples.py +++ b/masci_tools/util/sphinxext/usage_examples.py @@ -209,7 +209,7 @@ def _render_templates(template_folder: Path, usage_examples: dict[str, list[Usag output_folder.mkdir() with open(output_folder / f'{name}.md', 'w', encoding='utf-8') as file: - file.write(template.render(examples=examples, title=f'``{name}``',reference=name)) + file.write(template.render(examples=examples, title=f'``{name}``', reference=name)) logger.info('Rendered Usage example to "%s".', os.fspath(template_folder / f'{name}.md')) From 7358e624fd2182f4e3e9b5f420e6548945e9d07b Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 18 Jul 2022 08:52:31 +0200 Subject: [PATCH 23/36] more --- masci_tools/io/fleurxmlmodifier.py | 70 +++++++++++++++++++++-- masci_tools/util/xml/xml_setters_names.py | 70 +++++++++++++++++++++-- 2 files changed, 130 insertions(+), 10 deletions(-) diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 7117fe969..13db26f42 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -479,15 +479,40 @@ def set_species(self, *args: Any, **kwargs: Any) -> None: **changes** is a python dictionary containing dictionaries that specify attributes to be set inside the certain specie. For example, if one wants to set a MT radius it - can be done via:: + can be done via + + .. usage-example:: - changes = {'mtSphere' : {'radius' : 2.2}} + fm.set_species('Fe-1', {'mtSphere' : {'radius' : 2.7}}) + + .. usage-example:: + :title: Adding child elements + :description: The `changes` dictionary is not limited to setting attributes + Child elements can also be created. Notice here that if multiple + elements of a given name are allowed all previously existing elements + are deleted and replaced with the ones specified in `changes` - Another example:: + fm.set_species('Fe-1', {'ldaU' : {'l' : 3, 'U': 4.0, 'J': 0.5, 'l_amf': True}, + 'lo': [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}]}) - 'changes': {'special': {'socscale': 0.0}} + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` as the first argument applies the changes + to all species + + fm.set_species('all', {'mtSphere' : {'radius' : 2.7}}) + + .. usage-example:: + :title: Modifying a subset of species + :description: Providing `'all-'` as the first argument applies the changes + to all species which contain the search string in it's name - that switches SOC terms on a sertain specie. ``mtSphere``, ``atomicCutoffs``, + fm.set_species('all-Pt', {'mtSphere' : {'radius' : 2.7}, + 'lo': {'l': 0, 'n': 6, 'type': 'SCLO'},}) + + + ``mtSphere``, ``atomicCutoffs``, ``energyParameters``, ``lo``, ``electronConfig``, ``nocoParams``, ``ldaU`` and ``special`` keys are supported. To find possible keys of the inner dictionary please refer to the FLEUR documentation flapw.de @@ -951,6 +976,41 @@ def set_simple_tag(self, *args: Any, **kwargs: Any) -> None: fm.set_simple_tag('soc', {'theta': 0.1, 'phi': 0.2, 'l_soc': True}) + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_simple_tag('lo', [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}]) + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_simple_tag('lo', [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}], + contains='species') + + .. usage-example:: + :title: Nested creation + :description: With `create_parents=True` if the parents of the tag are missing they are + created + + fm.set_simple_tag('realAxis', {'ne': 1300, 'ellow': -1.0, 'elup': 1.0}, create_parents=True) + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_simple_tag('lo', [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}], + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_simple_tag()` to the list of tasks that will be done on the xmltree. """ diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 6b94e2ff9..4204c39d0 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -848,6 +848,41 @@ def set_simple_tag(xmltree: XMLLike, fm.set_simple_tag('soc', {'theta': 0.1, 'phi': 0.2, 'l_soc': True}) + .. usage-example:: + :title: Tag selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_simple_tag('lo', [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}]) + + .. usage-example:: + :title: Tag selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + + fm.set_simple_tag('lo', [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}], + contains='species') + + .. usage-example:: + :title: Nested creation + :description: With `create_parents=True` if the parents of the tag are missing they are + created + + fm.set_simple_tag('realAxis', {'ne': 1300, 'ellow': -1.0, 'elup': 1.0}, create_parents=True) + + .. usage-example:: + :title: Added filters + :description: The filters argument allows to be more specific + + fm.set_simple_tag('lo', [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}], + contains='species', + filters={ + 'species': { + 'atomicNumber': {'>': 30} + }}) + :returns: xmltree with set simple tags """ from masci_tools.util.xml.xml_setters_xpaths import xml_set_simple_tag @@ -983,15 +1018,40 @@ def set_species(xmltree: XMLLike, **changes** is a python dictionary containing dictionaries that specify attributes to be set inside the certain specie. For example, if one wants to set a MT radius it - can be done via:: + can be done via + + .. usage-example:: - changes = {'mtSphere' : {'radius' : 2.2}} + fm.set_species('Fe-1', {'mtSphere' : {'radius' : 2.7}}) + + .. usage-example:: + :title: Adding child elements + :description: The `changes` dictionary is not limited to setting attributes + Child elements can also be created. Notice here that if multiple + elements of a given name are allowed all previously existing elements + are deleted and replaced with the ones specified in `changes` + + fm.set_species('Fe-1', {'ldaU' : {'l' : 3, 'U': 4.0, 'J': 0.5, 'l_amf': True}, + 'lo': [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}]}) + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` as the first argument applies the changes + to all species + + fm.set_species('all', {'mtSphere' : {'radius' : 2.7}}) + + .. usage-example:: + :title: Modifying a subset of species + :description: Providing `'all-'` as the first argument applies the changes + to all species which contain the search string in it's name - Another example:: + fm.set_species('all-Pt', {'mtSphere' : {'radius' : 2.7}, + 'lo': {'l': 0, 'n': 6, 'type': 'SCLO'},}) - 'changes': {'special': {'socscale': 0.0}} - that switches SOC terms on a sertain specie. ``mtSphere``, ``atomicCutoffs``, + ``mtSphere``, ``atomicCutoffs``, ``energyParameters``, ``lo``, ``electronConfig``, ``nocoParams``, ``ldaU`` and ``special`` keys are supported. To find possible keys of the inner dictionary please refer to the FLEUR documentation flapw.de From 1b7c2fa2f639c046d796eb7b7c212ad678ce2df3 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Mon, 18 Jul 2022 09:01:29 +0200 Subject: [PATCH 24/36] fixes --- masci_tools/io/fleurxmlmodifier.py | 95 ++++++++++++---------- masci_tools/util/xml/xml_setters_names.py | 22 ++++- utils/write_fleurxmlmodifier_docstrings.py | 2 +- 3 files changed, 73 insertions(+), 46 deletions(-) diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 13db26f42..7e1a7e12d 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -428,7 +428,7 @@ def set_inpchanges(self, *args: Any, **kwargs: Any) -> None: 'l_ss': True } - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_inpchanges()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_inpchanges()` to the list of tasks that will be done on the xmltree. """ if 'change_dict' in kwargs: @@ -453,7 +453,7 @@ def shift_value(self, *args: Any, **kwargs: Any) -> None: changes = {'itmax' : 1, 'dVac': -0.123} - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value()` to the list of tasks that will be done on the xmltree. """ if 'change_dict' in kwargs: @@ -511,13 +511,26 @@ def set_species(self, *args: Any, **kwargs: Any) -> None: fm.set_species('all-Pt', {'mtSphere' : {'radius' : 2.7}, 'lo': {'l': 0, 'n': 6, 'type': 'SCLO'},}) - - ``mtSphere``, ``atomicCutoffs``, - ``energyParameters``, ``lo``, ``electronConfig``, ``nocoParams``, ``ldaU`` and - ``special`` keys are supported. To find possible - keys of the inner dictionary please refer to the FLEUR documentation flapw.de - - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_species()` to + Example species. All these attributes tags can be modified. + Additional keys can for example be found in the FLEUR documentation flapw.de + + .. code-block:: xml + + + + + + [Ne] + (3s1/2) (3p1/2) (3p3/2) (4s1/2) (3d3/2) (3d5/2) + + + + + + + + + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_species()` to the list of tasks that will be done on the xmltree. """ if 'attributedict' in kwargs: @@ -536,7 +549,7 @@ def set_species_label(self, *args: Any, **kwargs: Any) -> None: :param changes: a python dict specifying what you want to change. :param create: bool, if species does not exist create it and all subtags? - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_species_label()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_species_label()` to the list of tasks that will be done on the xmltree. """ if 'attributedict' in kwargs: @@ -555,7 +568,7 @@ def clone_species(self, *args: Any, **kwargs: Any) -> None: :param new_name: new name of the cloned species :param changes: a optional python dict specifying what you want to change. - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.clone_species()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.clone_species()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('clone_species', args, kwargs) @@ -573,7 +586,7 @@ def switch_species(self, *args: Any, **kwargs: Any) -> None: :param filters: Dict specifying constraints to apply on the xpath. See :py:class:`~masci_tools.util.xml.xpathbuilder.XPathBuilder` for details - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('switch_species', args, kwargs) @@ -588,7 +601,7 @@ def switch_species_label(self, *args: Any, **kwargs: Any) -> None: from one species the species will be cloned with :py:func:`clone_species()` :param changes: changes to do if the species is cloned - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species_label()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species_label()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('switch_species_label', args, kwargs) @@ -610,7 +623,7 @@ def shift_value_species_label(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value_species_label()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value_species_label()` to the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: @@ -638,7 +651,7 @@ def set_atomgroup(self, *args: Any, **kwargs: Any) -> None: 'changes': {'nocoParams': {'beta': val}} - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` to the list of tasks that will be done on the xmltree. """ if 'attributedict' in kwargs: @@ -666,7 +679,7 @@ def set_atomgroup_label(self, *args: Any, **kwargs: Any) -> None: 'changes': {'nocoParams': {'beta': val}} - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup_label()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup_label()` to the list of tasks that will be done on the xmltree. """ if 'attributedict' in kwargs: @@ -745,7 +758,7 @@ def create_tag(self, *args: Any, **kwargs: Any) -> None: } }) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.create_tag()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.create_tag()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('create_tag', args, kwargs) @@ -796,7 +809,7 @@ def delete_tag(self, *args: Any, **kwargs: Any) -> None: } }) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.delete_tag()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.delete_tag()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('delete_tag', args, kwargs) @@ -851,7 +864,7 @@ def delete_att(self, *args: Any, **kwargs: Any) -> None: } }) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.delete_att()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.delete_att()` to the list of tasks that will be done on the xmltree. """ if 'attrib_name' in kwargs: @@ -906,7 +919,7 @@ def replace_tag(self, *args: Any, **kwargs: Any) -> None: 'atomicNumber': {'>': 30} }}) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.replace_tag()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.replace_tag()` to the list of tasks that will be done on the xmltree. """ if 'newelement' in kwargs: @@ -943,7 +956,7 @@ def set_complex_tag(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_complex_tag()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_complex_tag()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_complex_tag', args, kwargs) @@ -1011,7 +1024,7 @@ def set_simple_tag(self, *args: Any, **kwargs: Any) -> None: 'atomicNumber': {'>': 30} }}) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_simple_tag()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_simple_tag()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_simple_tag', args, kwargs) @@ -1076,7 +1089,7 @@ def set_text(self, *args: Any, **kwargs: Any) -> None: './lo/@n': {'>': 4} }}) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_text()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_text()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_text', args, kwargs) @@ -1133,7 +1146,7 @@ def set_first_text(self, *args: Any, **kwargs: Any) -> None: './lo/@n': {'>': 4} }}) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_text()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_text()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_first_text', args, kwargs) @@ -1193,7 +1206,7 @@ def set_attrib_value(self, *args: Any, **kwargs: Any) -> None: 'atomicNumber': {'>': 30} }}) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_attrib_value()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_attrib_value()` to the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: @@ -1258,7 +1271,7 @@ def set_first_attrib_value(self, *args: Any, **kwargs: Any) -> None: 'atomicNumber': {'>': 30} }}) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_attrib_value()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_first_attrib_value()` to the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: @@ -1321,7 +1334,7 @@ def add_number_to_attrib(self, *args: Any, **kwargs: Any) -> None: 'atomicNumber': {'>': 30} }}) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_attrib()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_attrib()` to the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: @@ -1383,7 +1396,7 @@ def add_number_to_first_attrib(self, *args: Any, **kwargs: Any) -> None: 'atomicNumber': {'>': 30} }}) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_first_attrib()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.add_number_to_first_attrib()` to the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: @@ -1417,7 +1430,7 @@ def xml_create_tag(self, *args: Any, **kwargs: Any) -> None: :raises ValueError: If the insertion failed in any way (tag_order does not match, failed to insert, ...) - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_create_tag()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_create_tag()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('xml_create_tag', args, kwargs) @@ -1431,7 +1444,7 @@ def xml_replace_tag(self, *args: Any, **kwargs: Any) -> None: :param occurrences: int or list of int. Which occurrence of the parent nodes to create a tag. By default all nodes are used. - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_replace_tag()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_replace_tag()` to the list of tasks that will be done on the xmltree. """ if 'newelement' in kwargs: @@ -1448,7 +1461,7 @@ def xml_delete_tag(self, *args: Any, **kwargs: Any) -> None: :param occurrences: int or list of int. Which occurrence of the parent nodes to create a tag. By default all nodes are used. - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_delete_tag()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_delete_tag()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('xml_delete_tag', args, kwargs) @@ -1462,7 +1475,7 @@ def xml_delete_att(self, *args: Any, **kwargs: Any) -> None: :param occurrences: int or list of int. Which occurrence of the parent nodes to create a tag. By default all nodes are used. - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_delete_att()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_delete_att()` to the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: @@ -1483,7 +1496,7 @@ def xml_set_attrib_value_no_create(self, *args: Any, **kwargs: Any) -> None: :raises ValueError: If the lengths of attribv or occurrences do not match number of nodes - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_set_attrib_value_no_create()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_set_attrib_value_no_create()` to the list of tasks that will be done on the xmltree. """ if 'attributename' in kwargs: @@ -1505,7 +1518,7 @@ def xml_set_text_no_create(self, *args: Any, **kwargs: Any) -> None: :raises ValueError: If the lengths of text or occurrences do not match number of nodes - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_set_text_no_create()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_basic.xml_set_text_no_create()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('xml_set_text_no_create', args, kwargs) @@ -1529,7 +1542,7 @@ def set_nmmpmat(self, *args: Any, **kwargs: Any) -> None: :raises ValueError: If something in the input is wrong :raises KeyError: If no LDA+U procedure is found on a species - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.set_nmmpmat()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.set_nmmpmat()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_nmmpmat', args, kwargs) @@ -1548,7 +1561,7 @@ def rotate_nmmpmat(self, *args: Any, **kwargs: Any) -> None: :raises ValueError: If something in the input is wrong :raises KeyError: If no LDA+U procedure is found on a species - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.rotate_nmmpmat()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.rotate_nmmpmat()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('rotate_nmmpmat', args, kwargs) @@ -1569,7 +1582,7 @@ def align_nmmpmat_to_sqa(self, *args: Any, **kwargs: Any) -> None: :raises ValueError: If something in the input is wrong :raises KeyError: If no LDA+U procedure is found on a species - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.align_nmmpmat_to_sqa()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_nmmpmat.align_nmmpmat_to_sqa()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('align_nmmpmat_to_sqa', args, kwargs) @@ -1594,7 +1607,7 @@ def set_kpointlist(self, *args: Any, **kwargs: Any) -> None: :param switch: bool, if True the kPointlist will be used by Fleur when starting the next calculation :param overwrite: bool, if True and a kPointlist with the given name already exists it will be overwritten - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointlist()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointlist()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_kpointlist', args, kwargs) @@ -1608,7 +1621,7 @@ def switch_kpointset(self, *args: Any, **kwargs: Any) -> None: :param list_name: name of the kPoint set to use - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.switch_kpointset()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.switch_kpointset()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('switch_kpointset', args, kwargs) @@ -1624,7 +1637,7 @@ def set_nkpts(self, *args: Any, **kwargs: Any) -> None: :param gamma: bool that controls if the gamma-point should be included in the k-point mesh - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_nkpts()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_nkpts()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_nkpts', args, kwargs) @@ -1641,7 +1654,7 @@ def set_kpath(self, *args: Any, **kwargs: Any) -> None: :param gamma: bool that controls if the gamma-point should be included in the k-point mesh - This registration method does not modify the file immediately but only appendsa :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpath()` to + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpath()` to the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_kpath', args, kwargs) diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 4204c39d0..9f937fcb3 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -1050,11 +1050,25 @@ def set_species(xmltree: XMLLike, fm.set_species('all-Pt', {'mtSphere' : {'radius' : 2.7}, 'lo': {'l': 0, 'n': 6, 'type': 'SCLO'},}) + Example species. All these attributes tags can be modified. + Additional keys can for example be found in the FLEUR documentation flapw.de + + .. code-block:: xml + + + + + + [Ne] + (3s1/2) (3p1/2) (3p3/2) (4s1/2) (3d3/2) (3d5/2) + + + + + + + - ``mtSphere``, ``atomicCutoffs``, - ``energyParameters``, ``lo``, ``electronConfig``, ``nocoParams``, ``ldaU`` and - ``special`` keys are supported. To find possible - keys of the inner dictionary please refer to the FLEUR documentation flapw.de """ from masci_tools.util.xml.xml_setters_xpaths import xml_set_complex_tag diff --git a/utils/write_fleurxmlmodifier_docstrings.py b/utils/write_fleurxmlmodifier_docstrings.py index c738d5922..dd9b4bf62 100644 --- a/utils/write_fleurxmlmodifier_docstrings.py +++ b/utils/write_fleurxmlmodifier_docstrings.py @@ -27,7 +27,7 @@ def get_method_docstring(name, docstring, module): additional_lines = [ 'This registration method does not modify the file immediately ' - f'but only appendsa :py:func:`~masci_tools.util.xml.{module}.{name}()` to', + f'but only appends a :py:func:`~masci_tools.util.xml.{module}.{name}()` to', 'the list of tasks that will be done on the xmltree.', '' ] if lines[-1]: From 00fb4d44a5f9dc23220d5a7a3200280506f72d7a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 10 Aug 2022 20:57:05 +0000 Subject: [PATCH 25/36] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- masci_tools/io/fleurxmlmodifier.py | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 7e1a7e12d..08cae4c01 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -1661,11 +1661,7 @@ def set_kpath(self, *args: Any, **kwargs: Any) -> None: self._tasks.append(ModifierTask('set_kpath', args, kwargs)) def set_kpointpath(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointpath()` to - the list of tasks that will be done on the xmltree. - - Create a kpoint list for a bandstructure calculation (using ASE kpath generation) + """Create a kpoint list for a bandstructure calculation (using ASE kpath generation) The path can be defined explictly (see :py:func:`~ase.dft.kpoints.bandpath`) or derived from the unit cell @@ -1676,16 +1672,15 @@ def set_kpointpath(self, *args: Any, **kwargs: Any) -> None: :param switch: bool if True the kpoint list is direclty set as the used set :param overwrite: if True and a kpoint list of the given name already exists it will be overwritten :param special_points: dict mapping names to coordinates for special points to use + + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointpath()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_kpointpath', args, kwargs) self._tasks.append(ModifierTask('set_kpointpath', args, kwargs)) def set_kpointmesh(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointmesh()` to - the list of tasks that will be done on the xmltree. - - Create a kpoint mesh using spglib + """Create a kpoint mesh using spglib for details see :py:func:`~spglib.get_stabilized_reciprocal_mesh` @@ -1698,16 +1693,15 @@ def set_kpointmesh(self, *args: Any, **kwargs: Any) -> None: :param shift: shift the center of the kpint set :param time_reversal: bool if True time reversal symmetry will be used to reduce the kpoint set :param map_to_first_bz: bool if True the kpoints are mapped into the [0,1] interval + + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointmesh()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_kpointmesh', args, kwargs) self._tasks.append(ModifierTask('set_kpointmesh', args, kwargs)) def set_xcfunctional(self, *args: Any, **kwargs: Any) -> None: - """ - Appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_xcfunctional()` to - the list of tasks that will be done on the xmltree. - - Set the Exchange Correlation potential tag + """Set the Exchange Correlation potential tag Setting a inbuilt XC functional .. code-block:: python @@ -1724,6 +1718,9 @@ def set_xcfunctional(self, *args: Any, **kwargs: Any) -> None: `'exchange', 'correlation', 'etot_exchange' and 'etot_correlation'` :param xc_functional_options: dict with further general changes to the `xcFunctional` tag :param libxc: bool if True the functional is a LibXC functional + + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_xcfunctional()` to + the list of tasks that will be done on the xmltree. """ self._validate_arguments('set_xcfunctional', args, kwargs) self._tasks.append(ModifierTask('set_xcfunctional', args, kwargs)) From 11a955284812959db4810fb39fedd46a2431548e Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 11:08:01 +0200 Subject: [PATCH 26/36] Customize toggle descriptions --- .../fleurxmlmodifier_usage_examples/template.md.jinja | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja index c34657f2b..b9476f89a 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -31,7 +31,9 @@ kernelspec: {{ example.description }} ```{code-cell} ipython3 -:tags: [hide-output] +:tags: [hide-cell] +: code_prompt_show: "Show loading of initial XML file" +: code_prompt_hide: "Hide loading of initial XML file" from masci_tools.io.fleur_xml import load_inpxml from lxml import etree @@ -54,6 +56,8 @@ new_xmltree, additional_files = fm.modify_xmlfile(xmltree, validate_changes=Fals Changes in the ``inp.xml`` file ```{code-cell} ipython3 :tags: [remove-input, hide-output] +: code_prompt_show: "Show differences from initial XMl file" +: code_prompt_hide: "Hide differences from initial XMl file" from masci_tools.util.ipython import xml_diff xml_diff(xmltree, new_xmltree) ``` @@ -61,6 +65,8 @@ xml_diff(xmltree, new_xmltree) Conplete Modified ``inp.xml`` file ```{code-cell} ipython3 :tags: [remove-input, hide-output] +: code_prompt_show: "Show complete final XMl file" +: code_prompt_hide: "Hide complete final XMl file" new_xmltree ``` {% endif %} From 0e8e77a28409c0272e8fa07ac0a496ec5bd3dcf0 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 11:10:35 +0200 Subject: [PATCH 27/36] missing dependency --- pyproject.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d4d2c2796..e7d40b7d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -63,7 +63,8 @@ docs = [ #1.19.3 is broken 'sphinx-autodoc-typehints!=1.19.3', 'myst-nb', - 'sphinx-copybutton' + 'sphinx-copybutton', + 'sphinx-design' ] testing = [ 'pytest~=6.0', From 9b9aa5c29a738a7adc2dfaa65a9097d01252d419 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 11:14:21 +0200 Subject: [PATCH 28/36] fix --- .../fleurxmlmodifier_usage_examples/template.md.jinja | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja index b9476f89a..eababefcf 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -32,6 +32,7 @@ kernelspec: ```{code-cell} ipython3 :tags: [hide-cell] +:mystnb: : code_prompt_show: "Show loading of initial XML file" : code_prompt_hide: "Hide loading of initial XML file" @@ -56,6 +57,7 @@ new_xmltree, additional_files = fm.modify_xmlfile(xmltree, validate_changes=Fals Changes in the ``inp.xml`` file ```{code-cell} ipython3 :tags: [remove-input, hide-output] +:mystnb: : code_prompt_show: "Show differences from initial XMl file" : code_prompt_hide: "Hide differences from initial XMl file" from masci_tools.util.ipython import xml_diff @@ -65,6 +67,7 @@ xml_diff(xmltree, new_xmltree) Conplete Modified ``inp.xml`` file ```{code-cell} ipython3 :tags: [remove-input, hide-output] +:mystnb: : code_prompt_show: "Show complete final XMl file" : code_prompt_hide: "Hide complete final XMl file" new_xmltree From 846e581367a77796751de6effac13c23c0a9886a Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 11:23:29 +0200 Subject: [PATCH 29/36] More cleanup --- .../fleurxmlmodifier_usage_examples/template.md.jinja | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja index eababefcf..53341ac3c 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -54,22 +54,19 @@ new_xmltree, additional_files = fm.modify_xmlfile(xmltree, validate_changes=Fals ``` {% if not example.error %} -Changes in the ``inp.xml`` file ```{code-cell} ipython3 :tags: [remove-input, hide-output] :mystnb: -: code_prompt_show: "Show differences from initial XMl file" -: code_prompt_hide: "Hide differences from initial XMl file" +: code_prompt_show: "Show differences from initial ``inp.xml`` file" +: code_prompt_hide: "Hide differences from initial ``inp.xml`` file" from masci_tools.util.ipython import xml_diff xml_diff(xmltree, new_xmltree) ``` - -Conplete Modified ``inp.xml`` file ```{code-cell} ipython3 :tags: [remove-input, hide-output] :mystnb: -: code_prompt_show: "Show complete final XMl file" -: code_prompt_hide: "Hide complete final XMl file" +: code_prompt_show: "Show final ``inp.xml`` file" +: code_prompt_hide: "Hide final ``inp.xml`` file" new_xmltree ``` {% endif %} From 2a4581424afff717db7379e1a50233a85c9f3435 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 11:23:49 +0200 Subject: [PATCH 30/36] Fix error message --- masci_tools/io/parsers/fleur_schema/schema_dict.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/masci_tools/io/parsers/fleur_schema/schema_dict.py b/masci_tools/io/parsers/fleur_schema/schema_dict.py index 3583d3885..a113e1d64 100644 --- a/masci_tools/io/parsers/fleur_schema/schema_dict.py +++ b/masci_tools/io/parsers/fleur_schema/schema_dict.py @@ -227,7 +227,7 @@ def _add_condition(specification: str | Iterable[str] | None, condition: str) -> def _ensure_path_uniqueness(paths: Collection[str], description: str, - path_type: str | None = None, + path_type: str = '', **specifications: Any) -> str: """ Ensure that the given iterable of paths consists of only one path From af19aae11b0170e16814ab75c3dacd765e71e0a5 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 11:55:34 +0200 Subject: [PATCH 31/36] Add more usage examples --- masci_tools/io/fleurxmlmodifier.py | 140 +++++++++++++++++++++ masci_tools/util/xml/xml_setters_names.py | 142 ++++++++++++++++++++++ 2 files changed, 282 insertions(+) diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 08cae4c01..feef54954 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -549,6 +549,31 @@ def set_species_label(self, *args: Any, **kwargs: Any) -> None: :param changes: a python dict specifying what you want to change. :param create: bool, if species does not exist create it and all subtags? + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_species_label('222', {'mtSphere' : {'radius' : 2.7}}) + + .. usage-example:: + :title: Adding child elements + :description: The `changes` dictionary is not limited to setting attributes + Child elements can also be created. Notice here that if multiple + elements of a given name are allowed all previously existing elements + are deleted and replaced with the ones specified in `changes` + + fm.set_species_label('222', {'ldaU' : {'l' : 3, 'U': 4.0, 'J': 0.5, 'l_amf': True}, + 'lo': [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}]}) + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` as the first argument applies the changes + to all species + + fm.set_species_label('all', {'mtSphere' : {'radius' : 2.7}}) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_species_label()` to the list of tasks that will be done on the xmltree. """ @@ -568,6 +593,20 @@ def clone_species(self, *args: Any, **kwargs: Any) -> None: :param new_name: new name of the cloned species :param changes: a optional python dict specifying what you want to change. + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.clone_species('Fe-1', 'Fe-clone-1') + + .. usage-example:: + :title: Modifying the cloned species + :description: The `changes` dictionary is passed on to ``set_species`` + to modify the cloned species + + fm.clone_species('Fe-1', 'Fe-clone-1', {'mtSphere' : {'radius' : 2.7}}) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.clone_species()` to the list of tasks that will be done on the xmltree. """ @@ -586,6 +625,44 @@ def switch_species(self, *args: Any, **kwargs: Any) -> None: :param filters: Dict specifying constraints to apply on the xpath. See :py:class:`~masci_tools.util.xml.xpathbuilder.XPathBuilder` for details + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.switch_species('Pt-1', species='Fe-1') + + + .. usage-example:: + :title: Specifying the number of the atromgroup + :description: Providing the ``position`` argument will modify the n-th + atomgroup in the ``inp.xml`` file. (Indexing starts at 1) + + fm.switch_species('Pt-1', position=1) + + .. usage-example:: + :title: Create a clone of the old species + :description: Specifying a non-existent new species name and ``clone=True`` + will create a clone of the old species with that name. Additionally + the ``changes`` argument can then be used to apply changes to the new + clone + + fm.switch_species('Fe-clone-2', species='Fe-1', clone=True, changes={'mtSphere' : {'radius' : 2.7}}) + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` to either ``position`` or ``species``` + will modify the species of all atomgroups + + fm.switch_species('Fe-1', species='all') + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` to either ``position`` or ``species``` + will modify the species of all atomgroups + + fm.switch_species('Fe-1', species='all') + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species()` to the list of tasks that will be done on the xmltree. """ @@ -623,6 +700,35 @@ def shift_value_species_label(self, *args: Any, **kwargs: Any) -> None: :param contains: str, this string has to be in the final path :param not_contains: str, this string has to NOT be in the final path + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.shift_value_species_label('222', 'radius', 1) + + .. usage-example:: + :title: Relative shift + :description: Passing ``mode="rel"`` or ``mode="relative"`` will multiply + the initial attribute value with the provided number instead + of adding them + + fm.shift_value_species_label('222', 'radius', 1.2, mode="relative") + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` as the first argument applies the changes + to all species + + fm.shift_value_species_label('all', 'lmax', 2) + + .. usage-example:: + :title: Modifying a subset of species + :description: Providing `'all-'` as the first argument applies the changes + to all species which contain the search string in it's name + + fm.shift_value_species_label('all-Pt', 'lmax', 2) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value_species_label()` to the list of tasks that will be done on the xmltree. """ @@ -651,6 +757,26 @@ def set_atomgroup(self, *args: Any, **kwargs: Any) -> None: 'changes': {'nocoParams': {'beta': val}} + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_atomgroup({'nocoParams': {'beta': 1.57}}, species='Fe-1') + + .. usage-example:: + :title: Specifying the number of the atromgroup + :description: Providing the ``position`` argument will modify the n-th + atomgroup in the ``inp.xml`` file. (Indexing starts at 1) + + fm.set_atomgroup({'nocoParams': {'alpha': 1.57}}, position=1) + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` to either ``position`` or ``species``` + will modify all atomgroups + + fm.set_atomgroup({'nocoParams': {'beta': 1.57}}, species='all') + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` to the list of tasks that will be done on the xmltree. """ @@ -679,6 +805,20 @@ def set_atomgroup_label(self, *args: Any, **kwargs: Any) -> None: 'changes': {'nocoParams': {'beta': val}} + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_atomgroup_label('222', {'nocoParams': {'beta': 1.57}}) + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` as the first argument applies the changes + to all species + + fm.set_atomgroup_label('all', {'nocoParams': {'beta': 1.57}}) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup_label()` to the list of tasks that will be done on the xmltree. """ diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 9f937fcb3..6a9fc49d4 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -970,6 +970,31 @@ def set_species_label(xmltree: XMLLike, :param create: bool, if species does not exist create it and all subtags? :returns: xml etree of the new inp.xml + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_species_label('222', {'mtSphere' : {'radius' : 2.7}}) + + .. usage-example:: + :title: Adding child elements + :description: The `changes` dictionary is not limited to setting attributes + Child elements can also be created. Notice here that if multiple + elements of a given name are allowed all previously existing elements + are deleted and replaced with the ones specified in `changes` + + fm.set_species_label('222', {'ldaU' : {'l' : 3, 'U': 4.0, 'J': 0.5, 'l_amf': True}, + 'lo': [{'l': 0, 'n': 6, 'type': 'SCLO'}, + {'l': 1, 'n': 6, 'type': 'SCLO'}]}) + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` as the first argument applies the changes + to all species + + fm.set_species_label('all', {'mtSphere' : {'radius' : 2.7}}) + """ from masci_tools.util.schema_dict_util import evaluate_attribute @@ -1103,6 +1128,20 @@ def clone_species(xmltree: XMLLike, :param changes: a optional python dict specifying what you want to change. :returns xmltree: xml etree of the new inp.xml + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.clone_species('Fe-1', 'Fe-clone-1') + + .. usage-example:: + :title: Modifying the cloned species + :description: The `changes` dictionary is passed on to ``set_species`` + to modify the cloned species + + fm.clone_species('Fe-1', 'Fe-clone-1', {'mtSphere' : {'radius' : 2.7}}) + """ from masci_tools.util.schema_dict_util import evaluate_attribute from masci_tools.util.xml.common_functions import eval_xpath_one @@ -1158,6 +1197,35 @@ def shift_value_species_label(xmltree: XMLLike, :param not_contains: str, this string has to NOT be in the final path :returns: xml etree of the new inp.xml + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.shift_value_species_label('222', 'radius', 1) + + .. usage-example:: + :title: Relative shift + :description: Passing ``mode="rel"`` or ``mode="relative"`` will multiply + the initial attribute value with the provided number instead + of adding them + + fm.shift_value_species_label('222', 'radius', 1.2, mode="relative") + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` as the first argument applies the changes + to all species + + fm.shift_value_species_label('all', 'lmax', 2) + + .. usage-example:: + :title: Modifying a subset of species + :description: Providing `'all-'` as the first argument applies the changes + to all species which contain the search string in it's name + + fm.shift_value_species_label('all-Pt', 'lmax', 2) + """ from masci_tools.util.schema_dict_util import evaluate_attribute from masci_tools.util.xml.xml_setters_xpaths import xml_add_number_to_first_attrib @@ -1215,6 +1283,20 @@ def set_atomgroup_label(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, 'changes': {'nocoParams': {'beta': val}} + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_atomgroup_label('222', {'nocoParams': {'beta': 1.57}}) + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` as the first argument applies the changes + to all species + + fm.set_atomgroup_label('all', {'nocoParams': {'beta': 1.57}}) + """ from masci_tools.util.schema_dict_util import evaluate_attribute if atom_label == 'all': @@ -1262,6 +1344,27 @@ def set_atomgroup(xmltree: XMLLike, 'changes': {'nocoParams': {'beta': val}} + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_atomgroup({'nocoParams': {'beta': 1.57}}, species='Fe-1') + + .. usage-example:: + :title: Specifying the number of the atromgroup + :description: Providing the ``position`` argument will modify the n-th + atomgroup in the ``inp.xml`` file. (Indexing starts at 1) + + fm.set_atomgroup({'nocoParams': {'alpha': 1.57}}, position=1) + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` to either ``position`` or ``species``` + will modify all atomgroups + + fm.set_atomgroup({'nocoParams': {'beta': 1.57}}, species='all') + + """ from masci_tools.util.xml.xml_setters_xpaths import xml_set_complex_tag @@ -1342,6 +1445,45 @@ def switch_species(xmltree: XMLLike, See :py:class:`~masci_tools.util.xml.xpathbuilder.XPathBuilder` for details :returns: xml etree of the new inp.xml + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.switch_species('Pt-1', species='Fe-1') + + + .. usage-example:: + :title: Specifying the number of the atromgroup + :description: Providing the ``position`` argument will modify the n-th + atomgroup in the ``inp.xml`` file. (Indexing starts at 1) + + fm.switch_species('Pt-1', position=1) + + .. usage-example:: + :title: Create a clone of the old species + :description: Specifying a non-existent new species name and ``clone=True`` + will create a clone of the old species with that name. Additionally + the ``changes`` argument can then be used to apply changes to the new + clone + + fm.switch_species('Fe-clone-2', species='Fe-1', clone=True, changes={'mtSphere' : {'radius' : 2.7}}) + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` to either ``position`` or ``species``` + will modify the species of all atomgroups + + fm.switch_species('Fe-1', species='all') + + .. usage-example:: + :title: Modifying all species + :description: Providing `'all'` to either ``position`` or ``species``` + will modify the species of all atomgroups + + fm.switch_species('Fe-1', species='all') + + """ from masci_tools.util.schema_dict_util import evaluate_attribute from masci_tools.util.xml.xml_setters_xpaths import xml_set_attrib_value From 40db2db4ab67cde8cd38bf4ad064c748d99ec6ea Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 12:09:48 +0200 Subject: [PATCH 32/36] More updates --- .../template.md.jinja | 8 +-- masci_tools/io/fleurxmlmodifier.py | 52 ++++++++++------- masci_tools/util/xml/xml_setters_names.py | 56 +++++++++++-------- 3 files changed, 68 insertions(+), 48 deletions(-) diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja index 53341ac3c..81d3a6f58 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/template.md.jinja @@ -57,16 +57,16 @@ new_xmltree, additional_files = fm.modify_xmlfile(xmltree, validate_changes=Fals ```{code-cell} ipython3 :tags: [remove-input, hide-output] :mystnb: -: code_prompt_show: "Show differences from initial ``inp.xml`` file" -: code_prompt_hide: "Hide differences from initial ``inp.xml`` file" +: code_prompt_show: "Show differences from initial XML file" +: code_prompt_hide: "Hide differences from initial XML file" from masci_tools.util.ipython import xml_diff xml_diff(xmltree, new_xmltree) ``` ```{code-cell} ipython3 :tags: [remove-input, hide-output] :mystnb: -: code_prompt_show: "Show final ``inp.xml`` file" -: code_prompt_hide: "Hide final ``inp.xml`` file" +: code_prompt_show: "Show final XML file" +: code_prompt_hide: "Hide final XML file" new_xmltree ``` {% endif %} diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index feef54954..2116249b5 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -453,6 +453,20 @@ def shift_value(self, *args: Any, **kwargs: Any) -> None: changes = {'itmax' : 1, 'dVac': -0.123} + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.shift_value({'itmax' : 5, 'mindistance': 1}) + + .. usage-example:: + :title: Relative shift + :description: Passing ``mode="rel"`` or ``mode="relative"`` will multiply + the initial attribute values with the provided number instead + of adding them + + fm.shift_value({'itmax' : 2, 'mindistance': 3}, mode="relative") + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value()` to the list of tasks that will be done on the xmltree. """ @@ -656,13 +670,6 @@ def switch_species(self, *args: Any, **kwargs: Any) -> None: fm.switch_species('Fe-1', species='all') - .. usage-example:: - :title: Modifying all species - :description: Providing `'all'` to either ``position`` or ``species``` - will modify the species of all atomgroups - - fm.switch_species('Fe-1', species='all') - This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.switch_species()` to the list of tasks that will be done on the xmltree. """ @@ -761,7 +768,7 @@ def set_atomgroup(self, *args: Any, **kwargs: Any) -> None: .. usage-example:: - fm.set_atomgroup({'nocoParams': {'beta': 1.57}}, species='Fe-1') + fm.set_atomgroup({'nocoParams': {'alpha': 1.57}}, species='Fe-1') .. usage-example:: :title: Specifying the number of the atromgroup @@ -775,7 +782,7 @@ def set_atomgroup(self, *args: Any, **kwargs: Any) -> None: :description: Providing `'all'` to either ``position`` or ``species``` will modify all atomgroups - fm.set_atomgroup({'nocoParams': {'beta': 1.57}}, species='all') + fm.set_atomgroup({'nocoParams': {'alpha': 1.57}}, species='all') This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup()` to the list of tasks that will be done on the xmltree. @@ -810,14 +817,14 @@ def set_atomgroup_label(self, *args: Any, **kwargs: Any) -> None: .. usage-example:: - fm.set_atomgroup_label('222', {'nocoParams': {'beta': 1.57}}) + fm.set_atomgroup_label('222', {'nocoParams': {'alpha': 1.57}}) .. usage-example:: :title: Modifying all species :description: Providing `'all'` as the first argument applies the changes to all species - fm.set_atomgroup_label('all', {'nocoParams': {'beta': 1.57}}) + fm.set_atomgroup_label('all', {'nocoParams': {'alpha': 1.57}}) This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_atomgroup_label()` to the list of tasks that will be done on the xmltree. @@ -1843,22 +1850,25 @@ def set_kpointmesh(self, *args: Any, **kwargs: Any) -> None: def set_xcfunctional(self, *args: Any, **kwargs: Any) -> None: """Set the Exchange Correlation potential tag - Setting a inbuilt XC functional - .. code-block:: python - - set_xcfunctional(xmltree, schema_dict, 'vwn') - - Setting a LibXC XC functional - .. code-block:: python - - set_xcfunctional(xmltree, schema_dict, {'exchange': 'lda_x', 'correlation':"lda_c_xalpha"}, libxc=True) - :param xc_functional: str or dict. If str it is the name of a inbuilt XC functional. If it is a dict it specifies either the name or id for LibXC functionals for the keys `'exchange', 'correlation', 'etot_exchange' and 'etot_correlation'` :param xc_functional_options: dict with further general changes to the `xcFunctional` tag :param libxc: bool if True the functional is a LibXC functional + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_xcfunctional('vwn') + + + .. usage-example:: + :title: Setting a LibXC functional + + fm.set_xcfunctional({'exchange': 'lda_x', 'correlation':"lda_c_xalpha"}, libxc=True) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_xcfunctional()` to the list of tasks that will be done on the xmltree. """ diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 6a9fc49d4..84662013e 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -1288,14 +1288,14 @@ def set_atomgroup_label(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, .. usage-example:: - fm.set_atomgroup_label('222', {'nocoParams': {'beta': 1.57}}) + fm.set_atomgroup_label('222', {'nocoParams': {'alpha': 1.57}}) .. usage-example:: :title: Modifying all species :description: Providing `'all'` as the first argument applies the changes to all species - fm.set_atomgroup_label('all', {'nocoParams': {'beta': 1.57}}) + fm.set_atomgroup_label('all', {'nocoParams': {'alpha': 1.57}}) """ from masci_tools.util.schema_dict_util import evaluate_attribute @@ -1348,7 +1348,7 @@ def set_atomgroup(xmltree: XMLLike, .. usage-example:: - fm.set_atomgroup({'nocoParams': {'beta': 1.57}}, species='Fe-1') + fm.set_atomgroup({'nocoParams': {'alpha': 1.57}}, species='Fe-1') .. usage-example:: :title: Specifying the number of the atromgroup @@ -1362,8 +1362,7 @@ def set_atomgroup(xmltree: XMLLike, :description: Providing `'all'` to either ``position`` or ``species``` will modify all atomgroups - fm.set_atomgroup({'nocoParams': {'beta': 1.57}}, species='all') - + fm.set_atomgroup({'nocoParams': {'alpha': 1.57}}, species='all') """ from masci_tools.util.xml.xml_setters_xpaths import xml_set_complex_tag @@ -1476,14 +1475,6 @@ def switch_species(xmltree: XMLLike, fm.switch_species('Fe-1', species='all') - .. usage-example:: - :title: Modifying all species - :description: Providing `'all'` to either ``position`` or ``species``` - will modify the species of all atomgroups - - fm.switch_species('Fe-1', species='all') - - """ from masci_tools.util.schema_dict_util import evaluate_attribute from masci_tools.util.xml.xml_setters_xpaths import xml_set_attrib_value @@ -1549,6 +1540,21 @@ def shift_value(xmltree: XMLLike, An example of changes:: changes = {'itmax' : 1, 'dVac': -0.123} + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.shift_value({'itmax' : 5, 'mindistance': 1}) + + .. usage-example:: + :title: Relative shift + :description: Passing ``mode="rel"`` or ``mode="relative"`` will multiply + the initial attribute values with the provided number instead + of adding them + + fm.shift_value({'itmax' : 2, 'mindistance': 3}, mode="relative") + """ from masci_tools.util.case_insensitive_dict import CaseInsensitiveDict @@ -1632,16 +1638,6 @@ def set_xcfunctional(xmltree: XMLLike, """ Set the Exchange Correlation potential tag - Setting a inbuilt XC functional - .. code-block:: python - - set_xcfunctional(xmltree, schema_dict, 'vwn') - - Setting a LibXC XC functional - .. code-block:: python - - set_xcfunctional(xmltree, schema_dict, {'exchange': 'lda_x', 'correlation':"lda_c_xalpha"}, libxc=True) - :param xmltree: XML tree that represents inp.xml :param schema_dict: InputSchemaDict containing all information about the structure of the input :param xc_functional: str or dict. If str it is the name of a inbuilt XC functional. If it is a dict it @@ -1651,6 +1647,20 @@ def set_xcfunctional(xmltree: XMLLike, :param libxc: bool if True the functional is a LibXC functional :returns: an xmltree with modified xcFunctional tag + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_xcfunctional('vwn') + + + .. usage-example:: + :title: Setting a LibXC functional + + fm.set_xcfunctional({'exchange': 'lda_x', 'correlation':"lda_c_xalpha"}, libxc=True) + + """ if not libxc and isinstance(xc_functional, dict): From 313e6ddfb823c062b6d1dec866bd947bbd65e890 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 12:23:24 +0200 Subject: [PATCH 33/36] more --- .../files/inp_max4.xml | 104 ++++++++++++++++++ masci_tools/io/fleurxmlmodifier.py | 48 ++++++++ masci_tools/util/xml/xml_setters_names.py | 48 ++++++++ 3 files changed, 200 insertions(+) create mode 100644 docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp_max4.xml diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp_max4.xml b/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp_max4.xml new file mode 100644 index 000000000..8780fb5c9 --- /dev/null +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp_max4.xml @@ -0,0 +1,104 @@ + + + A Fleur input generator calculation with aiida + + + + + + + + + + 0.0 0.0 0.0 + + + + + + + 0.000000 0.000000 0.000000 + + + + + + + + + + + 1 0 0 .0000000000 + 0 1 0 .0000000000 + 0 0 1 .0000000000 + + + 1 0 0 .0000000000 + 0 -1 0 .0000000000 + 0 0 1 .0000000000 + + + + + 5.301179702900000 .000000000000000 .000000000000000 + .000000000000000 7.497000033000000 .000000000000000 + .000000000000000 .000000000000000 7.992850008800000 + + + + + + + + + + + + + + [Ar] + (4s1/2) (3d3/2) (3d5/2) + + + + + + + + + + + [Xe] (4f5/2) (4f7/2) + (6s1/2) (5d3/2) (5d5/2) + + + + + + + + .0000000000 .0000000000 -.9964250044 + + + + + 1.000/2.000 1.000/2.000 .9964250044 + + + + + + + + + + + + + + + + + + + diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 2116249b5..18cf39949 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -1784,6 +1784,21 @@ def set_nkpts(self, *args: Any, **kwargs: Any) -> None: :param gamma: bool that controls if the gamma-point should be included in the k-point mesh + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + :inputfile: inp_max4.xml + + fm.set_nkpts(200) + + + .. usage-example:: + :title: Include Gamma point + :inputfile: inp_max4.xml + + fm.set_nkpts(200, gamma=True) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_nkpts()` to the list of tasks that will be done on the xmltree. """ @@ -1801,6 +1816,14 @@ def set_kpath(self, *args: Any, **kwargs: Any) -> None: :param gamma: bool that controls if the gamma-point should be included in the k-point mesh + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + :inputfile: inp_max4.xml + + fm.set_kpath({'Point': [0, 0, 0], 'Point2': [1, 1, 1]}, 200) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpath()` to the list of tasks that will be done on the xmltree. """ @@ -1820,6 +1843,24 @@ def set_kpointpath(self, *args: Any, **kwargs: Any) -> None: :param overwrite: if True and a kpoint list of the given name already exists it will be overwritten :param special_points: dict mapping names to coordinates for special points to use + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_kpointpath(nkpts=50, switch=True) + + .. usage-example:: + :title: Specifying custom points + :description: By default the path is chosen by ASE. By providing path + this can be modified + + fm.set_kpointpath(path='CA', + special_points={ + 'C': [0, 0, 0], + 'A': [0, 0, 0.5] + }) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointpath()` to the list of tasks that will be done on the xmltree. """ @@ -1841,6 +1882,13 @@ def set_kpointmesh(self, *args: Any, **kwargs: Any) -> None: :param time_reversal: bool if True time reversal symmetry will be used to reduce the kpoint set :param map_to_first_bz: bool if True the kpoints are mapped into the [0,1] interval + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_kpointmesh([4, 4, 4], switch=True) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointmesh()` to the list of tasks that will be done on the xmltree. """ diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 84662013e..fa7b88960 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -1876,6 +1876,21 @@ def set_nkpts(xmltree: XMLLike, schema_dict: fleur_schema.SchemaDict, count: int in the k-point mesh :returns: an xmltree of the inp.xml file with changes. + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + :inputfile: inp_max4.xml + + fm.set_nkpts(200) + + + .. usage-example:: + :title: Include Gamma point + :inputfile: inp_max4.xml + + fm.set_nkpts(200, gamma=True) + """ raise NotImplementedError(f"'set_npkts' is not implemented for inputs of version '{schema_dict['inp_version']}'") @@ -1929,6 +1944,14 @@ def set_kpath(xmltree: XMLLike, in the k-point mesh :returns: an xmltree of the inp.xml file with changes. + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + :inputfile: inp_max4.xml + + fm.set_kpath({'Point': [0, 0, 0], 'Point2': [1, 1, 1]}, 200) + """ raise NotImplementedError( @@ -2004,6 +2027,24 @@ def set_kpointpath(xmltree: XMLLike, :param special_points: dict mapping names to coordinates for special points to use :returns: xmltree with a created kpoint path + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_kpointpath(nkpts=50, switch=True) + + .. usage-example:: + :title: Specifying custom points + :description: By default the path is chosen by ASE. By providing path + this can be modified + + fm.set_kpointpath(path='CA', + special_points={ + 'C': [0, 0, 0], + 'A': [0, 0, 0.5] + }) + """ from masci_tools.util.xml.xml_getters import get_cell from ase.dft.kpoints import bandpath @@ -2064,6 +2105,13 @@ def set_kpointmesh(xmltree: XMLLike, :param map_to_first_bz: bool if True the kpoints are mapped into the [0,1] interval :returns: xmltree with a created kpoint path + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_kpointmesh([4, 4, 4], switch=True) + """ from masci_tools.util.xml.xml_getters import get_symmetry_information, get_cell from spglib import get_stabilized_reciprocal_mesh From b2bd63bae0ffa219e71d9deee94ca7690112ad22 Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 12:35:28 +0200 Subject: [PATCH 34/36] update --- .../fleurxmlmodifier_usage_examples/files/inp_max4.xml | 5 +---- masci_tools/io/fleurxmlmodifier.py | 2 +- masci_tools/util/xml/xml_setters_names.py | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp_max4.xml b/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp_max4.xml index 8780fb5c9..4e4b6ef2b 100644 --- a/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp_max4.xml +++ b/docs/source/user_guide/fleurxmlmodifier_usage_examples/files/inp_max4.xml @@ -16,9 +16,7 @@ - - 0.000000 0.000000 0.000000 - + @@ -97,7 +95,6 @@ - diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 18cf39949..3e20eb6ca 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -1887,7 +1887,7 @@ def set_kpointmesh(self, *args: Any, **kwargs: Any) -> None: .. usage-example:: - fm.set_kpointmesh([4, 4, 4], switch=True) + fm.set_kpointmesh([4, 4, 1], switch=True) This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointmesh()` to the list of tasks that will be done on the xmltree. diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index fa7b88960..5b3b5f24a 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -2110,7 +2110,7 @@ def set_kpointmesh(xmltree: XMLLike, .. usage-example:: - fm.set_kpointmesh([4, 4, 4], switch=True) + fm.set_kpointmesh([4, 4, 1], switch=True) """ from masci_tools.util.xml.xml_getters import get_symmetry_information, get_cell From d46fcd3c51d47c20a38f8a9f63511c7e2b7b5a6e Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 12:50:06 +0200 Subject: [PATCH 35/36] More --- masci_tools/io/fleurxmlmodifier.py | 49 +++++++++++++++++++---- masci_tools/util/xml/xml_setters_names.py | 47 ++++++++++++++++++---- 2 files changed, 81 insertions(+), 15 deletions(-) diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 3e20eb6ca..79e28f083 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -428,6 +428,28 @@ def set_inpchanges(self, *args: Any, **kwargs: Any) -> None: 'l_ss': True } + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_inpchanges({'itmax' : 1, 'kmax': 4.3}) + + .. usage-example:: + :title: Attribute selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_inpchanges({'itmax' : 1, 'theta': 1.57}) + + .. usage-example:: + :title: Attribute selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + in the ``path_spec`` argument + + fm.set_inpchanges({'itmax' : 1, 'theta': 1.57}, + path_spec={'theta': {'contains': 'soc'}}) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_inpchanges()` to the list of tasks that will be done on the xmltree. """ @@ -725,17 +747,10 @@ def shift_value_species_label(self, *args: Any, **kwargs: Any) -> None: .. usage-example:: :title: Modifying all species :description: Providing `'all'` as the first argument applies the changes - to all species + to all atomgroups fm.shift_value_species_label('all', 'lmax', 2) - .. usage-example:: - :title: Modifying a subset of species - :description: Providing `'all-'` as the first argument applies the changes - to all species which contain the search string in it's name - - fm.shift_value_species_label('all-Pt', 'lmax', 2) - This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.shift_value_species_label()` to the list of tasks that will be done on the xmltree. """ @@ -1754,6 +1769,23 @@ def set_kpointlist(self, *args: Any, **kwargs: Any) -> None: :param switch: bool, if True the kPointlist will be used by Fleur when starting the next calculation :param overwrite: bool, if True and a kPointlist with the given name already exists it will be overwritten + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_kpointlist([[0,0,0],[0.5,0.5,0.5]], + [1,1], switch=True) + + .. usage-example:: + :title: MaX 4 compatibility + :description: For input files before the MaX 5 release the previous kpoint list will always + be overwritten and the ``switch`` argument has no effect + :inputfile: inp_max4.xml + + fm.set_kpointlist([[0,0,0],[0.5,0.5,0.5]], + [1,1]) + This registration method does not modify the file immediately but only appends a :py:func:`~masci_tools.util.xml.xml_setters_names.set_kpointlist()` to the list of tasks that will be done on the xmltree. """ @@ -1856,6 +1888,7 @@ def set_kpointpath(self, *args: Any, **kwargs: Any) -> None: this can be modified fm.set_kpointpath(path='CA', + nkpts=25, special_points={ 'C': [0, 0, 0], 'A': [0, 0, 0.5] diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index 5b3b5f24a..fe69fbc1b 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -1215,16 +1215,10 @@ def shift_value_species_label(xmltree: XMLLike, .. usage-example:: :title: Modifying all species :description: Providing `'all'` as the first argument applies the changes - to all species + to all atomgroups fm.shift_value_species_label('all', 'lmax', 2) - .. usage-example:: - :title: Modifying a subset of species - :description: Providing `'all-'` as the first argument applies the changes - to all species which contain the search string in it's name - - fm.shift_value_species_label('all-Pt', 'lmax', 2) """ from masci_tools.util.schema_dict_util import evaluate_attribute @@ -1595,6 +1589,28 @@ def set_inpchanges(xmltree: XMLLike, } :returns: an xmltree of the inp.xml file with changes. + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_inpchanges({'itmax' : 1, 'kmax': 4.3}) + + .. usage-example:: + :title: Attribute selection not unique + :result: Error + :description: If no or multiple locations could be possible an error is raised + + fm.set_inpchanges({'itmax' : 1, 'theta': 1.57}) + + .. usage-example:: + :title: Attribute selection + :description: Selection can be done by adding conditions on what the XPath should(n't) contain + in the ``path_spec`` argument + + fm.set_inpchanges({'itmax' : 1, 'theta': 1.57}, + path_spec={'theta': {'contains': 'soc'}}) + """ from masci_tools.util.xml.xml_setters_xpaths import xml_set_first_attrib_value, xml_set_first_text from masci_tools.util.xml.common_functions import split_off_attrib @@ -1715,6 +1731,22 @@ def set_kpointlist(xmltree: XMLLike, :param overwrite: bool, if True and a kPointlist with the given name already exists it will be overwritten :returns: an xmltree of the inp.xml file with changes. + + Usage Examples (fm refers to an instance of :py:class:`~masci_tools.io.fleurxmlmodifier.FleurXMLModifier`) + + .. usage-example:: + + fm.set_kpointlist([[0,0,0],[0.5,0.5,0.5]], + [1,1], switch=True) + + .. usage-example:: + :title: MaX 4 compatibility + :description: For input files before the MaX 5 release the previous kpoint list will always + be overwritten and the ``switch`` argument has no effect + :inputfile: inp_max4.xml + + fm.set_kpointlist([[0,0,0],[0.5,0.5,0.5]], + [1,1]) """ from masci_tools.util.xml.builder import FleurElementMaker from masci_tools.util.schema_dict_util import evaluate_attribute @@ -2040,6 +2072,7 @@ def set_kpointpath(xmltree: XMLLike, this can be modified fm.set_kpointpath(path='CA', + nkpts=25, special_points={ 'C': [0, 0, 0], 'A': [0, 0, 0.5] From 0f447b6e6420e791b0dc2c1bd7c397d53f75bd1e Mon Sep 17 00:00:00 2001 From: janssenhenning Date: Fri, 12 May 2023 13:01:52 +0200 Subject: [PATCH 36/36] fixes --- masci_tools/io/fleurxmlmodifier.py | 2 +- masci_tools/util/ipython.py | 3 +++ masci_tools/util/xml/xml_setters_names.py | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/masci_tools/io/fleurxmlmodifier.py b/masci_tools/io/fleurxmlmodifier.py index 79e28f083..69433f047 100644 --- a/masci_tools/io/fleurxmlmodifier.py +++ b/masci_tools/io/fleurxmlmodifier.py @@ -1942,7 +1942,7 @@ def set_xcfunctional(self, *args: Any, **kwargs: Any) -> None: .. usage-example:: - fm.set_xcfunctional('vwn') + fm.set_xcfunctional('pbe') .. usage-example:: diff --git a/masci_tools/util/ipython.py b/masci_tools/util/ipython.py index b1355c921..3f011cecc 100644 --- a/masci_tools/util/ipython.py +++ b/masci_tools/util/ipython.py @@ -53,6 +53,9 @@ def xml_diff(old: XMLLike, new: XMLLike, indent: bool = True) -> HTML: lines = list(difflib.unified_diff(old_lines, new_lines)) + if not lines: + return '' + for index, line in enumerate(lines): if line.startswith('@@'): first_block = index diff --git a/masci_tools/util/xml/xml_setters_names.py b/masci_tools/util/xml/xml_setters_names.py index fe69fbc1b..49b7a1438 100644 --- a/masci_tools/util/xml/xml_setters_names.py +++ b/masci_tools/util/xml/xml_setters_names.py @@ -1668,7 +1668,7 @@ def set_xcfunctional(xmltree: XMLLike, .. usage-example:: - fm.set_xcfunctional('vwn') + fm.set_xcfunctional('pbe') .. usage-example::