diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2f28e9f952e..a058bdaf38a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -18,7 +18,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v5 with: - python-version: "3.9" + python-version: '3.x' - name: Install dependencies run: | diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index baa912a8a3d..b6d5930dd17 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -35,11 +35,11 @@ jobs: resolution: highest extras: ci,optional - os: ubuntu-latest - python: "3.12" + python: '>3.9' resolution: lowest-direct extras: ci,optional - os: macos-latest - python: "3.10" + python: '3.10' resolution: lowest-direct extras: ci # test with only required dependencies installed diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 34a9dba513a..bba0fa50a46 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,7 +22,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.10.0 + rev: v1.10.1 hooks: - id: mypy @@ -33,6 +33,7 @@ repos: stages: [ commit, commit-msg ] exclude_types: [ html ] additional_dependencies: [ tomli ] # needed to read pyproject.toml below py3.11 + exclude: src/pymatgen/analysis/aflow_prototypes.json - repo: https://github.com/MarcoGorelli/cython-lint rev: v0.16.2 @@ -42,7 +43,7 @@ repos: - id: double-quote-cython-strings - repo: https://github.com/adamchainz/blacken-docs - rev: 1.16.0 + rev: 1.18.0 hooks: - id: blacken-docs @@ -64,6 +65,6 @@ repos: args: [ --drop-empty-cells, --keep-output ] - repo: https://github.com/RobertCraigie/pyright-python - rev: v1.1.366 + rev: v1.1.369 hooks: - id: pyright diff --git a/dev_scripts/update_spacegroup_data.py b/dev_scripts/update_spacegroup_data.py new file mode 100644 index 00000000000..a4607cdbee7 --- /dev/null +++ b/dev_scripts/update_spacegroup_data.py @@ -0,0 +1,95 @@ +"""Script to update symm_ops.json and symm_data.yaml in symmetry module due to issues #3845 and #3862. +symm_ops.json: +- adds Hermann_mauguin point group key and short Hermann Mauguin space group symbol +- converts screw axis notation to symm_data standard +symm_data.json +- removes mapping of rhombohedral space group types onto symbol + appended H +- replaces I/P2_12_121 key with I/P2_12_12_1 +""" + +from __future__ import annotations + +import sys + +from monty.serialization import dumpfn, loadfn +from pymatgen.symmetry.groups import PointGroup + +__author__ = "Katharina Ueltzen @kaueltzen" +__date__ = "2024-06-06" + +SYMM_OPS = loadfn("../src/pymatgen/symmetry/symm_ops.json") +SYMM_DATA = loadfn("../src/pymatgen/symmetry/symm_data.json") + + +def convert_symmops_to_sg_encoding(symbol: str) -> str: + """ + Utility function to convert SYMMOPS space group type symbol notation + into SYMM_DATA["space_group_encoding"] key notation with underscores before + translational part of screw axes. + Args: + symbol (str): "hermann_mauguin" or "universal_h_m" key of symmops.json + Returns: + symbol in the format of SYMM_DATA["space_group_encoding"] keys + """ + symbol_representation = symbol.split(":") + representation = ":" + "".join(symbol_representation[1].split(" ")) if len(symbol_representation) > 1 else "" + + blickrichtungen = symbol_representation[0].split(" ") + blickrichtungen_new = [] + for br in blickrichtungen: + if len(br) > 1 and br[0].isdigit() and br[1].isdigit(): + blickrichtungen_new.append(br[0] + "_" + br[1:]) + else: + blickrichtungen_new.append(br) + return "".join(blickrichtungen_new) + representation + + +def remove_identity_from_full_hermann_mauguin(symbol: str) -> str: + """ + Utility function to remove identity along blickrichtung (except in P1). + Args: + symbol (str): "hermann_mauguin" key of symmops.json + Returns: + short "hermann_mauguin" key + """ + if symbol in ("P 1", "C 1", "P 1 "): + return symbol + blickrichtungen = symbol.split(" ") + blickrichtungen_new = [] + for br in blickrichtungen: + if br != "1": + blickrichtungen_new.append(br + " ") + return "".join(blickrichtungen_new) + + +new_symm_data = {} +for k, v in SYMM_DATA["space_group_encoding"].items(): + if k.endswith("H"): + new_symm_data[k.removesuffix("H")] = v + elif k == "I2_12_121": + new_symm_data["I2_12_12_1"] = v + elif k == "P2_12_121": + new_symm_data["P2_12_12_1"] = v + else: + new_symm_data[k] = v + +SYMM_DATA["space_group_encoding"] = new_symm_data + +for spg_idx, spg in enumerate(SYMM_OPS): + if "(" in spg["hermann_mauguin"]: + SYMM_OPS[spg_idx]["hermann_mauguin"] = spg["hermann_mauguin"].split("(")[0] + + short_h_m = remove_identity_from_full_hermann_mauguin(SYMM_OPS[spg_idx]["hermann_mauguin"]) + SYMM_OPS[spg_idx]["short_h_m"] = convert_symmops_to_sg_encoding(short_h_m) + SYMM_OPS[spg_idx]["hermann_mauguin_u"] = convert_symmops_to_sg_encoding(spg["hermann_mauguin"]) + +for spg_idx, spg in enumerate(SYMM_OPS): + try: + pg = PointGroup.from_space_group(spg["short_h_m"]) + except AssertionError as e: + print(spg, str(e)) + sys.exit(1) + SYMM_OPS[spg_idx]["point_group"] = pg.symbol + +dumpfn(SYMM_DATA, "../src/pymatgen/symmetry/symm_data.json") +dumpfn(SYMM_OPS, "../src/pymatgen/symmetry/symm_ops.json") diff --git a/docs/CHANGES.md b/docs/CHANGES.md index 6b162785e8e..b080903b763 100644 --- a/docs/CHANGES.md +++ b/docs/CHANGES.md @@ -6,6 +6,14 @@ nav_order: 4 # Changelog +## v2024.7.18 +- Fix `setuptools` for packaging (#3934) +- Improve Keep Redundant Spaces algorithm for PatchedPhaseDiagram (#3900) +- Add electronic structure methods for Species (#3902) +- Migrate `spglib` to new `SpglibDataset` format with version 2.5.0 (#3923) +- SpaceGroup changes (#3859) +- Add MD input set to FHI-aims (#3896) + ## v2024.6.10 * Fix bug in `update_charge_from_potcar` (#3866) * Fix bug in VASP parameter parsing (@mkhorton) diff --git a/docs/compatibility.md b/docs/compatibility.md index 61bdee2354c..115ed7ebe7e 100644 --- a/docs/compatibility.md +++ b/docs/compatibility.md @@ -67,6 +67,24 @@ Windows and Linux. ## Recent Breaking Changes +### v2024.?.? + +The `symbol` attribute of `SpaceGroup` now always refers to its Hermann-Mauguin symbol +(see [#3859](https://github.com/materialsproject/pymatgen/pull/3859)). In order to replace +the old symbol, run + +```py +from pymatgen.symmetry.groups import SpaceGroup + +try: + new_symbol = SpaceGroup(old_symbol).symbol +except ValueError: + if old_symbol in ["P2_12_121", "I2_12_121"]: + new_symbol = SpaceGroup(old_symbol[:-1]+"_1").symbol + else: + new_symbol = SpaceGroup(old_symbol[:-1]).symbol +``` + ### v2024.5.31 * Update VASP sets to transition `atomate2` to use `pymatgen` input sets exclusively by @esoteric-ephemera in [#3835](https://github.com/materialsproject/pymatgen/pull/3835) diff --git a/docs/modules.html b/docs/modules.html index 8176ffd9a89..45c32066fbe 100644 --- a/docs/modules.html +++ b/docs/modules.html @@ -305,15 +305,7 @@
IStructure.frac_coords
IStructure.from_dict()
IStructure.from_file()
IStructure.from_id()
IStructure.from_magnetic_spacegroup()
IStructure.from_sites()
IStructure.from_spacegroup()
AimsControlIn
AimsCube
AimsGeometryIn
AimsSpeciesFile
SpeciesDefaults
Generate TransformedStructure from a CIF string.
+Generate TransformedStructure from a cif string.
cif_string (str) – Input CIF string. Should contain only one +
cif_string (str) – Input cif string. Should contain only one structure. For CIFs containing multiple structures, please use CifTransmuter.
transformations (list[Transformation]) – Sequence of transformations @@ -662,18 +662,19 @@
Bases: StandardTransmuter
Generate a Transmuter from a CIF string, possibly containing multiple structures.
-Generate a Transmuter from a CIF string, possibly +
Generate a Transmuter from a cif string, possibly containing multiple +structures.
+Generate a Transmuter from a cif string, possibly containing multiple structures.
cif_string – A string containing a CIF or a series of CIFs
cif_string – A string containing a cif or a series of CIFs
transformations – New transformations to be applied to all structures
primitive – Whether to generate the primitive cell from the CIF.
primitive – Whether to generate the primitive cell from the cif.
extend_collection – Whether to use more than one output structure from one-to-many transformations. extend_collection can be a number, which determines the maximum branching for each @@ -683,13 +684,13 @@
Generate a TransformedStructureCollection from a cif, possibly containing multiple structures.
filenames – List of strings of the CIF files
filenames – List of strings of the cif files
transformations – New transformations to be applied to all structures
primitive – Same meaning as in __init__.
Bases: StandardTransmuter
Generate a transmuter from a sequence of POSCARs.
Convenient constructor to generates a POSCAR transmuter from a list of POSCAR filenames.
Batch write vasp input for a sequence of transformed structures to output_dir, following the format output_dir/{group}/{formula}_{number}.
Additional condition for this strategy.
Compute the environments.
Draw cg.
Visualizing a coordination geometry :param cg: :param zoom: diff --git a/docs/pymatgen.analysis.html b/docs/pymatgen.analysis.html index cf7a2f00d15..d78fc3640ec 100644 --- a/docs/pymatgen.analysis.html +++ b/docs/pymatgen.analysis.html @@ -2330,15 +2330,7 @@
Bases: InterfacialReactivity
Extends upon InterfacialReactivity to allow for modelling possible reactions at the interface between two solids in the presence of an open element. The @@ -6076,7 +6068,7 @@
Generate the opposite number of energy above grand potential convex hull for both reactants.
Bases: MSONable
Model an interface between two solids and its possible reactions. The two reactants are provided as Composition objects (c1 and c2), along with the @@ -6131,7 +6123,7 @@
Get the normalized correction term Δμ for chemical potential of a gas phase consisting of element at given temperature and pressure, referenced to that in the standard state (T_std = 298.15 K, @@ -6241,7 +6233,7 @@
Bases: NearNeighbors
Determine coordination number using Brunner’s algorithm which counts the atoms that are within the largest gap in differences in real space @@ -6259,7 +6251,7 @@
Get all near-neighbor sites as well as the associated image locations and weights of the site with index n in structure.
Bases: NearNeighbors
Determine coordination number using Brunner’s algorithm which counts the atoms that are within the largest gap in differences in real space @@ -6329,7 +6321,7 @@
Get all near-neighbor sites as well as the associated image locations and weights of the site with index n in structure.
Bases: NearNeighbors
Determine coordination number using Brunner’s algorithm which counts the atoms that are within the largest gap in differences in real space @@ -6398,7 +6390,7 @@
Get all near-neighbor sites as well as the associated image locations and weights of the site with index n in structure.
Bases: BrunnerNNReal
Bases: BrunnerNNReciprocal
Bases: BrunnerNNRelative
Bases: NearNeighbors
Performs a topological analysis using critic2 to obtain neighbor information, using a sum of atomic charge densities. If an actual charge density is available (e.g. from a @@ -6651,7 +6643,7 @@
Get all near-neighbor sites as well as the associated image locations and weights of the site with index n in structure.
Bases: NearNeighbors
This is a custom near-neighbor method intended for use in all kinds of periodic structures (metals, minerals, porous structures, etc). It is based on a Voronoi algorithm and uses the @@ -6774,7 +6766,7 @@
Bases: NamedTuple
Create new instance of NNData(all_nninfo, cn_weights, cn_nninfo)
Get coordination number, CN, of site with index n in structure.
Get coordination number, CN, of each element bonded to site with index n in structure.
The main logic of the method to compute near neighbor.
Get all near-neighbor information.
Given NNData, transforms data to the specified fingerprint length
Bases: NearNeighbors
A basic NN class using a dictionary of fixed cut-off distances. Only pairs of elements listed in the cut-off dictionary are considered @@ -6987,7 +6979,7 @@
Initialize a CutOffDictNN according to a preset set of cutoffs.
Get all near-neighbor sites as well as the associated image locations and weights of the site with index n in structure.
Bases: NearNeighbors
Determines the average effective coordination number for each cation in a given structure using Hoppe’s algorithm.
@@ -7089,7 +7081,7 @@Get all near-neighbor sites as well as the associated image locations and weights of the site with index n in structure.
Bases: object
This class permits the calculation of various types of local structure order parameters.
@@ -7474,7 +7466,7 @@Compute all order parameters of site n.
Identify and add missed coordinate bond edges for metals.
Identify and add missed O-C or O-H bonds. This is particularly important when oxygen is forming three bonds, e.g. in H3O+ or XOH2+. See https://github.com/materialsproject/pymatgen/pull/2903 for details.
@@ -11579,7 +11571,7 @@Generate a symmetrized force constant matrix from an unsymmetrized matrix that has no unstable modes and also obeys the acoustic sum rule through an iterative procedure.
@@ -11723,7 +11715,7 @@Generate a random piezoelectric tensor based on a structure and corresponding symmetry.
Calculate spectroscopy limited maximum efficiency (SLME) given dielectric function data.
-Forked and adjusted from : -https://github.com/usnistgov/jarvis
-Calculate the optical absorption coefficient from an input set of -pymatgen vasprun dielectric constant data.
-dielectric (list) – A list containing the dielectric response function
-in the pymatgen vasprun format.
-- element 0: list of energies
-- element 1: real dielectric tensors, in [xx, yy, zz, xy, xz, yz]
format.
-- element 2: imaginary dielectric tensors, in [xx, yy, zz, xy, xz, yz]
format.
absorption coefficient using eV as frequency units (cm^-1).
-np.array
-Convert a set of 2D vasprun formatted dielectric data to -the eigenvalues of each corresponding 3x3 symmetric numpy matrices.
-data (list) – length N list of dielectric data. Each entry should be
-a list of [xx, yy, zz, xy , xz, yz ]
dielectric tensor elements.
for the corresponding row in data.
-np.array
-Calculate the SLME.
-material_energy_for_absorbance_data – energy grid for absorbance data
material_absorbance_data – absorption coefficient in m^-1
material_direct_allowed_gap – direct bandgap in eV
material_indirect_gap – indirect bandgap in eV
thickness – thickness of the material in m
temperature – working temperature in K
absorbance_in_inverse_centimeters – whether the absorbance data is in the unit of cm^-1
cut_off_absorbance_below_direct_allowed_gap – whether to discard all absorption below bandgap
plot_current_voltage – whether to plot the current-voltage curve
The calculated maximum efficiency.
-Convert a list of matrix components to a symmetric 3x3 matrix. -Inputs should be in the order xx, yy, zz, xy, yz, xz.
-xx (float) – xx component of the matrix.
yy (float) – yy component of the matrix.
zz (float) – zz component of the matrix.
xy (float) – xy component of the matrix.
yz (float) – yz component of the matrix.
xz (float) – xz component of the matrix.
The matrix, as a 3x3 numpy array.
-np.array
-Get magnetization info from OUTCARs.
dirc (str) – Directory name
dir (str) – Directory name
ion_list (list[int]) – List of ions to obtain magnetization information for.
Add/update keys in .pmgrc.yaml config file.
Build bader package.
Build enum.
Handle configure command.
Install all optional external software.
Setup CP2K basis and potential data directory.
Setup POTCAR directories.
Bases: object
Perform Bader charge analysis for Cube files or VASP outputs.
Convenient constructor that takes in the path name of VASP run to perform Bader analysis.
Convenience method to get the charge on a particular atom. This is the “raw” charge generated by the Bader program, not a partial atomic charge. If the cube file is a spin-density file, then this will return the spin density per atom with @@ -349,7 +349,7 @@
Get a charge decorated structure.
Note, this assumes that the Bader analysis was correctly performed on a file with electron densities
@@ -357,7 +357,7 @@Get the charge transferred for a particular atom. A positive value means that the site has gained electron density (i.e. exhibits anionic character) whereas a negative value means the site has lost electron density (i.e. exhibits @@ -381,7 +381,7 @@
Get a property-decorated structure from the Bader analysis.
This is distinct from getting charge decorated structure, which assumes the “standard” Bader analysis of electron densities followed by converting @@ -412,7 +412,7 @@
Get an oxidation state decorated structure based on bader analysis results. Each site is assigned a charge based on the computed partial atomic charge from bader.
Note, this assumes that the Bader analysis was correctly performed on a file @@ -432,7 +432,7 @@
Convenience method to get the partial charge on a particular atom. This is simply the negative value of the charge transferred. A positive value indicates that the atom has cationic character, whereas a negative value indicates the @@ -462,7 +462,7 @@
Convenience method to run Bader analysis from a set of pymatgen Chgcar and Potcar objects.
This method will:
@@ -487,7 +487,7 @@Convenience method to run Bader analysis on a folder containing typical VASP output files.
This method will:
@@ -1053,7 +1053,7 @@An adaptor for enumlib.
Helper function for calling mcsqs with different arguments :param structure: Disordered pymatgen Structure object :type structure: Structure diff --git a/docs/pymatgen.core.html b/docs/pymatgen.core.html index 2dd0af47d30..1b40a0b7d11 100644 --- a/docs/pymatgen.core.html +++ b/docs/pymatgen.core.html @@ -1080,7 +1080,6 @@
IStructure.frac_coords
IStructure.from_dict()
IStructure.from_file()
IStructure.from_id()
IStructure.from_magnetic_spacegroup()
IStructure.from_sites()
IStructure.from_spacegroup()
Bases: dict
, MSONable
Represent set of chemical potentials. Can be: multiplied/divided by a Number multiplied by a Composition (returns an energy) added/subtracted with other ChemicalPotentials.
@@ -1631,7 +1630,7 @@Calculate the energy of a composition.
Bases: Hashable
, Mapping
, MSONable
, Stringify
Represents a Composition, which is essentially a {element:amount} mapping type. Composition is written to be immutable and hashable, @@ -1712,7 +1711,7 @@
Assign oxidation states based on guessed oxidation states.
See oxi_state_guesses for an explanation of how oxidation states are guessed. This operation uses the set of oxidation states for each site @@ -1725,12 +1724,11 @@
Check if the composition is charge-balanced and returns back all charge-balanced oxidation state combinations. Composition must have integer values. Note that more num_atoms in the composition gives @@ -2097,12 +2095,11 @@
Takes in a formula where capitalization might not be correctly entered, and suggests a ranked list of potential Composition matches. Author: Anubhav Jain.
@@ -2165,7 +2162,7 @@Get a new Composition with charges from each Species removed.
Replace elements in a composition. Returns a new Composition, leaving the old one unchanged.
Bases: Exception
Exception class for composition errors.
Helper function to reduce a sym_amt dict to a reduced formula and factor.
Bases: DummySpecies
This maps the historical grammatically inaccurate DummySpecie to DummySpecies to maintain backwards compatibility.
@@ -6775,7 +6772,7 @@Bases: Species
A special specie for representing non-traditional elements or species. For example, representation of vacancies (charged or otherwise), or special @@ -6871,13 +6868,13 @@
MSONable dict representation.
dct (dict) – Dict representation.
@@ -6890,7 +6887,7 @@Get a Dummy from a string representation.
Bases: Enum
Enum for element types.
Bases: Species
This maps the historical grammatically inaccurate Specie to Species to maintain backwards compatibility.
@@ -8799,7 +8796,7 @@Bases: MSONable
, Stringify
An extension of Element with optional oxidation state and spin. Properties associated with Species should be “idealized” values, not calculated values. For example, @@ -8827,7 +8824,7 @@
JSON-able dictionary representation.
dct (dict) – Dict representation.
@@ -8882,7 +8879,7 @@Calculate the crystal field spin based on coordination and spin configuration. Only works for transition metal species.
Get the local environment specific ionic radius for species.
Bases: SiteCollection
, MSONable
Basic immutable Molecule object without periodicity. Essentially a sequence of sites. IMolecule is made to be immutable so that they can @@ -9566,13 +9563,13 @@
JSON-serializable dict representation of Molecule.
Get two molecules based on breaking the bond between atoms at index ind1 and ind2.
Convenience method to get a copy of the molecule.
Reconstitute a Molecule object from a dict representation created using as_dict().
Read a molecule from a file. Supported formats include xyz, gaussian input (gjf|g03|g09|com|inp), Gaussian output (.out|and pymatgen’s JSON-serialized molecules. Using openbabel, @@ -9651,7 +9648,7 @@
Convenience constructor to make a Molecule from a list of sites.
Reads the molecule from a string.
Create a Structure from a Molecule by putting the Molecule in the center of a orthorhombic box. Useful for creating Structure for calculating molecules using periodic codes.
@@ -9738,7 +9735,7 @@Get a Molecule centered at the center of mass.
Determine the covalent bonds in a molecule.
Get distance between site i and j.
Get all neighbors to a site within a sphere of radius r. Excludes the site itself.
Get all sites in a shell centered on origin (coords) between radii r-dr and r+dr.
Find all sites within a sphere from a point.
Get a z-matrix representation of the molecule.
Outputs the molecule to a file or string.
Bases: SiteCollection
, MSONable
Basic immutable Structure object with periodicity. Essentially a sequence of PeriodicSites having a common lattice. IStructure is made to be @@ -9947,7 +9944,7 @@
Create a Pandas DataFrame of the sites. Structure-level attributes are stored in DataFrame.attrs.
Example
@@ -9958,7 +9955,7 @@Dict representation of Structure.
Convenience method to get a copy of the structure, with options to add site properties.
Reconstitute a Structure from a dict representation of Structure created using as_dict().
Read a structure from a file. For example, anything ending in a “cif” is assumed to be a Crystallographic Information Format file. Supported formats include CIF, POSCAR/CONTCAR, CHGCAR, LOCPOT, @@ -10080,24 +10077,9 @@
Load a structure file based on an id, usually from an online source.
-id – The id associated with the structure. E.g., the Materials Project id.
source – Source of the data. Defaults to “Materials Project”.
**kwargs – Pass-through to any API calls.
Generate a structure using a magnetic spacegroup. Note that only symmetrically distinct species, coords and magmoms should be provided.] All equivalent sites are generated from the spacegroup operations.
@@ -10156,7 +10138,7 @@Convenience constructor to make a IStructure from a list of sites.
Generate a structure using a spacegroup. Note that only symmetrically distinct species and coords should be provided. All equivalent sites are generated from the spacegroup operations.
@@ -10238,7 +10220,7 @@Read a structure from a string.
Get neighbors for each atom in the unit cell, out to a distance r. Use this method if you are planning on looping over all sites in the crystal. If you only want neighbors for a particular site, use the @@ -10313,12 +10295,12 @@
Get neighbors for each atom in the unit cell, out to a distance r. Use this method if you are planning on looping over all sites in the crystal. If you only want neighbors for a particular site, use the @@ -10363,7 +10345,7 @@
Get distance between site i and j assuming periodic boundary conditions. If the index jimage of two sites atom j is not specified it selects the jimage nearest to the i atom and returns the distance and @@ -10387,7 +10369,7 @@
Get the Miller index of a plane from a set of sites indexes.
A minimum of 3 sites are required. If more than 3 sites are given the best plane that minimises the distance to all points will be @@ -10415,7 +10397,7 @@
Get neighbor lists using numpy array representations without constructing Neighbor objects. If the cython extension is installed, this method will be orders of magnitude faster than get_all_neighbors_old and 2-3x faster @@ -10453,7 +10435,7 @@
Get all neighbors to a site within a sphere of radius r. Excludes the site itself.
Get all sites in a shell centered on origin (coords) between radii r-dr and r+dr.
Get list of orderings for a disordered structure. If structure does not contain disorder, the default structure is returned.
Find a smaller unit cell than the input. Sometimes it doesn’t find the smallest possible one, so this method is recursively called until it is unable to find a smaller cell.
@@ -10559,7 +10541,7 @@Get a reduced structure.