diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 3ed50930f..657d83fa3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -26,7 +26,7 @@ body: attributes: label: freud Version description: What version of freud are you using? - placeholder: v2.11.0 + placeholder: v2.12.0 validations: required: true - type: input diff --git a/.mailmap b/.mailmap index 0858b2bf3..146defe2f 100644 --- a/.mailmap +++ b/.mailmap @@ -45,6 +45,7 @@ Jiwoong Yu yjw0510 Kelly Wang Kelly Wang <47036428+klywang@users.noreply.github.com> Michael Stryk mstryk <60406122+mstryk@users.noreply.github.com> Tommy Waltmann tommy-waltmann <53307607+tommy-waltmann@users.noreply.github.com> +Tommy Waltmann Tommy Waltmann <53307607+tommy-waltmann@users.noreply.github.com> Patrick Lawton patricklawton dependabot dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Pavel Buslaev pbuslaev @@ -59,3 +60,4 @@ DomFijan domagoj DomFijan Domagoj Fijan <50439291+DomFijan@users.noreply.github.com> DomFijan Domagoj Fijan Dylan Marx marxd1 <93282247+marxd1@users.noreply.github.com> +Alain Kadar AlainKadar <73320455+AlainKadar@users.noreply.github.com> diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 166e1a364..3365b5291 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -29,7 +29,7 @@ repos: - id: debug-statements - id: requirements-txt-fixer - repo: https://github.com/asottile/pyupgrade - rev: 'v2.38.2' + rev: 'v3.2.0' hooks: - id: pyupgrade args: @@ -39,7 +39,7 @@ repos: hooks: - id: isort - repo: https://github.com/psf/black - rev: '22.8.0' + rev: '22.10.0' hooks: - id: black - repo: https://github.com/PyCQA/flake8 diff --git a/ChangeLog.md b/ChangeLog.md index a3efe24ec..b45c3f9d7 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -4,10 +4,16 @@ The format is based on and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## vX.Y.Z -- YYYY-MM-DD +## v3.0.0 -- YYYY-MM-DD + +### Changed +* The `normalize` argument to `freud.density.RDF` is now `normalization_mode`. + +## v2.12.0 -- 2022-11-09 ### Added -* Mass dependence in `freud.cluster.ClusterProperties` and calculation of inertia tensor and center of mass. +* Mass dependence in `freud.cluster.ClusterProperties`. +* Inertia tensor calculation in `freud.cluster.ClusterProperties`. ### Fixed * Compatibility with new namespace for `MDAnalysis.coordinates.timestep.Timestep`. diff --git a/contributors.txt b/contributors.txt index b20d4e111..bc32bb2dc 100644 --- a/contributors.txt +++ b/contributors.txt @@ -1,19 +1,19 @@ - 2356 Bradley Dice + 2357 Bradley Dice 2146 Vyas Ramasubramani 1030 Eric Harper + 462 Tommy Waltmann 456 Jin Soo Ihm - 379 Tommy Waltmann 316 Joshua A. Anderson 240 Matthew Spellings 167 Kelly Wang - 138 dependabot + 163 dependabot 137 DomFijan 110 Erin Teich 97 Brandon Butler 89 Charlotte Shiqi Zhao 66 M. Eric Irrgang + 54 pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 53 Chrisy Du - 52 pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> 41 Yezhi Jin 40 Antonio Osorio 35 Michael Stryk @@ -22,6 +22,7 @@ 25 Andrew Kerr 25 Carl Simon Adorf 22 Jens Glaser + 21 Alain Kadar 20 Tim Moore 18 Kody Takada 13 Pavel Buslaev diff --git a/cpp/density/RDF.cc b/cpp/density/RDF.cc index 310e18822..ab09fc5dd 100644 --- a/cpp/density/RDF.cc +++ b/cpp/density/RDF.cc @@ -11,8 +11,8 @@ namespace freud { namespace density { -RDF::RDF(unsigned int bins, float r_max, float r_min, bool normalize) - : BondHistogramCompute(), m_normalize(normalize) +RDF::RDF(unsigned int bins, float r_max, float r_min, NormalizationMode normalization_mode) + : BondHistogramCompute(), m_norm_mode(normalization_mode) { if (bins == 0) { @@ -59,7 +59,7 @@ void RDF::reduce() // Define prefactors with appropriate types to simplify and speed later code. float number_density = float(m_n_query_points) / m_box.getVolume(); - if (m_normalize) + if (m_norm_mode == NormalizationMode::finite_size) { number_density *= static_cast(m_n_query_points - 1) / static_cast(m_n_query_points); } diff --git a/cpp/density/RDF.h b/cpp/density/RDF.h index 50af6cbb9..fbf0b27a1 100644 --- a/cpp/density/RDF.h +++ b/cpp/density/RDF.h @@ -16,8 +16,16 @@ namespace freud { namespace density { class RDF : public locality::BondHistogramCompute { public: + //! Enum for each normalization mode + enum NormalizationMode + { + exact, + finite_size + }; + //! Constructor - RDF(unsigned int bins, float r_max, float r_min = 0, bool normalize = false); + RDF(unsigned int bins, float r_max, float r_min = 0, + NormalizationMode normalization_mode = NormalizationMode::exact); //! Destructor ~RDF() override = default; @@ -51,7 +59,7 @@ class RDF : public locality::BondHistogramCompute } private: - bool m_normalize; //!< Whether to enforce that the RDF should tend to 1 (instead of + NormalizationMode m_norm_mode; //!< Whether to enforce that the RDF should tend to 1 (instead of //!< num_query_points/num_points). util::ManagedArray m_pcf; //!< The computed pair correlation function. util::ManagedArray diff --git a/doc/source/conf.py b/doc/source/conf.py index 9979531ff..15b070ff8 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -70,8 +70,8 @@ # built documents. # # version and release are set the same for this package. -version = "2.11.0" -release = "2.11.0" +version = "2.12.0" +release = "2.12.0" # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/doc/source/gettingstarted/migration.rst b/doc/source/gettingstarted/migration.rst new file mode 100644 index 000000000..2fadd59bc --- /dev/null +++ b/doc/source/gettingstarted/migration.rst @@ -0,0 +1,25 @@ +.. _migration: + +============================ +Migration to freud Version 3 +============================ + +Version 3 of the freud library introduces a few breaking changes to make the API +more intuitive and facilitate future development. This guide explains how to +alter scripts which use freud v2 APIs so they can be used with freud v3. + +Overview of API Changes +======================= + +.. list-table:: + :header-rows: 1 + + * - Goal + - v2 API + - v3 API + * - Use default RDF normalization. + - ``freud.density.RDF(..., normalize=False)`` + - ``freud.density.RDF(..., normalization_mode='exact')`` + * - Normalize small system RDFs to 1. + - ``freud.density.RDF(..., normalize=True)`` + - ``freud.density.RDF(..., normalization_mode='finite_size')`` diff --git a/doc/source/index.rst b/doc/source/index.rst index cc48d6c60..19e969623 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -10,6 +10,7 @@ Table of Contents gettingstarted/introduction gettingstarted/installation gettingstarted/quickstart + gettingstarted/migration gettingstarted/tutorial gettingstarted/examples diff --git a/doc/source/reference/credits.rst b/doc/source/reference/credits.rst index c258bc331..d0f7ee9ae 100644 --- a/doc/source/reference/credits.rst +++ b/doc/source/reference/credits.rst @@ -332,6 +332,7 @@ Tommy Waltmann * ``DiffractionPattern`` now raises an error when used with non-cubic boxes. * Implement ``StaticStructureFactorDebye`` for 2D systems. * Add support for compilation with the C++17 standard. +* Update and test the ``normalization_mode`` argument to ``freud.density.RDF`` class. Maya Martirossyan diff --git a/freud/__init__.py b/freud/__init__.py index 6cc64ef12..ee6264e39 100644 --- a/freud/__init__.py +++ b/freud/__init__.py @@ -23,7 +23,7 @@ # automatic selection runs, the user cannot change it. set_num_threads(0) -__version__ = "2.11.0" +__version__ = "2.12.0" __all__ = [ "__version__", diff --git a/freud/_density.pxd b/freud/_density.pxd index d2654f5d6..3eb0b55a1 100644 --- a/freud/_density.pxd +++ b/freud/_density.pxd @@ -49,7 +49,12 @@ cdef extern from "LocalDensity.h" namespace "freud::density": cdef extern from "RDF.h" namespace "freud::density": cdef cppclass RDF(BondHistogramCompute): - RDF(float, float, float, bool) except + + + ctypedef enum NormalizationMode "NormalizationMode": + exact "freud::density::RDF::NormalizationMode::exact" + finite_size "freud::density::RDF::NormalizationMode::finite_size" + + RDF(float, float, float, NormalizationMode) except + const freud._box.Box & getBox() const void accumulate(const freud._locality.NeighborQuery*, const vec3[float]*, diff --git a/freud/density.pyx b/freud/density.pyx index d3c58cdb5..120fbf139 100644 --- a/freud/density.pyx +++ b/freud/density.pyx @@ -576,10 +576,21 @@ cdef class RDF(_SpatialHistogram1D): behavior of :math:`\lim_{r \to \infty} g(r)=1` is recovered. However, for very small systems the long range behavior of the radial distribution will instead tend to :math:`\frac{N-1}{N}`. In small systems, where this - deviation is noticeable, the ``normalize`` flag may be used to rescale the - results and force the long range behavior to 1. Note that this option will - have little to no effect on larger systems (for example, for systems of 100 - particles the RDF will differ by 1%). + deviation is noticeable, the ``normalization_mode`` argument may be used to + rescale the results and force the long range behavior to 1. Note that this + option will have little to no effect on larger systems (for example, for + systems of 100 particles the RDF will differ by 1%). + + .. note:: + For correct normalization behavior, let the set of points be either: 1) + the same as the set of query points or 2) completely disjoint from the + set of query points (points shouldn't contain any particles in query + points). + + .. note:: + For correct normalization behavior when using + ``normalization_mode='finite_size'``, the ``points`` _must_ be the same + as the ``query_points`` and ``exclude_ii`` must be set to ``False``. .. note:: **2D:** :class:`freud.density.RDF` properly handles 2D boxes. @@ -593,27 +604,23 @@ cdef class RDF(_SpatialHistogram1D): r_min (float, optional): Minimum interparticle distance to include in the calculation (Default value = :code:`0`). - normalize (bool, optional): - Scale the RDF values by - :math:`\frac{N_{query\_points}}{N_{query\_points}-1}`. This - argument primarily exists to deal with standard RDF calculations - where no special ``query_points`` or ``neighbors`` are provided, - but where the number of ``query_points`` is small enough that the - long-ranged limit of :math:`g(r)` deviates significantly from - :math:`1`. It should not be used if :code:`query_points` is - provided as a different set of points, or if unusual query - arguments are provided to :meth:`~.compute`, specifically if - :code:`exclude_ii` is set to :code:`False`. This normalization is - not meaningful in such cases and will simply convolute the data. - + normalization_mode (str, optional): + There are two valid string inputs for this argument. The first + option, ``exact``, handles the normalization as shown mathematically + at the beginning of this class's docstring. The other option, + ``finite_size``, adds an extra rescaling factor of + :math:`\frac{N_{query\_points}}{N_{query\_ponts} - 1}` so the RDF + values will tend to 1 at large :math:`r` for small systems (Default + value = :code:`'exact'`). """ cdef freud._density.RDF * thisptr def __cinit__(self, unsigned int bins, float r_max, float r_min=0, - normalize=False): + normalization_mode='exact'): + norm_mode = self._validate_normalization_mode(normalization_mode) if type(self) == RDF: self.thisptr = self.histptr = new freud._density.RDF( - bins, r_max, r_min, normalize) + bins, r_max, r_min, norm_mode) # r_max is left as an attribute rather than a property for now # since that change needs to happen at the _SpatialHistogram level @@ -624,6 +631,15 @@ cdef class RDF(_SpatialHistogram1D): if type(self) == RDF: del self.thisptr + def _validate_normalization_mode(self, mode): + """Ensure the normalization mode is one of the approved values.""" + if mode == 'exact': + return freud._density.RDF.NormalizationMode.exact + elif mode == 'finite_size': + return freud._density.RDF.NormalizationMode.finite_size + else: + raise ValueError(f"invalid input {mode} for normalization_mode") + def compute(self, system, query_points=None, neighbors=None, reset=True): r"""Calculates the RDF and adds to the current RDF histogram. diff --git a/setup.cfg b/setup.cfg index d863d1e31..b94e92fce 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 2.11.0 +current_version = 2.12.0 commit = True tag = False message = Bump up to version {new_version}. diff --git a/setup.py b/setup.py index a58163ce0..30fa091ad 100644 --- a/setup.py +++ b/setup.py @@ -5,7 +5,7 @@ from skbuild import setup -version = "2.11.0" +version = "2.12.0" # Read README for PyPI, fallback to short description if it fails. description = "Powerful, efficient trajectory analysis in scientific Python." diff --git a/tests/test_density_RDF.py b/tests/test_density_RDF.py index f1f7bcfcc..b00e4a587 100644 --- a/tests/test_density_RDF.py +++ b/tests/test_density_RDF.py @@ -71,6 +71,19 @@ def test_invalid_rdf(self): freud.density.RDF(r_max=1, bins=10, r_min=2) with pytest.raises(ValueError): freud.density.RDF(r_max=1, bins=10, r_min=-1) + with pytest.raises(ValueError): + freud.density.RDF(r_max=1, bins=10, r_min=-1, normalization_mode="blah") + + @pytest.mark.parametrize("mode", ["exact", "finite_size"]) + def test_normalization_mode(self, mode): + """Make sure RDF can be computed with different normalization modes.""" + r_max = 10.0 + bins = 10 + num_points = 100 + box_size = r_max * 3.1 + sys = freud.data.make_random_system(box_size, num_points, is2D=True) + rdf = freud.density.RDF(r_max=r_max, bins=bins, normalization_mode=mode) + rdf.compute(sys) @pytest.mark.parametrize("r_min", [0, 0.1, 3.0]) def test_random_point(self, r_min):