plot 允许导出数据

使用统一的 hdf5 和 zpp 读写函数
This commit is contained in:
陈浩南 2023-10-09 13:40:19 +08:00
parent 2460c298c7
commit f4a20a84ea
4 changed files with 134 additions and 54 deletions

View File

@ -15,8 +15,11 @@ namespace ufo
std::vector<std::vector<Eigen::Vector3d>> Qpoints;
std::pair<unsigned, unsigned> Resolution;
std::pair<double, double> Range;
std::string Filename;
std::optional<std::vector<double>> YTicks;
std::string PictureFilename;
struct DataFileType { std::string Filename, Format; };
std::optional<std::vector<DataFileType>> DataFiles;
};
std::vector<FigureConfigType> Figures;
@ -30,8 +33,21 @@ namespace ufo
InputType(std::string config_file);
};
struct OutputType
{
std::vector<std::vector<double>> Values;
std::vector<double> XTicks;
std::vector<double> YTicks;
std::pair<unsigned, unsigned> Resolution;
std::pair<double, double> Range;
OutputType() = default;
const OutputType& write(std::string filename, std::string format) const;
using serialize = zpp::bits::members<5>;
};
protected:
InputType Input_;
std::optional<std::vector<OutputType>> Output_;
public:
PlotSolver(std::string config_file);
PlotSolver& operator()() override;
@ -56,7 +72,7 @@ namespace ufo
static void plot
(
const std::vector<std::vector<double>>& values,
const decltype(InputType::FigureConfigType::Filename)& filename,
const std::string& filename,
const std::vector<double>& x_ticks, const std::vector<double>& y_ticks
);
};

View File

@ -46,7 +46,16 @@ namespace ufo
using namespace std::literals;
struct PhonopyComplex { double r, i; };
inline HighFive::CompoundType create_compound_complex()
{ return {{"r", HighFive::AtomicType<double>{}}, {"i", HighFive::AtomicType<double>{}}}; }
{ return {{ "r", HighFive::AtomicType<double>{}}, {"i", HighFive::AtomicType<double>{}}}; }
namespace detail_
{
template <typename T> struct SpecializationOfBitsMembersHelper : std::false_type {};
template <std::size_t N> struct SpecializationOfBitsMembersHelper<zpp::bits::members<N>> : std::true_type {};
}
template <typename T> concept ZppSerializable
= requires() { detail_::SpecializationOfBitsMembersHelper<T>::value == true; };
class Solver
{
public:
@ -65,6 +74,54 @@ namespace ufo
x * range[1] * range[2] + y * range[2] + z
};
}
template <ZppSerializable T> inline static void zpp_write(const T& object, std::string filename)
{
auto [data, out] = zpp::bits::data_out();
out(object).or_throw();
static_assert(sizeof(char) == sizeof(std::byte));
std::ofstream file(filename, std::ios::binary | std::ios::out);
file.exceptions(std::ios::badbit | std::ios::failbit);
file.write(reinterpret_cast<const char*>(data.data()), data.size());
}
template <ZppSerializable T> inline static T zpp_read(std::string filename)
{
auto input = std::ifstream(filename, std::ios::binary | std::ios::in);
input.exceptions(std::ios::badbit | std::ios::failbit);
static_assert(sizeof(std::byte) == sizeof(char));
std::vector<std::byte> data;
{
std::vector<char> string(std::istreambuf_iterator<char>(input), {});
data.assign
(
reinterpret_cast<std::byte*>(string.data()),
reinterpret_cast<std::byte*>(string.data() + string.size())
);
}
auto in = zpp::bits::in(data);
T output;
in(output).or_throw();
return output;
}
class Hdf5File
{
public:
inline Hdf5File(std::string filename) : File_(filename, HighFive::File::ReadWrite
| HighFive::File::Create | HighFive::File::Truncate) {}
template <typename T> inline Hdf5File& read(T& object, std::string name)
{
object = File_.getDataSet(name).read<std::remove_cvref_t<decltype(object)>>();
return *this;
}
template <typename T> inline Hdf5File& write(const T& object, std::string name)
{
File_.createDataSet(name, HighFive::DataSpace::From(object)).write(object);
return *this;
}
protected:
HighFive::File File_;
};
};
}

View File

@ -4,22 +4,7 @@ namespace ufo
{
PlotSolver::InputType::SourceType::SourceType(std::string filename)
{
auto input = std::ifstream(filename, std::ios::binary | std::ios::in);
input.exceptions(std::ios::badbit | std::ios::failbit);
static_assert(sizeof(std::byte) == sizeof(char));
std::vector<std::byte> data;
{
std::vector<char> string(std::istreambuf_iterator<char>(input), {});
data.assign
(
reinterpret_cast<std::byte*>(string.data()),
reinterpret_cast<std::byte*>(string.data() + string.size())
);
}
auto in = zpp::bits::in(data);
UnfoldSolver::OutputType output;
in(output).or_throw();
static_cast<UnfoldSolver::OutputType&>(*this) = std::move(output);
static_cast<UnfoldSolver::OutputType&>(*this) = zpp_read<UnfoldSolver::OutputType>(filename);
}
PlotSolver::InputType::InputType(std::string config_file)
@ -45,18 +30,48 @@ namespace ufo
throw std::runtime_error("Not enough lines in a figure");
Figures.back().Resolution = figure["Resolution"].as<std::pair<unsigned, unsigned>>();
Figures.back().Range = figure["Range"].as<std::pair<double, double>>();
Figures.back().Filename = figure["Filename"].as<std::string>();
Figures.back().PictureFilename = figure["PictureFilename"].as<std::string>();
if (figure["YTicks"])
Figures.back().YTicks = figure["YTicks"].as<std::vector<double>>();
if (figure["DataFiles"])
{
Figures.back().DataFiles.emplace();
for (auto& data_file : figure["DataFiles"].as<std::vector<YAML::Node>>())
{
Figures.back().DataFiles->emplace_back
(
data_file["Filename"].as<std::string>(),
data_file["Format"].as<std::string>()
);
if (!std::set{ "hdf5"s, "zpp"s }.contains(Figures.back().DataFiles->back().Format))
throw std::runtime_error(fmt::format("Unknown data file format: {}",
Figures.back().DataFiles->back().Format));
}
}
}
SourceFilename = input["SourceFilename"].as<std::string>();
Source = SourceType(SourceFilename);
}
const PlotSolver::OutputType& PlotSolver::OutputType::write(std::string filename, std::string format) const
{
if (format == "zpp")
zpp_write(*this, filename);
else if (format == "hdf5")
{
Hdf5File(filename).write(Values, "Values")
.write(XTicks, "XTicks")
.write(YTicks, "YTicks")
.write(Resolution, "Resolution")
.write(Range, "Range");
}
return *this;
}
PlotSolver::PlotSolver(std::string config_file) : Input_(config_file) {}
PlotSolver& PlotSolver::operator()()
{
Output_.emplace();
for (auto& figure : Input_.Figures)
{
// 外层表示不同的线段的端点,内层表示这个线段上的 q 点
@ -73,11 +88,22 @@ namespace ufo
));
}
auto [values, x_ticks] = calculate_values
(Input_.PrimativeCell, lines, qpoints, figure.Resolution, figure.Range);
(
Input_.PrimativeCell, lines, qpoints, figure.Resolution, figure.Range
);
auto y_ticks = figure.YTicks.value_or(std::vector<double>{});
for (auto& _ : y_ticks)
_ = (_ - figure.Range.first) / (figure.Range.second - figure.Range.first) * figure.Resolution.second;
plot(values, figure.Filename, x_ticks, y_ticks);
plot(values, figure.PictureFilename, x_ticks, y_ticks);
Output_->emplace_back();
Output_->back().Values = std::move(values);
Output_->back().XTicks = std::move(x_ticks);
Output_->back().YTicks = std::move(y_ticks);
Output_->back().Resolution = figure.Resolution;
Output_->back().Range = figure.Range;
if (figure.DataFiles)
for (auto& data_file : *figure.DataFiles)
Output_->back().write(data_file.Filename, data_file.Format);
}
return *this;
}
@ -205,7 +231,7 @@ namespace ufo
void PlotSolver::plot
(
const std::vector<std::vector<double>>& values,
const decltype(InputType::FigureConfigType::Filename)& filename,
const std::string& filename,
const std::vector<double>& x_ticks, const std::vector<double>& y_ticks
)
{

View File

@ -133,14 +133,12 @@ namespace ufo
}
else if (QpointDataInputFile.Format == "hdf5")
{
HighFive::File file(QpointDataInputFile.FileName, HighFive::File::ReadOnly);
auto size = file.getDataSet("/frequency").getDimensions();
auto frequency = file.getDataSet("/frequency")
.read<std::vector<std::vector<std::vector<double>>>>();
auto eigenvector_vector = file.getDataSet("/eigenvector")
.read<std::vector<std::vector<std::vector<std::vector<PhonopyComplex>>>>>();
auto path = file.getDataSet("/path")
.read<std::vector<std::vector<std::vector<double>>>>();
std::vector<std::vector<std::vector<double>>> frequency, path;
std::vector<std::vector<std::vector<std::vector<PhonopyComplex>>>> eigenvector_vector;
Hdf5File(QpointDataInputFile.FileName).read(frequency, "/frequency")
.read(eigenvector_vector, "/eigenvector")
.read(path, "/path");
std::vector size = { frequency.size(), frequency[0].size(), frequency[0][0].size() };
QpointData.resize(size[0] * size[1]);
for (unsigned i = 0; i < size[0]; i++)
for (unsigned j = 0; j < size[1]; j++)
@ -233,20 +231,10 @@ namespace ufo
output.write(filename, "yaml", 3);
}
else if (format == "zpp")
{
auto [data, out] = zpp::bits::data_out();
out(*this).or_throw();
static_assert(sizeof(char) == sizeof(std::byte));
std::ofstream file(filename, std::ios::binary | std::ios::out);
file.exceptions(std::ios::badbit | std::ios::failbit);
file.write(reinterpret_cast<const char*>(data.data()), data.size());
}
zpp_write(*this, filename);
else if (format == "hdf5")
{
std::vector<std::vector<double>> Qpoint;
std::vector<std::vector<double>> Source;
std::vector<std::vector<double>> Frequency;
std::vector<std::vector<double>> Weight;
std::vector<std::vector<double>> Qpoint, Source, Frequency, Weight;
for (auto& qpoint : QpointData)
{
Qpoint.emplace_back(qpoint.Qpoint.data(), qpoint.Qpoint.data() + 3);
@ -259,17 +247,10 @@ namespace ufo
Weight.back().push_back(mode.Weight);
}
}
HighFive::File file(filename,
HighFive::File::ReadWrite | HighFive::File::Create | HighFive::File::Truncate);
file.createDataSet<double>("Qpoint",
HighFive::DataSpace::From(Qpoint)).write(Qpoint);
file.createDataSet<double>("Source",
HighFive::DataSpace::From(Source)).write(Source);
file.createDataSet<double>("Frequency",
HighFive::DataSpace::From(Frequency)).write(Frequency);
file.createDataSet<double>("Weight",
HighFive::DataSpace::From(Weight)).write(Weight);
Hdf5File(filename).write(Qpoint, "/Qpoint")
.write(Source, "/Source")
.write(Frequency, "/Frequency")
.write(Weight, "/Weight");
}
}