Coverage for src/meshpy/four_c/header_functions.py: 89%

92 statements  

« prev     ^ index     » next       coverage.py v7.8.0, created at 2025-04-28 04:21 +0000

1# The MIT License (MIT) 

2# 

3# Copyright (c) 2018-2025 MeshPy Authors 

4# 

5# Permission is hereby granted, free of charge, to any person obtaining a copy 

6# of this software and associated documentation files (the "Software"), to deal 

7# in the Software without restriction, including without limitation the rights 

8# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 

9# copies of the Software, and to permit persons to whom the Software is 

10# furnished to do so, subject to the following conditions: 

11# 

12# The above copyright notice and this permission notice shall be included in 

13# all copies or substantial portions of the Software. 

14# 

15# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 

16# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 

17# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 

18# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 

19# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 

20# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 

21# THE SOFTWARE. 

22"""This module defines functions that can be used to add header information to 

23an input file.""" 

24 

25from typing import List as _List 

26from typing import Union as _Union 

27 

28from meshpy.core.conf import mpy as _mpy 

29from meshpy.four_c.input_file import InputFile as _InputFile 

30 

31 

32def _get_segmentation_strategy(segmentation): 

33 """Get the 4C string for a geometry pair strategy.""" 

34 if segmentation: 

35 return "segmentation" 

36 else: 

37 return "gauss_point_projection_without_boundary_segmentation" 

38 

39 

40def set_runtime_output( 

41 input_file, 

42 *, 

43 output_solid=True, 

44 output_stress_strain=False, 

45 btsvmt_output=True, 

46 btss_output=True, 

47 output_triad=True, 

48 every_iteration=False, 

49 absolute_beam_positions=True, 

50 element_owner=True, 

51 element_gid=True, 

52 element_mat_id=True, 

53 output_energy=False, 

54 output_strains=True, 

55 option_overwrite=False, 

56): 

57 """Set the basic runtime output options. 

58 

59 Args 

60 ---- 

61 input_file: 

62 Input file that the options will be added to. 

63 output_solid: bool 

64 If the solid output should be written at runtime. 

65 output_stress_strain: bool 

66 If stress and strain output should be written for the solid. 

67 btsvmt_output: bool 

68 If the output for btsvmt should be written. 

69 btss_output: bool 

70 If the output for beam-to-surface coupling should be written. 

71 output_triad: bool 

72 If the triads along the beam should be written. 

73 every_iteration: int 

74 If output at every Newton iteration should be written. 

75 absolute_beam_positions: bool 

76 If the beams should be written at the current position or always at 

77 the reference position. 

78 element_owner: bool 

79 If the owing rank of each element should be output (currently 

80 only affects the solid elements in 4C, beam element owners are 

81 written by default). 

82 element_gid: bool 

83 If the 4C internal GID of each element should be output. 

84 element_mat_id: bool 

85 If the 4C internal material ID of each element should be output. 

86 output_energy: bool 

87 If the energy output from 4C should be activated. 

88 output_strains: bool 

89 If the strains in the Gauss points should be output. 

90 option_overwrite: bool 

91 If existing options should be overwritten. If this is false and an 

92 option is already defined, and error will be thrown. 

93 """ 

94 

95 # Set the basic runtime output options. 

96 input_file.add( 

97 { 

98 "IO/RUNTIME VTK OUTPUT": { 

99 "OUTPUT_DATA_FORMAT": "binary", 

100 "INTERVAL_STEPS": 1, 

101 "EVERY_ITERATION": every_iteration, 

102 } 

103 }, 

104 option_overwrite=option_overwrite, 

105 ) 

106 

107 # Set the structure runtime output options 

108 input_file.add( 

109 { 

110 "IO/RUNTIME VTK OUTPUT/STRUCTURE": { 

111 "OUTPUT_STRUCTURE": output_solid, 

112 "DISPLACEMENT": True, 

113 "STRESS_STRAIN": output_stress_strain, 

114 "ELEMENT_OWNER": element_owner, 

115 "ELEMENT_GID": element_gid, 

116 "ELEMENT_MAT_ID": element_mat_id, 

117 } 

118 }, 

119 option_overwrite=option_overwrite, 

120 ) 

121 

122 # Set the beam runtime output options 

123 input_file.add( 

124 { 

125 "IO/RUNTIME VTK OUTPUT/BEAMS": { 

126 "OUTPUT_BEAMS": True, 

127 "DISPLACEMENT": True, 

128 "USE_ABSOLUTE_POSITIONS": absolute_beam_positions, 

129 "TRIAD_VISUALIZATIONPOINT": output_triad, 

130 "STRAINS_GAUSSPOINT": output_strains, 

131 "ELEMENT_GID": element_gid, 

132 } 

133 }, 

134 option_overwrite=option_overwrite, 

135 ) 

136 

137 if btsvmt_output: 

138 # Set the beam to solid volume mesh tying runtime output options. 

139 input_file.add( 

140 { 

141 "BEAM INTERACTION/BEAM TO SOLID VOLUME MESHTYING/RUNTIME VTK OUTPUT": { 

142 "WRITE_OUTPUT": True, 

143 "NODAL_FORCES": True, 

144 "MORTAR_LAMBDA_DISCRET": True, 

145 "MORTAR_LAMBDA_CONTINUOUS": True, 

146 "MORTAR_LAMBDA_CONTINUOUS_SEGMENTS": 5, 

147 "SEGMENTATION": True, 

148 "INTEGRATION_POINTS": True, 

149 } 

150 }, 

151 option_overwrite=option_overwrite, 

152 ) 

153 

154 if btss_output: 

155 # Set the beam to solid surface coupling runtime output options. 

156 input_file.add( 

157 { 

158 "BEAM INTERACTION/BEAM TO SOLID SURFACE/RUNTIME VTK OUTPUT": { 

159 "WRITE_OUTPUT": True, 

160 "NODAL_FORCES": True, 

161 "MORTAR_LAMBDA_DISCRET": True, 

162 "MORTAR_LAMBDA_CONTINUOUS": True, 

163 "MORTAR_LAMBDA_CONTINUOUS_SEGMENTS": 5, 

164 "SEGMENTATION": True, 

165 "INTEGRATION_POINTS": True, 

166 "AVERAGED_NORMALS": True, 

167 } 

168 }, 

169 option_overwrite=option_overwrite, 

170 ) 

171 

172 if output_energy: 

173 input_file.add( 

174 { 

175 "STRUCTURAL DYNAMIC": { 

176 "RESEVERYERGY": 1, 

177 } 

178 }, 

179 option_overwrite=option_overwrite, 

180 ) 

181 

182 

183def set_beam_to_solid_meshtying( 

184 input_file, 

185 interaction_type, 

186 *, 

187 contact_discretization=None, 

188 segmentation=True, 

189 segmentation_search_points=2, 

190 couple_restart=False, 

191 mortar_shape="none", 

192 n_gauss_points=6, 

193 n_integration_points_circ=None, 

194 penalty_parameter=None, 

195 coupling_type=None, 

196 binning_parameters: dict = {}, 

197 option_overwrite=False, 

198): 

199 """Set the beam to solid meshtying options. 

200 

201 Args 

202 ---- 

203 input_file: 

204 Input file that the options will be added to. 

205 interaction_type: BeamToSolidInteractionType 

206 Type of beam-to-solid interaction. 

207 contact_discretization: str 

208 Type of contact (mortar, Gauss point, ...) 

209 segmentation: bool 

210 If segmentation should be used in the numerical integration. 

211 segmentation_search_points: int 

212 Number of search points for segmentation. 

213 couple_restart: bool 

214 If the restart configuration should be used for the coupling 

215 mortar_shape: str 

216 Type of shape function for mortar discretization. 

217 n_gauss_points: int 

218 Number of Gauss points for numerical integration. 

219 n_integration_points_circ: int 

220 Number of integration points along the circumference of the cross 

221 section. 

222 penalty_parameter: float 

223 Penalty parameter for contact enforcement. 

224 coupling_type: str 

225 Type of coupling for beam-to-surface coupling. 

226 binning_parameters: 

227 Keyword parameters for the binning section 

228 option_overwrite: bool 

229 If existing options should be overwritten. If this is false and an 

230 option is already defined, and error will be thrown. 

231 """ 

232 

233 # Set the beam contact options. 

234 input_file.add( 

235 {"BEAM INTERACTION": {"REPARTITIONSTRATEGY": "everydt"}}, option_overwrite=True 

236 ) 

237 input_file.add( 

238 {"BEAM CONTACT": {"MODELEVALUATOR": "Standard"}}, option_overwrite=True 

239 ) 

240 

241 set_binning_strategy_section( 

242 input_file, 

243 option_overwrite=option_overwrite, 

244 **binning_parameters, 

245 ) 

246 

247 # Add the beam to solid volume mesh tying options. 

248 bts_parameters = {} 

249 if interaction_type == _mpy.beam_to_solid.volume_meshtying: 

250 bts_section_name = "BEAM INTERACTION/BEAM TO SOLID VOLUME MESHTYING" 

251 elif interaction_type == _mpy.beam_to_solid.surface_meshtying: 

252 bts_section_name = "BEAM INTERACTION/BEAM TO SOLID SURFACE MESHTYING" 

253 if coupling_type is not None: 

254 bts_parameters["COUPLING_TYPE"] = coupling_type 

255 else: 

256 raise ValueError( 

257 "Got wrong beam-to-solid mesh tying type. " 

258 f"Got {interaction_type} of type {type(interaction_type)}." 

259 ) 

260 bts_parameters["CONSTRAINT_STRATEGY"] = "penalty" 

261 if penalty_parameter is not None: 

262 bts_parameters["PENALTY_PARAMETER"] = penalty_parameter 

263 bts_parameters["GAUSS_POINTS"] = n_gauss_points 

264 

265 if contact_discretization == "mortar": 

266 bts_parameters["CONTACT_DISCRETIZATION"] = "mortar" 

267 bts_parameters["MORTAR_SHAPE_FUNCTION"] = mortar_shape 

268 segmentation_strategy = _get_segmentation_strategy(segmentation) 

269 elif contact_discretization == "gp": 

270 bts_parameters["CONTACT_DISCRETIZATION"] = "gauss_point_to_segment" 

271 segmentation_strategy = _get_segmentation_strategy(segmentation) 

272 elif contact_discretization == "circ": 

273 bts_parameters["CONTACT_DISCRETIZATION"] = "gauss_point_cross_section" 

274 bts_parameters["INTEGRATION_POINTS_CIRCUMFERENCE"] = n_integration_points_circ 

275 segmentation_strategy = "gauss_point_projection_cross_section" 

276 else: 

277 raise ValueError( 

278 f'Wrong contact_discretization "{contact_discretization}" given!' 

279 ) 

280 

281 bts_parameters["GEOMETRY_PAIR_STRATEGY"] = segmentation_strategy 

282 bts_parameters["GEOMETRY_PAIR_SEGMENTATION_SEARCH_POINTS"] = ( 

283 segmentation_search_points 

284 ) 

285 if interaction_type == _mpy.beam_to_solid.volume_meshtying: 

286 bts_parameters["COUPLE_RESTART_STATE"] = couple_restart 

287 

288 input_file.add( 

289 {bts_section_name: bts_parameters}, option_overwrite=option_overwrite 

290 ) 

291 

292 

293def set_header_static( 

294 input_file, 

295 *, 

296 time_step=None, 

297 n_steps=None, 

298 total_time=None, 

299 max_iter=20, 

300 tol_residuum=1e-8, 

301 tol_increment=1e-10, 

302 load_lin=False, 

303 write_bin=False, 

304 write_stress="no", 

305 write_strain="no", 

306 prestress="None", 

307 prestress_time=0, 

308 option_overwrite=False, 

309): 

310 """Set the default parameters for a static structure analysis. 

311 

312 At least two of the three time stepping keyword arguments ["time_step", 

313 "n_steps", "total_time"] have to be set. 

314 

315 Args 

316 ---- 

317 input_file: 

318 Input file that the options will be added to. 

319 time_step: float 

320 Time increment per step. 

321 n_steps: int 

322 Number of time steps. 

323 total_time: float 

324 Total time of simulation 

325 max_iter: int 

326 Maximal number of Newton iterations. 

327 tol_residuum: float 

328 Tolerance for the convergence of the residuum. 

329 tol_increment: int 

330 Tolerance for the convergence of the displacement increment. 

331 load_lin: bool 

332 If the load_lin option should be set. 

333 write_bin: bool 

334 If binary output should be written. 

335 write_stress: string 

336 If and which stress output to write 

337 write_strain: string 

338 If and which strain output to write 

339 prestress: string 

340 Type of prestressing strategy to be used 

341 presetrss_time: int 

342 Prestress Time 

343 option_overwrite: bool 

344 If existing options should be overwritten. If this is false and an 

345 option is already defined, and error will be thrown. 

346 """ 

347 

348 # Set the parameters for a static analysis. 

349 input_file.add( 

350 { 

351 "PROBLEM TYPE": { 

352 "PROBLEMTYPE": "Structure", 

353 } 

354 }, 

355 option_overwrite=option_overwrite, 

356 ) 

357 

358 input_file.add( 

359 { 

360 "IO": { 

361 "OUTPUT_BIN": write_bin, 

362 "STRUCT_DISP": False, 

363 "STRUCT_STRESS": write_stress, 

364 "STRUCT_STRAIN": write_strain, 

365 "VERBOSITY": "Standard", 

366 } 

367 }, 

368 option_overwrite=option_overwrite, 

369 ) 

370 

371 # Set the time step parameters 

372 given_time_arguments = sum( 

373 1 for arg in (time_step, n_steps, total_time) if arg is not None 

374 ) 

375 if given_time_arguments < 2: 

376 raise ValueError( 

377 'At least two of the following arguments "time_step", "n_steps" or ' 

378 '"total_time" are required' 

379 ) 

380 if time_step is None: 

381 time_step = total_time / n_steps 

382 elif n_steps is None: 

383 n_steps = round(total_time / time_step) 

384 elif total_time is None: 

385 total_time = time_step * n_steps 

386 

387 input_file.add( 

388 { 

389 "STRUCTURAL DYNAMIC": { 

390 "LINEAR_SOLVER": 1, 

391 "INT_STRATEGY": "Standard", 

392 "DYNAMICTYPE": "Statics", 

393 "PREDICT": "TangDis", 

394 "PRESTRESS": prestress, 

395 "PRESTRESSTIME": prestress_time, 

396 "TIMESTEP": time_step, 

397 "NUMSTEP": n_steps, 

398 "MAXTIME": total_time, 

399 "LOADLIN": load_lin, 

400 } 

401 }, 

402 option_overwrite=option_overwrite, 

403 ) 

404 

405 input_file.add( 

406 { 

407 "SOLVER 1": { 

408 "NAME": "Structure_Solver", 

409 "SOLVER": "Superlu", 

410 } 

411 }, 

412 option_overwrite=option_overwrite, 

413 ) 

414 

415 # Set the contents of the NOX xml file. 

416 nox_xml = f""" 

417 <ParameterList name="Status Test"> 

418 <!-- Outer Status Test: This test is an OR combination of the structural convergence and the maximum number of iterations --> 

419 <ParameterList name="Outer Status Test"> 

420 <Parameter name="Test Type" type="string" value="Combo"/> 

421 <Parameter name="Combo Type" type="string" value="OR" /> 

422 <!-- Structural convergence is an AND combination of the residuum and step update --> 

423 <ParameterList name="Test 0"> 

424 <Parameter name="Test Type" type="string" value="Combo" /> 

425 <Parameter name="Combo Type" type="string" value="AND" /> 

426 <!-- BEGIN: Combo AND - Test 0: "NormF" --> 

427 <ParameterList name="Test 0"> 

428 <Parameter name="Test Type" type="string" value="NormF" /> 

429 <!-- NormF - Quantity 0: Check the right-hand-side norm of the structural quantities --> 

430 <ParameterList name="Quantity 0"> 

431 <Parameter name="Quantity Type" type="string" value="Structure" /> 

432 <Parameter name="Tolerance Type" type="string" value="Absolute" /> 

433 <Parameter name="Tolerance" type="double" value="{tol_residuum}" /> 

434 <Parameter name="Norm Type" type="string" value="Two Norm" /> 

435 <Parameter name="Scale Type" type="string" value="Scaled" /> 

436 </ParameterList> 

437 </ParameterList> 

438 <!-- END: Combo AND - Test 0: "NormF" --> 

439 <!-- BEGIN: Combo AND - Test 1: "NormWRMS" --> 

440 <ParameterList name="Test 1"> 

441 <Parameter name="Test Type" type="string" value="NormUpdate" /> 

442 <!-- NormWRMS - Quantity 0: Check the increment of the structural displacements --> 

443 <ParameterList name="Quantity 0"> 

444 <Parameter name="Quantity Type" type="string" value="Structure" /> 

445 <Parameter name="Tolerance Type" type="string" value="Absolute" /> 

446 <Parameter name="Tolerance" type="double" value="{tol_increment}" /> 

447 <Parameter name="Norm Type" type="string" value="Two Norm" /> 

448 <Parameter name="Scale Type" type="string" value="Scaled" /> 

449 </ParameterList> 

450 </ParameterList> 

451 <!-- END: Combo AND - Test 1: "NormWRMS" --> 

452 </ParameterList> 

453 <!-- END: Combo 0 - Test 0: "Combo" --> 

454 <!-- BEGIN: Combo OR - Test 1: "MaxIters" --> 

455 <ParameterList name="Test 1"> 

456 <Parameter name="Test Type" type="string" value="MaxIters" /> 

457 <Parameter name="Maximum Iterations" type="int" value="{max_iter}" /> 

458 </ParameterList> <!--END: "MaxIters" --> 

459 </ParameterList> 

460 </ParameterList> 

461 """ 

462 

463 input_file.add( 

464 { 

465 "STRUCT NOX/Printing": { 

466 "Error": True, 

467 "Inner Iteration": False, 

468 "Details": True, 

469 "Linear Solver Details": True, 

470 "Test Details": True, 

471 } 

472 }, 

473 option_overwrite=option_overwrite, 

474 ) 

475 

476 # Set the xml content in the input file. 

477 input_file.nox_xml = nox_xml 

478 

479 

480def set_binning_strategy_section( 

481 input_file: _InputFile, 

482 binning_bounding_box: _Union[_List[int], None] = None, 

483 binning_cutoff_radius: _Union[float, None] = None, 

484 *, 

485 option_overwrite: bool = False, 

486): 

487 """Set binning strategy in section of the input file. 

488 

489 Args 

490 ---- 

491 input_file: 

492 Input file that the options will be added to. 

493 binning_bounding_box: 

494 List with the limits of the bounding box. 

495 binning_cutoff_radius: 

496 Maximal influence radius of pair elements. 

497 option_overwrite: 

498 If existing options should be overwritten. If this is false and an 

499 option is already defined, and error will be thrown. 

500 """ 

501 

502 if binning_bounding_box is not None and binning_cutoff_radius is not None: 

503 binning_bounding_box_string = " ".join( 

504 [str(val) for val in binning_bounding_box] 

505 ) 

506 

507 input_file.add( 

508 { 

509 "BINNING STRATEGY": { 

510 "BIN_SIZE_LOWER_BOUND": binning_cutoff_radius, 

511 "DOMAINBOUNDINGBOX": binning_bounding_box_string, 

512 } 

513 }, 

514 option_overwrite=option_overwrite, 

515 ) 

516 elif [binning_bounding_box, binning_cutoff_radius].count(None) == 2: 

517 return 

518 else: 

519 raise ValueError( 

520 f"The variables binning_bounding_box {binning_bounding_box} and binning_cutoff_radius {binning_cutoff_radius} must both be set." 

521 ) 

522 

523 

524def set_beam_interaction_section( 

525 input_file: _InputFile, 

526 *, 

527 repartition_strategy: str = "everydt", 

528 search_strategy: str = "bounding_volume_hierarchy", 

529 option_overwrite: bool = False, 

530): 

531 """Set beam interaction section in input file. 

532 

533 Args 

534 ---- 

535 input_file: 

536 Input file that the options will be added to. 

537 repartition_strategy: 

538 Type of employed repartitioning strategy 

539 Options: "adaptive" or "everydt" 

540 search_strategy: 

541 Type of search strategy used for finding coupling pairs. 

542 Options: "bruteforce_with_binning", "bounding_volume_hierarchy" 

543 option_overwrite: 

544 If existing options should be overwritten. If this is false and an 

545 option is already defined, and error will be thrown. 

546 """ 

547 

548 input_file.add( 

549 { 

550 "BEAM INTERACTION": { 

551 "REPARTITIONSTRATEGY": repartition_strategy, 

552 "SEARCH_STRATEGY": search_strategy, 

553 } 

554 }, 

555 option_overwrite=option_overwrite, 

556 ) 

557 

558 

559def set_beam_contact_runtime_output( 

560 input_file: _InputFile, 

561 *, 

562 every_iteration: bool = False, 

563 option_overwrite: bool = False, 

564): 

565 """Output the beam-to-beam contact forces and gaps with runtime output. 

566 

567 input_file: 

568 Input file that the options will be added to. 

569 every_iteration: 

570 If output at every Newton iteration should be written. 

571 option_overwrite: 

572 If existing options should be overwritten. If this is false and an 

573 option is already defined, and error will be thrown. 

574 """ 

575 

576 input_file.add( 

577 { 

578 "BEAM CONTACT/RUNTIME VTK OUTPUT": { 

579 "VTK_OUTPUT_BEAM_CONTACT": True, 

580 "EVERY_ITERATION": every_iteration, 

581 "INTERVAL_STEPS": 1, 

582 "CONTACT_FORCES": True, 

583 "GAPS": True, 

584 } 

585 }, 

586 option_overwrite=option_overwrite, 

587 ) 

588 

589 

590def set_beam_contact_section( 

591 input_file: _InputFile, 

592 *, 

593 interaction_strategy: str = "penalty", 

594 btb_penalty: float = 0, 

595 btb_line_penalty: float = 0, 

596 per_shift_angle: list[float] = [70, 80], 

597 par_shift_angle: list[float] = [70, 80], 

598 b_seg_angle: float = 12, 

599 num_integration: int = 5, 

600 penalty_law: str = "LinPosQuadPen", 

601 penalty_regularization_g0: float = 0, 

602 penalty_regularization_f0: float = 0, 

603 penalty_regularization_c0: float = 0, 

604 binning_parameters: dict = {}, 

605 beam_interaction_parameters: dict = {}, 

606 option_overwrite: bool = False, 

607): 

608 """Set default beam contact section, for more and updated details see 

609 respective input file within 4C. Parameters for set_binning_strategy and 

610 set_beam_interaction may be forwarded as keyword arguments. 

611 

612 Args 

613 ---- 

614 input_file: 

615 Input file that the options will be added to. 

616 interaction_strategy: 

617 Type of employed solving strategy 

618 Options: "none", "penalty" or "gmshonly" 

619 btb_penalty: double 

620 Penalty parameter for beam-to-beam point contact 

621 btb_line_penalty: 

622 Penalty parameter per unit length for beam-to-beam line contact 

623 per_shift_angle: 

624 Lower and upper shift angle (in degrees) for penalty scaling of large-angle-contact 

625 par_shift_angle: 

626 Lower and upper shift angle (in degrees) for penalty scaling of small-angle-contact 

627 b_seg_angle: 

628 Maximal angle deviation allowed for contact search segmentation 

629 num_integration: 

630 Number of integration intervals per element 

631 option_overwrite: bool 

632 If existing options should be overwritten. If this is false and an 

633 option is already defined, and error will be thrown. 

634 penalty_law: 

635 Penalty Law Options: "LinPen", "QuadPen", "LinNegQuadPen", "LinPosQuadPen", "LinPosCubPen", "LinPosDoubleQuadPen", "LinPosExpPen" 

636 penalty_regularization_g0: 

637 First penalty regularization parameter G0 

638 penalty_regularization_f0: 

639 Second penalty regularization parameter F0 

640 penalty_regularization_c0: 

641 Third penalty regularization parameter C0 

642 binning_parameters: 

643 Keyword parameters for the binning section 

644 beam_interaction_parameters: 

645 Keyword parameters for the beam-contact section 

646 """ 

647 

648 if len(per_shift_angle) != 2: 

649 raise ValueError( 

650 "Please provide lower and upper value of BEAMS_PERPSHIFTANGLE." 

651 ) 

652 

653 if len(par_shift_angle) != 2: 

654 raise ValueError("Please provide lower and upper value of BEAMS_PARSHIFTANGLE.") 

655 

656 input_file.add( 

657 { 

658 "BEAM INTERACTION/BEAM TO BEAM CONTACT": { 

659 "STRATEGY": interaction_strategy, 

660 } 

661 }, 

662 option_overwrite=option_overwrite, 

663 ) 

664 

665 input_file.add( 

666 { 

667 "BEAM CONTACT": { 

668 "MODELEVALUATOR": "standard", 

669 "BEAMS_STRATEGY": "penalty", 

670 "BEAMS_BTBPENALTYPARAM": btb_penalty, 

671 "BEAMS_BTBLINEPENALTYPARAM": btb_line_penalty, 

672 "BEAMS_SEGCON": True, 

673 "BEAMS_PERPSHIFTANGLE1": per_shift_angle[0], 

674 "BEAMS_PERPSHIFTANGLE2": per_shift_angle[1], 

675 "BEAMS_PARSHIFTANGLE1": par_shift_angle[0], 

676 "BEAMS_PARSHIFTANGLE2": par_shift_angle[1], 

677 "BEAMS_SEGANGLE": b_seg_angle, 

678 "BEAMS_NUMINTEGRATIONINTERVAL": num_integration, 

679 "BEAMS_PENALTYLAW": penalty_law, 

680 "BEAMS_PENREGPARAM_G0": penalty_regularization_g0, 

681 "BEAMS_PENREGPARAM_F0": penalty_regularization_f0, 

682 "BEAMS_PENREGPARAM_C0": penalty_regularization_c0, 

683 "BEAMS_MAXDELTADISSCALEFAC": -1.0, 

684 } 

685 }, 

686 option_overwrite=option_overwrite, 

687 ) 

688 

689 # beam contact needs a binning strategy 

690 set_binning_strategy_section( 

691 input_file, option_overwrite=option_overwrite, **binning_parameters 

692 ) 

693 

694 # beam contact needs interaction strategy 

695 set_beam_interaction_section( 

696 input_file, option_overwrite=option_overwrite, **beam_interaction_parameters 

697 ) 

698 

699 

700def add_result_description( 

701 input_file: _InputFile, 

702 displacements: _List, 

703 node_ids: _List[int], 

704 *, 

705 tol: float = 1e-10, 

706): 

707 """Add result descriptions for structure problems to the input file. 

708 

709 Args: 

710 input_file: Input file to add the result description to 

711 displacements: Array with the displacements (n_nodes x 3) 

712 node_ids: List with the IDs of the nodes to check 

713 tol: Tolerance 

714 """ 

715 for i_node, node in enumerate(node_ids): 

716 for i_dir, direction in enumerate(["x", "y", "z"]): 

717 input_file.add( 

718 { 

719 "RESULT DESCRIPTION": [ 

720 { 

721 "STRUCTURE": { 

722 "DIS": "structure", 

723 "NODE": node, 

724 "QUANTITY": f"disp{direction}", 

725 "VALUE": displacements[i_node][i_dir], 

726 "TOLERANCE": tol, 

727 }, 

728 } 

729 ] 

730 } 

731 )