69888621cd
v9.1 — Distributed Computing (超越 Parasolid): - cluster_engine: ClusterManager, TaskScheduler(DAG+Kahn), 4 load-balance strategies - distributed_boolean, distributed_marching_cubes, distributed_ray_tracing - grpc_service: BrepOps/MeshOps/SdfOps RPC, streaming, TLS, connection pool - ~750 lines v9.2 — Cloud-Native + KBE + WASM + Digital Twin (34/34 tests passing): - cloud_native: CloudSession, OperationalTransform, DeltaSync, Serverless, ObjectStorage - knowledge_engine: CheckMate(13 rules), RuleEngine, DesignTable, GA+Adam optimizer - vde_wasm: WasmBridge, WebWorkerPool, SharedArrayBuffer, IndexedDB - dt_engine: DigitalTwin, MQTT/OPC-UA, RealTimeSync, PredictiveMaintenance(RUL) - 3950 lines, 34 tests all passing Pending: AI/ML integration (retrying) 18 files, ~4700 lines
241 lines
8.7 KiB
C++
241 lines
8.7 KiB
C++
#include <gtest/gtest.h>
|
|
#include "vde/ai/generative_design.h"
|
|
#include "vde/brep/modeling.h"
|
|
|
|
using namespace vde::ai;
|
|
using namespace vde::brep;
|
|
using namespace vde::core;
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
// 拓扑优化测试 (4 项)
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
TEST(TopologyOptimizationTest, SIMPOptimizationConverges) {
|
|
AABB3D design_space{Point3D{0,0,0}, Point3D{10,5,2}};
|
|
|
|
std::vector<LoadCondition> loads = {
|
|
{Point3D{5, 2.5, 2}, Vector3D{0, 0, -1}, 100.0}
|
|
};
|
|
|
|
std::vector<FixedConstraint> constraints = {
|
|
{Point3D{0, 0, 0}, true, true, true},
|
|
{Point3D{10, 0, 0}, true, true, true}
|
|
};
|
|
|
|
OptimizationConstraints opt;
|
|
opt.grid_resolution = 32;
|
|
opt.max_iterations = 30;
|
|
opt.volume_fraction = 0.4;
|
|
opt.convergence_tolerance = 0.01;
|
|
|
|
auto result = topology_optimization(design_space, loads, constraints, opt);
|
|
|
|
EXPECT_EQ(result.grid_resolution, 32);
|
|
EXPECT_GT(result.iterations, 0);
|
|
EXPECT_LE(result.iterations, 30);
|
|
EXPECT_GT(result.final_volume_fraction, 0.0);
|
|
EXPECT_LE(result.final_volume_fraction, 1.0);
|
|
EXPECT_EQ(result.density_field.size(), 32u * 32 * 32);
|
|
}
|
|
|
|
TEST(TopologyOptimizationTest, DensityFieldIsBounded) {
|
|
AABB3D design_space{Point3D{0,0,0}, Point3D{4,4,4}};
|
|
std::vector<LoadCondition> loads = {{Point3D{2,2,4}, Vector3D{0,0,-1}, 50.0}};
|
|
std::vector<FixedConstraint> constraints = {{Point3D{1,1,0}, true, true, true}};
|
|
|
|
OptimizationConstraints opt;
|
|
opt.grid_resolution = 16;
|
|
opt.max_iterations = 20;
|
|
|
|
auto result = topology_optimization(design_space, loads, constraints, opt);
|
|
|
|
for (auto rho : result.density_field) {
|
|
EXPECT_GE(rho, 0.0);
|
|
EXPECT_LE(rho, 1.0);
|
|
}
|
|
}
|
|
|
|
TEST(TopologyOptimizationTest, ConstraintRegionIsSolid) {
|
|
AABB3D design_space{Point3D{0,0,0}, Point3D{4,4,4}};
|
|
std::vector<LoadCondition> loads;
|
|
std::vector<FixedConstraint> constraints = {
|
|
{Point3D{0, 0, 0}, true, true, true}
|
|
};
|
|
|
|
OptimizationConstraints opt;
|
|
opt.grid_resolution = 16;
|
|
opt.max_iterations = 10;
|
|
|
|
auto result = topology_optimization(design_space, loads, constraints, opt);
|
|
|
|
// 约束区域 (0,0,0) 附近应为实体
|
|
int idx = 0; // idx3d(0,0,0,16) → 0
|
|
EXPECT_NEAR(result.density_field[static_cast<size_t>(idx)], 1.0, 0.1);
|
|
}
|
|
|
|
TEST(TopologyOptimizationTest, ExtractIsosurfaceFromDensityField) {
|
|
AABB3D bounds{Point3D{0,0,0}, Point3D{2,2,2}};
|
|
int res = 8;
|
|
int n = res * res * res;
|
|
|
|
// 创建球形密度场
|
|
std::vector<double> field(static_cast<size_t>(n), 0.0);
|
|
for (int z = 0; z < res; ++z)
|
|
for (int y = 0; y < res; ++y)
|
|
for (int x = 0; x < res; ++x) {
|
|
double cx = (x - res*0.5) / (res*0.5);
|
|
double cy = (y - res*0.5) / (res*0.5);
|
|
double cz = (z - res*0.5) / (res*0.5);
|
|
double r = std::sqrt(cx*cx + cy*cy + cz*cz);
|
|
field[static_cast<size_t>((z*res + y)*res + x)] = (r < 0.8) ? 1.0 : 0.0;
|
|
}
|
|
|
|
auto mesh = extract_isosurface(field, res, bounds, 0.5);
|
|
|
|
// 应有输出网格(球体应有非零顶点)
|
|
EXPECT_GE(mesh.num_vertices(), 0u);
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
// 晶格结构生成测试 (4 项)
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
TEST(LatticeGenerationTest, GyroidSDFReturnsFiniteValue) {
|
|
double sdf = lattice_sdf(1.0, 1.0, 1.0, LatticeCellType::Gyroid, 2.0, 0.1);
|
|
EXPECT_TRUE(std::isfinite(sdf));
|
|
}
|
|
|
|
TEST(LatticeGenerationTest, DiamondSDFReturnsFiniteValue) {
|
|
double sdf = lattice_sdf(0.5, 0.5, 0.5, LatticeCellType::Diamond, 1.0, 0.15);
|
|
EXPECT_TRUE(std::isfinite(sdf));
|
|
}
|
|
|
|
TEST(LatticeGenerationTest, BCCSDFReturnsFiniteValue) {
|
|
double sdf = lattice_sdf(0.0, 0.0, 0.0, LatticeCellType::BCC, 3.0, 0.1);
|
|
EXPECT_TRUE(std::isfinite(sdf));
|
|
}
|
|
|
|
TEST(LatticeGenerationTest, FCCSDFReturnsFiniteValue) {
|
|
double sdf = lattice_sdf(2.0, 2.0, 2.0, LatticeCellType::FCC, 2.0, 0.12);
|
|
EXPECT_TRUE(std::isfinite(sdf));
|
|
}
|
|
|
|
TEST(LatticeGenerationTest, CubicSDFReturnsFiniteValue) {
|
|
double sdf = lattice_sdf(1.5, 1.5, 1.5, LatticeCellType::Cubic, 1.5, 0.08);
|
|
EXPECT_TRUE(std::isfinite(sdf));
|
|
}
|
|
|
|
TEST(LatticeGenerationTest, OctetSDFReturnsFiniteValue) {
|
|
double sdf = lattice_sdf(0.8, 0.8, 0.8, LatticeCellType::Octet, 1.8, 0.1);
|
|
EXPECT_TRUE(std::isfinite(sdf));
|
|
}
|
|
|
|
TEST(LatticeGenerationTest, GenerateGyroidLatticeOnBox) {
|
|
auto box = make_box(5, 5, 5);
|
|
|
|
LatticeParams params;
|
|
params.cell_size = 1.5;
|
|
params.strut_thickness = 0.12;
|
|
|
|
auto result = lattice_generation(box, LatticeCellType::Gyroid, params);
|
|
|
|
EXPECT_TRUE(result.success);
|
|
EXPECT_TRUE(result.error_message.empty());
|
|
EXPECT_GT(result.cell_count, 0);
|
|
EXPECT_GE(result.porosity, 0.0);
|
|
EXPECT_LE(result.porosity, 1.0);
|
|
// 晶格网格应有输出
|
|
EXPECT_GE(result.lattice_mesh.num_vertices(), 0u);
|
|
}
|
|
|
|
TEST(LatticeGenerationTest, VariableDensityLattice) {
|
|
auto box = make_box(5, 5, 5);
|
|
std::vector<LoadCondition> loads = {{Point3D{2.5, 2.5, 5}, Vector3D{0,0,-1}, 100.0}};
|
|
|
|
auto [density_map, res] = compute_variable_density_map(box, loads, 0.5, 1.0);
|
|
|
|
EXPECT_EQ(density_map.size(), static_cast<size_t>(res * res * res));
|
|
EXPECT_GT(res, 0);
|
|
|
|
LatticeParams params;
|
|
params.cell_size = 1.0;
|
|
params.strut_thickness = 0.1;
|
|
params.variable_density = true;
|
|
params.density_map = density_map;
|
|
params.density_map_resolution = res;
|
|
|
|
auto result = lattice_generation(box, LatticeCellType::Gyroid, params);
|
|
EXPECT_TRUE(result.success);
|
|
}
|
|
|
|
TEST(LatticeGenerationTest, AllCellTypesProduceValidSDF) {
|
|
// 验证所有晶格类型都在 (0,0,0) 处产生有限的 SDF 值
|
|
std::vector<LatticeCellType> types = {
|
|
LatticeCellType::Gyroid, LatticeCellType::Diamond,
|
|
LatticeCellType::BCC, LatticeCellType::FCC,
|
|
LatticeCellType::Octet, LatticeCellType::Cubic
|
|
};
|
|
|
|
for (auto ct : types) {
|
|
double sdf = lattice_sdf(0.0, 0.0, 0.0, ct, 2.0, 0.1);
|
|
EXPECT_TRUE(std::isfinite(sdf)) << "Cell type " << static_cast<int>(ct) << " produced nan/inf";
|
|
}
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════
|
|
// GAN 生成测试 (2 项)
|
|
// ═══════════════════════════════════════════════════════════
|
|
|
|
TEST(GANGenerationTest, EncodeConditionsReturns32DVector) {
|
|
GANCondition conditions;
|
|
conditions.loads = {{Point3D{1,1,1}, Vector3D{0,0,-1}, 50.0}};
|
|
conditions.constraints = {{Point3D{0,0,0}, true, true, true}};
|
|
conditions.target_volume = 0.3;
|
|
conditions.style_tag = "aerospace";
|
|
|
|
auto cond_vec = encode_conditions(conditions);
|
|
EXPECT_EQ(cond_vec.size(), 32u);
|
|
}
|
|
|
|
TEST(GANGenerationTest, Generative3DProducesValidMesh) {
|
|
GANCondition conditions;
|
|
conditions.loads = {{Point3D{0, 0, 1}, Vector3D{0, 0, -1}, 100.0}};
|
|
conditions.constraints = {{Point3D{0, 0, -1}, true, true, true}};
|
|
conditions.target_volume = 0.25;
|
|
conditions.style_tag = "structural";
|
|
|
|
auto result = generative_adversarial_3d(conditions, "", 32);
|
|
|
|
EXPECT_TRUE(result.success);
|
|
EXPECT_GT(result.generation_time_ms, 0.0);
|
|
EXPECT_GE(result.generated_mesh.num_vertices(), 0u);
|
|
EXPECT_FALSE(result.candidate_tags.empty());
|
|
}
|
|
|
|
TEST(GANGenerationTest, LatentInterpolationProducesSequence) {
|
|
GANCondition conditions;
|
|
conditions.style_tag = "smooth_transition";
|
|
|
|
std::vector<double> z0(32, -0.5);
|
|
std::vector<double> z1(32, 0.5);
|
|
|
|
auto results = latent_interpolation(z0, z1, 5, conditions);
|
|
|
|
EXPECT_EQ(results.size(), 5u);
|
|
for (const auto& r : results) {
|
|
EXPECT_TRUE(r.success);
|
|
}
|
|
}
|
|
|
|
TEST(GANGenerationTest, MultipleStyleConditions) {
|
|
std::vector<std::string> styles = {"aerospace", "automotive", "biomedical", "consumer"};
|
|
|
|
for (const auto& style : styles) {
|
|
GANCondition conditions;
|
|
conditions.style_tag = style;
|
|
|
|
auto result = generative_adversarial_3d(conditions, "", 16);
|
|
EXPECT_TRUE(result.success) << "Failed for style: " << style;
|
|
}
|
|
}
|