Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerWorkflows/FreeCADBatchFEMTools/tests/cubemeshtest/cubemeshtest_freecadscript.py
3206 views
1
doc = App.newDocument('cube geometry')
2
import sys
3
import os
4
import time
5
import math
6
import FreeCAD
7
8
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..'))
9
import FreeCADBatchFEMTools
10
11
12
def cut_xy_plane(part, cut_len, cut_width, cut_height):
13
doc.recompute()
14
doc.recompute()
15
reduced_name = part.Name + '_xy'
16
tool_box = doc.addObject("Part::Box", "CutBox" + reduced_name + '_obj')
17
tool_box.Length = cut_len
18
tool_box.Width = cut_width
19
tool_box.Height = cut_height
20
c_x = part.Shape.BoundBox.Center.x
21
c_y = part.Shape.BoundBox.Center.y
22
tool_box.Placement = App.Placement(App.Vector(c_x-cut_len/2., c_y-cut_width/2., -cut_height),
23
App.Rotation(App.Vector(0, 0, 1), 0))
24
25
cut_part = doc.addObject("Part::Cut", reduced_name + '_obj')
26
cut_part.Base = part
27
cut_part.Tool = tool_box
28
return cut_part
29
30
def print_line(line_str, start_time):
31
"""
32
Prints elapsed time and flushes stdout.
33
34
:param line_str: A string.
35
:param start_time: A float.
36
"""
37
elapsed_time = round(time.time() - start_time, 1)
38
print('Elapsed time: {} seconds'.format(elapsed_time))
39
print(line_str)
40
sys.stdout.flush()
41
return elapsed_time
42
43
def create_air_geometry(entities_list, length, width, height, shift, mesh_size):
44
"""
45
Creates air around created parts in part_list.
46
47
:param entities_list: A list containing entities dicts.
48
:param length: A float.
49
:param width: A float.
50
:param height: A float.
51
:param shift: A float.
52
:param mesh_size: A float or None.
53
54
:return: Air part object.
55
"""
56
bounding_box_part = doc.addObject("Part::Box", "air_obj")
57
bounding_box_part.Length = length
58
bounding_box_part.Width = width
59
bounding_box_part.Height = height
60
bounding_box_part.Placement = App.Placement(App.Vector(-shift, -shift, 0),
61
App.Rotation(App.Vector(0, 0, 1), 0))
62
doc.recompute()
63
64
solid_objects = [bounding_box_part] + [solid['main object'] for solid in entities_list]
65
air_part = FreeCADBatchFEMTools.create_xor_object(solid_objects, doc)
66
doc.recompute()
67
# remove already created faces
68
faces_in_symmetry_plane = FreeCADBatchFEMTools.faces_with_vertices_in_symmetry_plane(air_part.Shape.Faces,
69
plane='xy')
70
used_faces = []
71
for part in entities_list:
72
used_faces.extend([face_entity['geometric object'] for face_entity in part['faces']])
73
FreeCADBatchFEMTools.remove_compare_faces_from_list(used_faces, faces_in_symmetry_plane)
74
faces = []
75
for face in faces_in_symmetry_plane:
76
FreeCADBatchFEMTools.add_entity_in_list(faces, 'beta0', face)
77
solids = []
78
FreeCADBatchFEMTools.add_entity_in_list(solids, 'air', air_part, {'mesh size': mesh_size})
79
entities_dict = FreeCADBatchFEMTools.create_entities_dict('air', faces, solids, main_object=air_part)
80
doc.recompute()
81
82
return entities_dict
83
84
def create_sphere_geometry(nof_spheres, mesh_size, diameter, distance):
85
"""
86
Create sphere geometry. Spheres are moved down 10% and cut from xy plane
87
because caused problems with air otherwise.
88
89
:param nof_spheres: Number of spheres.
90
:param mesh_size: Mesh size of spheres.
91
:param diameter: Diameter of spheres.
92
:param distance: Distance between spheres.
93
94
:return: A list containing entities dictionaries.
95
"""
96
sphere_entities_dict_list = []
97
r = diameter/2.0
98
shift = diameter/10.0
99
n = int(math.ceil(math.sqrt(nof_spheres)))
100
bbox_len = n*(diameter+distance)
101
counter = 0
102
for i in range(n):
103
for j in range(n):
104
sphere_name = 'sphere{:04d}'.format(counter + 1)
105
sphere = doc.addObject('Part::Sphere', sphere_name + '_obj')
106
sphere.Radius = r
107
sphere.Placement = App.Placement(App.Vector(r + i*(diameter+distance), r + j*(diameter+distance), r-shift),
108
App.Rotation(App.Vector(0, 0, 1), 0))
109
doc.recompute()
110
sphere = cut_xy_plane(sphere, bbox_len, bbox_len, diameter)
111
doc.recompute()
112
# create entities dict
113
face_picks = [('alpha1', 0), ('beta0', 1)]
114
faces = FreeCADBatchFEMTools.pick_faces_from_geometry(sphere, face_picks)
115
solids = []
116
FreeCADBatchFEMTools.add_entity_in_list(solids, sphere_name, sphere, {'mesh size': mesh_size})
117
entities_dict = FreeCADBatchFEMTools.create_entities_dict(sphere_name, faces, solids, sphere)
118
sphere_entities_dict_list.append(entities_dict)
119
doc.recompute()
120
counter += 1
121
if counter == nof_spheres:
122
return sphere_entities_dict_list
123
124
def create_cube_geometry(nof_cubes, mesh_size, length, width, height, cube_distance):
125
"""
126
Create cube geometry.
127
128
:param nof_cubes: Number of cubes.
129
:param mesh_size: Mesh size of cubes.
130
:param length: Length of cubes.
131
:param width: Width of cubes.
132
:param height: Height of cubes.
133
:param cube_distance: Distance between cubes.
134
135
:return: A list containing entities dictionaries.
136
"""
137
cube_entities_dict_list = []
138
n = int(math.ceil(math.sqrt(nof_cubes)))
139
counter = 0
140
for i in range(n):
141
for j in range(n):
142
cube_name = 'cube{:04d}'.format(counter + 1)
143
cube = doc.addObject('Part::Box', cube_name + '_obj')
144
cube.Length = length
145
cube.Width = width
146
cube.Height = height
147
cube.Placement = App.Placement(App.Vector(i * (length+cube_distance), j * (width+cube_distance), 0),
148
App.Rotation(App.Vector(0, 0, 1), 0))
149
doc.recompute()
150
# create entities dict
151
face_picks = [('alpha0', 5), ('alpha1', 0), ('beta0', 4), ('beta1', 2), ('gamma0', 3), ('gamma1', 1)]
152
faces = FreeCADBatchFEMTools.pick_faces_from_geometry(cube, face_picks)
153
solids = []
154
FreeCADBatchFEMTools.add_entity_in_list(solids, cube_name, cube, {'mesh size': mesh_size})
155
entities_dict = FreeCADBatchFEMTools.create_entities_dict(cube_name, faces, solids, cube)
156
cube_entities_dict_list.append(entities_dict)
157
doc.recompute()
158
counter += 1
159
if counter == nof_cubes:
160
return cube_entities_dict_list
161
162
163
def create_geometry(nof_cubes, mesh_size, find_boundaries_from_entities_dict, find_solids_from_entities_dict, directory,
164
add_air, point_search, use_spheres, mesh_size_air):
165
"""
166
Creates geometry for cubes/spheres and exports unv file.
167
168
:param nof_cubes: Number of cubes/spheres created.
169
:param mesh_size: Mesh size for cubes/spheres.
170
:param find_boundaries_from_entities_dict: 'True' or 'False'.
171
:param find_solids_from_entities_dict: 'True' or 'False'.
172
:param directory: Path to directory of this script.
173
:param add_air: A boolean. Is air added to geometry.
174
:param point_search: A boolean.
175
:param use_spheres: A boolean.
176
:param mesh_size_air: A float.
177
178
:return: A list containing tuples (name, execution time).
179
"""
180
total_start_time = time.time()
181
entities_list = []
182
return_time_list = []
183
cube_edge_length, cube_distance = 200, 20
184
mesh_size_max = max(mesh_size, mesh_size_air)
185
if use_spheres:
186
print_line('Creating sphere geometry...', total_start_time)
187
entities_list.extend(create_sphere_geometry(nof_cubes, mesh_size, cube_edge_length, cube_distance))
188
else:
189
print_line('Creating cube geometry...', total_start_time)
190
entities_list.extend(create_cube_geometry(nof_cubes, mesh_size, cube_edge_length, cube_edge_length,
191
cube_edge_length, cube_distance))
192
if add_air:
193
n = int(math.ceil(math.sqrt(nof_cubes)))
194
air_edge_length = n*(cube_edge_length+cube_distance) + cube_distance
195
air_height = cube_edge_length+2*cube_distance
196
print_line("Creating air geometry...", total_start_time)
197
entities_list.append(create_air_geometry(entities_list, air_edge_length, air_edge_length, air_height,
198
cube_distance, mesh_size_air))
199
entities_list.reverse() # give air first to get mesh sizes correctly
200
print_line("Merging entities dictionaries...", total_start_time)
201
entities_dict = FreeCADBatchFEMTools.merge_entities_dicts(entities_list, 'All', default_mesh_size=mesh_size_max,
202
add_prefixes={'solids': False, 'faces': True})
203
print_line("Getting solids from entities dictionaries...", total_start_time)
204
solid_objects = FreeCADBatchFEMTools.get_solids_from_entities_dict(entities_dict)
205
print_line("Creating mesh object and compound filter...", total_start_time)
206
mesh_object, compound_filter = FreeCADBatchFEMTools.create_mesh_object_and_compound_filter(solid_objects,
207
mesh_size_max, doc)
208
if find_boundaries_from_entities_dict.lower() == 'true':
209
print_line("Finding boundaries...", total_start_time)
210
start_time = time.time()
211
FreeCADBatchFEMTools.find_boundaries_with_entities_dict(mesh_object, compound_filter,
212
entities_dict, doc)
213
return_time_list.append(('-Find boundaries:', time.time() - start_time))
214
if find_solids_from_entities_dict.lower() == 'true':
215
print_line("Finding bodies...", total_start_time)
216
start_time = time.time()
217
body_mesh_groups = FreeCADBatchFEMTools.find_bodies_with_entities_dict(mesh_object, compound_filter,
218
entities_dict, doc, point_search)
219
return_time_list.append(('-Find solids:', time.time() - start_time))
220
print_line("Defining mesh sizes...", total_start_time)
221
start_time = time.time()
222
# ignore air from mesh definition, mesh_object forces air to largest mesh
223
if find_solids_from_entities_dict.lower() == 'true':
224
FreeCADBatchFEMTools.define_mesh_sizes_with_mesh_groups(mesh_object, body_mesh_groups, doc, ignore_list=['air'])
225
else: # in this case mesh sizes needs to be found
226
FreeCADBatchFEMTools.define_mesh_sizes(mesh_object, compound_filter, entities_dict, doc, point_search,
227
ignore_list=['air'])
228
return_time_list.append(('-Define mesh sizes:', time.time() - start_time))
229
FreeCADBatchFEMTools.fit_view()
230
start_time = time.time()
231
print_line("Creating mesh...", total_start_time)
232
FreeCADBatchFEMTools.create_mesh(mesh_object)
233
return_time_list.append(('-Create mesh:', time.time() - start_time))
234
print_line("Exporting unv...", total_start_time)
235
FreeCADBatchFEMTools.export_unv(os.path.join(directory, 'cubemeshtest.unv'), mesh_object)
236
print_line("Geometry done", total_start_time)
237
return return_time_list + [('-Total time:', time.time() - total_start_time)]
238
239
240
script_directory = os.path.dirname(__file__)
241
242
with open(os.path.join(script_directory, 'cubemeshtestparameters.txt')) as f:
243
[number_of_cubes, cube_mesh_size, find_boundaries, find_solids, create_air, air_mesh_size,
244
find_with_points, create_spheres, append_file] = f.read().split()
245
246
create_air = create_air.lower() == 'true'
247
find_with_points = find_with_points.lower() == 'true'
248
create_spheres = create_spheres.lower() == 'true'
249
if air_mesh_size == 'None':
250
air_mesh_size = cube_mesh_size
251
try:
252
elapsed_times = create_geometry(int(number_of_cubes), float(cube_mesh_size), find_boundaries, find_solids,
253
script_directory, create_air, find_with_points, create_spheres, float(air_mesh_size))
254
except Exception:
255
import traceback
256
print(str(traceback.format_exc()))
257
else:
258
if create_air:
259
info_line = '\nexecution times with {} cubes (air: {}, spheres: {}, fb: {}, '.format(number_of_cubes, create_air,
260
create_spheres, find_boundaries)
261
info_line += 'fs: {}, mesh_size: {}, air_mesh_size: {}, point_search: {}):'.format(find_solids, cube_mesh_size,
262
air_mesh_size, find_with_points)
263
else:
264
info_line = '\nexecution times with {} cubes (air: {}, spheres: {}, fb: {}, '.format(number_of_cubes, create_air,
265
create_spheres, find_boundaries)
266
info_line += 'fs: {}, mesh_size: {}, point_search: {}):'.format(find_solids, cube_mesh_size, find_with_points)
267
print(info_line)
268
for time_tuple in elapsed_times:
269
print(time_tuple[0], round(time_tuple[1], 1))
270
sys.stdout.flush()
271
if append_file.lower() == 'true':
272
with open(os.path.join(script_directory, 'cubemeshtestexecutiontimes.txt'), 'a') as f:
273
f.write(info_line + '\n')
274
for time_tuple in elapsed_times:
275
f.write('{} {}\n'.format(time_tuple[0], round(time_tuple[1], 1)))
276
f.write('\n')
277
if not FreeCAD.GuiUp:
278
exit()
279
280