Coverage for src/beamme/four_c/beam_interaction_conditions.py: 96%

27 statements  

« prev     ^ index     » next       coverage.py v7.15.2, created at 2026-07-28 15:20 +0000

1# The MIT License (MIT) 

2# 

3# Copyright (c) 2018-2026 BeamMe 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 file contains a function to add the beam interaction conditions for 4C.""" 

23 

24import beamme.core.conf as _conf 

25from beamme.core.boundary_condition import BoundaryCondition as _BoundaryCondition 

26from beamme.core.geometry_set import GeometrySet as _GeometrySet 

27from beamme.core.mesh import Mesh as _Mesh 

28 

29 

30def get_next_possible_id_for_boundary_condition( 

31 mesh: _Mesh, 

32 bc_type: _conf.BoundaryCondition, 

33 geometry_type: _conf.Geometry, 

34 condition_string: str, 

35) -> int: 

36 """Returns the next possible id, which can be used for a boundary condition based on 

37 all previous added boundary conditions within a mesh. 

38 

39 It returns the first ID which is not yet occupied within the existing boundary conditions 

40 w.r.t. to the given search_string and regex group index. 

41 

42 Args: 

43 mesh: Mesh containing already set boundary conditions. 

44 bc_type: Type of the boundary condition to be searched. 

45 geometry_type: Geometry type of the boundary condition. 

46 condition_string: String defining the condition ID tag. 

47 

48 Returns: 

49 id: Smallest available ID 

50 """ 

51 found_conditions = [] 

52 

53 # loop through every possible geometry and find the conditions 

54 if (bc_type, geometry_type) in mesh.boundary_conditions: 

55 for bc_condition in mesh.boundary_conditions[(bc_type, geometry_type)]: 

56 found_conditions.append(bc_condition) 

57 

58 if not found_conditions: 

59 # return starting id, since no conditions of type has been added. 

60 return 0 

61 else: 

62 existing_ids = [] 

63 

64 # compare string of each condition with input and store existing ids 

65 for bc in found_conditions: 

66 if condition_string in bc.data: 

67 existing_ids.append(bc.data[condition_string]) 

68 else: 

69 raise KeyError( 

70 f"The key {condition_string} is not in the data {bc.data}" 

71 ) 

72 

73 # return lowest found id 

74 return min(set(range(len(existing_ids) + 1)) - set(existing_ids)) 

75 

76 

77def add_beam_interaction_condition( 

78 mesh: _Mesh, 

79 geometry_set_1: _GeometrySet, 

80 geometry_set_2: _GeometrySet, 

81 bc_type: _conf.BoundaryCondition, 

82 *, 

83 id: int | None = None, 

84) -> int: 

85 """Adds a pair of beam interaction boundary conditions to the given mesh and 

86 estimates automatically the id of them based on all previously added boundary 

87 conditions of the mesh. 

88 

89 Args: 

90 mesh: Mesh to which the boundary conditions will be added. 

91 geometry_set_1: GeometrySet 1 for beam interaction boundary condition 

92 geometry_set_2: GeometrySet 2 for beam interaction boundary condition 

93 id: id of the two conditions 

94 

95 Returns: 

96 id: Used id for the created condition. 

97 """ 

98 condition_string = "COUPLING_ID" 

99 if id is None: 

100 id = get_next_possible_id_for_boundary_condition( 

101 mesh, 

102 bc_type, 

103 geometry_set_1.geometry_type, 

104 condition_string=condition_string, 

105 ) 

106 

107 id_2 = get_next_possible_id_for_boundary_condition( 

108 mesh, 

109 bc_type, 

110 geometry_set_2.geometry_type, 

111 condition_string=condition_string, 

112 ) 

113 

114 if not id == id_2: 

115 raise ValueError( 

116 f"The estimated IDs {id} and {id_2} do not match. Check Inputfile." 

117 ) 

118 

119 # Creates the two conditions with the same ID. 

120 for geometry_set in [geometry_set_1, geometry_set_2]: 

121 mesh.add( 

122 _BoundaryCondition( 

123 geometry_set, data={condition_string: id}, bc_type=bc_type 

124 ) 

125 ) 

126 

127 return id