feat(abaqus-subset-completion): step 0 — abaqus-input-contract

This commit is contained in:
KOKO\Mimi
2026-08-01 02:24:24 +09:00
parent 18361e4eb2
commit 2b83b1128f
36 changed files with 938 additions and 1 deletions
+9
View File
@@ -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
)
+54
View File
@@ -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 - - - - - - - - - - -
1 # 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
2 node_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
3 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
4 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
5 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
6 material_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
7 elastic_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
8 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
9 boundary_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
10 cload_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
11 step_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
12 static_valid valid valid/flat_complete.inp - - 0 2 1 1 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
13 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
14 part_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
15 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
16 assembly_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
17 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
18 instance_valid valid valid/hierarchical_complete.inp - - 0 2 1 2 1 6 1 phase1_default 0.8333333333333334 0.8333333333333334 Fixed:1 Beam:1
19 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
20 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
21 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
22 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
23 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
24 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
25 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
26 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
27 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
28 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
29 node_duplicate_invalid invalid invalid/node_duplicate.inp semantic abaqus.semantic.duplicate_node_label 3 - - - - - - - - - - -
30 element_type_invalid invalid invalid/element_wrong_type.inp semantic abaqus.semantic.unsupported_element 4 - - - - - - - - - - -
31 part_unclosed_invalid invalid invalid/part_unclosed.inp syntax abaqus.syntax.unclosed_part 1 - - - - - - - - - - -
32 assembly_multiple_invalid invalid invalid/assembly_multiple.inp syntax abaqus.syntax.multiple_assemblies 3 - - - - - - - - - - -
33 instance_transform_invalid invalid invalid/instance_transform.inp semantic abaqus.semantic.instance_transform 5 - - - - - - - - - - -
34 instance_local_mesh_invalid invalid invalid/instance_local_mesh.inp syntax abaqus.syntax.instance_local_keyword 5 - - - - - - - - - - -
35 mixed_mesh_invalid invalid invalid/mixed_mesh.inp semantic abaqus.semantic.mixed_mesh_organization 1 - - - - - - - - - - -
36 nset_parameter_invalid invalid invalid/nset_missing_name.inp semantic abaqus.semantic.missing_parameter 1 - - - - - - - - - - -
37 elset_generate_invalid invalid invalid/elset_invalid_generate.inp semantic abaqus.semantic.invalid_generate 2 - - - - - - - - - - -
38 nested_set_cycle_invalid invalid invalid/nested_set_cycle.inp semantic abaqus.semantic.set_cycle 4 - - - - - - - - - - -
39 set_instance_invalid invalid invalid/assembly_set_wrong_instance.inp semantic abaqus.semantic.wrong_instance 6 - - - - - - - - - - -
40 material_missing_elastic_invalid invalid invalid/material_missing_elastic.inp semantic abaqus.semantic.missing_elastic 1 - - - - - - - - - - -
41 elastic_data_invalid invalid invalid/elastic_invalid_data.inp semantic abaqus.semantic.invalid_elastic_data 3 - - - - - - - - - - -
42 section_type_invalid invalid invalid/section_wrong_type.inp semantic abaqus.semantic.unsupported_section 4 - - - - - - - - - - -
43 section_duplicate_invalid invalid invalid/section_duplicate_assignment.inp semantic abaqus.semantic.duplicate_section_assignment 7 - - - - - - - - - - -
44 transverse_scf_invalid invalid invalid/transverse_nonzero_scf.inp semantic abaqus.semantic.nonzero_scf 8 - - - - - - - - - - -
45 boundary_conflict_invalid invalid invalid/boundary_conflict.inp semantic abaqus.semantic.conflicting_boundary 10 - - - - - - - - - - -
46 cload_dof_invalid invalid invalid/cload_invalid_dof.inp semantic abaqus.semantic.invalid_dof 6 - - - - - - - - - - -
47 step_multiple_invalid invalid invalid/step_multiple.inp semantic abaqus.semantic.step_count 4 - - - - - - - - - - -
48 static_data_invalid invalid invalid/static_invalid_data.inp semantic abaqus.semantic.invalid_static_data 3 - - - - - - - - - - -
49 end_step_missing_invalid invalid invalid/end_step_missing.inp syntax abaqus.syntax.unclosed_step 1 - - - - - - - - - - -
50 heading_parameter_invalid invalid invalid/heading_invalid_parameter.inp syntax abaqus.syntax.unsupported_parameter 1 - - - - - - - - - - -
51 preprint_parameter_invalid invalid invalid/preprint_invalid_parameter.inp syntax abaqus.syntax.unsupported_parameter 1 - - - - - - - - - - -
52 restart_scope_invalid invalid invalid/restart_outside_step.inp syntax abaqus.syntax.invalid_restart_scope 1 - - - - - - - - - - -
53 output_parameter_invalid invalid invalid/output_invalid_parameter.inp syntax abaqus.syntax.unsupported_parameter 3 - - - - - - - - - - -
54 unknown_keyword_invalid invalid invalid/unknown_include.inp syntax abaqus.unsupported_keyword 1 - - - - - - - - - - -
+4
View File
@@ -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
+11
View File
@@ -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
+7
View File
@@ -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
+8
View File
@@ -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
+2
View File
@@ -0,0 +1,2 @@
*STEP
*STATIC
@@ -0,0 +1 @@
*HEADING, NAME=Unsupported
+8
View File
@@ -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
+7
View File
@@ -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
+8
View File
@@ -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
+7
View File
@@ -0,0 +1,7 @@
*NSET, NSET=First
Second
*NSET, NSET=Second
First
*STEP
*STATIC
*END STEP
+6
View File
@@ -0,0 +1,6 @@
*NODE
1, 0.0, 0.0, 0.0
1, 1.0, 0.0, 0.0
*STEP
*STATIC
*END STEP
+5
View File
@@ -0,0 +1,5 @@
*NSET
1
*STEP
*STATIC
*END STEP
@@ -0,0 +1,4 @@
*STEP
*STATIC
*OUTPUT, FIELD, VARIABLE=ALL
*END STEP
+3
View File
@@ -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
+9
View File
@@ -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
+4
View File
@@ -0,0 +1,4 @@
*STEP
*STATIC
1.0, -1.0
*END STEP
+6
View File
@@ -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
+1
View File
@@ -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
View File
@@ -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
+28
View File
@@ -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
+31
View File
@@ -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
View File
@@ -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