#pragma once

#include <qlat/hmc.h>
#include <qlat/qcd-topology.h>

namespace qlat
{  //

void set_wilson_flow_z(GaugeMomentum& z, const GaugeField& gf,
                       const RealD c1 = 0.0);

void gf_wilson_flow_step_euler(GaugeField& gf, const RealD epsilon,
                               const RealD c1 = 0.0);

void gf_wilson_flow_step(GaugeField& gf, const RealD epsilon,
                         const RealD c1 = 0.0);

void gf_energy_density_dir_field(Field<RealD>& fd, const GaugeField& gf);

void gf_energy_density_field(Field<RealD>& fd, const GaugeField& gf);

RealD gf_energy_density(const GaugeField& gf);

std::vector<RealD> gf_wilson_flow(GaugeField& gf,
                                  const RealD existing_flow_time,
                                  const RealD flow_time, const Int steps,
                                  const RealD c1 = 0.0);

void set_plaq_flow_z(GaugeMomentum& z, const GaugeField& gf,
                     const Field<RealD>& plaq_factor);

void gf_block_stout_smear(GaugeField& gf, const GaugeField& gf0,
                          const Coordinate& block_site, const RealD step_size);

void gf_local_stout_smear(GaugeField& gf, const GaugeField& gf0,
                          const Coordinate& block_site, const RealD step_size);

void set_local_tree_gauge_f_dir(Field<Int>& f_dir, const Geometry& geo,
                                const Coordinate& block_site,
                                const bool is_uniform, const RngState& rs);

void gt_local_tree_gauge(GaugeTransform& gt_inv, const GaugeField& gf,
                         const Field<Int>& f_dir, const Int num_step);

}  // namespace qlat
