From 7f582d600328fdd4be43760aa9d5fb70368727ab Mon Sep 17 00:00:00 2001 From: Luis Barroso-Luque Date: Mon, 18 Sep 2023 10:35:15 -0700 Subject: [PATCH 1/7] ENH: add available basis sets function --- smol/cofe/__init__.py | 2 ++ smol/cofe/space/basis.py | 7 ++++++- smol/utils/class_utils.py | 9 +++++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/smol/cofe/__init__.py b/smol/cofe/__init__.py index 71b890ffd..744f9e530 100644 --- a/smol/cofe/__init__.py +++ b/smol/cofe/__init__.py @@ -9,6 +9,8 @@ from .expansion import ClusterExpansion, RegressionData from .space.clusterspace import ClusterSubspace, PottsSubspace +from .space.basis import available_site_basis_sets + __all__ = [ "ClusterSubspace", diff --git a/smol/cofe/space/basis.py b/smol/cofe/space/basis.py index 6e785c975..5f288b4a3 100644 --- a/smol/cofe/space/basis.py +++ b/smol/cofe/space/basis.py @@ -19,7 +19,7 @@ from numpy.polynomial.legendre import legval from numpy.polynomial.polynomial import polyval -from smol.utils.class_utils import derived_class_factory, get_subclasses +from smol.utils.class_utils import derived_class_factory, get_subclasses, get_subclass_names from .domain import SiteSpace @@ -605,3 +605,8 @@ def basis_factory(basis_name, site_space): iterator_name = basis_name.capitalize() + "Iterator" basis_funcs = derived_class_factory(iterator_name, BasisIterator, species) return StandardBasis(site_space, basis_funcs) + + +def available_site_basis_sets(): + """Return a list of available site basis sets.""" + return tuple(name.split("Iterator")[0].lower() for name in get_subclass_names(BasisIterator)) diff --git a/smol/utils/class_utils.py b/smol/utils/class_utils.py index 61f6f09b9..9545d2577 100644 --- a/smol/utils/class_utils.py +++ b/smol/utils/class_utils.py @@ -74,3 +74,12 @@ def get_subclasses(base_class: object) -> Dict[str, object]: sub_classes[sub_class.__name__] = sub_class return sub_classes + + +def get_subclass_names(base_class: object) -> tuple[str]: + """Get names of all non-abstract subclasses of a class. + + Gets all names of non-abstract classes that inherit from the given base class in + a module. + """ + return tuple(get_subclasses(base_class).keys()) From 7521da48047bcbdd200caef0e3eda636c6b624b2 Mon Sep 17 00:00:00 2001 From: Luis Barroso-Luque Date: Mon, 18 Sep 2023 10:53:44 -0700 Subject: [PATCH 2/7] ENH: add functions to list available kernels, ushers, bias --- smol/cofe/__init__.py | 7 ++++--- smol/cofe/space/basis.py | 2 +- smol/moca/__init__.py | 7 +++++++ smol/moca/kernel/__init__.py | 12 +++++++++++- smol/moca/kernel/bias.py | 11 ++++++++++- smol/moca/kernel/mcusher.py | 7 ++++++- smol/utils/class_utils.py | 8 +++++++- 7 files changed, 46 insertions(+), 8 deletions(-) diff --git a/smol/cofe/__init__.py b/smol/cofe/__init__.py index 744f9e530..99ad95243 100644 --- a/smol/cofe/__init__.py +++ b/smol/cofe/__init__.py @@ -7,9 +7,9 @@ from smol.cofe.wrangling.wrangler import StructureWrangler -from .expansion import ClusterExpansion, RegressionData -from .space.clusterspace import ClusterSubspace, PottsSubspace -from .space.basis import available_site_basis_sets +from smol.cofe.expansion import ClusterExpansion, RegressionData +from smol.cofe.space.clusterspace import ClusterSubspace, PottsSubspace +from smol.cofe.space.basis import available_site_basis_sets __all__ = [ @@ -18,4 +18,5 @@ "StructureWrangler", "ClusterExpansion", "RegressionData", + "available_site_basis_sets" ] diff --git a/smol/cofe/space/basis.py b/smol/cofe/space/basis.py index 5f288b4a3..1dde526cd 100644 --- a/smol/cofe/space/basis.py +++ b/smol/cofe/space/basis.py @@ -609,4 +609,4 @@ def basis_factory(basis_name, site_space): def available_site_basis_sets(): """Return a list of available site basis sets.""" - return tuple(name.split("Iterator")[0].lower() for name in get_subclass_names(BasisIterator)) + return tuple(name.split("iterator")[0] for name in get_subclass_names(BasisIterator)) diff --git a/smol/moca/__init__.py b/smol/moca/__init__.py index d072f002d..9fa513132 100644 --- a/smol/moca/__init__.py +++ b/smol/moca/__init__.py @@ -15,6 +15,10 @@ ) from smol.moca.sampler.container import SampleContainer from smol.moca.sampler.sampler import Sampler +from smol.moca.kernel import available_mckernels +from smol.moca.kernel.mcusher import available_step_types +from smol.moca.kernel.bias import available_bias_types + __all__ = [ "ClusterExpansionProcessor", @@ -25,4 +29,7 @@ "Sampler", "SampleContainer", "CompositionSpace", + "available_mckernels", + "available_step_types", + "available_bias_types", ] diff --git a/smol/moca/kernel/__init__.py b/smol/moca/kernel/__init__.py index 6aaadadca..418ec1895 100644 --- a/smol/moca/kernel/__init__.py +++ b/smol/moca/kernel/__init__.py @@ -8,7 +8,7 @@ from smol.moca.kernel.metropolis import Metropolis, MulticellMetropolis from smol.moca.kernel.random import UniformlyRandom from smol.moca.kernel.wanglandau import WangLandau -from smol.utils.class_utils import class_name_from_str, derived_class_factory +from smol.utils.class_utils import class_name_from_str, derived_class_factory, get_subclass_names __all__ = [ "Metropolis", @@ -19,6 +19,15 @@ ] +def available_mckernels() -> tuple[str]: + """Return names of available MCMC kernels. + + Returns: + tuple[str]: names of available MCMC kernels + """ + return get_subclass_names(MCKernelInterface) + + def mckernel_factory(kernel_type, ensemble, step_type, *args, **kwargs): """Get a MCMC Kernel from string name. @@ -41,3 +50,4 @@ def mckernel_factory(kernel_type, ensemble, step_type, *args, **kwargs): return derived_class_factory( kernel_name, MCKernelInterface, ensemble, step_type, *args, **kwargs ) + diff --git a/smol/moca/kernel/bias.py b/smol/moca/kernel/bias.py index 000445e71..1b848c2a9 100644 --- a/smol/moca/kernel/bias.py +++ b/smol/moca/kernel/bias.py @@ -16,7 +16,7 @@ from smol.moca.composition.space import get_oxi_state from smol.moca.metadata import Metadata from smol.moca.occu_utils import get_dim_ids_table, occu_to_counts -from smol.utils.class_utils import class_name_from_str, derived_class_factory +from smol.utils.class_utils import class_name_from_str, derived_class_factory, get_subclass_names class MCBias(ABC): @@ -366,3 +366,12 @@ def mcbias_factory(bias_type, sublattices, *args, **kwargs): bias_type += "-bias" bias_name = class_name_from_str(bias_type) return derived_class_factory(bias_name, MCBias, sublattices, *args, **kwargs) + + +def available_bias_types() -> tuple[str]: + """Get a list of available MCMC biases. + + Returns: + tuple[str], list of available MCMC biases. + """ + return tuple(name.split("bias")[0] for name in get_subclass_names(MCBias)) diff --git a/smol/moca/kernel/mcusher.py b/smol/moca/kernel/mcusher.py index c6072a81c..259d3cae5 100644 --- a/smol/moca/kernel/mcusher.py +++ b/smol/moca/kernel/mcusher.py @@ -26,7 +26,7 @@ occu_to_counts, occu_to_species_list, ) -from smol.utils.class_utils import class_name_from_str, derived_class_factory +from smol.utils.class_utils import class_name_from_str, derived_class_factory, get_subclass_names from smol.utils.math import NUM_TOL, choose_section_from_partition, flip_weights_mask @@ -725,3 +725,8 @@ def mcusher_factory(usher_type, sublattices, *args, **kwargs): """ usher_name = class_name_from_str(usher_type) return derived_class_factory(usher_name, MCUsher, sublattices, *args, **kwargs) + + +def available_step_types() -> tuple[str]: + """Get available step types.""" + return get_subclass_names(MCUsher) diff --git a/smol/utils/class_utils.py b/smol/utils/class_utils.py index 9545d2577..7c3f91a9b 100644 --- a/smol/utils/class_utils.py +++ b/smol/utils/class_utils.py @@ -76,10 +76,16 @@ def get_subclasses(base_class: object) -> Dict[str, object]: return sub_classes -def get_subclass_names(base_class: object) -> tuple[str]: +def get_subclass_names(base_class: object, lower=True) -> tuple[str]: """Get names of all non-abstract subclasses of a class. Gets all names of non-abstract classes that inherit from the given base class in a module. + + Args: + base_class (object): base class to get subclasses of + lower (bool): whether to return names in lower case """ + if lower: + return tuple(name.lower() for name in get_subclasses(base_class).keys()) return tuple(get_subclasses(base_class).keys()) From 0b88124ce455a5d94b1b1001eea2e4c5fdff8e16 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 20 Sep 2023 21:31:59 +0000 Subject: [PATCH 3/7] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- smol/cofe/__init__.py | 8 +++----- smol/cofe/space/basis.py | 10 ++++++++-- smol/moca/__init__.py | 7 +++---- smol/moca/kernel/__init__.py | 7 +++++-- smol/moca/kernel/bias.py | 6 +++++- smol/moca/kernel/mcusher.py | 6 +++++- 6 files changed, 29 insertions(+), 15 deletions(-) diff --git a/smol/cofe/__init__.py b/smol/cofe/__init__.py index 99ad95243..9e9c395e9 100644 --- a/smol/cofe/__init__.py +++ b/smol/cofe/__init__.py @@ -5,12 +5,10 @@ functions to define and fit cluster expansions for crystalline materials. """ -from smol.cofe.wrangling.wrangler import StructureWrangler - from smol.cofe.expansion import ClusterExpansion, RegressionData -from smol.cofe.space.clusterspace import ClusterSubspace, PottsSubspace from smol.cofe.space.basis import available_site_basis_sets - +from smol.cofe.space.clusterspace import ClusterSubspace, PottsSubspace +from smol.cofe.wrangling.wrangler import StructureWrangler __all__ = [ "ClusterSubspace", @@ -18,5 +16,5 @@ "StructureWrangler", "ClusterExpansion", "RegressionData", - "available_site_basis_sets" + "available_site_basis_sets", ] diff --git a/smol/cofe/space/basis.py b/smol/cofe/space/basis.py index 1dde526cd..a636af0ab 100644 --- a/smol/cofe/space/basis.py +++ b/smol/cofe/space/basis.py @@ -19,7 +19,11 @@ from numpy.polynomial.legendre import legval from numpy.polynomial.polynomial import polyval -from smol.utils.class_utils import derived_class_factory, get_subclasses, get_subclass_names +from smol.utils.class_utils import ( + derived_class_factory, + get_subclass_names, + get_subclasses, +) from .domain import SiteSpace @@ -609,4 +613,6 @@ def basis_factory(basis_name, site_space): def available_site_basis_sets(): """Return a list of available site basis sets.""" - return tuple(name.split("iterator")[0] for name in get_subclass_names(BasisIterator)) + return tuple( + name.split("iterator")[0] for name in get_subclass_names(BasisIterator) + ) diff --git a/smol/moca/__init__.py b/smol/moca/__init__.py index 9fa513132..bb7e1fdcf 100644 --- a/smol/moca/__init__.py +++ b/smol/moca/__init__.py @@ -7,6 +7,9 @@ from smol.moca.composition.space import CompositionSpace from smol.moca.ensemble import Ensemble +from smol.moca.kernel import available_mckernels +from smol.moca.kernel.bias import available_bias_types +from smol.moca.kernel.mcusher import available_step_types from smol.moca.processor.composite import CompositeProcessor from smol.moca.processor.ewald import EwaldProcessor from smol.moca.processor.expansion import ( @@ -15,10 +18,6 @@ ) from smol.moca.sampler.container import SampleContainer from smol.moca.sampler.sampler import Sampler -from smol.moca.kernel import available_mckernels -from smol.moca.kernel.mcusher import available_step_types -from smol.moca.kernel.bias import available_bias_types - __all__ = [ "ClusterExpansionProcessor", diff --git a/smol/moca/kernel/__init__.py b/smol/moca/kernel/__init__.py index 418ec1895..71c81b72c 100644 --- a/smol/moca/kernel/__init__.py +++ b/smol/moca/kernel/__init__.py @@ -8,7 +8,11 @@ from smol.moca.kernel.metropolis import Metropolis, MulticellMetropolis from smol.moca.kernel.random import UniformlyRandom from smol.moca.kernel.wanglandau import WangLandau -from smol.utils.class_utils import class_name_from_str, derived_class_factory, get_subclass_names +from smol.utils.class_utils import ( + class_name_from_str, + derived_class_factory, + get_subclass_names, +) __all__ = [ "Metropolis", @@ -50,4 +54,3 @@ def mckernel_factory(kernel_type, ensemble, step_type, *args, **kwargs): return derived_class_factory( kernel_name, MCKernelInterface, ensemble, step_type, *args, **kwargs ) - diff --git a/smol/moca/kernel/bias.py b/smol/moca/kernel/bias.py index 1b848c2a9..942fd164c 100644 --- a/smol/moca/kernel/bias.py +++ b/smol/moca/kernel/bias.py @@ -16,7 +16,11 @@ from smol.moca.composition.space import get_oxi_state from smol.moca.metadata import Metadata from smol.moca.occu_utils import get_dim_ids_table, occu_to_counts -from smol.utils.class_utils import class_name_from_str, derived_class_factory, get_subclass_names +from smol.utils.class_utils import ( + class_name_from_str, + derived_class_factory, + get_subclass_names, +) class MCBias(ABC): diff --git a/smol/moca/kernel/mcusher.py b/smol/moca/kernel/mcusher.py index 259d3cae5..fcc029804 100644 --- a/smol/moca/kernel/mcusher.py +++ b/smol/moca/kernel/mcusher.py @@ -26,7 +26,11 @@ occu_to_counts, occu_to_species_list, ) -from smol.utils.class_utils import class_name_from_str, derived_class_factory, get_subclass_names +from smol.utils.class_utils import ( + class_name_from_str, + derived_class_factory, + get_subclass_names, +) from smol.utils.math import NUM_TOL, choose_section_from_partition, flip_weights_mask From 4bec3a34e609f618be820a2de7fda1fd0d9d411c Mon Sep 17 00:00:00 2001 From: lbluque Date: Thu, 21 Sep 2023 18:27:36 -0700 Subject: [PATCH 4/7] DOC: add choosing basis sets example --- .../notebooks/choosing-site-basis-sets.ipynb | 529 ++++++++++++++++++ docs/src/notebooks/index.ipynb | 2 +- 2 files changed, 530 insertions(+), 1 deletion(-) create mode 100644 docs/src/notebooks/choosing-site-basis-sets.ipynb diff --git a/docs/src/notebooks/choosing-site-basis-sets.ipynb b/docs/src/notebooks/choosing-site-basis-sets.ipynb new file mode 100644 index 000000000..1b1b9dc6d --- /dev/null +++ b/docs/src/notebooks/choosing-site-basis-sets.ipynb @@ -0,0 +1,529 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "84c95007-2aef-46f7-9d60-889ea985d82a", + "metadata": {}, + "source": [ + "# Choosing the site basis set for a cluster subspace" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "80002d8b-9368-434a-b6b1-1ab94f3e8582", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import random\n", + "import numpy as np\n", + "from monty.serialization import loadfn\n", + "from smol.cofe import ClusterSubspace, available_site_basis_sets" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "5e00f524-66d7-4b27-919e-1c7fe7f5c4c2", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "# load the prim structure\n", + "prim = loadfn('data/lmo_drx_prim.json')" + ] + }, + { + "cell_type": "markdown", + "id": "077ed718-be78-4e4f-84ce-362a2d1f5a22", + "metadata": { + "tags": [] + }, + "source": [ + "### 0) Listing available basis sets\n", + "\n", + "A variety of different site basis sets are available in **smol**. To list the options simply use the function `available_site_basis_sets`" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "c3f6cba3-5255-4f70-b05b-fb59cf69c744", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The available site basis set options are:\n", + " ('indicator', 'sinusoid', 'polynomial', 'chebyshev', 'legendre')\n" + ] + } + ], + "source": [ + "print(f\"The available site basis set options are:\\n {available_site_basis_sets()}\")" + ] + }, + { + "cell_type": "markdown", + "id": "d8d7de19-9057-4ef1-a332-40bd6cd00d81", + "metadata": {}, + "source": [ + "### 1) Setting the site basis type in a cluster subspace\n", + "\n", + "The default site basis set is `indicator`, also known as the \"occupancy\" basis or the \"lattice-gas\" basis. However, the basis type can be set using the `basis` keyword argument when creating a cluster subspace." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "40b7108c-7187-4e86-b426-4ea1173d1ccc", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "subspace_indicator = ClusterSubspace.from_cutoffs(\n", + " prim,\n", + " cutoffs={2: 4, 3: 3}, # will include orbits of 2 and 3 sites.\n", + " supercell_size='O2-'\n", + ")\n", + "\n", + "subspace_sine = ClusterSubspace.from_cutoffs(\n", + " prim,\n", + " cutoffs={2: 4, 3: 3}, # will include orbits of 2 and 3 sites.\n", + " basis=\"sinusoid\",\n", + " supercell_size='O2-'\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "b9a653a3-759d-4118-a1c6-d266b377c554", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Basis/Orthogonal/Orthonormal : indicator/False/False\n", + " Unit Cell Composition : Li+0.7 Mn2+0.7 Mn3+0.2 Mn4+0.2 O2-1\n", + " Number of Orbits : 17\n", + "No. of Correlation Functions : 123\n", + " Cluster Cutoffs : 2: 3.64, 3: 2.97\n", + " External Terms : []\n", + "Orbit Summary\n", + " ------------------------------------------------------------------------\n", + " | ID Degree Cluster Diameter Multiplicity No. Functions |\n", + " | 0 0 NA 0 1 |\n", + " | 1 1 0.0000 2 2 |\n", + " | 2 1 0.0000 1 4 |\n", + " | 3 2 1.8187 8 8 |\n", + " | 4 2 2.1000 6 3 |\n", + " | 5 2 2.9699 12 3 |\n", + " | 6 2 2.9699 6 10 |\n", + " | 7 2 3.4825 24 8 |\n", + " | 8 2 3.6373 4 3 |\n", + " | 9 2 3.6373 4 3 |\n", + " | 10 3 2.1000 12 12 |\n", + " | 11 3 2.9699 24 6 |\n", + " | 12 3 2.9699 12 12 |\n", + " | 13 3 2.9699 12 20 |\n", + " | 14 3 2.9699 8 4 |\n", + " | 15 3 2.9699 8 4 |\n", + " | 16 3 2.9699 8 20 |\n", + " ------------------------------------------------------------------------\n", + "Basis/Orthogonal/Orthonormal : sinusoid/True/False\n", + " Unit Cell Composition : Li+0.7 Mn2+0.7 Mn3+0.2 Mn4+0.2 O2-1\n", + " Number of Orbits : 17\n", + "No. of Correlation Functions : 123\n", + " Cluster Cutoffs : 2: 3.64, 3: 2.97\n", + " External Terms : []\n", + "Orbit Summary\n", + " ------------------------------------------------------------------------\n", + " | ID Degree Cluster Diameter Multiplicity No. Functions |\n", + " | 0 0 NA 0 1 |\n", + " | 1 1 0.0000 2 2 |\n", + " | 2 1 0.0000 1 4 |\n", + " | 3 2 1.8187 8 8 |\n", + " | 4 2 2.1000 6 3 |\n", + " | 5 2 2.9699 12 3 |\n", + " | 6 2 2.9699 6 10 |\n", + " | 7 2 3.4825 24 8 |\n", + " | 8 2 3.6373 4 3 |\n", + " | 9 2 3.6373 4 3 |\n", + " | 10 3 2.1000 12 12 |\n", + " | 11 3 2.9699 24 6 |\n", + " | 12 3 2.9699 12 12 |\n", + " | 13 3 2.9699 12 20 |\n", + " | 14 3 2.9699 8 4 |\n", + " | 15 3 2.9699 8 4 |\n", + " | 16 3 2.9699 8 20 |\n", + " ------------------------------------------------------------------------\n" + ] + } + ], + "source": [ + "print(subspace_indicator)\n", + "print(subspace_sine)" + ] + }, + { + "cell_type": "markdown", + "id": "dfe5ffd3-5fd6-41fd-8911-7fc46847f882", + "metadata": { + "tags": [] + }, + "source": [ + "#### Checking orthogonality and orthonormality\n", + "\n", + "We see from printing the subspace above that the `indicator` basis is not orthogonal, and that the `sinusoid` basis is not orthonormal (it orthonormal for binary systems only)\n", + "\n", + "We can also check if a the basis is orthogonal or orthonormal programmatically." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "9873a839-2d85-4e28-a7df-f9a322ffe134", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The indicator basis is orthogonal False\n", + "The indicator basis is orthogonal False\n", + "\n", + "The sinusoid basis is orthogonal True\n", + "The sinusoid basis is orthogonal False\n" + ] + } + ], + "source": [ + "print(f\"The {subspace_indicator.basis_type} basis is orthogonal {subspace_indicator.basis_orthogonal}\")\n", + "print(f\"The {subspace_indicator.basis_type} basis is orthogonal {subspace_indicator.basis_orthonormal}\\n\")\n", + "\n", + "print(f\"The {subspace_sine.basis_type} basis is orthogonal {subspace_sine.basis_orthogonal}\")\n", + "print(f\"The {subspace_sine.basis_type} basis is orthogonal {subspace_sine.basis_orthonormal}\")" + ] + }, + { + "cell_type": "markdown", + "id": "0d0a871c-2305-465b-acfd-55e9e77f9006", + "metadata": {}, + "source": [ + "#### Inspecting basis functions\n", + "\n", + "We can see the actual basis functions by printing the `basis_array` of singlet orbits. Each row of the basis array corresponds to a basis function." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "031d73b3-c6ae-48ad-8605-892602aae024", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Orbit 1\n", + " Multiplicity : 2 \n", + " No. functions : 2 \n", + "No. symmetry ops : 24 \n", + "Function ids : [1, 2]\n", + "Base Cluster : \n", + " | Diameter : 0.0000\n", + " | Charge : 1.0\n", + " | Centroid : 2.571966 1.818654 4.454775 -> 0.750000 0.750000 0.750000\n", + " | Sites (1)\n", + " | ------------------------------------------------------------------------------------------------------------------------\n", + " | 0 vacA0+:0.333, Li+:0.333, Mn2+:0.333 2.571966 1.818654 4.454775 -> 0.750000 0.750000 0.750000 \n", + "\n", + "indicator basis function:\n", + " [[1. 0. 0.]\n", + " [0. 1. 0.]]\n", + "\n", + "sinusoid basis function:\n", + " [[-1. 0.5 0.5 ]\n", + " [-0. -0.8660254 0.8660254]]\n", + "\n" + ] + } + ], + "source": [ + "i = 0\n", + "print(subspace_indicator.orbits[i], \"\\n\")\n", + "\n", + "print(f\"{subspace_indicator.basis_type} basis function:\\n {subspace_indicator.orbits[i].basis_arrays[0]}\\n\")\n", + "print(f\"{subspace_sine.basis_type} basis function:\\n {subspace_sine.orbits[i].basis_arrays[0]}\\n\")" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "0b6a0502-73f7-4689-be90-557db2a86524", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Orbit 2\n", + " Multiplicity : 1 \n", + " No. functions : 4 \n", + "No. symmetry ops : 48 \n", + "Function ids : [3, 4, 5, 6]\n", + "Base Cluster : \n", + " | Diameter : 0.0000\n", + " | Charge : 2.0\n", + " | Centroid : 0.000000 0.000000 0.000000 -> 0.000000 0.000000 0.000000\n", + " | Sites (1)\n", + " | ------------------------------------------------------------------------------------------------------------------------------------------------\n", + " | 0 vacA0+:0.200, Li+:0.200, Mn2+:0.200, Mn3+:0.200, Mn4+:0.200 0.000000 0.000000 0.000000 -> 0.000000 0.000000 0.000000 \n", + "\n", + "indicator basis function:\n", + " [[1. 0. 0. 0. 0.]\n", + " [0. 1. 0. 0. 0.]\n", + " [0. 0. 1. 0. 0.]\n", + " [0. 0. 0. 1. 0.]]\n", + "\n", + "sinusoid basis function:\n", + " [[-1. -0.30901699 0.80901699 0.80901699 -0.30901699]\n", + " [-0. -0.95105652 -0.58778525 0.58778525 0.95105652]\n", + " [-1. 0.80901699 -0.30901699 -0.30901699 0.80901699]\n", + " [-0. -0.58778525 0.95105652 -0.95105652 0.58778525]]\n", + "\n" + ] + } + ], + "source": [ + "i = 1\n", + "print(subspace_indicator.orbits[i], \"\\n\")\n", + "\n", + "print(f\"{subspace_indicator.basis_type} basis function:\\n {subspace_indicator.orbits[i].basis_arrays[0]}\\n\")\n", + "print(f\"{subspace_sine.basis_type} basis function:\\n {subspace_sine.orbits[i].basis_arrays[0]}\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "8337c30d-4c2a-471a-875f-3d7e6252ef13", + "metadata": {}, + "source": [ + "### 2) Changing the basis set of a cluster subspace\n", + "\n", + "We can change the basis set of a cluster subspace without having to create a new one (which is faster since it does not generate the orbits from scratch)\n", + "\n", + "**Note** that changing the basis set of a cluster subspace used in a cluster expansion that has already been fitted does not transform the ECI, so it will need to be re-fitted." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "c8de8d56-867f-41d4-ad57-78c773768152", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The chebyshev basis is orthogonal False\n", + "The chebyshev basis is orthogonal False\n" + ] + } + ], + "source": [ + "subspace_cheby = subspace_sine.copy()\n", + "subspace_cheby.change_site_bases(\"chebyshev\")\n", + "\n", + "print(f\"The {subspace_cheby.basis_type} basis is orthogonal {subspace_cheby.basis_orthogonal}\")\n", + "print(f\"The {subspace_cheby.basis_type} basis is orthogonal {subspace_cheby.basis_orthonormal}\")" + ] + }, + { + "cell_type": "markdown", + "id": "bbecd0ac-6230-4479-b726-f368a2ab71f3", + "metadata": {}, + "source": [ + "#### Hey! Isn't the Chebyshev basis from the original [Sanchez paper](https://doi.org/10.1016/0378-4371(84)90096-7) orthonormal?\n", + "\n", + "That is correct! But the default implementation in **smol** uses Chebyshev polynomials without orthonormalizing. In order to get the original Sanchez et al, basis you must use the `orthonormal=True` option." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "12a6a90d-b890-4e13-8de2-08abf3e63d11", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The chebyshev basis is orthogonal True\n", + "The chebyshev basis is orthogonal True\n" + ] + } + ], + "source": [ + "# this option is also available in the from_cutoffs method\n", + "subspace_cheby.change_site_bases(\"chebyshev\", orthonormal=True)\n", + "\n", + "print(f\"The {subspace_cheby.basis_type} basis is orthogonal {subspace_cheby.basis_orthogonal}\")\n", + "print(f\"The {subspace_cheby.basis_type} basis is orthogonal {subspace_cheby.basis_orthonormal}\")" + ] + }, + { + "cell_type": "markdown", + "id": "b31aa3c5-1bb7-4620-a200-8e5c9b99d38e", + "metadata": {}, + "source": [ + "#### Technically you can orthonormalize any basis!\n", + "\n", + "And they will be essentially equivalent!" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "c3c61235-1958-4885-88a0-72165c28b110", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "subspace_indicator_on = ClusterSubspace.from_cutoffs(\n", + " prim,\n", + " cutoffs={2: 4, 3: 3}, # will include orbits of 2 and 3 sites.\n", + " supercell_size='O2-',\n", + " basis=\"indicator\",\n", + " orthonormal=True\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "a1501f96-b550-4cca-90d6-c0b4572af3bb", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The indicator basis is orthogonal True\n", + "The indicator basis is orthogonal True\n" + ] + } + ], + "source": [ + "print(f\"The {subspace_indicator_on.basis_type} basis is orthogonal {subspace_indicator_on.basis_orthogonal}\")\n", + "print(f\"The {subspace_indicator_on.basis_type} basis is orthogonal {subspace_indicator_on.basis_orthonormal}\")" + ] + }, + { + "cell_type": "markdown", + "id": "a4870484-2535-4a18-9cc7-c8a90f7119ab", + "metadata": {}, + "source": [ + "#### This is actually no longer an indicator basis!\n", + "\n", + "Lets have a look at the basis functions" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "63025e5b-3410-4509-aa66-0ca081b32bbe", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Orbit 1\n", + " Multiplicity : 2 \n", + " No. functions : 2 \n", + "No. symmetry ops : 24 \n", + "Function ids : [1, 2]\n", + "Base Cluster : \n", + " | Diameter : 0.0000\n", + " | Charge : 1.0\n", + " | Centroid : 2.571966 1.818654 4.454775 -> 0.750000 0.750000 0.750000\n", + " | Sites (1)\n", + " | ------------------------------------------------------------------------------------------------------------------------\n", + " | 0 vacA0+:0.333, Li+:0.333, Mn2+:0.333 2.571966 1.818654 4.454775 -> 0.750000 0.750000 0.750000 \n", + "\n", + "chebyshev basis function:\n", + " [[-1.22474487 -0. 1.22474487]\n", + " [-0.70710678 1.41421356 -0.70710678]]\n", + "\n", + "indicator basis function:\n", + " [[-1.41421356 0.70710678 0.70710678]\n", + " [-0. 1.22474487 -1.22474487]]\n", + "\n" + ] + } + ], + "source": [ + "i = 0\n", + "print(subspace_cheby.orbits[i], \"\\n\")\n", + "\n", + "print(f\"{subspace_cheby.basis_type} basis function:\\n {subspace_cheby.orbits[i].basis_arrays[0]}\\n\")\n", + "print(f\"{subspace_indicator_on.basis_type} basis function:\\n {subspace_indicator_on.orbits[i].basis_arrays[0]}\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "7037ddc9-44ff-4086-98e5-4e94cc1dbdbc", + "metadata": {}, + "source": [ + "The orthonormalized chebyshev and orthonormalized indicator basis sets look remarkably similar! In fact they are related simply by a rotation!" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "matx_dev", + "language": "python", + "name": "matx_dev" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/docs/src/notebooks/index.ipynb b/docs/src/notebooks/index.ipynb index 23bd094b7..7c1e7949f 100644 --- a/docs/src/notebooks/index.ipynb +++ b/docs/src/notebooks/index.ipynb @@ -41,7 +41,7 @@ "* [Creating a basic cluster expansion](creating-a-ce.ipynb): Shows how to set up, create and fit a basic cluster expansion.\n", "* [Creating a cluster expansion with electrostatics](creating-a-ce-w-electrostatics.ipynb): Shows how to set up, create and fit a basic cluster expansion of an ionic system with an additional Ewald electrostatic term.\n", "* [Visualizing clusters](cluster-visualization.ipynb): Demonstrates how to use the **crystal-toolkit** package to visualize structures and clusters.\n", - "* [\"Choosing site basis sets\"](choosing-site-basis-sets.ipynb): Illustrates how to choose and inspecte different available site basis sets.\n", + "* [Choosing site basis sets](choosing-site-basis-sets.ipynb): Illustrates how to choose and inspecte different available site basis sets.\n", "* [Running canonical Monte Carlo](running-canonical-mc.ipynb): Shows an example of running simple canonical Monte Carlo sampling using a cluster expansion.\n", "* [Running semigrand canonical Monte Carlo](running-semigrand-mc.ipynb): Shows an example of running simple semigrand canonical Monte Carlo sampling using a cluster expansion.\n", "* [Running charge neutral semigrand canonical Monte Carlo](running-charge-balanced-gcmc.ipynb): An example of running charge neutral semigrand canonical Monte Carlo sampling using a cluster expansion with ionic species.\n", From 31fed1a5c78497536004c0bd46ffefcbe886287b Mon Sep 17 00:00:00 2001 From: lbluque Date: Thu, 21 Sep 2023 19:10:26 -0700 Subject: [PATCH 5/7] DOC: add choosing kernel and step type example --- docs/src/examples.rst | 3 +++ docs/src/notebooks/index.ipynb | 1 + 2 files changed, 4 insertions(+) diff --git a/docs/src/examples.rst b/docs/src/examples.rst index 89b0f6124..6a3ac105b 100644 --- a/docs/src/examples.rst +++ b/docs/src/examples.rst @@ -51,6 +51,7 @@ Advanced Examples - `Centering training data in stage-wise fit with electrostatics`_ - `Adding structures to a StructureWrangler in parallel`_ - `Simulated annealing with point electrostatics`_ +- `Choosing Monte Carlo kernels and step types`_ - `Wang-Landau sampling of an FCC Ising model`_ - `Generating special quasirandom structures`_ - `Solving for periodic ground-states`_ @@ -64,6 +65,8 @@ Advanced Examples .. _Simulated annealing with point electrostatics: notebooks/running-ewald-sim_anneal.ipynb +.. _Choosing Monte Carlo kernels and step types: notebooks/advanced-mc-settings.ipynb + .. _Wang-Landau sampling of an FCC Ising model: notebooks/wang-landau-ising.ipynb .. _Generating special quasirandom structures: notebooks/generating-sqs.ipynb diff --git a/docs/src/notebooks/index.ipynb b/docs/src/notebooks/index.ipynb index 7c1e7949f..c9ff78d3e 100644 --- a/docs/src/notebooks/index.ipynb +++ b/docs/src/notebooks/index.ipynb @@ -58,6 +58,7 @@ "* [Centering fitting data in a piece-wise fit](ce-fit-w-centering.ipynb): An example showing how to center fitting data when doing a \"piece-wise\" fit with electrostatics.\n", "* [Adding structures to a StructureWrangler in parallel](adding-structures-in-parallel.ipynb): Adding structures to fit a cluster expansion can be time-consuming one way to improve performance is to add them in parallel.\n", "* [Simulated annealing with point electrostatics](running-ewald-sim_anneal.ipynb): This example shows how to run simulated annealing using a point electrostatic potential which can be useful to obtain initial training structures for ionic systems.\n", + "* [Choosing Monte Carlo kernels and step types](advanced-mc-settings.ipynb): Shows how to specify the monte carlo algorithm (kernel) and monte carlo transition (step type).\n", "* [Wang-Landau sampling of an FCC Ising model](wang-landau-ising.ipynb): An example of using Wang-Landau sampling to estimate the DOS of an anti-ferromagnetic FCC Ising model.\n", "* [Generating special quasirandom structures](generating-sqs.ipynb): This example shows how to generate special quasi-random structures for a ternary alloy.\n", "* [Solving for periodic ground-states](finding-groundstates.ipynb): This examples hows how to solve for the ground-state of a cluster expansion in a given periodic supercell.\n", From 5a26da7abdd2115520e3cd2e931fc569e2db9f3d Mon Sep 17 00:00:00 2001 From: lbluque Date: Thu, 21 Sep 2023 19:21:49 -0700 Subject: [PATCH 6/7] fix adding hyphens in class names --- docs/src/notebooks/advanced-mc-settings.ipynb | 202 ++++++++++++++++++ smol/cofe/space/basis.py | 5 +- smol/moca/kernel/__init__.py | 4 +- smol/moca/kernel/bias.py | 4 +- smol/moca/kernel/mcusher.py | 4 +- smol/utils/class_utils.py | 13 +- 6 files changed, 221 insertions(+), 11 deletions(-) create mode 100644 docs/src/notebooks/advanced-mc-settings.ipynb diff --git a/docs/src/notebooks/advanced-mc-settings.ipynb b/docs/src/notebooks/advanced-mc-settings.ipynb new file mode 100644 index 000000000..9a2541158 --- /dev/null +++ b/docs/src/notebooks/advanced-mc-settings.ipynb @@ -0,0 +1,202 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0e321a87-9cdf-4e19-b63d-7c489c22f2ce", + "metadata": { + "tags": [] + }, + "source": [ + "# Advanced Monte Carlo settings - kernels and steps\n", + "\n", + "**smol** allows a lot of flexibility to set and control the specifics of montecarlo simulations, these are implemented in three types of helper classes that can be set when creating a sampler:\n", + "\n", + "- [`MCKernels`](https://cedergrouphub.github.io/smol/api_reference/moca/kernel.kernels.html) define the Monte Carlo sampling algorithm\n", + "- [`MCUshers`](https://cedergrouphub.github.io/smol/api_reference/moca/kernel.mcusher.html) specify the type of step or transition." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "5c7cd3a0-b8a9-44e6-9f5a-3b79d4244f7c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "import numpy as np\n", + "import json\n", + "from smol.io import load_work\n", + "from smol.moca import Ensemble, Sampler, available_mckernels, available_step_types, available_bias_types" + ] + }, + { + "cell_type": "markdown", + "id": "2a4185f7-d67d-4192-97cf-a042c71d7d8c", + "metadata": { + "tags": [] + }, + "source": [ + "### 0) Load the previous LNO CE with electrostatics" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "1ddde958-cd79-40eb-9417-4240a10de2c9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "work = load_work('./data/basic_ce_ewald.mson')\n", + "expansion = work['ClusterExpansion']" + ] + }, + { + "cell_type": "markdown", + "id": "1c0a79db-6ddc-4e75-8152-eac5d8075bc8", + "metadata": {}, + "source": [ + "### 1) Create a semigrand ensemble\n", + "The `Ensemble` class can also be used to run semigrand canonical MC by fixing relative chemical potentials." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ecc83016-42db-4038-a48e-f884f6345cd9", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from smol.moca import Ensemble\n", + "\n", + "sc_matrix = np.array([\n", + " [6, 1, 1],\n", + " [1, 2, 1],\n", + " [1, 1, 2]\n", + "])\n", + "\n", + "chemical_potentials = {'Li+': 0, 'Vacancy': 0, 'Ni3+': 0, 'Ni4+': 0}\n", + "\n", + "ensemble = Ensemble.from_cluster_expansion(\n", + " expansion, sc_matrix, chemical_potentials=chemical_potentials\n", + ")\n" + ] + }, + { + "cell_type": "markdown", + "id": "d8163845-03f7-4e5a-ac1f-25894682f39b", + "metadata": {}, + "source": [ + "### 2) List the available classes" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "ccaf87c4-8095-4502-91b6-19ae45e5c2fd", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The available Monte Carlo kernels are:\n", + "('metropolis', 'uniformly-random', 'wang-landau', 'multicell-metropolis')\n", + "\n", + "The available Monte Carlo step types are:\n", + "('flip', 'swap', 'multi-step', 'composite', 'table-flip')\n", + "\n" + ] + } + ], + "source": [ + "print(f\"The available Monte Carlo kernels are:\\n{available_mckernels()}\\n\")\n", + "print(f\"The available Monte Carlo step types are:\\n{available_step_types()}\\n\")" + ] + }, + { + "cell_type": "markdown", + "id": "9f77237b-d034-45c1-b214-b08461496e64", + "metadata": {}, + "source": [ + "### 3) Choosing the kernel and step type\n", + "\n", + "The specific choices of each of the above can be done when initializing a Sampler.\n", + "\n", + "Specific options for the kernel and the step type are passed as additional keyword arguments." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "874eca41-fc04-490e-af3d-f1d93f8cd46c", + "metadata": { + "tags": [] + }, + "outputs": [], + "source": [ + "from smol.moca.kernel.mcusher import Flip\n", + "\n", + "flip = Flip(ensemble.processor.get_sublattices())\n", + "\n", + "sampler = Sampler.from_ensemble(\n", + " ensemble,\n", + " # kernel settings\n", + " kernel_type=\"metropolis\", # this is the default value\n", + " temperature=1000,\n", + " # step type settings\n", + " step_type=\"multi-step\", # make sure the step type is valid if giving chemical potentials\n", + " mcusher=flip, # look at the documentation of Multistep to see the options\n", + " step_lengths=5, # each step will be composed of 5 random flips\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "id": "b1a7e6c7-7eaf-4218-8dd8-c4b162bf898b", + "metadata": { + "tags": [] + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Metadata(chemical_potentials={Species Li+: 0, Vacancy vacA0+: 0, Species Ni3+: 0, Species Ni4+: 0}, cls_name='SampleContainer', kernels=[Metadata(seed=274324443849665987189735601095705236747, step=Metadata(sublattices=[(Species Li+, Vacancy vacA0+), (Species Ni3+, Species Ni4+), (Species O2-,)], sublattice_probabilities=array([0.5, 0.5]), cls_name='MultiStep', step=Metadata(sublattices=[(Species Li+, Vacancy vacA0+), (Species Ni3+, Species Ni4+), (Species O2-,)], sublattice_probabilities=array([0.5, 0.5]), cls_name='Flip'), step_lengths=array([5]), step_probabilities=array([1.])), cls_name='Metropolis')])\n" + ] + } + ], + "source": [ + "print(sampler.samples.metadata)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "matx_dev", + "language": "python", + "name": "matx_dev" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.11" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/smol/cofe/space/basis.py b/smol/cofe/space/basis.py index a636af0ab..6d65b4753 100644 --- a/smol/cofe/space/basis.py +++ b/smol/cofe/space/basis.py @@ -21,8 +21,8 @@ from smol.utils.class_utils import ( derived_class_factory, - get_subclass_names, get_subclasses, + get_subclasses_str, ) from .domain import SiteSpace @@ -614,5 +614,6 @@ def basis_factory(basis_name, site_space): def available_site_basis_sets(): """Return a list of available site basis sets.""" return tuple( - name.split("iterator")[0] for name in get_subclass_names(BasisIterator) + name.split("iterator")[0] + for name in get_subclasses_str(BasisIterator, split=False) ) diff --git a/smol/moca/kernel/__init__.py b/smol/moca/kernel/__init__.py index 71c81b72c..1904a5dc1 100644 --- a/smol/moca/kernel/__init__.py +++ b/smol/moca/kernel/__init__.py @@ -11,7 +11,7 @@ from smol.utils.class_utils import ( class_name_from_str, derived_class_factory, - get_subclass_names, + get_subclasses_str, ) __all__ = [ @@ -29,7 +29,7 @@ def available_mckernels() -> tuple[str]: Returns: tuple[str]: names of available MCMC kernels """ - return get_subclass_names(MCKernelInterface) + return get_subclasses_str(MCKernelInterface) def mckernel_factory(kernel_type, ensemble, step_type, *args, **kwargs): diff --git a/smol/moca/kernel/bias.py b/smol/moca/kernel/bias.py index 942fd164c..25b21e90e 100644 --- a/smol/moca/kernel/bias.py +++ b/smol/moca/kernel/bias.py @@ -19,7 +19,7 @@ from smol.utils.class_utils import ( class_name_from_str, derived_class_factory, - get_subclass_names, + get_subclasses_str, ) @@ -378,4 +378,4 @@ def available_bias_types() -> tuple[str]: Returns: tuple[str], list of available MCMC biases. """ - return tuple(name.split("bias")[0] for name in get_subclass_names(MCBias)) + return tuple(name.split("bias")[0] for name in get_subclasses_str(MCBias)) diff --git a/smol/moca/kernel/mcusher.py b/smol/moca/kernel/mcusher.py index fcc029804..685d7f969 100644 --- a/smol/moca/kernel/mcusher.py +++ b/smol/moca/kernel/mcusher.py @@ -29,7 +29,7 @@ from smol.utils.class_utils import ( class_name_from_str, derived_class_factory, - get_subclass_names, + get_subclasses_str, ) from smol.utils.math import NUM_TOL, choose_section_from_partition, flip_weights_mask @@ -733,4 +733,4 @@ def mcusher_factory(usher_type, sublattices, *args, **kwargs): def available_step_types() -> tuple[str]: """Get available step types.""" - return get_subclass_names(MCUsher) + return get_subclasses_str(MCUsher) diff --git a/smol/utils/class_utils.py b/smol/utils/class_utils.py index 7c3f91a9b..84676f1a1 100644 --- a/smol/utils/class_utils.py +++ b/smol/utils/class_utils.py @@ -76,7 +76,9 @@ def get_subclasses(base_class: object) -> Dict[str, object]: return sub_classes -def get_subclass_names(base_class: object, lower=True) -> tuple[str]: +def get_subclasses_str( + base_class: object, lower: bool = True, split: bool = True +) -> tuple[str]: """Get names of all non-abstract subclasses of a class. Gets all names of non-abstract classes that inherit from the given base class in @@ -85,7 +87,12 @@ def get_subclass_names(base_class: object, lower=True) -> tuple[str]: Args: base_class (object): base class to get subclasses of lower (bool): whether to return names in lower case + split (bool): whether to split the class name and add hyphens between words """ + names = get_subclasses(base_class).keys() + + if split: + names = tuple("-".join(re.findall("[A-Z][^A-Z]*", name)) for name in names) if lower: - return tuple(name.lower() for name in get_subclasses(base_class).keys()) - return tuple(get_subclasses(base_class).keys()) + names = tuple(name.lower() for name in names) + return names From 2fca24f5f4175250e16a5493a471581c5c486495 Mon Sep 17 00:00:00 2001 From: Luis Barroso-Luque Date: Fri, 22 Sep 2023 10:25:50 -0700 Subject: [PATCH 7/7] DOC: update python badge --- docs/src/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/src/index.rst b/docs/src/index.rst index 855b95f9c..fe7ce5614 100644 --- a/docs/src/index.rst +++ b/docs/src/index.rst @@ -31,7 +31,7 @@ crystalline materials.* :alt: PyPi Version :target: https://pypi.org/project/smol -.. image:: https://img.shields.io/badge/python-3.8%2B-blue +.. image:: https://img.shields.io/badge/python-3.9%2B-blue :alt: Python Versions :target: https://www.python.org/downloads/