feat(abaqus-subset-completion): step 0 — abaqus-input-contract
This commit is contained in:
@@ -118,6 +118,7 @@ add_test(
|
||||
)
|
||||
|
||||
add_executable(fesa_abaqus_parser_tests
|
||||
unit/io/abaqus/input_contract_test.cpp
|
||||
unit/io/abaqus/parser_test.cpp
|
||||
)
|
||||
|
||||
@@ -147,6 +148,14 @@ add_test(
|
||||
--gtest_filter=ScopedDeck.*
|
||||
)
|
||||
|
||||
add_test(
|
||||
NAME AbaqusInputContract
|
||||
COMMAND "$<TARGET_FILE:fesa_abaqus_parser_tests>"
|
||||
--gtest_filter=AbaqusInputContract/*
|
||||
)
|
||||
# Steps 1-4 make this normative matrix pass, then remove WILL_FAIL.
|
||||
set_tests_properties(AbaqusInputContract PROPERTIES WILL_FAIL TRUE)
|
||||
|
||||
add_executable(fesa_deck_to_domain_tests
|
||||
integration/io/minimal_deck_to_domain_test.cpp
|
||||
)
|
||||
|
||||
Vendored
+54
@@ -0,0 +1,54 @@
|
||||
# case_id outcome fixture expected_stage expected_code expected_line node_count element_count node_set_count element_set_count prescribed_dof_count nodal_load_count shear_source shear_area_y shear_area_z checked_node_set checked_element_set
|
||||
node_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
element_b31_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
nset_explicit_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
elset_explicit_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
material_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
elastic_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
beam_general_section_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
boundary_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
cload_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
step_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
static_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
end_step_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
part_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
end_part_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
assembly_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
end_assembly_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
instance_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
end_instance_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
assembly_nset_instance_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
generate_nset_valid valid valid/generated_nested_sets.inp - - 0 3 2 2 2 18 1 phase1_default 0.8333333333333334 0.8333333333333334 AllNodes:1,2,3 AllElements:1,2
|
||||
generate_elset_valid valid valid/generated_nested_sets.inp - - 0 3 2 2 2 18 1 phase1_default 0.8333333333333334 0.8333333333333334 AllNodes:1,2,3 AllElements:1,2
|
||||
nested_sets_valid valid valid/generated_nested_sets.inp - - 0 3 2 2 2 18 1 phase1_default 0.8333333333333334 0.8333333333333334 AllNodes:1,2,3 AllElements:1,2
|
||||
transverse_shear_valid valid valid/explicit_transverse_shear.inp - - 0 2 1 1 1 6 1 input 0.8 0.5 Fixed:1 Beam:1
|
||||
heading_noop_valid valid valid/noop_directives.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
preprint_noop_valid valid valid/noop_directives.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
restart_noop_valid valid valid/noop_directives.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
output_noop_valid valid valid/noop_directives.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
|
||||
node_duplicate_invalid invalid invalid/node_duplicate.inp semantic abaqus.semantic.duplicate_node_label 3 - - - - - - - - - - -
|
||||
element_type_invalid invalid invalid/element_wrong_type.inp semantic abaqus.semantic.unsupported_element 4 - - - - - - - - - - -
|
||||
part_unclosed_invalid invalid invalid/part_unclosed.inp syntax abaqus.syntax.unclosed_part 1 - - - - - - - - - - -
|
||||
assembly_multiple_invalid invalid invalid/assembly_multiple.inp syntax abaqus.syntax.multiple_assemblies 3 - - - - - - - - - - -
|
||||
instance_transform_invalid invalid invalid/instance_transform.inp semantic abaqus.semantic.instance_transform 5 - - - - - - - - - - -
|
||||
instance_local_mesh_invalid invalid invalid/instance_local_mesh.inp syntax abaqus.syntax.instance_local_keyword 5 - - - - - - - - - - -
|
||||
mixed_mesh_invalid invalid invalid/mixed_mesh.inp semantic abaqus.semantic.mixed_mesh_organization 1 - - - - - - - - - - -
|
||||
nset_parameter_invalid invalid invalid/nset_missing_name.inp semantic abaqus.semantic.missing_parameter 1 - - - - - - - - - - -
|
||||
elset_generate_invalid invalid invalid/elset_invalid_generate.inp semantic abaqus.semantic.invalid_generate 2 - - - - - - - - - - -
|
||||
nested_set_cycle_invalid invalid invalid/nested_set_cycle.inp semantic abaqus.semantic.set_cycle 4 - - - - - - - - - - -
|
||||
set_instance_invalid invalid invalid/assembly_set_wrong_instance.inp semantic abaqus.semantic.wrong_instance 6 - - - - - - - - - - -
|
||||
material_missing_elastic_invalid invalid invalid/material_missing_elastic.inp semantic abaqus.semantic.missing_elastic 1 - - - - - - - - - - -
|
||||
elastic_data_invalid invalid invalid/elastic_invalid_data.inp semantic abaqus.semantic.invalid_elastic_data 3 - - - - - - - - - - -
|
||||
section_type_invalid invalid invalid/section_wrong_type.inp semantic abaqus.semantic.unsupported_section 4 - - - - - - - - - - -
|
||||
section_duplicate_invalid invalid invalid/section_duplicate_assignment.inp semantic abaqus.semantic.duplicate_section_assignment 7 - - - - - - - - - - -
|
||||
transverse_scf_invalid invalid invalid/transverse_nonzero_scf.inp semantic abaqus.semantic.nonzero_scf 8 - - - - - - - - - - -
|
||||
boundary_conflict_invalid invalid invalid/boundary_conflict.inp semantic abaqus.semantic.conflicting_boundary 10 - - - - - - - - - - -
|
||||
cload_dof_invalid invalid invalid/cload_invalid_dof.inp semantic abaqus.semantic.invalid_dof 6 - - - - - - - - - - -
|
||||
step_multiple_invalid invalid invalid/step_multiple.inp semantic abaqus.semantic.step_count 4 - - - - - - - - - - -
|
||||
static_data_invalid invalid invalid/static_invalid_data.inp semantic abaqus.semantic.invalid_static_data 3 - - - - - - - - - - -
|
||||
end_step_missing_invalid invalid invalid/end_step_missing.inp syntax abaqus.syntax.unclosed_step 1 - - - - - - - - - - -
|
||||
heading_parameter_invalid invalid invalid/heading_invalid_parameter.inp syntax abaqus.syntax.unsupported_parameter 1 - - - - - - - - - - -
|
||||
preprint_parameter_invalid invalid invalid/preprint_invalid_parameter.inp syntax abaqus.syntax.unsupported_parameter 1 - - - - - - - - - - -
|
||||
restart_scope_invalid invalid invalid/restart_outside_step.inp syntax abaqus.syntax.invalid_restart_scope 1 - - - - - - - - - - -
|
||||
output_parameter_invalid invalid invalid/output_invalid_parameter.inp syntax abaqus.syntax.unsupported_parameter 3 - - - - - - - - - - -
|
||||
unknown_keyword_invalid invalid invalid/unknown_include.inp syntax abaqus.unsupported_keyword 1 - - - - - - - - - - -
|
||||
|
@@ -0,0 +1,4 @@
|
||||
*ASSEMBLY, NAME=First
|
||||
*END ASSEMBLY
|
||||
*ASSEMBLY, NAME=Second
|
||||
*END ASSEMBLY
|
||||
@@ -0,0 +1,8 @@
|
||||
*PART, NAME=BeamPart
|
||||
*END PART
|
||||
*ASSEMBLY, NAME=Root
|
||||
*INSTANCE, NAME=Beam-1, PART=BeamPart
|
||||
*END INSTANCE
|
||||
*NSET, NSET=Fixed, INSTANCE=Other
|
||||
1
|
||||
*END ASSEMBLY
|
||||
@@ -0,0 +1,11 @@
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
*NSET, NSET=Fixed
|
||||
1
|
||||
*STEP
|
||||
*STATIC
|
||||
*BOUNDARY
|
||||
Fixed, 1, 1, 0.0
|
||||
*BOUNDARY
|
||||
Fixed, 1, 1, 1.0
|
||||
*END STEP
|
||||
@@ -0,0 +1,7 @@
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
*STEP
|
||||
*STATIC
|
||||
*CLOAD
|
||||
1, 7, 1.0
|
||||
*END STEP
|
||||
@@ -0,0 +1,6 @@
|
||||
*MATERIAL, NAME=Steel
|
||||
*ELASTIC
|
||||
-1.0, 0.25
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,8 @@
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
2, 1.0, 0.0, 0.0
|
||||
*ELEMENT, TYPE=B32, ELSET=Beam
|
||||
1, 1, 2
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,5 @@
|
||||
*ELSET, ELSET=Beam, GENERATE
|
||||
3, 1, 1
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,2 @@
|
||||
*STEP
|
||||
*STATIC
|
||||
@@ -0,0 +1 @@
|
||||
*HEADING, NAME=Unsupported
|
||||
@@ -0,0 +1,8 @@
|
||||
*PART, NAME=BeamPart
|
||||
*END PART
|
||||
*ASSEMBLY, NAME=Root
|
||||
*INSTANCE, NAME=Beam-1, PART=BeamPart
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
*END INSTANCE
|
||||
*END ASSEMBLY
|
||||
@@ -0,0 +1,7 @@
|
||||
*PART, NAME=BeamPart
|
||||
*END PART
|
||||
*ASSEMBLY, NAME=Root
|
||||
*INSTANCE, NAME=Beam-1, PART=BeamPart
|
||||
1.0, 2.0, 3.0
|
||||
*END INSTANCE
|
||||
*END ASSEMBLY
|
||||
@@ -0,0 +1,4 @@
|
||||
*MATERIAL, NAME=Steel
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,8 @@
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
*PART, NAME=BeamPart
|
||||
*END PART
|
||||
*ASSEMBLY, NAME=Root
|
||||
*INSTANCE, NAME=Beam-1, PART=BeamPart
|
||||
*END INSTANCE
|
||||
*END ASSEMBLY
|
||||
@@ -0,0 +1,7 @@
|
||||
*NSET, NSET=First
|
||||
Second
|
||||
*NSET, NSET=Second
|
||||
First
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,6 @@
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
1, 1.0, 0.0, 0.0
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,5 @@
|
||||
*NSET
|
||||
1
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,4 @@
|
||||
*STEP
|
||||
*STATIC
|
||||
*OUTPUT, FIELD, VARIABLE=ALL
|
||||
*END STEP
|
||||
@@ -0,0 +1,3 @@
|
||||
*PART, NAME=BeamPart
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
@@ -0,0 +1 @@
|
||||
*PREPRINT, COLOR=YES
|
||||
@@ -0,0 +1 @@
|
||||
*RESTART, WRITE, FREQUENCY=0
|
||||
@@ -0,0 +1,12 @@
|
||||
*MATERIAL, NAME=Steel
|
||||
*ELASTIC
|
||||
200.0, 0.25
|
||||
*BEAM GENERAL SECTION, SECTION=GENERAL, ELSET=Beam, MATERIAL=Steel
|
||||
1.0, 1.0, 0.0, 1.0, 1.0
|
||||
0.0, 1.0, 0.0
|
||||
*BEAM GENERAL SECTION, SECTION=GENERAL, ELSET=Beam, MATERIAL=Steel
|
||||
1.0, 2.0, 0.0, 2.0, 1.0
|
||||
0.0, 1.0, 0.0
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,9 @@
|
||||
*MATERIAL, NAME=Steel
|
||||
*ELASTIC
|
||||
200.0, 0.25
|
||||
*BEAM GENERAL SECTION, SECTION=ARBITRARY, ELSET=Beam, MATERIAL=Steel
|
||||
1.0, 1.0, 0.0, 1.0, 1.0
|
||||
0.0, 1.0, 0.0
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,4 @@
|
||||
*STEP
|
||||
*STATIC
|
||||
1.0, -1.0
|
||||
*END STEP
|
||||
@@ -0,0 +1,6 @@
|
||||
*STEP, NAME=First
|
||||
*STATIC
|
||||
*END STEP
|
||||
*STEP, NAME=Second
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1,11 @@
|
||||
*MATERIAL, NAME=Steel
|
||||
*ELASTIC
|
||||
200.0, 0.25
|
||||
*BEAM GENERAL SECTION, SECTION=GENERAL, ELSET=Beam, MATERIAL=Steel
|
||||
1.0, 1.0, 0.0, 1.0, 1.0
|
||||
0.0, 1.0, 0.0
|
||||
*TRANSVERSE SHEAR STIFFNESS
|
||||
64.0, 40.0, 0.25
|
||||
*STEP
|
||||
*STATIC
|
||||
*END STEP
|
||||
@@ -0,0 +1 @@
|
||||
*INCLUDE, INPUT=other.inp
|
||||
@@ -0,0 +1,24 @@
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
2, 1.0, 0.0, 0.0
|
||||
*ELEMENT, TYPE=B31, ELSET=Beam
|
||||
1, 1, 2
|
||||
*NSET, NSET=Fixed
|
||||
1
|
||||
*ELSET, ELSET=Beam
|
||||
1
|
||||
*MATERIAL, NAME=Steel
|
||||
*ELASTIC
|
||||
200.0, 0.25
|
||||
*BEAM GENERAL SECTION, SECTION=GENERAL, ELSET=Beam, MATERIAL=Steel
|
||||
1.0, 1.0, 0.0, 1.0, 1.0
|
||||
0.0, 1.0, 0.0
|
||||
*TRANSVERSE SHEAR STIFFNESS
|
||||
64.0, 40.0, 0.0
|
||||
*STEP
|
||||
*STATIC
|
||||
*BOUNDARY
|
||||
Fixed, 1, 6
|
||||
*CLOAD
|
||||
2, 2, -1.0
|
||||
*END STEP
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
2, 1.0, 0.0, 0.0
|
||||
*ELEMENT, TYPE=B31, ELSET=Beam
|
||||
1, 1, 2
|
||||
*NSET, NSET=Fixed
|
||||
1
|
||||
*ELSET, ELSET=Beam
|
||||
1
|
||||
*MATERIAL, NAME=Steel
|
||||
*ELASTIC
|
||||
200.0, 0.25
|
||||
*BEAM GENERAL SECTION, SECTION=GENERAL, ELSET=Beam, MATERIAL=Steel
|
||||
1.0, 1.0, 0.0, 1.0, 1.0
|
||||
0.0, 1.0, 0.0
|
||||
*BOUNDARY
|
||||
Fixed, 1, 6
|
||||
*STEP, NAME=Load
|
||||
*STATIC
|
||||
*CLOAD
|
||||
2, 2, -1.0
|
||||
*END STEP
|
||||
@@ -0,0 +1,28 @@
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
2, 1.0, 0.0, 0.0
|
||||
3, 2.0, 0.0, 0.0
|
||||
*ELEMENT, TYPE=B31
|
||||
1, 1, 2
|
||||
2, 2, 3
|
||||
*NSET, NSET=FirstTwo, GENERATE
|
||||
1, 2, 1
|
||||
*NSET, NSET=AllNodes
|
||||
FirstTwo, 3
|
||||
*ELSET, ELSET=GeneratedElements, GENERATE
|
||||
1, 2, 1
|
||||
*ELSET, ELSET=AllElements
|
||||
GeneratedElements
|
||||
*MATERIAL, NAME=Steel
|
||||
*ELASTIC
|
||||
200.0, 0.25
|
||||
*BEAM GENERAL SECTION, SECTION=GENERAL, ELSET=AllElements, MATERIAL=Steel
|
||||
1.0, 1.0, 0.0, 1.0, 1.0
|
||||
0.0, 1.0, 0.0
|
||||
*STEP
|
||||
*STATIC
|
||||
*BOUNDARY
|
||||
AllNodes, 1, 6
|
||||
*CLOAD
|
||||
3, 2, -1.0
|
||||
*END STEP
|
||||
@@ -0,0 +1,31 @@
|
||||
*PART, NAME=BeamPart
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
2, 1.0, 0.0, 0.0
|
||||
*ELEMENT, TYPE=B31, ELSET=Beam
|
||||
1, 1, 2
|
||||
*ELSET, ELSET=Beam
|
||||
1
|
||||
*BEAM GENERAL SECTION, SECTION=GENERAL, ELSET=Beam, MATERIAL=Steel
|
||||
1.0, 1.0, 0.0, 1.0, 1.0
|
||||
0.0, 1.0, 0.0
|
||||
*END PART
|
||||
*ASSEMBLY, NAME=RootAssembly
|
||||
*INSTANCE, NAME=Beam-1, PART=BeamPart
|
||||
*END INSTANCE
|
||||
*NSET, NSET=Fixed, INSTANCE=Beam-1
|
||||
1
|
||||
*NSET, NSET=Tip, INSTANCE=Beam-1
|
||||
2
|
||||
*END ASSEMBLY
|
||||
*MATERIAL, NAME=Steel
|
||||
*ELASTIC
|
||||
200.0, 0.25
|
||||
*STEP, NAME=Load, NLGEOM=NO
|
||||
*STATIC
|
||||
1.0, 1.0, 0.01, 1.0
|
||||
*BOUNDARY
|
||||
Fixed, 1, 6
|
||||
*CLOAD
|
||||
Tip, 2, -1.0
|
||||
*END STEP
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
*HEADING
|
||||
FESA recognized no-op heading
|
||||
*PREPRINT, ECHO=NO, MODEL=NO, HISTORY=NO, CONTACT=NO
|
||||
*NODE
|
||||
1, 0.0, 0.0, 0.0
|
||||
2, 1.0, 0.0, 0.0
|
||||
*ELEMENT, TYPE=B31, ELSET=Beam
|
||||
1, 1, 2
|
||||
*NSET, NSET=Fixed
|
||||
1
|
||||
*ELSET, ELSET=Beam
|
||||
1
|
||||
*MATERIAL, NAME=Steel
|
||||
*ELASTIC
|
||||
200.0, 0.25
|
||||
*BEAM GENERAL SECTION, SECTION=GENERAL, ELSET=Beam, MATERIAL=Steel
|
||||
1.0, 1.0, 0.0, 1.0, 1.0
|
||||
0.0, 1.0, 0.0
|
||||
*STEP
|
||||
*STATIC
|
||||
*BOUNDARY
|
||||
Fixed, 1, 6
|
||||
*CLOAD
|
||||
2, 2, -1.0
|
||||
*RESTART, WRITE, FREQUENCY=0
|
||||
*OUTPUT, FIELD, VARIABLE=PRESELECT
|
||||
*OUTPUT, HISTORY, VARIABLE=PRESELECT
|
||||
*END STEP
|
||||
@@ -0,0 +1,294 @@
|
||||
#include <fesa/io/abaqus/parser.hpp>
|
||||
#include <fesa/io/abaqus/semantic_mapper.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <optional>
|
||||
#include <ranges>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace {
|
||||
|
||||
struct ContractCase final {
|
||||
std::string id;
|
||||
bool valid;
|
||||
std::filesystem::path fixture;
|
||||
std::optional<fesa::DiagnosticStage> expected_stage;
|
||||
std::string expected_code;
|
||||
std::size_t expected_line;
|
||||
std::optional<std::size_t> node_count;
|
||||
std::optional<std::size_t> element_count;
|
||||
std::optional<std::size_t> node_set_count;
|
||||
std::optional<std::size_t> element_set_count;
|
||||
std::optional<std::size_t> prescribed_dof_count;
|
||||
std::optional<std::size_t> nodal_load_count;
|
||||
std::string shear_source;
|
||||
std::optional<double> shear_area_y;
|
||||
std::optional<double> shear_area_z;
|
||||
std::string checked_node_set;
|
||||
std::string checked_element_set;
|
||||
};
|
||||
|
||||
struct ContractOutcome final {
|
||||
std::optional<fesa::Domain> domain;
|
||||
std::vector<fesa::Diagnostic> diagnostics;
|
||||
};
|
||||
|
||||
std::vector<std::string> split(
|
||||
const std::string_view text,
|
||||
const char delimiter) {
|
||||
std::vector<std::string> fields;
|
||||
std::size_t first = 0;
|
||||
while (true) {
|
||||
const std::size_t next = text.find(delimiter, first);
|
||||
fields.emplace_back(
|
||||
text.substr(
|
||||
first,
|
||||
next == std::string_view::npos
|
||||
? std::string_view::npos
|
||||
: next - first));
|
||||
if (next == std::string_view::npos) {
|
||||
break;
|
||||
}
|
||||
first = next + 1U;
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
std::optional<std::size_t> optional_size(const std::string& field) {
|
||||
if (field == "-") {
|
||||
return std::nullopt;
|
||||
}
|
||||
return static_cast<std::size_t>(std::stoull(field));
|
||||
}
|
||||
|
||||
std::optional<double> optional_real(const std::string& field) {
|
||||
if (field == "-") {
|
||||
return std::nullopt;
|
||||
}
|
||||
return std::stod(field);
|
||||
}
|
||||
|
||||
std::optional<fesa::DiagnosticStage> optional_stage(
|
||||
const std::string& field) {
|
||||
if (field == "-") {
|
||||
return std::nullopt;
|
||||
}
|
||||
if (field == "io") {
|
||||
return fesa::DiagnosticStage::io;
|
||||
}
|
||||
if (field == "syntax") {
|
||||
return fesa::DiagnosticStage::syntax;
|
||||
}
|
||||
if (field == "semantic") {
|
||||
return fesa::DiagnosticStage::semantic;
|
||||
}
|
||||
if (field == "model") {
|
||||
return fesa::DiagnosticStage::model;
|
||||
}
|
||||
throw std::runtime_error{"Unknown diagnostic stage in contract manifest."};
|
||||
}
|
||||
|
||||
std::vector<ContractCase> load_contract_cases() {
|
||||
const std::filesystem::path path =
|
||||
std::filesystem::path{FESA_TEST_SOURCE_DIR} / "fixtures" / "abaqus" /
|
||||
"contract.tsv";
|
||||
std::ifstream input{path, std::ios::binary};
|
||||
if (!input) {
|
||||
throw std::runtime_error{"Unable to open Abaqus contract manifest."};
|
||||
}
|
||||
|
||||
std::vector<ContractCase> cases;
|
||||
std::string line;
|
||||
while (std::getline(input, line)) {
|
||||
if (line.empty() || line.front() == '#') {
|
||||
continue;
|
||||
}
|
||||
const std::vector<std::string> fields = split(line, '\t');
|
||||
if (fields.size() != 17U) {
|
||||
throw std::runtime_error{
|
||||
"Abaqus contract manifest row must contain 17 fields."};
|
||||
}
|
||||
const bool valid = fields[1] == "valid";
|
||||
if (!valid && fields[1] != "invalid") {
|
||||
throw std::runtime_error{
|
||||
"Abaqus contract outcome must be valid or invalid."};
|
||||
}
|
||||
cases.push_back({
|
||||
fields[0],
|
||||
valid,
|
||||
fields[2],
|
||||
optional_stage(fields[3]),
|
||||
fields[4] == "-" ? std::string{} : fields[4],
|
||||
static_cast<std::size_t>(std::stoull(fields[5])),
|
||||
optional_size(fields[6]),
|
||||
optional_size(fields[7]),
|
||||
optional_size(fields[8]),
|
||||
optional_size(fields[9]),
|
||||
optional_size(fields[10]),
|
||||
optional_size(fields[11]),
|
||||
fields[12],
|
||||
optional_real(fields[13]),
|
||||
optional_real(fields[14]),
|
||||
fields[15],
|
||||
fields[16],
|
||||
});
|
||||
}
|
||||
if (cases.empty()) {
|
||||
throw std::runtime_error{"Abaqus contract manifest is empty."};
|
||||
}
|
||||
return cases;
|
||||
}
|
||||
|
||||
ContractOutcome parse_and_map(const std::filesystem::path& path) {
|
||||
auto parsed = fesa::parse_deck(path);
|
||||
if (!parsed.deck.has_value()) {
|
||||
return {std::nullopt, std::move(parsed.diagnostics)};
|
||||
}
|
||||
auto mapped = fesa::map_deck_to_domain(*parsed.deck);
|
||||
return {std::move(mapped.domain), std::move(mapped.diagnostics)};
|
||||
}
|
||||
|
||||
std::string diagnostics_text(
|
||||
const std::vector<fesa::Diagnostic>& diagnostics) {
|
||||
std::ostringstream output;
|
||||
for (const auto& diagnostic : diagnostics) {
|
||||
output << diagnostic.code;
|
||||
if (diagnostic.source.has_value()) {
|
||||
output << '@' << diagnostic.source->line;
|
||||
}
|
||||
output << '\n';
|
||||
}
|
||||
return output.str();
|
||||
}
|
||||
|
||||
std::pair<std::string, std::vector<std::int64_t>> expected_set(
|
||||
const std::string& field) {
|
||||
const std::size_t colon = field.find(':');
|
||||
if (colon == std::string::npos) {
|
||||
throw std::runtime_error{"Set check must use name:label,... format."};
|
||||
}
|
||||
std::vector<std::int64_t> labels;
|
||||
for (const std::string& label :
|
||||
split(std::string_view{field}.substr(colon + 1U), ',')) {
|
||||
labels.push_back(std::stoll(label));
|
||||
}
|
||||
return {field.substr(0, colon), std::move(labels)};
|
||||
}
|
||||
|
||||
void expect_node_set(
|
||||
const fesa::Domain& domain,
|
||||
const std::string& field) {
|
||||
if (field == "-") {
|
||||
return;
|
||||
}
|
||||
const auto [name, expected_labels] = expected_set(field);
|
||||
const auto found = std::ranges::find(
|
||||
domain.node_sets(), name, &fesa::NodeSet::name);
|
||||
ASSERT_NE(found, domain.node_sets().end());
|
||||
|
||||
std::vector<std::int64_t> actual_labels;
|
||||
for (const fesa::NodeId member : found->members) {
|
||||
actual_labels.push_back(domain.node(member).origin.local_label);
|
||||
}
|
||||
std::ranges::sort(actual_labels);
|
||||
EXPECT_EQ(actual_labels, expected_labels);
|
||||
}
|
||||
|
||||
void expect_element_set(
|
||||
const fesa::Domain& domain,
|
||||
const std::string& field) {
|
||||
if (field == "-") {
|
||||
return;
|
||||
}
|
||||
const auto [name, expected_labels] = expected_set(field);
|
||||
const auto found = std::ranges::find(
|
||||
domain.element_sets(), name, &fesa::ElementSet::name);
|
||||
ASSERT_NE(found, domain.element_sets().end());
|
||||
|
||||
std::vector<std::int64_t> actual_labels;
|
||||
for (const fesa::ElementId member : found->members) {
|
||||
const auto element = std::ranges::find(
|
||||
domain.beam_elements(), member, &fesa::BeamElement::id);
|
||||
ASSERT_NE(element, domain.beam_elements().end());
|
||||
actual_labels.push_back(element->origin.local_label);
|
||||
}
|
||||
std::ranges::sort(actual_labels);
|
||||
EXPECT_EQ(actual_labels, expected_labels);
|
||||
}
|
||||
|
||||
class AbaqusInputContractTest
|
||||
: public testing::TestWithParam<ContractCase> {};
|
||||
|
||||
TEST_P(AbaqusInputContractTest, FixtureMatchesNormativeContract) {
|
||||
const ContractCase& contract = GetParam();
|
||||
const std::filesystem::path path =
|
||||
std::filesystem::path{FESA_TEST_SOURCE_DIR} / "fixtures" / "abaqus" /
|
||||
contract.fixture;
|
||||
SCOPED_TRACE(contract.id);
|
||||
ASSERT_TRUE(std::filesystem::is_regular_file(path));
|
||||
|
||||
const ContractOutcome outcome = parse_and_map(path);
|
||||
if (!contract.valid) {
|
||||
EXPECT_FALSE(outcome.domain.has_value());
|
||||
ASSERT_TRUE(contract.expected_stage.has_value());
|
||||
const auto diagnostic = std::ranges::find_if(
|
||||
outcome.diagnostics,
|
||||
[&contract](const fesa::Diagnostic& candidate) {
|
||||
return candidate.stage == *contract.expected_stage &&
|
||||
candidate.code == contract.expected_code &&
|
||||
candidate.source.has_value() &&
|
||||
candidate.source->line == contract.expected_line;
|
||||
});
|
||||
EXPECT_NE(diagnostic, outcome.diagnostics.end())
|
||||
<< "Expected " << contract.expected_code << '@'
|
||||
<< contract.expected_line << " but received:\n"
|
||||
<< diagnostics_text(outcome.diagnostics);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_TRUE(outcome.domain.has_value())
|
||||
<< diagnostics_text(outcome.diagnostics);
|
||||
ASSERT_TRUE(outcome.diagnostics.empty())
|
||||
<< diagnostics_text(outcome.diagnostics);
|
||||
const fesa::Domain& domain = *outcome.domain;
|
||||
EXPECT_EQ(domain.nodes().size(), *contract.node_count);
|
||||
EXPECT_EQ(domain.beam_elements().size(), *contract.element_count);
|
||||
EXPECT_EQ(domain.node_sets().size(), *contract.node_set_count);
|
||||
EXPECT_EQ(domain.element_sets().size(), *contract.element_set_count);
|
||||
EXPECT_EQ(
|
||||
domain.step().prescribed_dofs.size(),
|
||||
*contract.prescribed_dof_count);
|
||||
EXPECT_EQ(domain.step().nodal_loads.size(), *contract.nodal_load_count);
|
||||
|
||||
ASSERT_EQ(domain.sections().size(), 1U);
|
||||
const fesa::BeamSection& section = domain.sections().front();
|
||||
const auto expected_source = contract.shear_source == "input"
|
||||
? fesa::ShearPropertySource::input
|
||||
: fesa::ShearPropertySource::phase1_default;
|
||||
EXPECT_EQ(section.shear_source, expected_source);
|
||||
EXPECT_NEAR(section.shear_area_y, *contract.shear_area_y, 1.0e-12);
|
||||
EXPECT_NEAR(section.shear_area_z, *contract.shear_area_z, 1.0e-12);
|
||||
expect_node_set(domain, contract.checked_node_set);
|
||||
expect_element_set(domain, contract.checked_element_set);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
AbaqusInputContract,
|
||||
AbaqusInputContractTest,
|
||||
testing::ValuesIn(load_contract_cases()),
|
||||
[](const testing::TestParamInfo<ContractCase>& info) {
|
||||
return info.param.id;
|
||||
});
|
||||
|
||||
} // namespace
|
||||
Reference in New Issue
Block a user