Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static structure factor S(q) #660

Merged
merged 106 commits into from Sep 20, 2021
Merged
Show file tree
Hide file tree
Changes from 63 commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
0f23f16
Add static structure factor calculation (direct method). Not yet vali…
bdice Sep 4, 2020
710c387
Add sinc function.
bdice Sep 29, 2020
1542860
Add C++ implementation (untested, likely not correct yet).
bdice Sep 29, 2020
38e8e6d
Add C++ implementation.
bdice Sep 29, 2020
42eb797
Use normalization as private variable.
bdice Sep 30, 2020
3ec7b9e
Use util function for integration, fix integral domain.
bdice Sep 30, 2020
d177b26
Mark Histogram methods as const.
bdice Sep 30, 2020
0ea3c91
Use typename instead of class.
bdice Sep 30, 2020
aba583f
Add C++ direct method.
bdice Oct 1, 2020
0b3b34d
Use odd number of bins for Simpson's rule integration.
bdice Oct 1, 2020
8933c43
Intermediate cleanup.
bdice Oct 2, 2020
1e7bb7d
Intermediate work on reset/reduce.
bdice Oct 2, 2020
c356caa
Fixes to BondHistogramCompute.h
bdice Oct 2, 2020
59b1ece
Remove direct method from Python code since C++ version is complete.
bdice Oct 2, 2020
fcafd18
Update docs for StaticStructureFactor.
bdice Oct 2, 2020
0ac3cea
Skip invalid tests.
bdice Oct 2, 2020
251afd2
Add pure Python implementation to tests for validation.
bdice Oct 2, 2020
281452d
Fix ball query to exclude neighbors.
bdice Oct 3, 2020
a746545
Use direct method by default.
bdice Oct 5, 2020
0ede3aa
Cleanup changes from scikit-build.
bdice Nov 6, 2020
950640d
Fix cmake formatting of diffraction module.
bdice Nov 6, 2020
37a446b
Merge remote-tracking branch 'origin/master' into feature/structure-f…
bdice May 6, 2021
c3f9102
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] May 6, 2021
645e2ba
Merge branch 'master' into feature/structure-factor
bdice May 9, 2021
5089230
updated static structure factor documentation so that formula can be …
DomFijan May 25, 2021
0eb5c59
Changed documentation so that sinc definition is easier to see with a…
DomFijan May 25, 2021
0f059ff
Merge remote-tracking branch 'origin/master' into feature/structure-f…
bdice Jul 2, 2021
e16fca1
Use NeighborList with cutoff instead of all distances to avoid potent…
bdice Jul 2, 2021
51e8011
removed unsued import, still doesn't build
DomFijan Jul 2, 2021
1a84c02
typos
DomFijan Jul 5, 2021
dbbc70e
updated documentation, added support for partial cross-term structure…
emilybwsiew Jul 6, 2021
35d6969
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jul 6, 2021
2f5bdf9
style
DomFijan Jul 15, 2021
0974a53
Merge branch 'feature/structure-factor' of https://github.com/glotzer…
DomFijan Jul 15, 2021
da8a49b
Clean up docs / C++ bits.
bdice Aug 9, 2021
f96ba01
Include i-i bonds so that S(q) converges to 1.
bdice Aug 9, 2021
1c32443
Add docs for partial structure factor.
bdice Aug 9, 2021
1f551c4
Add n_total to C++.
bdice Aug 9, 2021
c7ccecd
Add n_total to pxd.
bdice Aug 9, 2021
30a6062
Merge remote-tracking branch 'origin/master' into feature/structure-f…
bdice Aug 9, 2021
3246842
Add N_total, fix tests.
bdice Aug 9, 2021
486fea8
Add tests for StaticStructureFactorDebye limiting cases and normaliza…
bdice Aug 9, 2021
96db0ab
Initialize members.
bdice Aug 10, 2021
f9bb946
Improve C++ style.
bdice Aug 10, 2021
996e07c
Fix class name in docs.
bdice Aug 10, 2021
37e1270
Fix tests to use better pytest style.
bdice Aug 10, 2021
5cff663
Add in missing prepare call and set tolerance for symmetry test appro…
vyasr Aug 12, 2021
3300e04
Merge branch 'master' into feature/structure-factor
vyasr Aug 12, 2021
5001436
Fix partial sum test.
bdice Aug 12, 2021
538ecf3
Clean up unused variables in Debye implementation.
bdice Aug 26, 2021
3ae18b4
Fix C++ style.
bdice Aug 26, 2021
a66d165
Add xfail test for S(0).
bdice Aug 26, 2021
3b24a87
Use lowercase raw strings.
bdice Aug 26, 2021
7d489f8
Set PBC to False for box passed to compute
DomFijan Sep 1, 2021
2c87d99
updated validation function to also not include PBC so that tests pass
DomFijan Sep 1, 2021
03dd664
reversed PBC = False; changed ball query to compute all distances and…
DomFijan Sep 3, 2021
52c2ab1
updated docs
DomFijan Sep 3, 2021
01ca1dc
added const to a variable
DomFijan Sep 3, 2021
766e650
Merge remote-tracking branch 'origin/master' into feature/structure-f…
DomFijan Sep 4, 2021
f055ca8
added test for validation against ASE
DomFijan Sep 8, 2021
e4797aa
added ase to test requirements in both setup.py and requirements/
DomFijan Sep 8, 2021
9e2841d
added missing =
DomFijan Sep 8, 2021
f15a5c4
python 3.6 CI testing takes requiremntes from circleci/ci-oldest-reqs…
DomFijan Sep 8, 2021
9e1aa01
changed required ase version to 3.21.1 to resolve the conflict in num…
DomFijan Sep 8, 2021
8a962b8
changed the name of histogram from StaticStructureFactorDebyeHistogra…
DomFijan Sep 10, 2021
0b3aeba
changed some auto assignments with concrete types
DomFijan Sep 10, 2021
4c36d6d
Update cpp/diffraction/StaticStructureFactorDebye.cc
DomFijan Sep 10, 2021
52f6b6e
Merge branch 'master' into feature/structure-factor
bdice Sep 12, 2021
a70731a
got rid of deconstructor
DomFijan Sep 13, 2021
8479aa3
Revert "changed some auto assignments with concrete types"
DomFijan Sep 13, 2021
7539d98
Throw exception if k_min<0
DomFijan Sep 13, 2021
a0ac897
consistency with #837 in this vs &
DomFijan Sep 13, 2021
3ae900c
added pytest optional skip for ase
DomFijan Sep 13, 2021
022b2c2
changed ase test to use calc_pattern instead of calculating manually
DomFijan Sep 13, 2021
c9a9a2f
Changed some of const assignments
DomFijan Sep 13, 2021
08be47b
changed east const to west const
DomFijan Sep 13, 2021
ab0ecd2
update the docs
DomFijan Sep 13, 2021
c273ff7
more docs updates
DomFijan Sep 13, 2021
0c680d4
plot function now obeys min_valid_k
DomFijan Sep 14, 2021
5680bdd
add Farrow2009 citation
andkerr Sep 17, 2021
8a2a6d3
update S(k) Debye docs
andkerr Sep 17, 2021
6990e72
fixed doc math issue for minvalidk
DomFijan Sep 17, 2021
66350e6
changed docs, this looks better
DomFijan Sep 17, 2021
73cbe69
freud/diffraction.pyx
DomFijan Sep 17, 2021
f0236de
fixed querypoints docs and system docs in compute
DomFijan Sep 17, 2021
1a7e81e
missing space in docs for :class:
DomFijan Sep 17, 2021
2f56ced
clang tidy - changed for loop to be range based
DomFijan Sep 18, 2021
100c3f1
Apply clang-tidy suggestion.
bdice Sep 19, 2021
2717c13
Test oldest requirements against ase 3.16.0.
bdice Sep 19, 2021
f871c79
Improve constness, references, and variable names.
bdice Sep 19, 2021
ade41ce
Revert NeighborQuery constructor and make_ball.
bdice Sep 19, 2021
c1e2ea7
Revert changes to Histogram constness (the methods return non-referen…
bdice Sep 19, 2021
e5230c0
Remove unused Simpson's integration.
bdice Sep 19, 2021
207846a
Remove unused imports.
bdice Sep 19, 2021
05c7aa7
Improve bib style.
bdice Sep 19, 2021
b4205b5
Merge branch 'master' into feature/structure-factor
bdice Sep 19, 2021
35af69b
Apply fixes to Debye from Direct implementation branch.
bdice Sep 20, 2021
c535179
Update changelog and credits.
bdice Sep 20, 2021
f3ccf0c
Fix documentation.
bdice Sep 20, 2021
780f24b
Remove unused includes.
bdice Sep 20, 2021
48d8f72
Refactor min_valid_k.
bdice Sep 20, 2021
99dec5a
clang-format
bdice Sep 20, 2021
b3d2bc5
Update C++ docs.
bdice Sep 20, 2021
2895702
Documentation revisions.
bdice Sep 20, 2021
4ebe6b5
Pin to newest ase==3.22.0.
bdice Sep 20, 2021
bf2ed8f
Update tests_require.
bdice Sep 20, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .circleci/ci-oldest-reqs.txt
@@ -1,3 +1,4 @@
ase==3.22.0
cmake==3.6.3.post1
cython==0.29.14
garnett==0.7.1
Expand Down
2 changes: 2 additions & 0 deletions cpp/CMakeLists.txt
Expand Up @@ -8,6 +8,7 @@ endif()

add_subdirectory(cluster)
add_subdirectory(density)
add_subdirectory(diffraction)
add_subdirectory(environment)
add_subdirectory(locality)
add_subdirectory(order)
Expand All @@ -19,6 +20,7 @@ add_library(
libfreud SHARED
$<TARGET_OBJECTS:_cluster>
$<TARGET_OBJECTS:_density>
$<TARGET_OBJECTS:_diffraction>
$<TARGET_OBJECTS:_environment>
$<TARGET_OBJECTS:_locality>
$<TARGET_OBJECTS:_order>
Expand Down
5 changes: 5 additions & 0 deletions cpp/diffraction/CMakeLists.txt
@@ -0,0 +1,5 @@
add_library(_diffraction OBJECT StaticStructureFactorDebye.h
StaticStructureFactorDebye.cc)

target_include_directories(_diffraction
PUBLIC ${PROJECT_SOURCE_DIR}/cpp/density)
104 changes: 104 additions & 0 deletions cpp/diffraction/StaticStructureFactorDebye.cc
@@ -0,0 +1,104 @@
// Copyright (c) 2010-2020 The Regents of the University of Michigan
// This file is from the freud project, released under the BSD 3-Clause License.

#include <algorithm>
#include <cmath>
#include <limits>
#include <stdexcept>

#include "Box.h"
#include "ManagedArray.h"
#include "NeighborComputeFunctional.h"
#include "NeighborQuery.h"
#include "RDF.h"
#include "StaticStructureFactorDebye.h"
#include "utils.h"

/*! \file StaticStructureFactorDebye.cc
\brief Routines for computing static structure factors.
*/

namespace freud { namespace diffraction {

StaticStructureFactorDebye::StaticStructureFactorDebye(unsigned int bins, float k_max, float k_min)
{
if (bins == 0)
{
throw std::invalid_argument("StaticStructureFactorDebye requires a nonzero number of bins.");
}
if (k_max <= 0)
{
throw std::invalid_argument("StaticStructureFactorDebye requires k_max to be positive.");
}
DomFijan marked this conversation as resolved.
Show resolved Hide resolved
if (k_max <= k_min)
{
throw std::invalid_argument("StaticStructureFactorDebye requires that k_max must be greater than k_min.");
}

// Construct the Histogram object that will be used to track the structure factor
auto axes
= StaticStructureFactorDebyeHistogram::Axes {std::make_shared<util::RegularAxis>(bins, k_min, k_max)};
m_histogram = StaticStructureFactorDebyeHistogram(axes);
m_local_histograms = StaticStructureFactorDebyeHistogram::ThreadLocalHistogram(m_histogram);
m_min_valid_k = std::numeric_limits<float>::infinity();
m_structure_factor.prepare(bins);
}

void StaticStructureFactorDebye::accumulate(const freud::locality::NeighborQuery* neighbor_query,
bdice marked this conversation as resolved.
Show resolved Hide resolved
const vec3<float>* query_points, unsigned int n_query_points, unsigned int n_total)
{
auto const& box = neighbor_query->getBox();

// The r_max should be just less than half of the smallest side length of the box
auto const box_L = box.getL();
auto const min_box_length
= box.is2D() ? std::min(box_L.x, box_L.y) : std::min(box_L.x, std::min(box_L.y, box_L.z));
auto const r_max = std::nextafter(float(0.5) * min_box_length, float(0));
auto const points= neighbor_query->getPoints();
auto const n_points= neighbor_query->getNPoints();

// The minimum k value of validity is 4 * pi / L, where L is the smallest side length.
// This is equal to 2 * pi / r_max.
m_min_valid_k = std::min(m_min_valid_k, freud::constants::TWO_PI / r_max);

auto distances = std::vector<float>(n_points * n_query_points);
DomFijan marked this conversation as resolved.
Show resolved Hide resolved
box.computeAllDistances(points, n_points, query_points, n_query_points, distances.data());

auto const k_bin_centers = m_histogram.getBinCenters()[0];

util::forLoopWrapper(0, m_histogram.getAxisSizes()[0], [&](size_t begin_k_index, size_t end_k_index) {
for (size_t k_index = begin_k_index; k_index < end_k_index; ++k_index)
{
auto const k = k_bin_centers[k_index];
double S_k = 0.0;
bdice marked this conversation as resolved.
Show resolved Hide resolved
for (size_t distance_index = 0; distance_index < distances.size(); ++distance_index)
{
auto const distance = distances[distance_index];
S_k += util::sinc(k * distance);
}
S_k /= static_cast<double>(n_total);
m_local_histograms.increment(k_index, S_k);
};
});
m_frame_counter++;
m_reduce = true;
}
DomFijan marked this conversation as resolved.
Show resolved Hide resolved

void StaticStructureFactorDebye::reduce()
{
m_structure_factor.prepare(m_histogram.shape());
m_local_histograms.reduceInto(m_structure_factor);

// Normalize by the frame count if necessary
if (m_frame_counter > 1)
{
util::forLoopWrapper(0, m_structure_factor.size(), [this](size_t begin, size_t end) {
DomFijan marked this conversation as resolved.
Show resolved Hide resolved
for (size_t i = begin; i < end; ++i)
{
m_structure_factor[i] /= static_cast<float>(m_frame_counter);
}
});
}
}

}; }; // namespace freud::diffraction
94 changes: 94 additions & 0 deletions cpp/diffraction/StaticStructureFactorDebye.h
@@ -0,0 +1,94 @@
// Copyright (c) 2010-2020 The Regents of the University of Michigan
// This file is from the freud project, released under the BSD 3-Clause License.

#ifndef STATIC_STRUCTURE_FACTOR_DEBYE_H
#define STATIC_STRUCTURE_FACTOR_DEBYE_H

#include "Box.h"
#include "Histogram.h"
#include "NeighborQuery.h"

/*! \file StaticStructureFactorDebye.h
\brief Routines for computing static structure factors.

Computes structure factors from the Fourier transform of a radial distribution function (RDF).
This method is not capable of resolving k-vectors smaller than the magnitude 4 * pi / L, where L is the
smallest side length of the system's periodic box.
*/

namespace freud { namespace diffraction {

class StaticStructureFactorDebye
{
using StaticStructureFactorDebyeHistogram = util::Histogram<float>;
tommy-waltmann marked this conversation as resolved.
Show resolved Hide resolved

public:
//! Constructor
StaticStructureFactorDebye(unsigned int bins, float k_max, float k_min = 0);

//! Destructor
virtual ~StaticStructureFactorDebye() = default;
DomFijan marked this conversation as resolved.
Show resolved Hide resolved

//! Compute the structure factor S(k) using the Debye formula
void accumulate(const freud::locality::NeighborQuery* neighbor_query, const vec3<float>* query_points,
unsigned int n_query_points, unsigned int n_total);

//! Reduce thread-local arrays onto the primary data arrays.
void reduce();

//! Return thing_to_return after reducing if necessary.
template<typename U> U& reduceAndReturn(U& thing_to_return)
{
if (m_reduce)
{
reduce();
}
m_reduce = false;
return thing_to_return;
}

//! Reset the histogram to all zeros
void reset()
{
m_local_histograms.reset();
m_frame_counter = 0;
m_reduce = true;
}

//! Get the structure factor
const util::ManagedArray<float>& getStructureFactor()
{
return reduceAndReturn(m_structure_factor);
}

//! Get the k bin edges
std::vector<float> getBinEdges() const
{
return m_histogram.getBinEdges()[0];
}

//! Get the k bin centers
std::vector<float> getBinCenters() const
{
return m_histogram.getBinCenters()[0];
}

//! Get the minimum valid k value
float getMinValidK() const
{
return m_min_valid_k;
}

private:
StaticStructureFactorDebyeHistogram m_histogram; //!< Histogram to hold computed structure factor
StaticStructureFactorDebyeHistogram::ThreadLocalHistogram
m_local_histograms; //!< Thread local histograms for TBB parallelism
util::ManagedArray<float> m_structure_factor; //!< The computed structure factor
unsigned int m_frame_counter {0}; //!< Number of frames calculated
float m_min_valid_k {0}; //!< The minimum valid k-value based on the computed box
bool m_reduce {true}; //!< Whether to reduce
};

}; }; // namespace freud::diffraction

#endif // STATIC_STRUCTURE_FACTOR_DEBYE_H
14 changes: 14 additions & 0 deletions cpp/locality/NeighborQuery.h
Expand Up @@ -51,6 +51,20 @@ struct QueryArgs
{
QueryArgs() = default;

//! Constructor
QueryArgs(QueryType mode, unsigned int num_neighbors, float r_max, float r_min, float r_guess,
float scale, bool exclude_ii)
: mode(mode), num_neighbors(num_neighbors), r_max(r_max), r_min(r_min), r_guess(r_guess),
scale(scale), exclude_ii(exclude_ii)
{}

//! Ball query factory
static QueryArgs make_ball(float r_max, float r_min = 0, bool exclude_ii = DEFAULT_EXCLUDE_II)
{
return QueryArgs(QueryType::ball, DEFAULT_NUM_NEIGHBORS, r_max, r_min, DEFAULT_R_GUESS, DEFAULT_SCALE,
exclude_ii);
}

bdice marked this conversation as resolved.
Show resolved Hide resolved
QueryType mode {DEFAULT_MODE}; //! Whether to perform a ball or k-nearest neighbor query.
unsigned int num_neighbors {DEFAULT_NUM_NEIGHBORS}; //! The number of nearest neighbors to find.
float r_max {DEFAULT_R_MAX}; //! The cutoff distance within which to find neighbors.
Expand Down
23 changes: 12 additions & 11 deletions cpp/util/Histogram.h
Expand Up @@ -72,13 +72,13 @@ class Axis
virtual size_t bin(const float& value) const = 0;

//! Return the boundaries of bins.
std::vector<float> getBinEdges() const
const std::vector<float> getBinEdges() const
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment goes for every new const return type declaration in this file: Either return the std::vector and allow a copy to be made or return by const std::vector<>&

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would there be any preference in one over the other in this case?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The decision would have to be made on a case-by-case basis. Anytime you are returning a local variable you should return by std::vector<>, most other cases it would probably be better to return by const std::vector<>&. If you want more advice with this we should talk in person.

Copy link
Member Author

@bdice bdice Sep 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The difference has to do with ownership and mutability. If the object is returning one of its members, it can return by constant reference (const std::vector<T>&) to avoid returning a new copy of the data, while also ensuring that the returned reference is immutable (constant) so that the calling code cannot mutate this object's internal state. If the vector being returned is not a member (for example, if it is allocated and filled by the function being called) then you must return std::vector<T> -- note that this cannot be constant because it is a returning by copy (or move if the copy is elided), and it cannot be a reference because the data's lifetime is limited to the function body and the reference would be invalid.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading this again, I am not sure what encouraged me to change this file at all. I think I was trying to fix warnings from VSCode but I'm not sure if this change actually does anything. Maybe let's just revert the changes in this file, or perhaps only make changes that return class members by constant reference (where applicable) and revert the rest.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried to do the latter suggestion from @bdice last comment. Let me know if I was successful.

{
return m_bin_edges;
}

//! Return the centers of bins.
std::vector<float> getBinCenters() const
const std::vector<float> getBinCenters() const
{
std::vector<float> bin_centers(m_nbins);
for (size_t i = 0; i < m_nbins; i++)
Expand Down Expand Up @@ -369,7 +369,7 @@ template<typename T> class Histogram
}

//! Get the shape of the computed histogram.
std::vector<size_t> shape() const
const std::vector<size_t> shape() const
{
return m_bin_counts.shape();
}
Expand All @@ -383,7 +383,7 @@ template<typename T> class Histogram
//! Return the edges of bins.
/*! This vector will be of size axis.size()+1 for each axis.
*/
std::vector<std::vector<float>> getBinEdges() const
const std::vector<std::vector<float>> getBinEdges() const
{
std::vector<std::vector<float>> bins(m_axes.size());
for (unsigned int i = 0; i < m_axes.size(); ++i)
Expand All @@ -396,7 +396,7 @@ template<typename T> class Histogram
//! Return the bin centers.
/*! This vector will be of size axis.size() for each axis.
*/
std::vector<std::vector<float>> getBinCenters() const
const std::vector<std::vector<float>> getBinCenters() const
{
std::vector<std::vector<float>> bins(m_axes.size());
for (unsigned int i = 0; i < m_axes.size(); ++i)
Expand All @@ -407,7 +407,7 @@ template<typename T> class Histogram
}

//! Return a vector of tuples (min, max) indicating the bounds of each axis.
std::vector<std::pair<float, float>> getBounds() const
const std::vector<std::pair<float, float>> getBounds() const
{
std::vector<std::pair<float, float>> bounds(m_axes.size());
for (unsigned int i = 0; i < m_axes.size(); ++i)
Expand All @@ -418,7 +418,7 @@ template<typename T> class Histogram
}

//! Return a vector indicating the number of bins in each axis.
std::vector<size_t> getAxisSizes() const
const std::vector<size_t> getAxisSizes() const
{
std::vector<size_t> sizes(m_axes.size());
for (unsigned int i = 0; i < m_axes.size(); ++i)
Expand Down Expand Up @@ -489,7 +489,7 @@ template<typename T> class Histogram
* variadic templating to accept an arbitrary set of float values and
* construct a vector out of them.
*/
std::pair<std::vector<float>, Weight<T>> getValueVector(float value) const
const std::pair<std::vector<float>, Weight<T>> getValueVector(float value) const
{
return {{value}, Weight<T>()};
}
Expand All @@ -499,14 +499,14 @@ template<typename T> class Histogram
* variadic templating to accept an arbitrary set of float values and
* construct a vector out of them.
*/
std::pair<std::vector<float>, Weight<T>> getValueVector(Weight<T> weight) const
const std::pair<std::vector<float>, Weight<T>> getValueVector(Weight<T> weight) const
{
return {{}, weight};
}

//! The recursive case for constructing a vector of values (see base-case function docs).
template<typename... FloatsOrWeight>
std::pair<std::vector<float>, Weight<T>> getValueVector(float value, FloatsOrWeight... values) const
const std::pair<std::vector<float>, Weight<T>> getValueVector(float value, FloatsOrWeight... values) const
{
std::pair<std::vector<float>, Weight<T>> tmp = getValueVector(values...);
tmp.first.insert(tmp.first.begin(), value);
Expand All @@ -515,7 +515,8 @@ template<typename T> class Histogram

//! The recursive case for constructing a vector of values (see base-case function docs).
template<typename... FloatsOrWeight>
std::pair<std::vector<float>, Weight<T>> getValueVector(Weight<T> weight, FloatsOrWeight... values) const
const std::pair<std::vector<float>, Weight<T>> getValueVector(Weight<T> weight,
FloatsOrWeight... values) const
{
std::pair<std::vector<float>, Weight<T>> tmp = getValueVector(values...);
tmp.second = weight;
Expand Down