Integrate Refactor solver sources and dual MSVC CMake builds

This commit is contained in:
KOKO\Mimi
2026-10-18 02:10:51 +09:00
parent 7ee32e5837
commit 12d51480de
218 changed files with 17842 additions and 9689 deletions
@@ -12,7 +12,6 @@
#include "fesa/analysis/analysis_model.h"
#include "fesa/build_info.h"
#include "fesa/core/diagnostic.h"
#include "fesa/elements/finite_rotation.h"
#include "fesa/fem/dof_manager.h"
#include "io/hdf5/hdf5_atomic_file.h"
#include "io/hdf5/hdf5_model_writer.h"
@@ -24,6 +23,10 @@ namespace {
using hdf5_internal::Hdf5Failure;
using hdf5_internal::Hdf5Handle;
using hdf5_internal::CopyVectorValues;
using hdf5_internal::FlattenNodalTriads;
using hdf5_internal::FlattenNodalDirectors;
using hdf5_internal::SpatialReactionValues;
struct AcceptedFrameRow {
std::uint64_t frame_index;
@@ -228,11 +231,6 @@ Status Failure(const char* code, const std::string& message) {
return hdf5_internal::OutputFailure(code, message);
}
/// @brief Copies one nonempty full-space vector in node-major order.
std::vector<double> Values(const Vector& values) {
return std::vector<double>{values.Data(), values.Data() + values.Size()};
}
/// @brief Removes inherited metadata before applying the dynamic schema.
void DeleteAttribute(const hid_t object, const char* name) {
if (H5Aexists(object, name) > 0) {
@@ -401,26 +399,6 @@ void ProcessDataset(const hid_t file, const std::string& path,
}
}
/// @brief Flattens nodal triad axes in A,B,D row order.
std::vector<double> FlattenTriad(const DynamicAcceptedFrameState& frame) {
std::vector<double> values;
values.reserve(frame.nodal_triad.size() * 9U);
for (const auto& triad : frame.nodal_triad) {
for (const auto& axis : triad)
values.insert(values.end(), axis.begin(), axis.end());
}
return values;
}
/// @brief Flattens nodal directors in stable node order.
std::vector<double> FlattenDirector(const DynamicAcceptedFrameState& frame) {
std::vector<double> values;
values.reserve(frame.nodal_director.size() * 3U);
for (const auto& director : frame.nodal_director)
values.insert(values.end(), director.begin(), director.end());
return values;
}
/// @brief Flattens physical recovery in element and Gauss order.
std::vector<double> FlattenShell(const DynamicAcceptedFrameState& frame,
const int quantity) {
@@ -442,27 +420,6 @@ std::vector<double> FlattenShell(const DynamicAcceptedFrameState& frame,
return values;
}
/// @brief Maps generalized support moments to work-conjugate spatial moments.
std::vector<double> SpatialReaction(const DynamicAcceptedFrameState& frame) {
std::vector<double> values = Values(frame.reaction);
for (std::size_t node = 0U; node < frame.nodal_internal_order.size();
++node) {
const std::size_t offset = node * 6U;
const Vector3 phi{frame.generalized_coordinates[offset + 3U],
frame.generalized_coordinates[offset + 4U],
frame.generalized_coordinates[offset + 5U]};
const Matrix transform = InverseTransposeLeftJacobianSO3(phi);
for (std::size_t row = 0U; row < 3U; ++row) {
values[offset + 3U + row] = 0.0;
for (std::size_t column = 0U; column < 3U; ++column) {
values[offset + 3U + row] +=
transform(row, column) * frame.reaction[offset + 3U + column];
}
}
}
return values;
}
/// @brief Writes or reads back all mandatory accepted-endpoint quantities.
void WriteFrame(const hid_t file, const Domain& domain,
const DynamicAcceptedFrameState& frame,
@@ -491,52 +448,55 @@ void WriteFrame(const hid_t file, const Domain& domain,
"force,force,force,force*length,force*length,force*length";
const std::vector<hsize_t> nodal{nodes, 6U};
WriteDataset(file, root + "/nodal/displacement", nodal,
Values(frame.generalized_coordinates), "UX,UY,UZ,URX,URY,URZ",
CopyVectorValues(frame.generalized_coordinates), "UX,UY,UZ,URX,URY,URZ",
"length,length,length,1,1,1", "global-cartesian", "nodal",
frame);
WriteDataset(file, root + "/nodal/velocity", nodal, Values(frame.velocity),
WriteDataset(file, root + "/nodal/velocity", nodal, CopyVectorValues(frame.velocity),
"V1,V2,V3,PHIDOT1,PHIDOT2,PHIDOT3",
"length/time,length/time,length/time,1/time,1/time,1/time",
"fixed-initial-global-chart", "nodal", frame);
WriteDataset(
file, root + "/nodal/acceleration", nodal, Values(frame.acceleration),
file, root + "/nodal/acceleration", nodal, CopyVectorValues(frame.acceleration),
"A1,A2,A3,PHIDDOT1,PHIDDOT2,PHIDDOT3",
"length/time^2,length/time^2,length/time^2,1/time^2,1/time^2,1/time^2",
"fixed-initial-global-chart", "nodal", frame);
WriteDataset(
file, root + "/nodal/algorithmic_acceleration", nodal,
Values(frame.algorithmic_acceleration), "AUX1,AUX2,AUX3,AUX4,AUX5,AUX6",
CopyVectorValues(frame.algorithmic_acceleration), "AUX1,AUX2,AUX3,AUX4,AUX5,AUX6",
"length/time^2,length/time^2,length/time^2,1/time^2,1/time^2,1/time^2",
"fixed-initial-global-chart", "nodal", frame);
WriteDataset(file, root + "/nodal/angular_velocity", {nodes, 3U},
Values(frame.angular_velocity), "OMEGA1,OMEGA2,OMEGA3",
CopyVectorValues(frame.angular_velocity), "OMEGA1,OMEGA2,OMEGA3",
"1/time,1/time,1/time", "global-cartesian", "nodal", frame);
WriteDataset(file, root + "/nodal/angular_acceleration", {nodes, 3U},
Values(frame.angular_acceleration),
CopyVectorValues(frame.angular_acceleration),
"OMEGADOT1,OMEGADOT2,OMEGADOT3", "1/time^2,1/time^2,1/time^2",
"global-cartesian", "nodal", frame);
WriteDataset(file, root + "/nodal/triad", {nodes, 3U, 3U},
FlattenTriad(frame), "X,Y,Z", "1,1,1", "global-cartesian",
FlattenNodalTriads(frame.nodal_triad), "X,Y,Z", "1,1,1", "global-cartesian",
"nodal", frame);
WriteDataset(file, root + "/nodal/director", {nodes, 3U},
FlattenDirector(frame), "D1,D2,D3", "1,1,1", "global-cartesian",
FlattenNodalDirectors(frame.nodal_director), "D1,D2,D3", "1,1,1", "global-cartesian",
"nodal", frame);
WriteDataset(file, root + "/nodal/generalized_inertia_force", nodal,
Values(frame.inertia_force), kGeneralized, kGeneralizedUnits,
CopyVectorValues(frame.inertia_force), kGeneralized, kGeneralizedUnits,
"fixed-initial-global-chart", "nodal", frame);
WriteDataset(file, root + "/nodal/generalized_internal_force", nodal,
Values(frame.internal_force), kGeneralized, kGeneralizedUnits,
CopyVectorValues(frame.internal_force), kGeneralized, kGeneralizedUnits,
"fixed-initial-global-chart", "nodal", frame);
WriteDataset(file, root + "/nodal/generalized_external_force", nodal,
Values(frame.external_force), kGeneralized, kGeneralizedUnits,
CopyVectorValues(frame.external_force), kGeneralized, kGeneralizedUnits,
"fixed-initial-global-chart", "nodal", frame);
WriteDataset(file, root + "/nodal/generalized_residual", nodal,
Values(frame.residual), kGeneralized, kGeneralizedUnits,
CopyVectorValues(frame.residual), kGeneralized, kGeneralizedUnits,
"fixed-initial-global-chart", "nodal", frame);
WriteDataset(file, root + "/nodal/generalized_reaction", nodal,
Values(frame.reaction), kGeneralized, kGeneralizedUnits,
CopyVectorValues(frame.reaction), kGeneralized, kGeneralizedUnits,
"fixed-initial-global-chart", "nodal", frame);
WriteDataset(file, root + "/nodal/reaction", nodal, SpatialReaction(frame),
WriteDataset(file, root + "/nodal/reaction", nodal,
SpatialReactionValues(frame.generalized_coordinates,
frame.reaction,
frame.nodal_internal_order.size()),
"RF1,RF2,RF3,RM1,RM2,RM3", kGeneralizedUnits, "global-cartesian",
"nodal", frame);
const std::string shell = root + "/element/shell/";
@@ -810,13 +770,7 @@ void CheckModel(const hid_t file, const Domain& domain,
model.prescribed_displacement);
std::vector<double> directors;
std::vector<double> frames;
for (const auto& frame : domain.ShellNodeInitialFrames()) {
directors.insert(directors.end(), frame.director.begin(),
frame.director.end());
frames.insert(frames.end(), frame.tangent_a.begin(), frame.tangent_a.end());
frames.insert(frames.end(), frame.tangent_b.begin(), frame.tangent_b.end());
frames.insert(frames.end(), frame.director.begin(), frame.director.end());
}
hdf5_internal::AppendShellReferenceFrames(domain, directors, frames);
(void)CheckDoubles(file, "/model/shell/nodal_director", {count, 3U},
directors);
(void)CheckDoubles(file, "/model/shell/nodal_frame", {count, 3U, 3U}, frames);
+5 -23
View File
@@ -20,23 +20,16 @@
#include "io/hdf5/hdf5_model_writer.h"
#include "io/hdf5/hdf5_primitives.h"
#include "io/hdf5/hdf5_raii.h"
#include "math/finite_values.h"
namespace fesa {
namespace {
constexpr const char* kEigenRoot = "/steps/Step-1/eigen";
using math_internal::IsFinite;
void WriteQuantityAttributes(hid_t dataset, const std::string& components,
const std::string& units,
const std::string& coordinates,
const std::string& location) {
hdf5_internal::WriteStringAttribute(dataset, "component_names", components);
hdf5_internal::WriteStringAttribute(dataset, "component_unit_dimensions",
units);
hdf5_internal::WriteStringAttribute(dataset, "coordinate_system",
coordinates);
hdf5_internal::WriteStringAttribute(dataset, "location", location);
}
using hdf5_internal::WriteQuantityAttributes;
constexpr const char* kEigenRoot = "/steps/Step-1/eigen";
void WriteModalAttributes(hid_t dataset, const std::string& source_step) {
hdf5_internal::WriteUint64Attribute(dataset, "eigen_schema_version", 1U);
@@ -44,17 +37,6 @@ void WriteModalAttributes(hid_t dataset, const std::string& source_step) {
hdf5_internal::WriteStringAttribute(dataset, "domain", "mode");
}
bool IsFinite(const Matrix& matrix) {
for (std::size_t row = 0U; row < matrix.Rows(); ++row) {
for (std::size_t column = 0U; column < matrix.Columns(); ++column) {
if (!std::isfinite(matrix(row, column))) {
return false;
}
}
}
return true;
}
Status Validate(const Domain& domain, const EigenAnalysisState& state,
const std::vector<Diagnostic>& diagnostics) {
const FrequencyStepDefinition* frequency = domain.Frequency();
+1 -7
View File
@@ -489,13 +489,7 @@ bool CheckModelRows(hid_t file, const Domain& domain) {
[&](auto i) { return domain.ShellSections()[i].thickness; }))
return false;
std::vector<double> directors, frames;
for (const auto& frame : domain.ShellNodeInitialFrames()) {
directors.insert(directors.end(), frame.director.begin(),
frame.director.end());
frames.insert(frames.end(), frame.tangent_a.begin(), frame.tangent_a.end());
frames.insert(frames.end(), frame.tangent_b.begin(), frame.tangent_b.end());
frames.insert(frames.end(), frame.director.begin(), frame.director.end());
}
hdf5_internal::AppendShellReferenceFrames(domain, directors, frames);
return CheckArray<double>(file, "/model/shell/nodal_director", H5T_IEEE_F64LE,
H5T_NATIVE_DOUBLE,
{static_cast<hsize_t>(domain.Nodes().size()), 3U},
+1 -7
View File
@@ -419,13 +419,7 @@ void WriteShellModelData(const hid_t file, const Domain& domain,
directors.reserve(domain.Nodes().size() * 3U);
std::vector<double> frames;
frames.reserve(domain.Nodes().size() * 9U);
for (const auto& frame : domain.ShellNodeInitialFrames()) {
directors.insert(directors.end(), frame.director.begin(),
frame.director.end());
frames.insert(frames.end(), frame.tangent_a.begin(), frame.tangent_a.end());
frames.insert(frames.end(), frame.tangent_b.begin(), frame.tangent_b.end());
frames.insert(frames.end(), frame.director.begin(), frame.director.end());
}
hdf5_internal::AppendShellReferenceFrames(domain, directors, frames);
WriteModelDoubleDataset(file, "/model/shell/nodal_director",
{static_cast<hsize_t>(domain.Nodes().size()), 3U},
directors.data(), directors.size(), "D1,D2,D3",
+79 -10
View File
@@ -5,9 +5,13 @@
#include <cstdint>
#include <filesystem>
#include <limits>
#include <stdexcept>
#include <string>
#include <vector>
#include "fesa/elements/finite_rotation.h"
#include "fesa/math/vector3.h"
namespace fesa::hdf5_internal {
Status OutputFailure(const std::string& code, const std::string& message) {
@@ -60,10 +64,20 @@ bool IsValidUtf8(const std::string& value) {
return true;
}
bool SameIdentity(const SourceEntityId& left, const SourceEntityId& right) {
return left.instance_name == right.instance_name &&
left.source_label == right.source_label &&
left.source_label_text == right.source_label_text;
bool SameIdentity(const SourceEntityId& left,
const SourceEntityId& right) {
return fesa::SourceIdentityEquals(left, right);
}
void AppendShellReferenceFrames(const Domain& domain,
std::vector<double>& directors,
std::vector<double>& frames) {
for (const auto& frame : domain.ShellNodeInitialFrames()) {
directors.insert(directors.end(), frame.director.begin(), frame.director.end());
frames.insert(frames.end(), frame.tangent_a.begin(), frame.tangent_a.end());
frames.insert(frames.end(), frame.tangent_b.begin(), frame.tangent_b.end());
frames.insert(frames.end(), frame.director.begin(), frame.director.end());
}
}
bool IsShellDomain(const Domain& domain) noexcept {
@@ -95,6 +109,55 @@ std::string SourceInputIdentity(const Domain& domain) {
";content_identity=" + domain.SourceContentIdentity();
}
std::vector<double> CopyVectorValues(const Vector& source) {
std::vector<double> values(source.Size());
for (std::size_t index = 0U; index < source.Size(); ++index) {
values[index] = source[index];
}
return values;
}
std::vector<double> FlattenNodalTriads(
const std::vector<std::array<std::array<double, 3>, 3>>& triads) {
std::vector<double> values;
values.reserve(triads.size() * 9U);
for (const auto& triad : triads) {
for (const auto& axis : triad) {
values.insert(values.end(), axis.begin(), axis.end());
}
}
return values;
}
std::vector<double> FlattenNodalDirectors(
const std::vector<std::array<double, 3>>& directors) {
std::vector<double> values;
values.reserve(directors.size() * 3U);
for (const auto& director : directors) {
values.insert(values.end(), director.begin(), director.end());
}
return values;
}
std::vector<double> SpatialReactionValues(const Vector& rotation,
const Vector& reaction,
const std::size_t node_count) {
std::vector<double> values = CopyVectorValues(reaction);
for (std::size_t node = 0U; node < node_count; ++node) {
const std::size_t offset = kDofsPerNode * node;
const Vector3 phi{rotation[offset + 3U], rotation[offset + 4U],
rotation[offset + 5U]};
const Vector3 generalized{reaction[offset + 3U], reaction[offset + 4U],
reaction[offset + 5U]};
const auto moment = SpatialMomentSO3(phi, generalized);
if (!moment.HasValue())
throw std::runtime_error{"Spatial reaction moment is nonfinite."};
for (std::size_t row = 0U; row < 3U; ++row)
values[offset + 3U + row] = moment.Value()[row];
}
return values;
}
Hdf5Handle MakeUtf8StringType() {
Hdf5Handle type{
RequireHdf5Id(H5Tcopy(H5T_C_S1), "Unable to copy an HDF5 string type."),
@@ -186,7 +249,7 @@ Hdf5Handle CreateDatasetSpace(const std::vector<hsize_t>& dimensions) {
H5Sclose};
}
void WriteResultAttributes(const hid_t dataset,
void WriteQuantityAttributes(const hid_t dataset,
const std::string& component_names,
const std::string& component_units,
const std::string& coordinate_system,
@@ -195,6 +258,15 @@ void WriteResultAttributes(const hid_t dataset,
WriteStringAttribute(dataset, "component_unit_dimensions", component_units);
WriteStringAttribute(dataset, "coordinate_system", coordinate_system);
WriteStringAttribute(dataset, "location", location);
}
void WriteResultAttributes(const hid_t dataset,
const std::string& component_names,
const std::string& component_units,
const std::string& coordinate_system,
const std::string& location) {
WriteQuantityAttributes(dataset, component_names, component_units,
coordinate_system, location);
WriteStringAttribute(dataset, "step_name", kStepName);
WriteUint64Attribute(dataset, "frame_index", 0U);
}
@@ -238,11 +310,8 @@ void WriteModelDoubleDataset(const hid_t file, const std::string& path,
const std::string& coordinate_system,
const std::string& location) {
auto dataset = WriteDoubleValues(file, path, dimensions, values, value_count);
WriteStringAttribute(dataset.Get(), "component_names", component_names);
WriteStringAttribute(dataset.Get(), "component_unit_dimensions",
component_units);
WriteStringAttribute(dataset.Get(), "coordinate_system", coordinate_system);
WriteStringAttribute(dataset.Get(), "location", location);
WriteQuantityAttributes(dataset.Get(), component_names, component_units,
coordinate_system, location);
}
void WriteUint8Dataset(const hid_t file, const std::string& path,
+33 -10
View File
@@ -13,11 +13,15 @@
#include "fesa/core/source_identity.h"
#include "fesa/core/status.h"
#include "fesa/math/vector.h"
#include "fesa/model/domain.h"
#include "io/hdf5/hdf5_raii.h"
#include "math/finite_values.h"
namespace fesa::hdf5_internal {
using math_internal::IsFinite;
inline constexpr std::size_t kDofsPerNode = 6U;
inline constexpr std::size_t kEndpointCount = 2U;
inline constexpr std::size_t kGaussPointCount = 2U;
@@ -64,16 +68,11 @@ Status OutputFailure(const std::string& code, const std::string& message);
/// @brief Tests exact preserved source identity.
bool SameIdentity(const SourceEntityId& left, const SourceEntityId& right);
/// @brief Tests a fixed component record for finite values.
template <std::size_t Size>
bool IsFinite(const std::array<double, Size>& values) {
for (const double value : values) {
if (!std::isfinite(value)) {
return false;
}
}
return true;
}
/// @brief Appends source-ordered reference directors and a,b,d frame columns.
/// @note Callers retain allocation, schema, write/readback and failure ownership.
void AppendShellReferenceFrames(const Domain& domain,
std::vector<double>& directors,
std::vector<double>& frames);
/// @brief Validates UTF-8 without accepting overlong or surrogate encodings.
bool IsValidUtf8(const std::string& value);
@@ -93,6 +92,25 @@ std::string NormalizedPathString(const std::filesystem::path& path);
/// @brief Returns schema-v0 source path and content identity metadata.
std::string SourceInputIdentity(const Domain& domain);
/// @brief Copies validated vector values in their existing component order.
std::vector<double> CopyVectorValues(const Vector& source);
/// @brief Flattens global nodal A,B,D axes in stable node/axis/component order.
std::vector<double> FlattenNodalTriads(
const std::vector<std::array<std::array<double, 3>, 3>>& triads);
/// @brief Flattens global nodal directors in stable node/component order.
std::vector<double> FlattenNodalDirectors(
const std::vector<std::array<double, 3>>& directors);
/// @brief Preserves force rows and maps generalized moments to spatial moments.
/// @pre Both six-DOF vectors and node_count were validated by the typed writer.
/// @note Rotation entries are at offsets 3..5; conversion uses J^T m = q.
/// @throws std::runtime_error when the existing spatial-moment solve fails.
std::vector<double> SpatialReactionValues(const Vector& rotation,
const Vector& reaction,
std::size_t node_count);
Hdf5Handle MakeUtf8StringType();
void WriteStringAttribute(hid_t object, const char* name,
const std::string& value);
@@ -101,6 +119,11 @@ void WriteUint8Attribute(hid_t object, const char* name, std::uint8_t value);
void WriteDoubleAttribute(hid_t object, const char* name, double value);
Hdf5Handle CreateGroup(hid_t file, const char* path);
Hdf5Handle CreateDatasetSpace(const std::vector<hsize_t>& dimensions);
/// @brief Writes quantity identity attributes, without family/frame metadata.
void WriteQuantityAttributes(hid_t dataset, const std::string& component_names,
const std::string& component_units,
const std::string& coordinate_system,
const std::string& location);
void WriteResultAttributes(hid_t dataset, const std::string& component_names,
const std::string& component_units,
const std::string& coordinate_system,
+2 -10
View File
@@ -756,27 +756,19 @@ void WriteResultDatasets(const hid_t file, const Domain& domain,
WriteStress(file, state);
}
std::vector<double> CopyVector(const Vector& source) {
std::vector<double> values(source.Size());
for (std::size_t index = 0U; index < source.Size(); ++index) {
values[index] = source[index];
}
return values;
}
std::vector<DoubleDatasetPlan> BuildResultDatasetPlans(
const Domain& domain, const AnalysisState& state) {
std::vector<DoubleDatasetPlan> datasets;
const std::vector<std::size_t> nodal_dimensions{domain.Nodes().size(),
kDofsPerNode};
datasets.push_back({std::string{kStepRoot} + "/nodal/displacement",
nodal_dimensions, CopyVector(state.Displacement()),
nodal_dimensions, CopyVectorValues(state.Displacement()),
"UX,UY,UZ,URX,URY,URZ",
"length,length,length,radian,radian,radian",
"global-cartesian", "nodal"});
datasets.push_back(
{std::string{kStepRoot} + "/nodal/reaction", nodal_dimensions,
CopyVector(state.Reaction()), "RF1,RF2,RF3,RM1,RM2,RM3",
CopyVectorValues(state.Reaction()), "RF1,RF2,RF3,RM1,RM2,RM3",
"force,force,force,force*length,force*length,force*length",
"global-cartesian", "nodal"});
if (IsShellDomain(domain)) {
+2 -9
View File
@@ -11,6 +11,7 @@
#include "fesa/build_info.h"
#include "io/hdf5/hdf5_raii.h"
#include "io/hdf5/hdf5_primitives.h"
namespace fesa::hdf5_internal {
@@ -596,15 +597,7 @@ void SelfCheckFile(const std::filesystem::path& path, const Domain& domain,
std::vector<double> frames;
directors.reserve(domain.Nodes().size() * 3U);
frames.reserve(domain.Nodes().size() * 9U);
for (const auto& frame : domain.ShellNodeInitialFrames()) {
directors.insert(directors.end(), frame.director.begin(),
frame.director.end());
frames.insert(frames.end(), frame.tangent_a.begin(),
frame.tangent_a.end());
frames.insert(frames.end(), frame.tangent_b.begin(),
frame.tangent_b.end());
frames.insert(frames.end(), frame.director.begin(), frame.director.end());
}
hdf5_internal::AppendShellReferenceFrames(domain, directors, frames);
RequireModelDoubleDataset(file.Get(), "/model/shell/nodal_director",
{static_cast<hsize_t>(domain.Nodes().size()), 3U},
"D1,D2,D3", "1,1,1", "global-cartesian", "nodal",
@@ -1,6 +1,5 @@
#include "fesa/io/hdf5/nonlinear_hdf5_results_writer.h"
#include <algorithm>
#include <array>
#include <cmath>
#include <cstddef>
@@ -14,17 +13,20 @@
#include "fesa/analysis/analysis_model.h"
#include "fesa/build_info.h"
#include "fesa/elements/finite_rotation.h"
#include "fesa/fem/dof_manager.h"
#include "fesa/math/vector3.h"
#include "io/hdf5/hdf5_atomic_file.h"
#include "io/hdf5/hdf5_primitives.h"
#include "io/hdf5/hdf5_raii.h"
#include "io/hdf5/hdf5_self_check.h"
#include "math/finite_values.h"
#include "results/shell_result_recovery.h"
namespace fesa {
namespace {
using math_internal::IsFinite;
using hdf5_internal::Hdf5Failure;
using hdf5_internal::Hdf5Handle;
@@ -90,43 +92,9 @@ struct DiagnosticWriteRow {
const char* message;
};
template <std::size_t Size>
bool IsFinite(const std::array<double, Size>& values) {
return std::all_of(values.begin(), values.end(),
[](const double value) { return std::isfinite(value); });
}
bool IsFinite(const Vector& values) {
for (std::size_t index = 0U; index < values.Size(); ++index) {
if (!std::isfinite(values[index])) {
return false;
}
}
return true;
}
bool SameIdentity(const SourceEntityId& left, const SourceEntityId& right) {
return left.instance_name == right.instance_name &&
left.source_label == right.source_label &&
left.source_label_text == right.source_label_text;
}
bool IsFinite(const ShellResultRow& row) {
if (!IsFinite(row.natural_coordinates) || !IsFinite(row.generalized_strain) ||
!IsFinite(row.section_resultant)) {
return false;
}
for (const auto& axis : row.local_frame) {
if (!IsFinite(axis)) {
return false;
}
}
for (const auto& stress : row.stress) {
if (!std::isfinite(stress.zeta) || !IsFinite(stress.components)) {
return false;
}
}
return true;
bool SameIdentity(const SourceEntityId& left,
const SourceEntityId& right) {
return fesa::SourceIdentityEquals(left, right);
}
Status Failure(const char* code, const std::string& message) {
@@ -300,7 +268,8 @@ Status ValidateState(const Domain& domain, const NonlinearAnalysisState& state)
const std::size_t element = row_index / kShellLocationsPerElement;
const std::size_t location = row_index % kShellLocationsPerElement;
if (row.element != element || row.location != locations[location] ||
row.natural_coordinates != coordinates[location] || !IsFinite(row)) {
row.natural_coordinates != coordinates[location] ||
!results_internal::IsFiniteShellRow(row)) {
return Failure("invalid-result-state",
"Accepted shell rows must preserve element and GP order.");
}
@@ -315,13 +284,8 @@ void WriteCommonNumericAttributes(const hid_t dataset,
const std::string& coordinate_system,
const std::string& location) {
hdf5_internal::WriteUint64Attribute(dataset, "schema_version", 1U);
hdf5_internal::WriteStringAttribute(dataset, "component_names",
component_names);
hdf5_internal::WriteStringAttribute(dataset, "component_unit_dimensions",
component_units);
hdf5_internal::WriteStringAttribute(dataset, "coordinate_system",
coordinate_system);
hdf5_internal::WriteStringAttribute(dataset, "location", location);
hdf5_internal::WriteQuantityAttributes(
dataset, component_names, component_units, coordinate_system, location);
}
void WriteFrameAttributes(const hid_t dataset, const AcceptedFrameState& frame) {
@@ -660,12 +624,7 @@ void WriteModelData(const hid_t file, const Domain& domain,
std::vector<double> frames;
directors.reserve(domain.Nodes().size() * 3U);
frames.reserve(domain.Nodes().size() * 9U);
for (const auto& frame : domain.ShellNodeInitialFrames()) {
directors.insert(directors.end(), frame.director.begin(), frame.director.end());
frames.insert(frames.end(), frame.tangent_a.begin(), frame.tangent_a.end());
frames.insert(frames.end(), frame.tangent_b.begin(), frame.tangent_b.end());
frames.insert(frames.end(), frame.director.begin(), frame.director.end());
}
hdf5_internal::AppendShellReferenceFrames(domain, directors, frames);
const hsize_t node_count = static_cast<hsize_t>(domain.Nodes().size());
(void)WriteModelDoubleDataset(file, "/model/shell/nodal_director",
{node_count, 3U}, directors.data(),
@@ -772,14 +731,6 @@ void WriteAcceptedFrameTable(const hid_t file,
hdf5_internal::WriteUint64Attribute(dataset.Get(), "schema_version", 1U);
}
std::vector<double> CopyVector(const Vector& source) {
std::vector<double> values(source.Size());
for (std::size_t index = 0U; index < source.Size(); ++index) {
values[index] = source[index];
}
return values;
}
std::vector<double> NodalDisplacement(const AcceptedFrameState& frame) {
std::vector<double> values(frame.displacement.Size());
for (std::size_t node = 0U; node < frame.nodal_internal_order.size(); ++node) {
@@ -793,47 +744,6 @@ std::vector<double> NodalDisplacement(const AcceptedFrameState& frame) {
return values;
}
std::vector<double> FlattenTriads(const AcceptedFrameState& frame) {
std::vector<double> values;
values.reserve(frame.nodal_triad.size() * 9U);
for (const auto& triad : frame.nodal_triad) {
for (const auto& axis : triad) {
values.insert(values.end(), axis.begin(), axis.end());
}
}
return values;
}
std::vector<double> FlattenDirectors(const AcceptedFrameState& frame) {
std::vector<double> values;
values.reserve(frame.nodal_director.size() * 3U);
for (const auto& director : frame.nodal_director) {
values.insert(values.end(), director.begin(), director.end());
}
return values;
}
std::vector<double> SpatialReaction(const AcceptedFrameState& frame) {
std::vector<double> values = CopyVector(frame.reaction);
for (std::size_t node = 0U; node < frame.nodal_internal_order.size(); ++node) {
const std::size_t offset = kDofsPerNode * node;
const Vector3 phi{frame.rotation_vector[offset + 3U],
frame.rotation_vector[offset + 4U],
frame.rotation_vector[offset + 5U]};
const Matrix transform = InverseTransposeLeftJacobianSO3(phi);
const std::array<double, 3> generalized{
frame.reaction[offset + 3U], frame.reaction[offset + 4U],
frame.reaction[offset + 5U]};
for (std::size_t row = 0U; row < 3U; ++row) {
values[offset + 3U + row] = 0.0;
for (std::size_t column = 0U; column < 3U; ++column) {
values[offset + 3U + row] += transform(row, column) * generalized[column];
}
}
}
return values;
}
void WriteShellIdentity(const hid_t dataset, const bool has_section_positions,
const std::string& local_frame_path) {
hdf5_internal::WriteStringAttribute(dataset, "source_element_type_dataset",
@@ -864,35 +774,36 @@ void WriteFrame(const hid_t file, const Domain& domain,
file, root + "/nodal/displacement", nodal_dimensions, displacement.data(),
displacement.size(), "UX,UY,UZ,URX,URY,URZ", "length,length,length,1,1,1",
"global-cartesian", "nodal", frame);
const auto triads = FlattenTriads(frame);
const auto triads = hdf5_internal::FlattenNodalTriads(frame.nodal_triad);
(void)WriteFrameDoubleDataset(file, root + "/nodal/triad",
{node_count, 3U, 3U}, triads.data(), triads.size(),
"X,Y,Z", "1,1,1", "global-cartesian",
"nodal-triad", frame);
const auto directors = FlattenDirectors(frame);
const auto directors = hdf5_internal::FlattenNodalDirectors(frame.nodal_director);
(void)WriteFrameDoubleDataset(file, root + "/nodal/director", {node_count, 3U},
directors.data(), directors.size(), "D1,D2,D3",
"1,1,1", "global-cartesian", "nodal-director",
frame);
const auto internal = CopyVector(frame.internal_force);
const auto internal = hdf5_internal::CopyVectorValues(frame.internal_force);
(void)WriteFrameDoubleDataset(
file, root + "/nodal/generalized_internal_force", nodal_dimensions,
internal.data(), internal.size(), "FI1,FI2,FI3,MI_PHI1,MI_PHI2,MI_PHI3",
"force,force,force,force*length,force*length,force*length",
"global-cartesian", "nodal", frame);
const auto external = CopyVector(frame.external_force);
const auto external = hdf5_internal::CopyVectorValues(frame.external_force);
(void)WriteFrameDoubleDataset(
file, root + "/nodal/generalized_external_force", nodal_dimensions,
external.data(), external.size(), "FE1,FE2,FE3,ME_PHI1,ME_PHI2,ME_PHI3",
"force,force,force,force*length,force*length,force*length",
"global-cartesian", "nodal", frame);
const auto residual = CopyVector(frame.residual);
const auto residual = hdf5_internal::CopyVectorValues(frame.residual);
(void)WriteFrameDoubleDataset(
file, root + "/nodal/generalized_residual", nodal_dimensions,
residual.data(), residual.size(), "RU1,RU2,RU3,RPHI1,RPHI2,RPHI3",
"force,force,force,force*length,force*length,force*length",
"global-cartesian", "nodal", frame);
const auto reaction = SpatialReaction(frame);
const auto reaction = hdf5_internal::SpatialReactionValues(
frame.rotation_vector, frame.reaction, frame.nodal_internal_order.size());
(void)WriteFrameDoubleDataset(
file, root + "/nodal/reaction", nodal_dimensions, reaction.data(),
reaction.size(), "RF1,RF2,RF3,RM1,RM2,RM3",
+7 -12
View File
@@ -27,11 +27,6 @@ using U = std::vector<std::uint64_t>;
using B = std::vector<std::uint8_t>;
using D = std::vector<double>;
using S = std::vector<std::string>;
std::vector<double> Values(const Vector& vector) {
D result;
for (std::size_t i = 0; i < vector.Size(); ++i) result.push_back(vector[i]);
return result;
}
void Parent(hid_t file, const std::string& path) {
const auto parent = path.substr(0, path.find_last_of('/'));
if (!parent.empty() && H5Lexists(file, parent.c_str(), H5P_DEFAULT) <= 0)
@@ -110,11 +105,11 @@ void FrameData(SolidPlan& plan, const Domain& domain, std::size_t frame,
value.doubles = {{dynamic ? "time" : "load_factor", coordinate}};
plan.datasets.push_back(std::move(value));
};
add(Data(root + "/nodal/displacement", {n, 3}, Values(u), "U1,U2,U3",
add(Data(root + "/nodal/displacement", {n, 3}, CopyVectorValues(u), "U1,U2,U3",
"length", "nodal"));
add(Data(root + "/nodal/reaction", {n, 3}, Values(rf), "RF1,RF2,RF3", "force",
add(Data(root + "/nodal/reaction", {n, 3}, CopyVectorValues(rf), "RF1,RF2,RF3", "force",
"nodal"));
add(Data(root + "/nodal/residual", {n, 3}, Values(r), "R1,R2,R3", "force",
add(Data(root + "/nodal/residual", {n, 3}, CopyVectorValues(r), "R1,R2,R3", "force",
"nodal"));
D stress, strain;
Check(points.size() == 8 * e, "Solid point count is invalid.");
@@ -249,7 +244,7 @@ void Model(SolidPlan& plan, const Domain& domain, const DofManager& dofs) {
for (std::size_t i = 0; i < domain.Elements().Size(); ++i) {
auto element = factory.Create(domain.Elements()[i], domain);
Check(element.HasValue(), "Solid factory reference failed.");
const auto* hex = dynamic_cast<const Hex8Element*>(element.Value().get());
auto hex = factory.BindSolidTrial(*element.Value());
Check(hex != nullptr, "Solid kernel identity failed.");
auto response = hex->EvaluateLinear(Vector{24});
Check(response.HasValue(), "Solid reference recovery failed.");
@@ -426,15 +421,15 @@ Result<SolidPlan> BuildSolidPlan(const Domain& domain, SolidStateView view,
plan.datasets.push_back(std::move(data));
};
add(Data(root + "/nodal/velocity", {domain.Nodes().size(), 3},
Values(frame.velocity), "V1,V2,V3", "length/time", "nodal"));
CopyVectorValues(frame.velocity), "V1,V2,V3", "length/time", "nodal"));
auto a = Data(root + "/nodal/acceleration", {domain.Nodes().size(), 3},
Values(frame.acceleration), "A1,A2,A3", "length/time^2",
CopyVectorValues(frame.acceleration), "A1,A2,A3", "length/time^2",
"nodal");
a.strings["acceleration_kind"] = "physical";
add(std::move(a));
a = Data(root + "/nodal/algorithmic_acceleration",
{domain.Nodes().size(), 3},
Values(frame.algorithmic_acceleration), "A1,A2,A3",
CopyVectorValues(frame.algorithmic_acceleration), "A1,A2,A3",
"length/time^2", "nodal");
a.strings["acceleration_kind"] = "algorithmic";
add(std::move(a));
+4 -5
View File
@@ -7,7 +7,9 @@
#include <string>
#include <vector>
#include "fesa/analysis/analysis_model.h"
#include "fesa/build_info.h"
#include "fesa/fem/dof_manager.h"
#include "io/hdf5/hdf5_primitives.h"
#include "io/hdf5/hdf5_raii.h"
@@ -424,8 +426,7 @@ void Frames(hid_t f, const ThermalAnalysisState& s) {
Number(g.Get(), "is_initial", H5T_STD_U8LE, H5T_NATIVE_UINT8,
static_cast<std::uint8_t>(frame.is_initial));
ResultValues(f, root + "/nodal/temperature", {s.NodeOrder().size(), 5},
{frame.temperature.Data(),
frame.temperature.Data() + frame.temperature.Size()},
CopyVectorValues(frame.temperature),
"NT11,NT12,NT13,NT14,NT15", "temperature", "scalar",
"nodal-thickness-stations");
if (frame.is_initial) {
@@ -433,9 +434,7 @@ void Frames(hid_t f, const ThermalAnalysisState& s) {
Absent(f, root + "/element", "heat_flux");
} else {
const auto& payload = *frame.completed;
std::vector<double> reaction(payload.reaction_heat_rate.Size());
for (std::size_t i = 0; i < reaction.size(); ++i)
reaction[i] = payload.reaction_heat_rate[i];
const auto reaction = CopyVectorValues(payload.reaction_heat_rate);
ResultValues(f, root + "/nodal/reaction_heat_rate", {reaction.size()},
reaction, "RFL", "power", "scalar",
"prescribed-temperature-dofs");