mirror of
https://github.com/CHN-beta/ufo.git
synced 2024-10-22 19:58:44 +08:00
plot 允许导出数据
使用统一的 hdf5 和 zpp 读写函数
This commit is contained in:
parent
2460c298c7
commit
f4a20a84ea
@ -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
|
||||
);
|
||||
};
|
||||
|
@ -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_;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
66
src/plot.cpp
66
src/plot.cpp
@ -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
|
||||
)
|
||||
{
|
||||
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user