6#include <itertools/itertools.hpp>
24namespace triqs::experimental::lattice {
57 template <
int kdim> nda::matrix<double>
make_R_mat(
auto const &r_list) {
58 nda::matrix<double> rm(r_list.size(), kdim);
59 for (
long i = 0; i < static_cast<long>(r_list.size()); ++i)
60 for (
int d = 0; d < kdim; ++d) rm(i, d) = static_cast<double>(r_list[i][d]);
78 template <
int coeff_dim,
int kdim,
typename CoeffArr>
79 auto fourier_eval(nda::matrix_const_view<double> R_mat, CoeffArr
const &coeff_arr, std::array<double, kdim>
const &k) {
80 auto c_shape = coeff_arr.shape();
86 if constexpr (coeff_dim == 0)
88 else if constexpr (coeff_dim == 2)
89 return nda::matrix<dcomplex>::zeros(nda::stdutil::front_pop(c_shape));
91 return nda::array<dcomplex, coeff_dim>::zeros(nda::stdutil::front_pop(c_shape));
94 long nR = R_mat.shape(0);
95 for (
long idx = 0; idx < nR; ++idx) {
97 for (
int d = 0; d < kdim; ++d) kR += k[d] * R_mat(idx, d);
98 res += std::exp(2i * M_PI * kR) * coeff_arr(idx, nda::ellipsis{});
116 template <
int coeff_dim,
typename CoeffArr>
117 nda::array<dcomplex, coeff_dim + 1>
fourier_eval(nda::matrix_const_view<double> R_mat, CoeffArr
const &coeff_arr,
118 nda::array_const_view<double, 2> k_list) {
119 auto ks = nda::matrix_const_view<double>(k_list);
120 long nk = ks.shape(0);
123 nda::array<double, 2> kdotR(nk, R_mat.shape(0));
124 nda::blas::gemm(1., ks,
transpose(R_mat), 0, kdotR);
125 nda::matrix<dcomplex> phases = nda::exp(2i * M_PI * kdotR);
127 auto c_shape = coeff_arr.shape();
131 for (
int i = 1; i < coeff_dim + 1; ++i) trailing *= c_shape[i];
133 auto coeff_arr_view = nda::reshape(coeff_arr, std::array{c_shape[0], trailing});
135 auto result_shape = c_shape;
136 result_shape[0] = nk;
137 auto result = nda::array<dcomplex, coeff_dim + 1>(result_shape);
138 auto result_mat_view = nda::reshape(result, std::array{nk, trailing});
140 nda::blas::gemm(1, phases, coeff_arr_view, 0, result_mat_view);
158 template <
int coeff_dim,
int kdim,
typename CoeffArr,
typename V>
159 requires(std::ranges::contiguous_range<V>)
160 nda::array<dcomplex, coeff_dim + 1>
fourier_eval(nda::matrix_const_view<double> R_mat, CoeffArr
const &coeff_arr, V
const &k_iterator) {
161 auto kvecs = nda::matrix<double>(k_iterator.size(), kdim);
162 for (
auto [ik, k] : itertools::enumerate(k_iterator)) {
163 for (
auto idim : nda::range(kdim)) { kvecs(ik, idim) = k[idim]; }
191 std::vector<std::array<long, kdim>>
R_list;
196 void h5_write_impl(h5::group g, std::string
const &name,
char const *format)
const {
197 auto gr = g.create_group(name);
198 h5::write_hdf5_format_as_string(gr, format);
199 h5::write(gr,
"R_list",
R_list);
204 void h5_read_impl(h5::group g, std::string
const &name,
char const *exp_format) {
205 auto gr = g.open_group(name);
206 h5::assert_hdf5_format_as_string(gr, exp_format,
true);
207 h5::read(gr,
"R_list",
R_list);
231 fourier_polynomial(std::vector<std::array<
long, kdim>> R_list_, std::vector<nda::array<dcomplex, coeff_dim>> const &coeff_list_)
235 coeff_arr.resize(nda::stdutil::front_append(coeff_list_[0].shape(), coeff_list_.size()));
236 for (
long i = 0; i < static_cast<long>(coeff_list_.size()); ++i)
coeff_arr(i, nda::ellipsis{}) = coeff_list_[i];
245 fourier_polynomial(std::vector<std::array<long, kdim>> R_list_, nda::array<dcomplex, coeff_dim + 1> coeff_arr_)
261 mpi::broadcast(x.
R_list, c, root);
271 [[nodiscard]]
static std::string
hdf5_format() {
return "fourier_polynomial"; }
324 [[nodiscard]]
long n_R()
const {
return static_cast<long>(
R_list.size()); }
367 auto it = std::ranges::find(
R_list, R);
369 return std::distance(
R_list.begin(), it);
386 template <
typename... T>
387 requires((std::is_same_v<T, double> or nda::clef::is_lazy<T>) and ...)
388 auto operator()(T... ks)
const {
390 static_assert(
sizeof...(T) == kdim,
"Incorrect number of arguments");
391 constexpr auto ph_number = ((nda::clef::is_lazy<T> + ...));
394 if constexpr (ph_number == 0)
return operator()(std::array{ks...});
396 else if constexpr ((ph_number == 1) and (kdim != 1)) {
398 constexpr auto is_ph = std::array{(nda::clef::is_lazy<T> ? 1 : 0)...};
399 constexpr int ph_position = [](
auto &&v) {
400 for (
int i = 0; i < v.size(); ++i)
401 if (v[i] == 1)
return i;
405 return nda::clef::make_expr_call(partial_eval<ph_position>(ks...),
406 auto{std::get<ph_position>(std::tie(ks...))});
417 template <
int placeholder_pos>
419 requires((kdim == 3) or (kdim == 2))
422 auto [it1, it2] = std::ranges::minmax_element(
R_list, {}, [](
auto const &r) {
return r[placeholder_pos]; });
424 auto Rz_min = (*it1)[placeholder_pos];
425 auto Rz_max = (*it2)[placeholder_pos];
427 long n_new = Rz_max - Rz_min + 1;
428 auto new_Rs = std::vector<std::array<long, 1>>(n_new);
429 auto coeff_shape = nda::stdutil::front_pop(
coeff_arr.shape());
430 auto new_coeff_arr = nda::array<dcomplex, coeff_dim + 1>::zeros(nda::stdutil::front_append(coeff_shape, n_new));
432 constexpr int p1 = (placeholder_pos + 1) % kdim;
433 constexpr int p2 = (placeholder_pos + 2) % kdim;
434 auto kst = std::tie(ks...);
436 for (
long idx = 0; idx <
n_R(); ++idx) {
437 auto Rz =
R_list[idx][placeholder_pos];
438 long new_idx = Rz - Rz_min;
439 new_Rs[new_idx] = {Rz};
441 double kR = std::get<p1>(kst) *
R_list[idx][p1];
442 if constexpr (kdim == 3) kR += std::get<p2>(kst) *
R_list[idx][p2];
443 new_coeff_arr(new_idx, nda::ellipsis{}) +=
coeff_arr(idx, nda::ellipsis{}) * std::exp(2i * M_PI * kR);
446 return {std::move(new_Rs), std::move(new_coeff_arr)};
458 nda::array<dcomplex, coeff_dim + 1>
operator()(nda::array_const_view<double, 2> k_list)
const {
468 nda::array<dcomplex, coeff_dim + 1>
operator()(std::ranges::contiguous_range
auto const &k_iterator)
const {
487template <
int coeff_dim,
int kdim>
488inline constexpr bool nda::clef::supports_partial_eval_of_calls<triqs::experimental::lattice::fourier_polynomial<coeff_dim, kdim>> =
true;
const_view_type operator()() const
Make a const view of *this.
Owning container for a Fourier-series representation of a lattice function.
auto operator[](std::array< long, kdim > R) const
Access the coefficient associated with a given R-vector (const overload).
void h5_write_impl(h5::group g, std::string const &name, char const *format) const
HDF5 write helper for derived classes: writes R_list and coeff_arr under the given format tag.
nda::array< dcomplex, coeff_dim+1 > operator()(nda::array_const_view< double, 2 > k_list) const
Evaluate the Fourier polynomial at a batch of k-points given as a matrix.
auto get_coeff_arr() const
Get the packed coefficient array (const overload).
friend void mpi_broadcast(fourier_polynomial &x, mpi::communicator c={}, int root=0)
Broadcast a Fourier polynomial over an MPI communicator.
fourier_polynomial(fourier_polynomial &&) noexcept=default
Move constructor.
long get_R_idx(std::array< long, kdim > R) const
Get the storage index of a given R-vector.
auto operator[](long i)
Access the coefficient at a given storage index.
auto operator()(std::array< double, kdim > ks) const
Evaluate the Fourier polynomial at a single k-point.
nda::matrix< double > R_mat
Lattice vectors as doubles, of shape [nR, kdim], for BLAS.
nda::array< dcomplex, coeff_dim+1 > operator()(std::ranges::contiguous_range auto const &k_iterator) const
Evaluate the Fourier polynomial at a contiguous range of k-points.
auto operator[](std::array< long, kdim > R)
Access the coefficient associated with a given R-vector.
nda::array< dcomplex, coeff_dim+1 > coeff_arr
Packed Fourier coefficients, of shape [nR, coeff_shape...].
friend void h5_read(h5::group g, std::string const &name, fourier_polynomial &x)
Read a Fourier polynomial from HDF5.
fourier_polynomial(fourier_polynomial const &)=default
Copy constructor.
static std::string hdf5_format()
Get the HDF5 format tag.
long n_R() const
Get the number of R-vectors.
std::vector< std::array< long, kdim > > R_list
Lattice vectors as integer arrays.
auto const & get_R_list() const
Get the list of real-space lattice vectors.
fourier_polynomial()=default
Default constructor: construct an empty Fourier polynomial.
friend void h5_write(h5::group g, std::string const &name, fourier_polynomial const &x)
Write a Fourier polynomial to HDF5.
auto const & get_R_mat() const
Get the packed matrix of lattice vectors.
auto get_coeff_arr()
Get the packed coefficient array.
void h5_read_impl(h5::group g, std::string const &name, char const *exp_format)
HDF5 read helper for derived classes: reads R_list and coeff_arr in place; rebuilds R_mat.
auto operator[](long i) const
Access the coefficient at a given storage index (const overload).
fourier_polynomial(std::vector< std::array< long, kdim > > R_list_, nda::array< dcomplex, coeff_dim+1 > coeff_arr_)
Construct from a list of R-vectors and a packed coefficient array.
TRIQS exception hierarchy and related macros.
auto fourier_eval(nda::matrix_const_view< double > R_mat, CoeffArr const &coeff_arr, std::array< double, kdim > const &k)
Evaluate a Fourier series at a single k-point.
nda::matrix< double > make_R_mat(auto const &r_list)
Build the packed matrix of lattice vectors from a sequence of R-vectors.
gf< M, matrix_valued > transpose(gf_view< M, matrix_valued > g)
Transpose the target matrix of a matrix-valued Green's function, returning a new Green's function.
#define TRIQS_RUNTIME_ERROR
Throw a triqs::runtime_error with the current source location.
#define TRIQS_ASSERT(X)
Throw a triqs::runtime_error if the boolean expression X evaluates to false.