From d8bbfbe35e0cbfe7c4d2fe6d70f1c333f1f1e4d4 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:12 +0100 Subject: [PATCH 01/28] FEM: FemMeshTools, add new methods to make a faster search for pressure faces: - get_femnodes_ele_table() - get_copy_of_empty_femelement_table() - get_bit_pattern_dict() - get_ccxelement_faces_from_binary_search() - thanks to Ulrich Brammer for implementing the methods --- src/Mod/Fem/FemMeshTools.py | 119 ++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/src/Mod/Fem/FemMeshTools.py b/src/Mod/Fem/FemMeshTools.py index a1b375dac6..b09f9a5590 100644 --- a/src/Mod/Fem/FemMeshTools.py +++ b/src/Mod/Fem/FemMeshTools.py @@ -103,6 +103,125 @@ def get_femelement_table(femmesh): return femelement_table +def get_femnodes_ele_table(femnodes_mesh, femelement_table): + '''the femnodes_ele_table contains for each node its membership in elements + {nodeID : [[eleID, NodePosition], [], ...], nodeID : [[], [], ...], ...} + stored informatation are: + element number, the number of nodes per element, the position of the node in the element. + The position of the node in the element is coded as a set bit at that position in a bit array (integer) + Fixme: the number of nodes per element should be replaced by the type of the element + but I did not know, how to get this from the mesh. + Since the femelement_table contains either volume or face or edgemesh the femnodes_ele_table only + has either volume or face or edge elements, see get_femelement_table() + ''' + femnodes_ele_table = {} # node_dict in ulrichs class + for n in femnodes_mesh: # initialize it with sorted node keys and empty lists + femnodes_ele_table[n] = [] + for ele in femelement_table: + ele_list = femelement_table[ele] + # print(ele_list) + pos = int(1) + for ele_node in ele_list: + femnodes_ele_table[ele_node].append([ele, pos]) + pos = pos << 1 + print('len femnodes_ele_table:' + str(len(femnodes_ele_table))) + # print('femnodes_ele_table: ', femnodes_ele_table) + return femnodes_ele_table + + +def get_copy_of_empty_femelement_table(femelement_table): + '''{eleID : 0, eleID : 0, ...} + ''' + empty_femelement_table = {} + for ele in femelement_table: # initialize it with sorted element keys and empty int + empty_femelement_table[ele] = 0 + return empty_femelement_table.copy() + + +def get_bit_pattern_dict(femelement_table, femnodes_ele_table, node_set): + '''Now we are looking for nodes inside of the Faces = filling the bit_pattern_dict + {eleID : [lenEleNodes, binary_position]} + see forumpost for a ver good explanation whats really happening + http://forum.freecadweb.org/viewtopic.php?f=18&p=141133&sid=013c93f496a63872951d2ce521702ffa#p141108 + The bit_pattern_dict holds later an integer (bit array) for each element, which gives us + the information we are searching for: + Is this element part of the node list (searching for elements) or has this element a face we are searching for? + The number in the ele_dict is organized as a bit array. + The corresponding bit is set, if the node of the node_set is contained in the element. + ''' + print('len femnodes_ele_table:' + str(len(femnodes_ele_table))) + print('len node_set: ' + str(len(node_set))) + # print('node_set: ', node_set) + bit_pattern_dict = get_copy_of_empty_femelement_table(femelement_table) + # # initializing the bit_pattern_dict + for ele in femelement_table: + len_ele = len(femelement_table[ele]) + bit_pattern_dict[ele] = [len_ele, 0] + for node in node_set: + for nList in femnodes_ele_table[node]: + bit_pattern_dict[nList[0]][1] += nList[1] + print('len bit_pattern_dict:' + str(len(bit_pattern_dict))) + # print('bit_pattern_dict: ', bit_pattern_dict) + return bit_pattern_dict + + +def get_ccxelement_faces_from_binary_search(bit_pattern_dict): + '''get the CalculiX element face numbers + ''' + tet10_mask = { + 119: 1, + 411: 2, + 717: 3, + 814: 4} + tet4_mask = { + 7: 1, + 11: 2, + 13: 3, + 14: 4} + hex8_mask = { + 240: 1, + 15: 2, + 102: 3, + 204: 4, + 153: 5, + 51: 6} + hex20_mask = { + 61680: 1, + 3855: 2, + 402022: 3, + 804044: 4, + 624793: 5, + 201011: 6} + pent6_mask = { + 56: 1, + 7: 2, + 54: 3, + 45: 4, + 27: 5} + pent15_mask = { + 3640: 1, + 455: 2, + 25782: 3, + 22829: 4, + 12891: 5} + vol_dict = { + 4: tet4_mask, + 6: pent6_mask, + 8: hex8_mask, + 10: tet10_mask, + 15: pent15_mask, + 20: hex20_mask} + faces = [] + for ele in bit_pattern_dict: + mask_dict = vol_dict[bit_pattern_dict[ele][0]] + for key in mask_dict: + if (key & bit_pattern_dict[ele][1]) == key: + faces.append([ele, mask_dict[key]]) + print('found Faces: ', len(faces)) + print('faces: ', faces) + return faces + + def get_femelements_by_femnodes(femelement_table, node_list): '''for every femelement of femelement_table if all nodes of the femelement are in node_list, From 2f944d07ef55e0a17d8abe8dc3823f1446b5cce5 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:23 +0100 Subject: [PATCH 02/28] FEM: ccx input writer, make use of the new faster binary search method for getting the pressure faces --- src/Mod/Fem/FemInputWriter.py | 21 +++++++++++++++++++-- src/Mod/Fem/FemMeshTools.py | 12 +++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/Mod/Fem/FemInputWriter.py b/src/Mod/Fem/FemInputWriter.py index 970a78e641..f69d48b5c2 100644 --- a/src/Mod/Fem/FemInputWriter.py +++ b/src/Mod/Fem/FemInputWriter.py @@ -85,6 +85,7 @@ class FemInputWriter(): self.femnodes_mesh = {} self.femelement_table = {} self.constraint_conflict_nodes = [] + self.femnodes_ele_table = {} def get_constraints_fixed_nodes(self): # get nodes @@ -159,9 +160,25 @@ class FemInputWriter(): def get_constraints_pressure_faces(self): # TODO see comments in get_constraints_force_nodeloads(), it applies here too. Mhh it applies to all constraints ... + ''' + # depreciated version # get the faces and face numbers for femobj in self.pressure_objects: # femobj --> dict, FreeCAD document object is femobj['Object'] - femobj['PressureFaces'] = FemMeshTools.get_pressure_obj_faces(self.femmesh, femobj) - # print femobj['PressureFaces'] + femobj['PressureFaces'] = FemMeshTools.get_pressure_obj_faces_depreciated(self.femmesh, femobj) + # print(femobj['PressureFaces']) + ''' + + if not self.femnodes_mesh: + self.femnodes_mesh = self.femmesh.Nodes + if not self.femelement_table: + self.femelement_table = FemMeshTools.get_femelement_table(self.femmesh) + if not self.femnodes_ele_table: + self.femnodes_ele_table = FemMeshTools.get_femnodes_ele_table(self.femnodes_mesh, self.femelement_table) + + for femobj in self.pressure_objects: # femobj --> dict, FreeCAD document object is femobj['Object'] + pressure_faces = FemMeshTools.get_pressure_obj_faces(self.femmesh, self.femelement_table, self.femnodes_ele_table, femobj) + # print(len(pressure_faces)) + femobj['PressureFaces'] = [(femobj['Object'].Name + ': face load', pressure_faces)] + # print(femobj['PressureFaces']) # @} diff --git a/src/Mod/Fem/FemMeshTools.py b/src/Mod/Fem/FemMeshTools.py index b09f9a5590..5a4c005651 100644 --- a/src/Mod/Fem/FemMeshTools.py +++ b/src/Mod/Fem/FemMeshTools.py @@ -491,7 +491,7 @@ def get_force_obj_edge_nodeload_table(femmesh, femelement_table, femnodes_mesh, return force_obj_node_load_table -def get_pressure_obj_faces(femmesh, femobj): +def get_pressure_obj_faces_depreciated(femmesh, femobj): pressure_faces = [] for o, elem_tup in femobj['Object'].References: for elem in elem_tup: @@ -503,6 +503,16 @@ def get_pressure_obj_faces(femmesh, femobj): return pressure_faces +def get_pressure_obj_faces(femmesh, femelement_table, femnodes_ele_table, femobj): + # get the nodes + prs_face_node_set = get_femnodes_by_femobj_with_references(femmesh, femobj) # sorted and duplicates removed + # print('prs_face_node_set: ', prs_face_node_set) + # fill the bit_pattern_dict and search for the faces + bit_pattern_dict = get_bit_pattern_dict(femelement_table, femnodes_ele_table, prs_face_node_set) + pressure_faces = get_ccxelement_faces_from_binary_search(bit_pattern_dict) + return pressure_faces + + def get_force_obj_face_nodeload_table(femmesh, femelement_table, femnodes_mesh, frc_obj): # force_obj_node_load_table = [('refshape_name.elemname',node_load_table), ..., ('refshape_name.elemname',node_load_table)] force_obj_node_load_table = [] From db933128f68c86d118ebe1bb3d97477b3227a8a7 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:28 +0100 Subject: [PATCH 03/28] FEM: fix unit test after activating new pressure face search --- src/Mod/Fem/test_files/ccx/cube_static.inp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Mod/Fem/test_files/ccx/cube_static.inp b/src/Mod/Fem/test_files/ccx/cube_static.inp index a832a6c8d9..09f6380124 100644 --- a/src/Mod/Fem/test_files/ccx/cube_static.inp +++ b/src/Mod/Fem/test_files/ccx/cube_static.inp @@ -547,7 +547,7 @@ FemConstraintFixed,3 ** Element + CalculiX face + load in [MPa] ** written by write_constraints_pressure function *DLOAD -** face load on shape: Box:Face2 +** FemConstraintPressure: face load 635,P1,1000.0 638,P3,1000.0 641,P2,1000.0 From 1ebfd4bf0ad95ee701ef0d9519ff3e3f3c13bcc2 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:32 +0100 Subject: [PATCH 04/28] FEM: FemMeshTools, add binary search method for get_femelements_by_femnodes, but do not make it activ --- src/Mod/Fem/FemMeshTools.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/src/Mod/Fem/FemMeshTools.py b/src/Mod/Fem/FemMeshTools.py index 5a4c005651..f36069b567 100644 --- a/src/Mod/Fem/FemMeshTools.py +++ b/src/Mod/Fem/FemMeshTools.py @@ -48,7 +48,7 @@ def get_femelements_by_references(femmesh, femelement_table, references): references_femelements = [] for ref in references: ref_femnodes = get_femnodes_by_refshape(femmesh, ref) # femnodes for the current ref - references_femelements += get_femelements_by_femnodes(femelement_table, ref_femnodes) # femelements for all references + references_femelements += get_femelements_by_femnodes_std(femelement_table, ref_femnodes) # femelements for all references return references_femelements @@ -222,12 +222,41 @@ def get_ccxelement_faces_from_binary_search(bit_pattern_dict): return faces -def get_femelements_by_femnodes(femelement_table, node_list): +def get_femelements_by_femnodes_bin(femelement_table, femnodes_ele_table, node_list): + '''for every femelement of femelement_table + if all nodes of the femelement are in node_list, + the femelement is added to the list which is returned + blind fast binary search, but workd for volumes only + ''' + print('binary search: get_femelements_by_femnodes_bin') + vol_masks = { + 4: 15, + 6: 63, + 8: 255, + 10: 1023, + 15: 32767, + 20: 1048575} + # Now we are looking for nodes inside of the Volumes = filling the bit_pattern_dict + print('len femnodes_ele_table:' + str(len(femnodes_ele_table))) + bit_pattern_dict = get_bit_pattern_dict(femelement_table, femnodes_ele_table, node_list) + # search + ele_list = [] # The ele_list contains the result of the search. + for ele in bit_pattern_dict: + # print('bit_pattern_dict[ele][0]: ', bit_pattern_dict[ele][0]) + if bit_pattern_dict[ele][1] == vol_masks[bit_pattern_dict[ele][0]]: + ele_list.append(ele) + print('found Volumes: ', len(ele_list)) + print(' volumes: ', len(ele_list)) + return ele_list + + +def get_femelements_by_femnodes_std(femelement_table, node_list): '''for every femelement of femelement_table if all nodes of the femelement are in node_list, the femelement is added to the list which is returned e: elementlist nodes: nodelist ''' + print('std search: get_femelements_by_femnodes_std') e = [] # elementlist for elementID in sorted(femelement_table): nodecount = 0 @@ -612,7 +641,7 @@ def get_ref_edgenodes_table(femmesh, femelement_table, refedge): # FIXME duplicate_mesh_elements: as soon as contact ans springs are supported the user should decide on which edge the load is applied edge_table = delete_duplicate_mesh_elements(edge_table) elif is_edge_femmesh(femmesh): - refedge_fem_edgeelements = get_femelements_by_femnodes(femelement_table, refedge_nodes) + refedge_fem_edgeelements = get_femelements_by_femnodes_std(femelement_table, refedge_nodes) for elem in refedge_fem_edgeelements: edge_table[elem] = femelement_table[elem] # { edgeID : ( nodeID, ... , nodeID )} # all nodes off this femedgeelement return edge_table @@ -700,7 +729,7 @@ def get_ref_facenodes_table(femmesh, femelement_table, ref_face): face_table[mf] = femmesh.getElementNodes(mf) elif is_face_femmesh(femmesh): ref_face_nodes = femmesh.getNodesByFace(ref_face) - ref_face_elements = get_femelements_by_femnodes(femelement_table, ref_face_nodes) + ref_face_elements = get_femelements_by_femnodes_std(femelement_table, ref_face_nodes) for mf in ref_face_elements: face_table[mf] = femelement_table[mf] # print face_table From ecbe075bb7cafabd3858981e68f60521ba386caa Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:36 +0100 Subject: [PATCH 05/28] FEM: activate binary search get_femelement_by_femnodes_bin for volume meshes --- src/Mod/Fem/FemInputWriterCcx.py | 7 ++++++- src/Mod/Fem/FemMeshTools.py | 13 +++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Mod/Fem/FemInputWriterCcx.py b/src/Mod/Fem/FemInputWriterCcx.py index 378a442406..df1628e68c 100644 --- a/src/Mod/Fem/FemInputWriterCcx.py +++ b/src/Mod/Fem/FemInputWriterCcx.py @@ -974,7 +974,12 @@ class FemInputWriterCcx(FemInputWriter.FemInputWriter): if all_found is False: if not self.femelement_table: self.femelement_table = FemMeshTools.get_femelement_table(self.femmesh) - FemMeshTools.get_femelement_sets(self.femmesh, self.femelement_table, self.material_objects) + # we gone use the binary search for get_femelements_by_femnodes(), thus we need the parameter values self.femnodes_ele_table + if not self.femnodes_mesh: + self.femnodes_mesh = self.femmesh.Nodes + if not self.femnodes_ele_table: + self.femnodes_ele_table = FemMeshTools.get_femnodes_ele_table(self.femnodes_mesh, self.femelement_table) + FemMeshTools.get_femelement_sets(self.femmesh, self.femelement_table, self.material_objects, self.femnodes_ele_table) for mat_data in self.material_objects: mat_obj = mat_data['Object'] ccx_elset = {} diff --git a/src/Mod/Fem/FemMeshTools.py b/src/Mod/Fem/FemMeshTools.py index f36069b567..ae269ba75a 100644 --- a/src/Mod/Fem/FemMeshTools.py +++ b/src/Mod/Fem/FemMeshTools.py @@ -42,13 +42,18 @@ def get_femnodes_by_femobj_with_references(femmesh, femobj): return node_set -def get_femelements_by_references(femmesh, femelement_table, references): +def get_femelements_by_references(femmesh, femelement_table, references, femnodes_ele_table=None): '''get the femelements for a list of references ''' references_femelements = [] for ref in references: ref_femnodes = get_femnodes_by_refshape(femmesh, ref) # femnodes for the current ref - references_femelements += get_femelements_by_femnodes_std(femelement_table, ref_femnodes) # femelements for all references + if femnodes_ele_table: + # blind fast binary search, works for volumes only + references_femelements += get_femelements_by_femnodes_bin(femelement_table, femnodes_ele_table, ref_femnodes) # femelements for all references + else: + # standars search + references_femelements += get_femelements_by_femnodes_std(femelement_table, ref_femnodes) # femelements for all references return references_femelements @@ -324,7 +329,7 @@ def get_femvolumeelements_by_femfacenodes(femelement_table, node_list): return e -def get_femelement_sets(femmesh, femelement_table, fem_objects): # fem_objects = FreeCAD FEM document objects +def get_femelement_sets(femmesh, femelement_table, fem_objects, femnodes_ele_table=None): # fem_objects = FreeCAD FEM document objects # get femelements for reference shapes of each obj.References count_femelements = 0 referenced_femelements = [] @@ -334,7 +339,7 @@ def get_femelement_sets(femmesh, femelement_table, fem_objects): # fem_objects fem_object['ShortName'] = get_elset_short_name(obj, fem_object_i) # unique short identifier if obj.References: ref_shape_femelements = [] - ref_shape_femelements = get_femelements_by_references(femmesh, femelement_table, obj.References) + ref_shape_femelements = get_femelements_by_references(femmesh, femelement_table, obj.References, femnodes_ele_table) referenced_femelements += ref_shape_femelements count_femelements += len(ref_shape_femelements) fem_object['FEMElements'] = ref_shape_femelements From 0bf436b4848279c520bdacac6b192f848a710d31 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:40 +0100 Subject: [PATCH 06/28] FEM: code formating, get flake8 quired --- src/Mod/Fem/FemInputWriterCcx.py | 2 +- src/Mod/Fem/_FemSolverCalculix.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/Fem/FemInputWriterCcx.py b/src/Mod/Fem/FemInputWriterCcx.py index df1628e68c..c046a0c12d 100644 --- a/src/Mod/Fem/FemInputWriterCcx.py +++ b/src/Mod/Fem/FemInputWriterCcx.py @@ -66,7 +66,7 @@ class FemInputWriterCcx(FemInputWriter.FemInputWriter): print('FemInputWriterCcx --> self.file_name --> ' + self.file_name) def write_calculix_input_file(self): - if self.solver_obj.SplitInputWriter == True: + if self.solver_obj.SplitInputWriter is True: self.write_calculix_splitted_input_file() else: self.write_calculix_one_input_file() diff --git a/src/Mod/Fem/_FemSolverCalculix.py b/src/Mod/Fem/_FemSolverCalculix.py index 3a7c89db77..0f54e5febb 100644 --- a/src/Mod/Fem/_FemSolverCalculix.py +++ b/src/Mod/Fem/_FemSolverCalculix.py @@ -42,7 +42,7 @@ class _FemSolverCalculix(): obj.addProperty("App::PropertyString", "SolverType", "Base", "Type of the solver", 1) # the 1 set the property to ReadOnly obj.SolverType = str(self.Type) - fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") + # fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/General") # not needed ATM ccx_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Ccx") obj.addProperty("App::PropertyPath", "WorkingDir", "Fem", "Working directory for calculations, will only be used it is left blank in preferences") From c0757bf322c629c97c52e3404c57901a336bf3c9 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:44 +0100 Subject: [PATCH 07/28] FEM: code formating, add brackets to prints --- src/Mod/Fem/FemMeshTools.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Mod/Fem/FemMeshTools.py b/src/Mod/Fem/FemMeshTools.py index ae269ba75a..6c92e9f2af 100644 --- a/src/Mod/Fem/FemMeshTools.py +++ b/src/Mod/Fem/FemMeshTools.py @@ -35,10 +35,10 @@ def get_femnodes_by_femobj_with_references(femmesh, femobj): node_set = [] if femmesh.GroupCount: node_set = get_femnode_set_from_group_data(femmesh, femobj) - # print 'node_set_group: ', node_set + # print('node_set_group: ', node_set) if not node_set: node_set = get_femnodes_by_references(femmesh, femobj['Object'].References) - # print 'node_set_nogroup: ', node_set + # print('node_set_nogroup: ', node_set) return node_set @@ -325,7 +325,7 @@ def get_femvolumeelements_by_femfacenodes(femelement_table, node_list): e.append(elementID) else: FreeCAD.Console.PrintError('Error in get_femvolumeelements_by_femfacenodes(): not known volume element: ' + el_nd_ct + '\n') - # print sorted(e) + # print(sorted(e)) return e @@ -737,7 +737,7 @@ def get_ref_facenodes_table(femmesh, femelement_table, ref_face): ref_face_elements = get_femelements_by_femnodes_std(femelement_table, ref_face_nodes) for mf in ref_face_elements: face_table[mf] = femelement_table[mf] - # print face_table + # print(face_table) return face_table @@ -751,10 +751,10 @@ def build_mesh_faces_of_volume_elements(face_table, femelement_table): index = femelement_table[veID].index(n) # print(index) face_nodenumber_table[veID].append(index + 1) # lokale node number = index + 1 - # print 'VolElement:', veID - # print ' --> ', femelement_table[veID] - # print ' --> ', face_table[veID] - # print ' --> ', face_nodenumber_table[veID] + # print('VolElement:', veID) + # print(' --> ', femelement_table[veID]) + # print(' --> ', face_table[veID]) + # print(' --> ', face_nodenumber_table[veID]) for veID in face_nodenumber_table: vol_node_ct = len(femelement_table[veID]) face_node_indexs = sorted(face_nodenumber_table[veID]) @@ -844,7 +844,7 @@ def build_mesh_faces_of_volume_elements(face_table, femelement_table): i -= 1 # node_number starts with 1, index starts with 0 --> index = node number - 1 face_nodes.append(femelement_table[veID][i]) face_table[veID] = face_nodes # reset the entry in face_table - # print ' --> ', face_table[veID] + # print(' --> ', face_table[veID]) return face_table @@ -1049,7 +1049,7 @@ def get_analysis_group_elements(aAnalysis, aPart): print(empty_references) # check if all groups have elements: for g in group_elements: - # print group_elements[g][1] + # print(group_elements[g][1]) if len(group_elements[g][1]) == 0: FreeCAD.Console.PrintError('Error: shapes for: ' + g + 'not found!\n') return group_elements From aaafac1d55b0e7d145e712faa5c422c6fd26a892 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:48 +0100 Subject: [PATCH 08/28] FEM: typo in solver view providers --- src/Mod/Fem/_ViewProviderFemSolverCalculix.py | 2 +- src/Mod/Fem/_ViewProviderFemSolverZ88.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Mod/Fem/_ViewProviderFemSolverCalculix.py b/src/Mod/Fem/_ViewProviderFemSolverCalculix.py index 557de6363c..38e0c53a6d 100644 --- a/src/Mod/Fem/_ViewProviderFemSolverCalculix.py +++ b/src/Mod/Fem/_ViewProviderFemSolverCalculix.py @@ -20,7 +20,7 @@ # * * # *************************************************************************** -__title__ = "_FemViewProviderSolverCalculix" +__title__ = "_ViewProviderFemSolverCalculix" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" diff --git a/src/Mod/Fem/_ViewProviderFemSolverZ88.py b/src/Mod/Fem/_ViewProviderFemSolverZ88.py index dc7dc9f38d..5750e2f757 100644 --- a/src/Mod/Fem/_ViewProviderFemSolverZ88.py +++ b/src/Mod/Fem/_ViewProviderFemSolverZ88.py @@ -20,7 +20,7 @@ # * * # *************************************************************************** -__title__ = "_FemViewProviderSolverZ88" +__title__ = "_ViewProviderFemSolverZ88" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" From 8d54a2a89414ad40d073f0ede4dd1ae941c3a8b9 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:52 +0100 Subject: [PATCH 09/28] FEM: solver obj, remove not needed comment since all attributes are implemented in the python solver objects --- src/Mod/Fem/App/FemSolverObject.cpp | 15 +-------------- src/Mod/Fem/App/FemSolverObject.h | 24 +----------------------- 2 files changed, 2 insertions(+), 37 deletions(-) diff --git a/src/Mod/Fem/App/FemSolverObject.cpp b/src/Mod/Fem/App/FemSolverObject.cpp index ae7b89605d..43ef3d8300 100644 --- a/src/Mod/Fem/App/FemSolverObject.cpp +++ b/src/Mod/Fem/App/FemSolverObject.cpp @@ -42,20 +42,7 @@ PROPERTY_SOURCE(Fem::FemSolverObject, App::DocumentObject) FemSolverObject::FemSolverObject() { - - /* - ADD_PROPERTY_TYPE(SolverName,("Calculix"), "Data",Prop_None,"Solver program name"); - ADD_PROPERTY_TYPE(Category,("FEM"), "Data",Prop_None,"FEM, CFD ..."); - ADD_PROPERTY_TYPE(Module,(""), "Data",Prop_None,"Python module name"); - ADD_PROPERTY_TYPE(ExternalCaseEditor,(""), "Data",Prop_None,"External case editor programe"); - ADD_PROPERTY_TYPE(ExternalResultViewer,(""), "Data",Prop_None,"External result viewer name"); - - ADD_PROPERTY_TYPE(AnalysisType,("Static"), "Solver",Prop_None,"Specific analysis type"); - ADD_PROPERTY_TYPE(WorkingDir,(Base::FileInfo::getTempPath()), "Solver",Prop_None,"Solver working directory"); - ADD_PROPERTY_TYPE(InputCaseName,("TestCase"), "Solver",Prop_None,"Solver input file without suffix"); - ADD_PROPERTY_TYPE(Parallel,(false), "Solver",Prop_None,"Run solver in parallel like MPI"); - ADD_PROPERTY_TYPE(ResultObtained,(false), "Solver",Prop_None,"if true, result has been obtained"); - */ + // Attributes are implemented in the FemSolverObjectPython } FemSolverObject::~FemSolverObject() diff --git a/src/Mod/Fem/App/FemSolverObject.h b/src/Mod/Fem/App/FemSolverObject.h index 0632a4c874..e0c76aa3cf 100644 --- a/src/Mod/Fem/App/FemSolverObject.h +++ b/src/Mod/Fem/App/FemSolverObject.h @@ -43,29 +43,7 @@ public: FemSolverObject(void); virtual ~FemSolverObject(); - /* - /// Solver name, unique to identify solver in registered_solver dict - App::PropertyString SolverName; - /// CAE category like FEM, all capitalised letters - App::PropertyString Category; - /// python module name - App::PropertyString Module; - /// Path or program name for external case editor, empty string means using FreeCAD to view - App::PropertyString ExternalCaseEditor; - /// Path to External Result Viewer like Paraview, empty string means using FreeCAD - App::PropertyString ExternalResultViewer; - - /// for FEM: Static, Frequency, etc - App::PropertyString AnalysisType; - /// Path of working dir for the solver - App::PropertyString WorkingDir; - /// name for the case file without suffix - App::PropertyString InputCaseName; - /// run parallel in MPI (message passing interface)/multiple cores or serial(single CPU) - App::PropertyBool Parallel; - /// result has been obtained, purge result may be needed for rerun - App::PropertyBool ResultObtained; - */ + // Attributes are implemented in the FemSolverObjectPython /// returns the type name of the ViewProvider virtual const char* getViewProviderName(void) const { From 3ff2ec7c942308b3743eaf97391b18fb601c0081 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:46:56 +0100 Subject: [PATCH 10/28] FEM: solver obj, delete not needed includes --- src/Mod/Fem/App/FemSolverObject.cpp | 2 -- src/Mod/Fem/App/FemSolverObject.h | 4 ---- 2 files changed, 6 deletions(-) diff --git a/src/Mod/Fem/App/FemSolverObject.cpp b/src/Mod/Fem/App/FemSolverObject.cpp index 43ef3d8300..c318a3f2eb 100644 --- a/src/Mod/Fem/App/FemSolverObject.cpp +++ b/src/Mod/Fem/App/FemSolverObject.cpp @@ -28,8 +28,6 @@ #endif #include "FemSolverObject.h" - -#include #include #include diff --git a/src/Mod/Fem/App/FemSolverObject.h b/src/Mod/Fem/App/FemSolverObject.h index e0c76aa3cf..65713246c8 100644 --- a/src/Mod/Fem/App/FemSolverObject.h +++ b/src/Mod/Fem/App/FemSolverObject.h @@ -25,11 +25,7 @@ #ifndef Fem_FemSolverObject_H #define Fem_FemSolverObject_H -#include -#include -#include #include -#include "FemSolverObject.h" namespace Fem { From 752a6506752d1d1a038a83df95a9ccd82d6b71d0 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:01 +0100 Subject: [PATCH 11/28] FEM: temporary remove not supported tools from tool bar --- src/Mod/Fem/Gui/Workbench.cpp | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index e785f27bd1..ebc18caf06 100755 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -64,7 +64,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "Fem_BeamSection" << "Fem_ShellThickness" << "Separator" - << "Fem_CreateNodesSet" + //<< "Fem_CreateNodesSet" << "Separator" << "Fem_ConstraintFixed" << "Fem_ConstraintDisplacement" @@ -75,12 +75,11 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "Fem_ConstraintSelfWeight" << "Fem_ConstraintForce" << "Fem_ConstraintPressure" - << "Separator" - << "Fem_ConstraintBearing" - << "Fem_ConstraintGear" - << "Fem_ConstraintPulley" - << "Separator" - << "Fem_ConstraintFluidBoundary" + //<< "Separator" + //<< "Fem_ConstraintBearing" + //<< "Fem_ConstraintGear" + //<< "Fem_ConstraintPulley" + //<< "Fem_ConstraintFluidBoundary" << "Separator" << "Fem_ConstraintTemperature" << "Fem_ConstraintHeatflux" From 5a404521d499edadbd37238e464bb21d3cd6487c Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:07 +0100 Subject: [PATCH 12/28] FEM: do not longer open mesh at analyse creation better make mesh last as before the constraints because of group meshing --- src/Mod/Fem/_CommandAnalysis.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Mod/Fem/_CommandAnalysis.py b/src/Mod/Fem/_CommandAnalysis.py index 779e979b47..d1241d3079 100644 --- a/src/Mod/Fem/_CommandAnalysis.py +++ b/src/Mod/Fem/_CommandAnalysis.py @@ -58,11 +58,6 @@ class _CommandAnalysis(FemCommands): if (len(sel) == 1): if(sel[0].isDerivedFrom("Fem::FemMeshObject")): FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [App.activeDocument()." + sel[0].Name + "]") - if(sel[0].isDerivedFrom("Part::Feature")): - FreeCADGui.doCommand("App.activeDocument().addObject('Fem::FemMeshShapeNetgenObject', '" + sel[0].Name + "_Mesh')") - FreeCADGui.doCommand("App.activeDocument().ActiveObject.Shape = App.activeDocument()." + sel[0].Name) - FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [App.activeDocument().ActiveObject]") - FreeCADGui.doCommand("Gui.activeDocument().setEdit(App.ActiveDocument.ActiveObject.Name)") FreeCADGui.Selection.clearSelection() if FreeCAD.GuiUp: From 6d3c5efda7d6c96f0573680234144e03abf49ff1 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:12 +0100 Subject: [PATCH 13/28] FEM: solver task panel, delete not used def --- src/Mod/Fem/_TaskPanelFemSolverCalculix.py | 50 +++++++++++----------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/src/Mod/Fem/_TaskPanelFemSolverCalculix.py b/src/Mod/Fem/_TaskPanelFemSolverCalculix.py index 3dfff975d8..5a574e9894 100644 --- a/src/Mod/Fem/_TaskPanelFemSolverCalculix.py +++ b/src/Mod/Fem/_TaskPanelFemSolverCalculix.py @@ -32,12 +32,11 @@ import FreeCAD import os import time -if FreeCAD.GuiUp: - import FreeCADGui - import FemGui - from PySide import QtCore, QtGui - from PySide.QtCore import Qt - from PySide.QtGui import QApplication +import FreeCADGui +import FemGui +from PySide import QtCore, QtGui +from PySide.QtCore import Qt +from PySide.QtGui import QApplication class _TaskPanelFemSolverCalculix: @@ -83,6 +82,25 @@ class _TaskPanelFemSolverCalculix: self.update() + def getStandardButtons(self): + # only show a close button + # def accept() in no longer needed, since there is no OK button + return int(QtGui.QDialogButtonBox.Close) + + def reject(self): + FreeCADGui.ActiveDocument.resetEdit() + + def update(self): + 'fills the widgets' + self.form.le_working_dir.setText(self.solver_object.WorkingDir) + if self.solver_object.AnalysisType == 'static': + self.form.rb_static_analysis.setChecked(True) + elif self.solver_object.AnalysisType == 'frequency': + self.form.rb_frequency_analysis.setChecked(True) + elif self.solver_object.AnalysisType == 'thermomech': + self.form.rb_thermomech_analysis.setChecked(True) + return + def femConsoleMessage(self, message="", color="#000000"): self.fem_console_message = self.fem_console_message + '{0:4.1f}: {2}
'.\ format(time.time() - self.Start, color, message.encode('utf-8', 'replace')) @@ -152,26 +170,6 @@ class _TaskPanelFemSolverCalculix: QApplication.restoreOverrideCursor() self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) - def getStandardButtons(self): - return int(QtGui.QDialogButtonBox.Close) - - def update(self): - 'fills the widgets' - self.form.le_working_dir.setText(self.solver_object.WorkingDir) - if self.solver_object.AnalysisType == 'static': - self.form.rb_static_analysis.setChecked(True) - elif self.solver_object.AnalysisType == 'frequency': - self.form.rb_frequency_analysis.setChecked(True) - elif self.solver_object.AnalysisType == 'thermomech': - self.form.rb_thermomech_analysis.setChecked(True) - return - - def accept(self): - FreeCADGui.ActiveDocument.resetEdit() - - def reject(self): - FreeCADGui.ActiveDocument.resetEdit() - def choose_working_dir(self): current_wd = self.setup_working_dir() wd = QtGui.QFileDialog.getExistingDirectory(None, 'Choose CalculiX working directory', From 3ca8f0d823685843db2d42757603153d1c2dd42e Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:16 +0100 Subject: [PATCH 14/28] FEM: small change in Fem Z88 tools --- src/Mod/Fem/FemToolsZ88.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Mod/Fem/FemToolsZ88.py b/src/Mod/Fem/FemToolsZ88.py index 0d24c92c60..dc00472ce0 100644 --- a/src/Mod/Fem/FemToolsZ88.py +++ b/src/Mod/Fem/FemToolsZ88.py @@ -110,8 +110,7 @@ class FemToolsZ88(FemTools.FemTools): self.z88_binary = z88_path else: if not z88_binary: - self.fem_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Z88") - z88_binary = self.fem_prefs.GetString("z88BinaryPath", "") + z88_binary = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Z88").GetString("z88BinaryPath", "") if not z88_binary: if system() == "Linux": z88_binary = "z88r" From 29fd512937e80b9e935448169c65a950b7d5f7cf Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:19 +0100 Subject: [PATCH 15/28] FEM: catch an error if Result dialog will be opened without an result in the analysis --- src/Mod/Fem/_TaskPanelShowResult.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/Mod/Fem/_TaskPanelShowResult.py b/src/Mod/Fem/_TaskPanelShowResult.py index 07968f7593..5c713eb979 100644 --- a/src/Mod/Fem/_TaskPanelShowResult.py +++ b/src/Mod/Fem/_TaskPanelShowResult.py @@ -31,12 +31,11 @@ import FreeCAD import FemTools import numpy as np -if FreeCAD.GuiUp: - import FreeCADGui - import FemGui - from PySide import QtCore, QtGui - from PySide.QtCore import Qt - from PySide.QtGui import QApplication +import FreeCADGui +import FemGui +from PySide import QtCore, QtGui +from PySide.QtCore import Qt +from PySide.QtGui import QApplication class _TaskPanelShowResult: @@ -304,10 +303,6 @@ class _TaskPanelShowResult: def update(self): self.MeshObject = None self.result_object = get_results_object(FreeCADGui.Selection.getSelection()) - # Disable temperature radio button if it does ot exist in results - if len(self.result_object.Temperature) == 1: - self.form.rb_temperature.setEnabled(0) - for i in FemGui.getActiveAnalysis().Member: if i.isDerivedFrom("Fem::FemMeshObject"): self.MeshObject = i @@ -315,13 +310,21 @@ class _TaskPanelShowResult: self.suitable_results = False if self.result_object: + # Disable temperature radio button if it does ot exist in results + if len(self.result_object.Temperature) == 1: + self.form.rb_temperature.setEnabled(0) + if (self.MeshObject.FemMesh.NodeCount == len(self.result_object.NodeNumbers)): self.suitable_results = True else: if not self.MeshObject.FemMesh.VolumeCount: - FreeCAD.Console.PrintError('Graphical bending stress output for beam or shell FEM Meshes not yet supported!\n') + FreeCAD.Console.PrintError('FEM: Graphical bending stress output for beam or shell FEM Meshes not yet supported.\n') else: - FreeCAD.Console.PrintError('Result node numbers are not equal to FEM Mesh NodeCount!\n') + FreeCAD.Console.PrintError('FEM: Result node numbers are not equal to FEM Mesh NodeCount.\n') + else: + error_message = 'FEM: Result task panel, no result object to display results for.\n' + FreeCAD.Console.PrintError(error_message) + QtGui.QMessageBox.critical(None, 'No result object', error_message) def accept(self): FreeCADGui.Control.closeDialog() From c459b1e0898552aabd89898263712566cd27e76b Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:23 +0100 Subject: [PATCH 16/28] FEM: read frd result file, check if nodes could have been read. --- src/Mod/Fem/ccxFrdReader.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Mod/Fem/ccxFrdReader.py b/src/Mod/Fem/ccxFrdReader.py index 09a9701758..20bf5b80a6 100644 --- a/src/Mod/Fem/ccxFrdReader.py +++ b/src/Mod/Fem/ccxFrdReader.py @@ -331,6 +331,8 @@ def readResult(frd_input): elements_found = False frd_file.close() + if not nodes: + FreeCAD.Console.PrintError('FEM: No nodes found in Frd file.\n') return {'Nodes': nodes, 'Hexa8Elem': elements_hexa8, 'Penta6Elem': elements_penta6, 'Tetra4Elem': elements_tetra4, 'Tetra10Elem': elements_tetra10, 'Penta15Elem': elements_penta15, 'Hexa20Elem': elements_hexa20, 'Tria3Elem': elements_tria3, 'Tria6Elem': elements_tria6, From 0fc137762f4202c27d3f1c717fae43ac26045e3b Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:27 +0100 Subject: [PATCH 17/28] FEM: ccx tools, check if the active analysis has result object before try to open results --- src/Mod/Fem/FemToolsCcx.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Mod/Fem/FemToolsCcx.py b/src/Mod/Fem/FemToolsCcx.py index 147ba24548..4c079750a2 100644 --- a/src/Mod/Fem/FemToolsCcx.py +++ b/src/Mod/Fem/FemToolsCcx.py @@ -242,6 +242,9 @@ class FemToolsCcx(FemTools.FemTools): for m in self.analysis.Member: if m.isDerivedFrom("Fem::FemResultObject"): self.results_present = True + break + else: + FreeCAD.Console.PrintError('FEM: No result object in active Analysis.\n') else: raise Exception('FEM: No results found at {}!'.format(frd_result_file)) @@ -256,7 +259,7 @@ class FemToolsCcx(FemTools.FemTools): else: raise Exception('FEM: No .dat results found at {}!'.format(dat_result_file)) if mode_frequencies: - print(mode_frequencies) + # print(mode_frequencies) for m in self.analysis.Member: if m.isDerivedFrom("Fem::FemResultObject") and m.Eigenmode > 0: for mf in mode_frequencies: From 9fbf1d4b15f35d5078a7d43a05a8b9aee42765b5 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:31 +0100 Subject: [PATCH 18/28] FEM: code formating, cmake and init gui --- src/Mod/Fem/App/CMakeLists.txt | 4 ++-- src/Mod/Fem/CMakeLists.txt | 10 +++++----- src/Mod/Fem/InitGui.py | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index 2c69918e83..edf1e423aa 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -68,13 +68,13 @@ SET(FemScripts_SRCS _CommandBeamSection.py _CommandControlSolver.py _CommandConstraintSelfWeight.py - _CommandMechanicalMaterial.py - _CommandShowResult.py _CommandMaterialMechanicalNonlinear.py + _CommandMechanicalMaterial.py _CommandMeshFromShape.py _CommandPurgeResults.py _CommandRunSolver.py _CommandShellThickness.py + _CommandShowResult.py _CommandSolverCalculix.py _CommandSolverZ88.py _FemBeamSection.py diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 2503886744..0d3638f9c3 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -50,6 +50,11 @@ INSTALL( _TaskPanelFemShellThickness.py TaskPanelFemShellThickness.ui + FemConstraintSelfWeight.py + _FemConstraintSelfWeight.py + _ViewProviderFemConstraintSelfWeight.py + _CommandConstraintSelfWeight.py + MechanicalMaterial.py _MechanicalMaterial.py _ViewProviderMechanicalMaterial.py @@ -85,11 +90,6 @@ INSTALL( _ViewProviderFemSolverZ88.py _CommandSolverZ88.py - FemConstraintSelfWeight.py - _FemConstraintSelfWeight.py - _ViewProviderFemConstraintSelfWeight.py - _CommandConstraintSelfWeight.py - DESTINATION Mod/Fem ) diff --git a/src/Mod/Fem/InitGui.py b/src/Mod/Fem/InitGui.py index b144fb31ca..1eaf7a7e96 100644 --- a/src/Mod/Fem/InitGui.py +++ b/src/Mod/Fem/InitGui.py @@ -50,7 +50,6 @@ class FemWorkbench (Workbench): import _CommandRunSolver import _CommandPurgeResults import _CommandControlSolver - import _CommandMeshFromShape import _CommandAnalysis import _CommandShellThickness From b0b48bb92eff109ec2be63057b2be7b66e8aa7ac Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:34 +0100 Subject: [PATCH 19/28] FEM: code formating, make all python module start the same way - module info - doxygen documentation - imports - code --- src/Mod/Fem/FemAnalysis.py | 5 +++-- src/Mod/Fem/FemBeamSection.py | 4 ++-- src/Mod/Fem/FemCommands.py | 6 +++--- src/Mod/Fem/FemConstraintSelfWeight.py | 4 ++-- src/Mod/Fem/FemInputWriter.py | 14 ++------------ src/Mod/Fem/FemInputWriterCcx.py | 5 ++--- src/Mod/Fem/FemInputWriterZ88.py | 5 ++--- src/Mod/Fem/FemMaterialMechanicalNonlinear.py | 4 ++-- src/Mod/Fem/FemMeshTools.py | 5 ++--- src/Mod/Fem/FemSelectionObserver.py | 4 ++-- src/Mod/Fem/FemShellThickness.py | 4 ++-- src/Mod/Fem/FemSolverCalculix.py | 4 ++-- src/Mod/Fem/FemSolverZ88.py | 4 ++-- src/Mod/Fem/FemTools.py | 5 ++--- src/Mod/Fem/FemToolsCcx.py | 5 ++--- src/Mod/Fem/FemToolsZ88.py | 5 ++--- src/Mod/Fem/Init.py | 2 -- src/Mod/Fem/InitGui.py | 1 - src/Mod/Fem/MechanicalMaterial.py | 4 ++-- src/Mod/Fem/_CommandAnalysis.py | 6 ++---- src/Mod/Fem/_CommandBeamSection.py | 6 ++---- src/Mod/Fem/_CommandConstraintSelfWeight.py | 6 ++---- src/Mod/Fem/_CommandControlSolver.py | 6 ++---- src/Mod/Fem/_CommandMaterialMechanicalNonlinear.py | 8 +++----- src/Mod/Fem/_CommandMechanicalMaterial.py | 8 +++----- src/Mod/Fem/_CommandMeshFromShape.py | 6 ++---- src/Mod/Fem/_CommandPurgeResults.py | 6 ++---- src/Mod/Fem/_CommandRunSolver.py | 6 ++---- src/Mod/Fem/_CommandShellThickness.py | 6 ++---- src/Mod/Fem/_CommandShowResult.py | 6 ++---- src/Mod/Fem/_CommandSolverCalculix.py | 8 +++----- src/Mod/Fem/_CommandSolverZ88.py | 6 ++---- src/Mod/Fem/_FemBeamSection.py | 1 + src/Mod/Fem/_FemConstraintSelfWeight.py | 1 + src/Mod/Fem/_FemMaterialMechanicalNonlinear.py | 1 + src/Mod/Fem/_FemShellThickness.py | 1 + src/Mod/Fem/_MechanicalMaterial.py | 1 + src/Mod/Fem/_TaskPanelFemSolverCalculix.py | 1 - src/Mod/Fem/ccxDatReader.py | 8 ++++---- src/Mod/Fem/ccxFrdReader.py | 12 ++++++------ src/Mod/Fem/importInpMesh.py | 11 ++++++----- src/Mod/Fem/importZ88Mesh.py | 11 +++++------ src/Mod/Fem/z88DispReader.py | 11 +++++------ 43 files changed, 96 insertions(+), 137 deletions(-) diff --git a/src/Mod/Fem/FemAnalysis.py b/src/Mod/Fem/FemAnalysis.py index be5d599bc2..3e0897ebbc 100644 --- a/src/Mod/Fem/FemAnalysis.py +++ b/src/Mod/Fem/FemAnalysis.py @@ -20,8 +20,6 @@ # * * # *************************************************************************** -import FreeCAD - __title__ = "FEM Analysis managment" __author__ = "Juergen Riegel" __url__ = "http://www.freecadweb.org" @@ -29,6 +27,9 @@ __url__ = "http://www.freecadweb.org" ## \addtogroup FEM # @{ +import FreeCAD + + def makeFemAnalysis(name): '''makeFemAnalysis(name): makes a Fem Analysis object''' obj = FreeCAD.ActiveDocument.addObject("Fem::FemAnalysisPython", name) diff --git a/src/Mod/Fem/FemBeamSection.py b/src/Mod/Fem/FemBeamSection.py index cc41584e70..934168cb50 100644 --- a/src/Mod/Fem/FemBeamSection.py +++ b/src/Mod/Fem/FemBeamSection.py @@ -24,12 +24,12 @@ __title__ = "FemBeamSection" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import _FemBeamSection -## \addtogroup FEM -# @{ def makeFemBeamSection(width=20.0, height=20.0, name="BeamSection"): '''makeFemBeamSection([width], [height], [name]): creates an beamsection object to define a cross section''' diff --git a/src/Mod/Fem/FemCommands.py b/src/Mod/Fem/FemCommands.py index 356fa275c0..76e310a0c9 100644 --- a/src/Mod/Fem/FemCommands.py +++ b/src/Mod/Fem/FemCommands.py @@ -25,15 +25,15 @@ __title__ = "Fem Commands" __author__ = "Przemo Firszt" __url__ = "http://www.freecadweb.org" -import FreeCAD +## \addtogroup FEM +# @{ +import FreeCAD if FreeCAD.GuiUp: import FreeCADGui import FemGui from PySide import QtCore -## \addtogroup FEM -# @{ class FemCommands(object): def __init__(self): diff --git a/src/Mod/Fem/FemConstraintSelfWeight.py b/src/Mod/Fem/FemConstraintSelfWeight.py index 2544d4a3a5..3f919ffa68 100644 --- a/src/Mod/Fem/FemConstraintSelfWeight.py +++ b/src/Mod/Fem/FemConstraintSelfWeight.py @@ -24,12 +24,12 @@ __title__ = "FemConstraintSelfWeight" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import _FemConstraintSelfWeight -## \addtogroup FEM -# @{ def makeFemConstraintSelfWeight(name="FemConstraintSelfWeight"): '''makeFemFemConstraintSelfWeight([name]): creates an self weight object to define a gravity load''' diff --git a/src/Mod/Fem/FemInputWriter.py b/src/Mod/Fem/FemInputWriter.py index f69d48b5c2..f9d2e439e6 100644 --- a/src/Mod/Fem/FemInputWriter.py +++ b/src/Mod/Fem/FemInputWriter.py @@ -20,27 +20,17 @@ # * * # *************************************************************************** - -''' -- next step would be save the constraints node and element data in the in the FreeCAD FEM Mesh Object - and link them to the appropriate constraint object -- if the informations are used by the FEM Mesh file exporter FreeCAD would support writing FEM Mesh Groups -- which is a most needed feature of FEM module -- smesh supports mesh groups, how about pythonbinding in FreeCAD. Is there somethin implemented allready? -''' - - __title__ = "FemInputWriter" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import FemMeshTools import os -## \addtogroup FEM -# @{ class FemInputWriter(): def __init__(self, diff --git a/src/Mod/Fem/FemInputWriterCcx.py b/src/Mod/Fem/FemInputWriterCcx.py index c046a0c12d..283da75e62 100644 --- a/src/Mod/Fem/FemInputWriterCcx.py +++ b/src/Mod/Fem/FemInputWriterCcx.py @@ -21,11 +21,12 @@ # * * # *************************************************************************** - __title__ = "FemInputWriterCcx" __author__ = "Przemo Firszt, Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import os @@ -34,8 +35,6 @@ import time import FemMeshTools import FemInputWriter -## \addtogroup FEM -# @{ class FemInputWriterCcx(FemInputWriter.FemInputWriter): def __init__(self, diff --git a/src/Mod/Fem/FemInputWriterZ88.py b/src/Mod/Fem/FemInputWriterZ88.py index 081ab13ee1..9090496b6c 100644 --- a/src/Mod/Fem/FemInputWriterZ88.py +++ b/src/Mod/Fem/FemInputWriterZ88.py @@ -20,19 +20,18 @@ # * * # *************************************************************************** - __title__ = "FemInputWriterZ88" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import FemMeshTools import importZ88Mesh import FemInputWriter -## \addtogroup FEM -# @{ class FemInputWriterZ88(FemInputWriter.FemInputWriter): def __init__(self, diff --git a/src/Mod/Fem/FemMaterialMechanicalNonlinear.py b/src/Mod/Fem/FemMaterialMechanicalNonlinear.py index 65209e65e8..55dbf2ba9b 100644 --- a/src/Mod/Fem/FemMaterialMechanicalNonlinear.py +++ b/src/Mod/Fem/FemMaterialMechanicalNonlinear.py @@ -24,13 +24,13 @@ __title__ = "FemMaterialMechanicalNonlinear" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import FemGui import _FemMaterialMechanicalNonlinear -## \addtogroup FEM -# @{ def makeFemMaterialMechanicalNonlinear(base_material, name="MechanicalMaterialNonlinear"): '''makeFemMaterialMechanicalNonlinear(base_material, [name]): creates an nonlinear material object''' diff --git a/src/Mod/Fem/FemMeshTools.py b/src/Mod/Fem/FemMeshTools.py index 6c92e9f2af..5b6044a440 100644 --- a/src/Mod/Fem/FemMeshTools.py +++ b/src/Mod/Fem/FemMeshTools.py @@ -20,16 +20,15 @@ # * * # *************************************************************************** - __title__ = "Tools for the work with FEM meshes" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD -## \addtogroup FEM -# @{ def get_femnodes_by_femobj_with_references(femmesh, femobj): node_set = [] diff --git a/src/Mod/Fem/FemSelectionObserver.py b/src/Mod/Fem/FemSelectionObserver.py index 05385bf647..7e9dc9c5c7 100644 --- a/src/Mod/Fem/FemSelectionObserver.py +++ b/src/Mod/Fem/FemSelectionObserver.py @@ -24,12 +24,12 @@ __title__ = "Selection Observer" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import FreeCADGui -## \addtogroup FEM -# @{ class FemSelectionObserver: '''FemSelectionObserver''' diff --git a/src/Mod/Fem/FemShellThickness.py b/src/Mod/Fem/FemShellThickness.py index 617b15712e..89c95c9629 100644 --- a/src/Mod/Fem/FemShellThickness.py +++ b/src/Mod/Fem/FemShellThickness.py @@ -24,12 +24,12 @@ __title__ = "FemShellThickness" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import _FemShellThickness -## \addtogroup FEM -# @{ def makeFemShellThickness(thickness=20.0, name="ShellThickness"): '''makeFemShellThickness([thickness], [name]): creates an shellthickness object to define a plate thickness''' diff --git a/src/Mod/Fem/FemSolverCalculix.py b/src/Mod/Fem/FemSolverCalculix.py index fcc0e87d71..c4c70f013d 100644 --- a/src/Mod/Fem/FemSolverCalculix.py +++ b/src/Mod/Fem/FemSolverCalculix.py @@ -24,12 +24,12 @@ __title__ = "FemSolverCalculix" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import _FemSolverCalculix -## \addtogroup FEM -# @{ def makeFemSolverCalculix(name="CalculiX"): '''makeSolverCalculix(name): makes a Calculix solver object''' diff --git a/src/Mod/Fem/FemSolverZ88.py b/src/Mod/Fem/FemSolverZ88.py index ce1ed5a10a..70c483b49c 100644 --- a/src/Mod/Fem/FemSolverZ88.py +++ b/src/Mod/Fem/FemSolverZ88.py @@ -24,12 +24,12 @@ __title__ = "FemSolverZ88" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import _FemSolverZ88 -## \addtogroup FEM -# @{ def makeFemSolverZ88(name="Z88"): '''makeSolverZ88(name): makes a Z88 solver object''' diff --git a/src/Mod/Fem/FemTools.py b/src/Mod/Fem/FemTools.py index 70bbd4f0f1..3d11fb989d 100644 --- a/src/Mod/Fem/FemTools.py +++ b/src/Mod/Fem/FemTools.py @@ -21,17 +21,16 @@ # * * # *************************************************************************** - __title__ = "Fem Tools super class" __author__ = "Przemo Firszt, Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD from PySide import QtCore -## \addtogroup FEM -# @{ class FemTools(QtCore.QRunnable, QtCore.QObject): ## The constructor diff --git a/src/Mod/Fem/FemToolsCcx.py b/src/Mod/Fem/FemToolsCcx.py index 4c079750a2..58540573ad 100644 --- a/src/Mod/Fem/FemToolsCcx.py +++ b/src/Mod/Fem/FemToolsCcx.py @@ -21,11 +21,12 @@ # * * # *************************************************************************** - __title__ = "FemToolsCcx" __author__ = "Przemo Firszt, Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import FemTools @@ -33,8 +34,6 @@ from PySide import QtCore if FreeCAD.GuiUp: from PySide import QtGui -## \addtogroup FEM -# @{ class FemToolsCcx(FemTools.FemTools): diff --git a/src/Mod/Fem/FemToolsZ88.py b/src/Mod/Fem/FemToolsZ88.py index dc00472ce0..6f68220325 100644 --- a/src/Mod/Fem/FemToolsZ88.py +++ b/src/Mod/Fem/FemToolsZ88.py @@ -20,19 +20,18 @@ # * * # *************************************************************************** - __title__ = "FemToolsZ88" __author__ = "Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import FemTools from PySide import QtCore from PySide.QtGui import QApplication -## \addtogroup FEM -# @{ class FemToolsZ88(FemTools.FemTools): diff --git a/src/Mod/Fem/Init.py b/src/Mod/Fem/Init.py index 0dcfbc573b..865ebb09c5 100644 --- a/src/Mod/Fem/Init.py +++ b/src/Mod/Fem/Init.py @@ -25,10 +25,8 @@ # * Juergen Riegel 2002 * # ***************************************************************************/ - import FreeCAD - FreeCAD.addExportType("TetGen file (*.poly)", "convert2TetGen") FreeCAD.addImportType("FEM formats (*.unv *.med *.dat *.bdf)", "Fem") if("BUILD_FEM_VTK" in FreeCAD.__cmake__): diff --git a/src/Mod/Fem/InitGui.py b/src/Mod/Fem/InitGui.py index 1eaf7a7e96..577f2e65bc 100644 --- a/src/Mod/Fem/InitGui.py +++ b/src/Mod/Fem/InitGui.py @@ -29,7 +29,6 @@ #* Juergen Riegel 2002 * #***************************************************************************/ - import FreeCAD import FreeCADGui diff --git a/src/Mod/Fem/MechanicalMaterial.py b/src/Mod/Fem/MechanicalMaterial.py index cf4355bf79..a54ab9ef2a 100644 --- a/src/Mod/Fem/MechanicalMaterial.py +++ b/src/Mod/Fem/MechanicalMaterial.py @@ -24,12 +24,12 @@ __title__ = "MechanicalMaterial" __author__ = "Juergen Riegel, Bernd Hahnebach" __url__ = "http://www.freecadweb.org" +## \addtogroup FEM +# @{ import FreeCAD import _MechanicalMaterial -## \addtogroup FEM -# @{ def makeMechanicalMaterial(name): '''makeMaterial(name): makes an Material diff --git a/src/Mod/Fem/_CommandAnalysis.py b/src/Mod/Fem/_CommandAnalysis.py index d1241d3079..11803349ae 100644 --- a/src/Mod/Fem/_CommandAnalysis.py +++ b/src/Mod/Fem/_CommandAnalysis.py @@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore +import FreeCADGui +from PySide import QtCore class _CommandAnalysis(FemCommands): diff --git a/src/Mod/Fem/_CommandBeamSection.py b/src/Mod/Fem/_CommandBeamSection.py index 299b1e4bbb..8f411756fb 100644 --- a/src/Mod/Fem/_CommandBeamSection.py +++ b/src/Mod/Fem/_CommandBeamSection.py @@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore +import FreeCADGui +from PySide import QtCore class _CommandBeamSection(FemCommands): diff --git a/src/Mod/Fem/_CommandConstraintSelfWeight.py b/src/Mod/Fem/_CommandConstraintSelfWeight.py index b41ea042a6..604c653d05 100644 --- a/src/Mod/Fem/_CommandConstraintSelfWeight.py +++ b/src/Mod/Fem/_CommandConstraintSelfWeight.py @@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore +import FreeCADGui +from PySide import QtCore class _CommandConstraintSelfWeight(FemCommands): diff --git a/src/Mod/Fem/_CommandControlSolver.py b/src/Mod/Fem/_CommandControlSolver.py index e2ddca16aa..b5029bb138 100644 --- a/src/Mod/Fem/_CommandControlSolver.py +++ b/src/Mod/Fem/_CommandControlSolver.py @@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore +import FreeCADGui +from PySide import QtCore class _CommandControlSolver(FemCommands): diff --git a/src/Mod/Fem/_CommandMaterialMechanicalNonlinear.py b/src/Mod/Fem/_CommandMaterialMechanicalNonlinear.py index b27f7f98a2..2e78978fa6 100644 --- a/src/Mod/Fem/_CommandMaterialMechanicalNonlinear.py +++ b/src/Mod/Fem/_CommandMaterialMechanicalNonlinear.py @@ -29,11 +29,9 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - import FemGui - from PySide import QtCore +import FreeCADGui +import FemGui +from PySide import QtCore class _CommandMaterialMechanicalNonlinear(FemCommands): diff --git a/src/Mod/Fem/_CommandMechanicalMaterial.py b/src/Mod/Fem/_CommandMechanicalMaterial.py index df00f90bcf..97e312318b 100644 --- a/src/Mod/Fem/_CommandMechanicalMaterial.py +++ b/src/Mod/Fem/_CommandMechanicalMaterial.py @@ -29,11 +29,9 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - import FemGui - from PySide import QtCore +import FreeCADGui +import FemGui +from PySide import QtCore class _CommandMechanicalMaterial(FemCommands): diff --git a/src/Mod/Fem/_CommandMeshFromShape.py b/src/Mod/Fem/_CommandMeshFromShape.py index 11578a7caa..3f74e49f4a 100644 --- a/src/Mod/Fem/_CommandMeshFromShape.py +++ b/src/Mod/Fem/_CommandMeshFromShape.py @@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore +import FreeCADGui +from PySide import QtCore class _CommandMeshFromShape(FemCommands): diff --git a/src/Mod/Fem/_CommandPurgeResults.py b/src/Mod/Fem/_CommandPurgeResults.py index f6137a283d..edd60fcdda 100644 --- a/src/Mod/Fem/_CommandPurgeResults.py +++ b/src/Mod/Fem/_CommandPurgeResults.py @@ -30,10 +30,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands import FemTools - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore +import FreeCADGui +from PySide import QtCore class _CommandPurgeResults(FemCommands): diff --git a/src/Mod/Fem/_CommandRunSolver.py b/src/Mod/Fem/_CommandRunSolver.py index b705108bfd..1476c46bdb 100644 --- a/src/Mod/Fem/_CommandRunSolver.py +++ b/src/Mod/Fem/_CommandRunSolver.py @@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore, QtGui +import FreeCADGui +from PySide import QtCore, QtGui class _CommandRunSolver(FemCommands): diff --git a/src/Mod/Fem/_CommandShellThickness.py b/src/Mod/Fem/_CommandShellThickness.py index ffd5fb2165..1b77f7642c 100644 --- a/src/Mod/Fem/_CommandShellThickness.py +++ b/src/Mod/Fem/_CommandShellThickness.py @@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore +import FreeCADGui +from PySide import QtCore class _CommandShellThickness(FemCommands): diff --git a/src/Mod/Fem/_CommandShowResult.py b/src/Mod/Fem/_CommandShowResult.py index 793e3ef709..017e38d4cf 100644 --- a/src/Mod/Fem/_CommandShowResult.py +++ b/src/Mod/Fem/_CommandShowResult.py @@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore, QtGui +import FreeCADGui +from PySide import QtCore, QtGui class _CommandShowResult(FemCommands): diff --git a/src/Mod/Fem/_CommandSolverCalculix.py b/src/Mod/Fem/_CommandSolverCalculix.py index c075f7ad52..768e10b8fe 100644 --- a/src/Mod/Fem/_CommandSolverCalculix.py +++ b/src/Mod/Fem/_CommandSolverCalculix.py @@ -29,11 +29,9 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - import FemGui - from PySide import QtCore +import FreeCADGui +import FemGui +from PySide import QtCore class _CommandSolverCalculix(FemCommands): diff --git a/src/Mod/Fem/_CommandSolverZ88.py b/src/Mod/Fem/_CommandSolverZ88.py index e3bd8738bb..1a1c5db34e 100644 --- a/src/Mod/Fem/_CommandSolverZ88.py +++ b/src/Mod/Fem/_CommandSolverZ88.py @@ -29,10 +29,8 @@ __url__ = "http://www.freecadweb.org" import FreeCAD from FemCommands import FemCommands - -if FreeCAD.GuiUp: - import FreeCADGui - from PySide import QtCore +import FreeCADGui +from PySide import QtCore class _CommandSolverZ88(FemCommands): diff --git a/src/Mod/Fem/_FemBeamSection.py b/src/Mod/Fem/_FemBeamSection.py index 5a0df22f70..032c815a4f 100644 --- a/src/Mod/Fem/_FemBeamSection.py +++ b/src/Mod/Fem/_FemBeamSection.py @@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org" ## @package FemBeamSection # \ingroup FEM + class _FemBeamSection: "The FemBeamSection object" def __init__(self, obj): diff --git a/src/Mod/Fem/_FemConstraintSelfWeight.py b/src/Mod/Fem/_FemConstraintSelfWeight.py index 57045fcd99..28a5e2b649 100644 --- a/src/Mod/Fem/_FemConstraintSelfWeight.py +++ b/src/Mod/Fem/_FemConstraintSelfWeight.py @@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org" ## @package FemConstraintSelfWeight # \ingroup FEM + class _FemConstraintSelfWeight: "The FemConstraintSelfWeight object" def __init__(self, obj): diff --git a/src/Mod/Fem/_FemMaterialMechanicalNonlinear.py b/src/Mod/Fem/_FemMaterialMechanicalNonlinear.py index 769ad280e9..9d73865216 100644 --- a/src/Mod/Fem/_FemMaterialMechanicalNonlinear.py +++ b/src/Mod/Fem/_FemMaterialMechanicalNonlinear.py @@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org" ## @package FemMaterialMechanicalNonLinear # \ingroup FEM + class _FemMaterialMechanicalNonlinear: "The FemMaterialMechanicalNonlinear object" def __init__(self, obj): diff --git a/src/Mod/Fem/_FemShellThickness.py b/src/Mod/Fem/_FemShellThickness.py index 1a042fb7ed..7d9d94e3d8 100644 --- a/src/Mod/Fem/_FemShellThickness.py +++ b/src/Mod/Fem/_FemShellThickness.py @@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org" ## @package FemShellThickness # \ingroup FEM + class _FemShellThickness: "The FemShellThickness object" def __init__(self, obj): diff --git a/src/Mod/Fem/_MechanicalMaterial.py b/src/Mod/Fem/_MechanicalMaterial.py index 14fb9fa756..48f72dd113 100644 --- a/src/Mod/Fem/_MechanicalMaterial.py +++ b/src/Mod/Fem/_MechanicalMaterial.py @@ -27,6 +27,7 @@ __url__ = "http://www.freecadweb.org" ## @package MechanicalMaterial # \ingroup FEM + class _MechanicalMaterial: "The Material object" def __init__(self, obj): diff --git a/src/Mod/Fem/_TaskPanelFemSolverCalculix.py b/src/Mod/Fem/_TaskPanelFemSolverCalculix.py index 5a574e9894..92b60aea68 100644 --- a/src/Mod/Fem/_TaskPanelFemSolverCalculix.py +++ b/src/Mod/Fem/_TaskPanelFemSolverCalculix.py @@ -31,7 +31,6 @@ import FemToolsCcx import FreeCAD import os import time - import FreeCADGui import FemGui from PySide import QtCore, QtGui diff --git a/src/Mod/Fem/ccxDatReader.py b/src/Mod/Fem/ccxDatReader.py index bd59328498..ebda82e4b1 100644 --- a/src/Mod/Fem/ccxDatReader.py +++ b/src/Mod/Fem/ccxDatReader.py @@ -20,10 +20,6 @@ # * * # *************************************************************************** - -import FreeCAD -import os - __title__ = "ccxDatReader" __author__ = "Przemo Firszt" __url__ = "http://www.freecadweb.org" @@ -31,6 +27,10 @@ __url__ = "http://www.freecadweb.org" ## @package ccxDatReader # \ingroup FEM +import FreeCAD +import os + + if open.__module__ == '__builtin__': # because we'll redefine open below pyopen = open diff --git a/src/Mod/Fem/ccxFrdReader.py b/src/Mod/Fem/ccxFrdReader.py index 20bf5b80a6..d312ebc81d 100644 --- a/src/Mod/Fem/ccxFrdReader.py +++ b/src/Mod/Fem/ccxFrdReader.py @@ -22,12 +22,6 @@ # * * # *************************************************************************** - -import FreeCAD -import os -from math import pow, sqrt -import numpy as np - __title__ = "FreeCAD Calculix library" __author__ = "Juergen Riegel , Michael Hindley, Bernd Hahnebach" __url__ = "http://www.freecadweb.org" @@ -35,6 +29,12 @@ __url__ = "http://www.freecadweb.org" ## @package ccxFrdReader # \ingroup FEM +import FreeCAD +import os +from math import pow, sqrt +import numpy as np + + if open.__module__ == '__builtin__': pyopen = open # because we'll redefine open below diff --git a/src/Mod/Fem/importInpMesh.py b/src/Mod/Fem/importInpMesh.py index 1a736ab436..aae2740f15 100644 --- a/src/Mod/Fem/importInpMesh.py +++ b/src/Mod/Fem/importInpMesh.py @@ -20,11 +20,6 @@ # * * # *************************************************************************** -import FemMeshTools -import FreeCAD -import os -import string - __title__ = "FreeCAD .inp file reader" __author__ = "Frantisek Loeffelmann " __url__ = "http://www.freecadweb.org" @@ -33,6 +28,12 @@ __date__ = "04/08/2016" ## @package importInpMesh # \ingroup FEM +import FemMeshTools +import FreeCAD +import os +import string + + if open.__module__ == '__builtin__': pyopen = open # because we'll redefine open below diff --git a/src/Mod/Fem/importZ88Mesh.py b/src/Mod/Fem/importZ88Mesh.py index 5ba0da9957..e21b296fd8 100644 --- a/src/Mod/Fem/importZ88Mesh.py +++ b/src/Mod/Fem/importZ88Mesh.py @@ -20,12 +20,6 @@ # * * # *************************************************************************** - -import FreeCAD -import os -import FemMeshTools - - __title__ = "FreeCAD Z88 Mesh reader and writer" __author__ = "Bernd Hahnebach " __url__ = "http://www.freecadweb.org" @@ -33,6 +27,11 @@ __url__ = "http://www.freecadweb.org" ## @package importZ88Mesh # \ingroup FEM +import FreeCAD +import os +import FemMeshTools + + Debug = False if open.__module__ == '__builtin__': diff --git a/src/Mod/Fem/z88DispReader.py b/src/Mod/Fem/z88DispReader.py index d930e9d741..35e24a202d 100644 --- a/src/Mod/Fem/z88DispReader.py +++ b/src/Mod/Fem/z88DispReader.py @@ -20,12 +20,6 @@ # * * # *************************************************************************** - -import FreeCAD -import os -from math import pow, sqrt - - __title__ = "FreeCAD Z88 Disp Reader" __author__ = "Bernd Hahnebach " __url__ = "http://www.freecadweb.org" @@ -33,6 +27,11 @@ __url__ = "http://www.freecadweb.org" ## @package z88DispReader # \ingroup FEM +import FreeCAD +import os +from math import pow, sqrt + + Debug = False if open.__module__ == '__builtin__': From 06f3f46650f5a5c4488ba1bbf59dfcefe680079c Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:38 +0100 Subject: [PATCH 20/28] FEM: FemMeshTools, fix input file writing if groups have non expected group names --- src/Mod/Fem/FemMeshTools.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Mod/Fem/FemMeshTools.py b/src/Mod/Fem/FemMeshTools.py index 5b6044a440..c104d9f453 100644 --- a/src/Mod/Fem/FemMeshTools.py +++ b/src/Mod/Fem/FemMeshTools.py @@ -365,10 +365,11 @@ def get_femnode_set_from_group_data(femmesh, fem_object): # we assume the mesh group data fits with the reference shapes, no check is done in this regard !!! # what happens if a reference shape was changed, but the mesh and the mesh groups were not created new !?! obj = fem_object['Object'] + group_nodes = None if femmesh.GroupCount: for g in femmesh.Groups: grp_name = femmesh.getGroupName(g) - if grp_name.startswith(obj.Name + '_'): + if grp_name.startswith(obj.Name): if femmesh.getGroupElementType(g) == "Node": print("Constraint: " + obj.Name + " --> " + "mesh group: " + grp_name) group_nodes = femmesh.getGroupElements(g) # == ref_shape_femelements @@ -387,7 +388,7 @@ def get_femelement_sets_from_group_data(femmesh, fem_objects): if femmesh.GroupCount: for g in femmesh.Groups: grp_name = femmesh.getGroupName(g) - if grp_name.startswith(obj.Name + '_'): + if grp_name.startswith(obj.Name): if femmesh.getGroupElementType(g) == "Volume": print("Constraint: " + obj.Name + " --> " + "mesh group: " + grp_name) group_elements = femmesh.getGroupElements(g) # == ref_shape_femelements From aa9f0ab6eab7f671c2fc5b0808bc2e25365adb22 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:42 +0100 Subject: [PATCH 21/28] FEM: FemMeshTools, some changes need for the GMSH mesh tool --- src/Mod/Fem/FemMeshTools.py | 109 +++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 46 deletions(-) diff --git a/src/Mod/Fem/FemMeshTools.py b/src/Mod/Fem/FemMeshTools.py index c104d9f453..42ace7d64e 100644 --- a/src/Mod/Fem/FemMeshTools.py +++ b/src/Mod/Fem/FemMeshTools.py @@ -1003,13 +1003,13 @@ def get_analysis_group_elements(aAnalysis, aPart): {ConstraintName : ['ShapeType of the Elements'], [ElementID, ElementID, ...], ...} ''' aShape = aPart.Shape - group_elements = {} + group_elements = {} # { name : [element, element, ... , element]} empty_references = [] for m in aAnalysis.Member: if hasattr(m, "References"): # print(m.Name) key = m.Name - indexes = [] + elements = [] stype = None if m.References: for r in m.References: @@ -1031,117 +1031,134 @@ def get_analysis_group_elements(aAnalysis, aPart): # print(ref_shape) found_element = find_element_in_shape(aShape, ref_shape) if found_element is not None: - indexes.append(found_element) + elements.append(found_element) else: FreeCAD.Console.PrintError('Problem: No element found for: ' + str(ref_shape) + '\n') print(' ' + m.Name) print(' ' + str(m.References)) print(' ' + r[0].Name) - group_elements[key] = [stype, sorted(indexes)] + group_elements[key] = sorted(elements) else: - print('Empty reference: ' + m.Name) + print(' Empty reference: ' + m.Name) empty_references.append(m) if empty_references: if len(empty_references) == 1: group_elements = get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape) else: - FreeCAD.Console.PrintError('Error: more than one object with empty references!\n') - print(empty_references) + FreeCAD.Console.PrintError('Problem: more than one object with empty references.\n') + print('We gone try to get the empty material references anyway.\n') + # ShellThickness and BeamSection could have empty references, but on solid meshes only materials should have empty references + for er in empty_references: + print(er.Name) + group_elements = get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape) # check if all groups have elements: for g in group_elements: - # print(group_elements[g][1]) - if len(group_elements[g][1]) == 0: + # print(group_elements[g]) + if len(group_elements[g]) == 0: FreeCAD.Console.PrintError('Error: shapes for: ' + g + 'not found!\n') return group_elements def get_anlysis_empty_references_group_elements(group_elements, aAnalysis, aShape): '''get the elementIDs if the Reference shape is empty - see get_analysis_group_elements() + see get_analysis_group_elements() for more informatations + on solid meshes only material objects could have an empty reference without beeing something wrong! + face meshes could have empty ShellThickness and edge meshes could have empty BeamSection ''' + # print(group_elements) material_ref_shapes = [] material_shape_type = '' missed_material_refshapes = [] empty_reference_material = None for m in aAnalysis.Member: - # only materials could have an empty reference without beeing something wrong! if m.isDerivedFrom("App::MaterialObjectPython"): - if hasattr(m, "References") and m.References: - if not material_shape_type: - material_shape_type = group_elements[m.Name][0] - elif material_shape_type != group_elements[m.Name][0]: - print('Problem, material shape type does not match get_anlysis_empty_references_group_elements') - for i in group_elements[m.Name][1]: - material_ref_shapes.append(i) - elif hasattr(m, "References") and not m.References: + if hasattr(m, "References") and not m.References: if not empty_reference_material: empty_reference_material = m.Name else: - print('Problem in get_anlysis_empty_references_group_elements, we seams to have two materials with empty referneces') + FreeCAD.Console.PrintError('Problem in get_anlysis_empty_references_group_elements, we seams to have two or more materials with empty referneces') return {} + elif hasattr(m, "References") and m.References: + # ShapeType ot the group elements, strip the number of the first group element + # http://stackoverflow.com/questions/12851791/removing-numbers-from-string + group_shape_type = ''.join(i for i in group_elements[m.Name][0] if not i.isdigit()) + if not material_shape_type: + material_shape_type = group_shape_type + elif material_shape_type != group_shape_type: + FreeCAD.Console.PrintError('Problem, material shape type does not match get_anlysis_empty_references_group_elements') + for ele in group_elements[m.Name]: + material_ref_shapes.append(ele) if material_shape_type == 'Solid': # print(len(aShape.Solids)) for i in range(len(aShape.Solids)): - if i not in material_ref_shapes: - missed_material_refshapes.append(i) + ele = 'Solid' + str(i + 1) + if ele not in material_ref_shapes: + missed_material_refshapes.append(ele) elif material_shape_type == 'Face': # print(len(aShape.Faces)) for i in range(len(aShape.Faces)): - if i not in material_ref_shapes: - missed_material_refshapes.append(i) + ele = 'Face' + str(i + 1) + if ele not in material_ref_shapes: + missed_material_refshapes.append(ele) elif material_shape_type == 'Edge': # print(len(aShape.Edges)) for i in range(len(aShape.Edges)): - if i not in material_ref_shapes: - missed_material_refshapes.append(i) + ele = 'Edge' + str(i + 1) + if ele not in material_ref_shapes: + missed_material_refshapes.append(ele) else: - print('It seams we only have one material with no reference shapes. Means the whole solid is one material. Since we only support material groups for Solids at the moment this should be Solid') - material_shape_type = 'Solid' - missed_material_refshapes.append(0) + print(' One material with no reference shapes. No need to make a group for materials.') + # make no changes group_elements + return group_elements # print(sorted(material_ref_shapes)) # print(sorted(missed_material_refshapes)) # print(group_elements) - group_elements[empty_reference_material] = [material_shape_type, sorted(missed_material_refshapes)] + group_elements[empty_reference_material] = sorted(missed_material_refshapes) # print(group_elements) return group_elements def find_element_in_shape(aShape, anElement): # import Part - if anElement.ShapeType == 'Solid' or anElement.ShapeType == 'CompSolid': + ele_st = anElement.ShapeType + if ele_st == 'Solid' or ele_st == 'CompSolid': for index, solid in enumerate(aShape.Solids): # print(is_same_geometry(solid, anElement)) if is_same_geometry(solid, anElement): # print(index) # Part.show(aShape.Solids[index]) - return index + ele = ele_st + str(index + 1) + return ele FreeCAD.Console.PrintError('Solid ' + str(anElement) + ' not found in: ' + str(aShape) + '\n') - if anElement.ShapeType == 'Solid' and aShape.ShapeType == 'Solid': + if ele_st == 'Solid' and aShape.ShapeType == 'Solid': print('We have been searching for a Solid in a Solid and we have not found it. In most cases this should be searching for a Solid inside a CompSolid. Check the ShapeType of your Part to mesh.') # Part.show(anElement) # Part.show(aShape) - elif anElement.ShapeType == 'Face' or anElement.ShapeType == 'Shell': + elif ele_st == 'Face' or ele_st == 'Shell': for index, face in enumerate(aShape.Faces): # print(is_same_geometry(face, anElement)) if is_same_geometry(face, anElement): # print(index) # Part.show(aShape.Faces[index]) - return index - elif anElement.ShapeType == 'Edge' or anElement.ShapeType == 'Wire': - for index, face in enumerate(aShape.Edges): - # print(is_same_geometry(face, anElement)) - if is_same_geometry(face, anElement): + ele = ele_st + str(index + 1) + return ele + elif ele_st == 'Edge' or ele_st == 'Wire': + for index, edge in enumerate(aShape.Edges): + # print(is_same_geometry(edge, anElement)) + if is_same_geometry(edge, anElement): # print(index) # Part.show(aShape.Edges[index]) - return index - elif anElement.ShapeType == 'Vertex': - for index, face in enumerate(aShape.Vertexes): - # print(is_same_geometry(face, anElement)) - if is_same_geometry(face, anElement): + ele = ele_st + str(index + 1) + return ele + elif ele_st == 'Vertex': + for index, vertex in enumerate(aShape.Vertexes): + # print(is_same_geometry(vertex, anElement)) + if is_same_geometry(vertex, anElement): # print(index) # Part.show(aShape.Vertexes[index]) - return index - elif anElement.ShapeType == 'Compound': + ele = ele_st + str(index + 1) + return ele + elif ele_st == 'Compound': FreeCAD.Console.PrintError('Compound is not supported.\n') From e4803de36f52070483e7c3a28fc16466f8e73ddf Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:46 +0100 Subject: [PATCH 22/28] FEM: rename CommandMeshFromShape into _CommandMeshNetgenFromShape --- src/Mod/Fem/App/CMakeLists.txt | 2 +- src/Mod/Fem/CMakeLists.txt | 2 +- src/Mod/Fem/Gui/Workbench.cpp | 4 ++-- src/Mod/Fem/InitGui.py | 2 +- ...Shape.py => _CommandMeshNetgenFromShape.py} | 18 +++++++++--------- 5 files changed, 14 insertions(+), 14 deletions(-) rename src/Mod/Fem/{_CommandMeshFromShape.py => _CommandMeshNetgenFromShape.py} (82%) diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index edf1e423aa..448b304ce1 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -70,7 +70,7 @@ SET(FemScripts_SRCS _CommandConstraintSelfWeight.py _CommandMaterialMechanicalNonlinear.py _CommandMechanicalMaterial.py - _CommandMeshFromShape.py + _CommandMeshNetgenFromShape.py _CommandPurgeResults.py _CommandRunSolver.py _CommandShellThickness.py diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 0d3638f9c3..213166b678 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -24,7 +24,7 @@ INSTALL( TestFem.py FemCommands.py - _CommandMeshFromShape.py + _CommandMeshNetgenFromShape.py _CommandPurgeResults.py _CommandRunSolver.py _CommandControlSolver.py diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index ebc18caf06..86a3985ec1 100755 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -58,7 +58,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const *fem << "Fem_Analysis" << "Fem_SolverCalculix" // << "Fem_SolverZ88" - << "Fem_MeshFromShape" + << "Fem_MeshNetgenFromShape" << "Fem_MechanicalMaterial" << "Fem_MaterialMechanicalNonlinear" << "Fem_BeamSection" @@ -118,7 +118,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const *fem << "Fem_Analysis" << "Fem_SolverCalculix" << "Fem_SolverZ88" - << "Fem_MeshFromShape" + << "Fem_MeshNetgenFromShape" << "Fem_MechanicalMaterial" << "Fem_MaterialMechanicalNonlinear" << "Fem_BeamSection" diff --git a/src/Mod/Fem/InitGui.py b/src/Mod/Fem/InitGui.py index 577f2e65bc..369e21f596 100644 --- a/src/Mod/Fem/InitGui.py +++ b/src/Mod/Fem/InitGui.py @@ -49,7 +49,7 @@ class FemWorkbench (Workbench): import _CommandRunSolver import _CommandPurgeResults import _CommandControlSolver - import _CommandMeshFromShape + import _CommandMeshNetgenFromShape import _CommandAnalysis import _CommandShellThickness import _CommandBeamSection diff --git a/src/Mod/Fem/_CommandMeshFromShape.py b/src/Mod/Fem/_CommandMeshNetgenFromShape.py similarity index 82% rename from src/Mod/Fem/_CommandMeshFromShape.py rename to src/Mod/Fem/_CommandMeshNetgenFromShape.py index 3f74e49f4a..27e1f11274 100644 --- a/src/Mod/Fem/_CommandMeshFromShape.py +++ b/src/Mod/Fem/_CommandMeshNetgenFromShape.py @@ -20,11 +20,11 @@ # * * # *************************************************************************** -__title__ = "Command Mesh From Shape" +__title__ = "Command Mesh Netgen From Shape" __author__ = "Juergen Riegel" __url__ = "http://www.freecadweb.org" -## @package CommandMeshFromShape +## @package CommandMeshNetgenFromShape # \ingroup FEM import FreeCAD @@ -33,17 +33,17 @@ import FreeCADGui from PySide import QtCore -class _CommandMeshFromShape(FemCommands): - # the Fem_MeshFromShape command definition +class _CommandMeshNetgenFromShape(FemCommands): + # the Fem_MeshNetgenFromShape command definition def __init__(self): - super(_CommandMeshFromShape, self).__init__() + super(_CommandMeshNetgenFromShape, self).__init__() self.resources = {'Pixmap': 'fem-fem-mesh-from-shape', - 'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "FEM mesh from shape"), - 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "Create a FEM volume mesh from a solid shape")} + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "FEM mesh from shape by Netgen"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "Create a FEM volume mesh from a solid or face shape by Netgen internal mesher")} self.is_active = 'with_part_feature' def Activated(self): - FreeCAD.ActiveDocument.openTransaction("Create FEM mesh") + FreeCAD.ActiveDocument.openTransaction("Create FEM mesh Netgen") FreeCADGui.addModule("FemGui") sel = FreeCADGui.Selection.getSelection() if (len(sel) == 1): @@ -56,4 +56,4 @@ class _CommandMeshFromShape(FemCommands): if FreeCAD.GuiUp: - FreeCADGui.addCommand('Fem_MeshFromShape', _CommandMeshFromShape()) + FreeCADGui.addCommand('Fem_MeshNetgenFromShape', _CommandMeshNetgenFromShape()) From 735d70bca06bf1352fd53a64bca6a8ca973461b2 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:50 +0100 Subject: [PATCH 23/28] FEM: extend the C++ fem mesh object to be able make python mesh object childs --- src/Mod/Fem/App/AppFem.cpp | 1 + src/Mod/Fem/App/FemMeshObject.cpp | 23 +++++++++++++++++++++++ src/Mod/Fem/App/FemMeshObject.h | 4 ++++ src/Mod/Fem/Gui/AppFemGui.cpp | 1 + src/Mod/Fem/Gui/ViewProviderFemMesh.cpp | 12 ++++++++++++ src/Mod/Fem/Gui/ViewProviderFemMesh.h | 4 ++++ src/Mod/Fem/Gui/ViewProviderFemMeshPy.xml | 4 ++-- 7 files changed, 47 insertions(+), 2 deletions(-) diff --git a/src/Mod/Fem/App/AppFem.cpp b/src/Mod/Fem/App/AppFem.cpp index 1de53aae3f..f70df02c00 100644 --- a/src/Mod/Fem/App/AppFem.cpp +++ b/src/Mod/Fem/App/AppFem.cpp @@ -136,6 +136,7 @@ PyMODINIT_FUNC initFem() Fem::FeaturePython ::init(); Fem::FemMesh ::init(); Fem::FemMeshObject ::init(); + Fem::FemMeshObjectPython ::init(); Fem::FemMeshShapeObject ::init(); Fem::FemMeshShapeNetgenObject ::init(); Fem::PropertyFemMesh ::init(); diff --git a/src/Mod/Fem/App/FemMeshObject.cpp b/src/Mod/Fem/App/FemMeshObject.cpp index 768d388204..57a5ce7cda 100644 --- a/src/Mod/Fem/App/FemMeshObject.cpp +++ b/src/Mod/Fem/App/FemMeshObject.cpp @@ -29,6 +29,7 @@ #include "FemMeshObject.h" #include "FemMesh.h" #include +#include #include using namespace Fem; @@ -70,3 +71,25 @@ void FemMeshObject::onChanged(const Property* prop) } } + +// Python feature --------------------------------------------------------- + +namespace App { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(Fem::FemMeshObjectPython, Fem::FemMeshObject) +template<> const char* Fem::FemMeshObjectPython::getViewProviderName(void) const { + return "FemGui::ViewProviderFemMeshPython"; +} + +template<> PyObject* Fem::FemMeshObjectPython::getPyObject(void) { + if (PythonObject.is(Py::_None())) { + // ref counter is set to 1 + PythonObject = Py::Object(new App::FeaturePythonPyT(this),true); + } + return Py::new_reference_to(PythonObject); +} + +// explicit template instantiation +template class AppFemExport FeaturePythonT; + +} diff --git a/src/Mod/Fem/App/FemMeshObject.h b/src/Mod/Fem/App/FemMeshObject.h index 0a774c0605..161b4d2f9c 100644 --- a/src/Mod/Fem/App/FemMeshObject.h +++ b/src/Mod/Fem/App/FemMeshObject.h @@ -24,6 +24,7 @@ #ifndef Fem_FemMeshObject_H #define Fem_FemMeshObject_H +#include #include #include #include @@ -60,6 +61,9 @@ protected: virtual void onChanged (const App::Property* prop); }; +typedef App::FeaturePythonT FemMeshObjectPython; + + } //namespace Fem diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index ee950db3a4..840f98aba3 100644 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -109,6 +109,7 @@ PyMODINIT_FUNC initFemGui() FemGui::ViewProviderFemAnalysis ::init(); FemGui::ViewProviderFemAnalysisPython ::init(); FemGui::ViewProviderFemMesh ::init(); + FemGui::ViewProviderFemMeshPython ::init(); FemGui::ViewProviderFemMeshShape ::init(); FemGui::ViewProviderFemMeshShapeNetgen ::init(); FemGui::ViewProviderSolver ::init(); diff --git a/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp b/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp index 9ba4d148a9..689a96ecec 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp +++ b/src/Mod/Fem/Gui/ViewProviderFemMesh.cpp @@ -2464,3 +2464,15 @@ void ViewProviderFEMMeshBuilder::createMesh(const App::Property* prop, } + + +// Python feature ----------------------------------------------------------------------- + +namespace Gui { +/// @cond DOXERR +PROPERTY_SOURCE_TEMPLATE(FemGui::ViewProviderFemMeshPython, FemGui::ViewProviderFemMesh) +/// @endcond + +// explicit template instantiation +template class FemGuiExport ViewProviderPythonFeatureT; +} diff --git a/src/Mod/Fem/Gui/ViewProviderFemMesh.h b/src/Mod/Fem/Gui/ViewProviderFemMesh.h index d2b9d35ce8..6ba9f90c76 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemMesh.h +++ b/src/Mod/Fem/Gui/ViewProviderFemMesh.h @@ -26,6 +26,7 @@ #include #include +#include #include @@ -163,6 +164,9 @@ private: class Private; }; +typedef Gui::ViewProviderPythonFeatureT ViewProviderFemMeshPython; + + } //namespace FemGui diff --git a/src/Mod/Fem/Gui/ViewProviderFemMeshPy.xml b/src/Mod/Fem/Gui/ViewProviderFemMeshPy.xml index 75814be5f6..866ebb85ba 100644 --- a/src/Mod/Fem/Gui/ViewProviderFemMeshPy.xml +++ b/src/Mod/Fem/Gui/ViewProviderFemMeshPy.xml @@ -1,13 +1,13 @@ From 8839a19b613d16ac86a12556cd24dc053068adac Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:54 +0100 Subject: [PATCH 24/28] FEM: GMSH mesh tool, new python mesh object --- src/Mod/Fem/App/CMakeLists.txt | 3 + src/Mod/Fem/CMakeLists.txt | 4 + src/Mod/Fem/FemMeshGmsh.py | 43 +++++++++ src/Mod/Fem/_FemMeshGmsh.py | 69 ++++++++++++++ src/Mod/Fem/_ViewProviderFemMeshGmsh.py | 114 ++++++++++++++++++++++++ 5 files changed, 233 insertions(+) create mode 100644 src/Mod/Fem/FemMeshGmsh.py create mode 100644 src/Mod/Fem/_FemMeshGmsh.py create mode 100644 src/Mod/Fem/_ViewProviderFemMeshGmsh.py diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index 448b304ce1..bf1cb25dc9 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -80,6 +80,7 @@ SET(FemScripts_SRCS _FemBeamSection.py _FemConstraintSelfWeight.py _FemMaterialMechanicalNonlinear.py + _FemMeshGmsh.py _FemShellThickness.py _FemSolverCalculix.py _FemSolverZ88.py @@ -92,6 +93,7 @@ SET(FemScripts_SRCS _ViewProviderFemBeamSection.py _ViewProviderFemConstraintSelfWeight.py _ViewProviderFemMaterialMechanicalNonlinear.py + _ViewProviderFemMeshGmsh.py _ViewProviderFemShellThickness.py _ViewProviderFemSolverCalculix.py _ViewProviderFemSolverZ88.py @@ -111,6 +113,7 @@ SET(FemScripts_SRCS FemInputWriterCcx.py FemInputWriterZ88.py FemMaterialMechanicalNonlinear.py + FemMeshGmsh.py FemMeshTools.py FemShellThickness.py FemSolverCalculix.py diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 213166b678..3a8f33ce44 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -36,6 +36,10 @@ INSTALL( FemAnalysis.py _CommandAnalysis.py + FemMeshGmsh.py + _FemMeshGmsh.py + _ViewProviderFemMeshGmsh.py + FemBeamSection.py _FemBeamSection.py _ViewProviderFemBeamSection.py diff --git a/src/Mod/Fem/FemMeshGmsh.py b/src/Mod/Fem/FemMeshGmsh.py new file mode 100644 index 0000000000..fbc98684a1 --- /dev/null +++ b/src/Mod/Fem/FemMeshGmsh.py @@ -0,0 +1,43 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "FemMeshGmsh" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + +## \addtogroup FEM +# @{ + +import FreeCAD +import _FemMeshGmsh + + +def makeFemMeshGmsh(name="FEMMeshGMSH"): + '''makeFemMeshGmsh(name): makes a GMSH FEM mesh object''' + obj = FreeCAD.ActiveDocument.addObject("Fem::FemMeshObjectPython", name) + _FemMeshGmsh._FemMeshGmsh(obj) + if FreeCAD.GuiUp: + import _ViewProviderFemMeshGmsh + _ViewProviderFemMeshGmsh._ViewProviderFemMeshGmsh(obj.ViewObject) + return obj + +# @} diff --git a/src/Mod/Fem/_FemMeshGmsh.py b/src/Mod/Fem/_FemMeshGmsh.py new file mode 100644 index 0000000000..2dc0833e4b --- /dev/null +++ b/src/Mod/Fem/_FemMeshGmsh.py @@ -0,0 +1,69 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "_FemMeshGmsh" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + +## @package FemMeshGmsh +# \ingroup FEM + + +class _FemMeshGmsh(): + """The Fem::FemMeshObject's Proxy python type, add GMSH specific properties + """ + + # they will be used from the task panel too, thus they need to be outside of the __init__ + known_element_dimensions = ['Auto', '1D', '2D', '3D'] + known_element_orders = ['Auto', '1st', '2nd'] + + def __init__(self, obj): + self.Type = "FemMeshGmsh" + self.Object = obj # keep a ref to the DocObj for nonGui usage + obj.Proxy = self # link between App::DocumentObject to this object + + obj.addProperty("App::PropertyLink", "Part", "FEM Mesh", "Part object to mesh") + obj.Part = None + + obj.addProperty("App::PropertyFloat", "ElementSizeMax", "FEM Mesh Params", "Max mesh element size (0.0 = infinity)") + obj.ElementSizeMax = 0.0 # will be 1e+22 + + obj.addProperty("App::PropertyFloat", "ElementSizeMin", "FEM Mesh Params", "Min mesh element size") + obj.ElementSizeMin = 0.0 + + obj.addProperty("App::PropertyEnumeration", "ElementDimension", "FEM Mesh Params", "Dimension of mesh elements (Auto = according ShapeType of part to mesh)") + obj.ElementDimension = _FemMeshGmsh.known_element_dimensions + obj.ElementDimension = 'Auto' # according ShapeType of Part to mesh + + obj.addProperty("App::PropertyEnumeration", "ElementOrder", "FEM Mesh Params", "Order of mesh elements (Auto will be 2nd)") + obj.ElementOrder = _FemMeshGmsh.known_element_orders + obj.ElementOrder = 'Auto' # = 2nd + + def execute(self, obj): + return + + def __getstate__(self): + return self.Type + + def __setstate__(self, state): + if state: + self.Type = state diff --git a/src/Mod/Fem/_ViewProviderFemMeshGmsh.py b/src/Mod/Fem/_ViewProviderFemMeshGmsh.py new file mode 100644 index 0000000000..bcae493989 --- /dev/null +++ b/src/Mod/Fem/_ViewProviderFemMeshGmsh.py @@ -0,0 +1,114 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "_ViewProviderFemMeshGmsh" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + +## @package ViewProviderFemMeshGmsh +# \ingroup FEM + +import FreeCAD +import FreeCADGui +import FemGui + + +class _ViewProviderFemMeshGmsh: + "A View Provider for the FemMeshGmsh object" + def __init__(self, vobj): + vobj.Proxy = self + + def getIcon(self): + return ":/icons/fem-fem-mesh-from-shape.svg" + + def attach(self, vobj): + self.ViewObject = vobj + self.Object = vobj.Object + + def updateData(self, obj, prop): + return + + def onChanged(self, vobj, prop): + return + + def setEdit(self, vobj, mode): + self.ViewObject.show() # show the mesh on edit if it is hided + import _TaskPanelFemMeshGmsh + taskd = _TaskPanelFemMeshGmsh._TaskPanelFemMeshGmsh(self.Object) + taskd.obj = vobj.Object + FreeCADGui.Control.showDialog(taskd) + return True + + def unsetEdit(self, vobj, mode): + FreeCADGui.Control.closeDialog() + return + + def doubleClicked(self, vobj): + # Group meshing is only active on active analysis, we should make sure the analysis the mesh belongs too is active + gui_doc = FreeCADGui.getDocument(vobj.Object.Document) + if not gui_doc.getInEdit(): + # may be go the other way around and just activate the analysis the user has doubleClicked on ?! + # not a fast one, we need to iterate over all member of all analysis to know to which analyis the object belongs too!!! + if FemGui.getActiveAnalysis() is not None: + if FemGui.getActiveAnalysis().Document is FreeCAD.ActiveDocument: + if self.Object in FemGui.getActiveAnalysis().Member: + if not gui_doc.getInEdit(): + FreeCAD.Console.PrintError('TaskPanel test not yet implemented\n') + # gui_doc.setEdit(vobj.Object.Name) + else: + FreeCAD.Console.PrintError('Activate the analysis this mesh belongs to!\n') + else: + print('Mesh does not belong to the active analysis.') + for o in gui_doc.Document.Objects: + if o.isDerivedFrom('Fem::FemAnalysisPython'): + for m in o.Member: + if m == self.Object: + FemGui.setActiveAnalysis(o) + print('Analysis the Mesh belongs too was activated.') + FreeCAD.Console.PrintError('TaskPanel test not yet implemented\n') + # gui_doc.setEdit(vobj.Object.Name) + break + else: + FreeCAD.Console.PrintError('Active Analysis is not in active Document!\n') + else: + # no active analysis, we gone have a look if the obj belongs to a non active analysis, + for o in gui_doc.Document.Objects: + if o.isDerivedFrom('Fem::FemAnalysisPython'): + for m in o.Member: + if m == self.Object: + FemGui.setActiveAnalysis(o) + print('Analysis the Mesh belongs too was activated.') + FreeCAD.Console.PrintError('TaskPanel test not yet implemented\n') + # gui_doc.setEdit(vobj.Object.Name) + break + else: + print('Mesh GMSH object does not belong to an analysis. Group meshing will is deactivated.') + gui_doc.setEdit(vobj.Object.Name) + else: + FreeCAD.Console.PrintError('Active Task Dialog found! Please close this one first!\n') + return True + + def __getstate__(self): + return None + + def __setstate__(self, state): + return None From 55fcf495c8c6a5fe78dd49cdeb79520ae4c704ae Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:47:58 +0100 Subject: [PATCH 25/28] FEM: GMSH mesh tool, add command and add it to tool bar and make a menu entry --- src/Mod/Fem/App/CMakeLists.txt | 1 + src/Mod/Fem/CMakeLists.txt | 1 + src/Mod/Fem/Gui/Workbench.cpp | 2 + src/Mod/Fem/InitGui.py | 1 + src/Mod/Fem/_CommandMeshGmshFromShape.py | 65 ++++++++++++++++++++++++ 5 files changed, 70 insertions(+) create mode 100644 src/Mod/Fem/_CommandMeshGmshFromShape.py diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index bf1cb25dc9..448a962217 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -70,6 +70,7 @@ SET(FemScripts_SRCS _CommandConstraintSelfWeight.py _CommandMaterialMechanicalNonlinear.py _CommandMechanicalMaterial.py + _CommandMeshGmshFromShape.py _CommandMeshNetgenFromShape.py _CommandPurgeResults.py _CommandRunSolver.py diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 3a8f33ce44..b6e5c26c51 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -39,6 +39,7 @@ INSTALL( FemMeshGmsh.py _FemMeshGmsh.py _ViewProviderFemMeshGmsh.py + _CommandMeshGmshFromShape.py FemBeamSection.py _FemBeamSection.py diff --git a/src/Mod/Fem/Gui/Workbench.cpp b/src/Mod/Fem/Gui/Workbench.cpp index 86a3985ec1..543289e9bd 100755 --- a/src/Mod/Fem/Gui/Workbench.cpp +++ b/src/Mod/Fem/Gui/Workbench.cpp @@ -59,6 +59,7 @@ Gui::ToolBarItem* Workbench::setupToolBars() const << "Fem_SolverCalculix" // << "Fem_SolverZ88" << "Fem_MeshNetgenFromShape" + << "Fem_MeshGmshFromShape" << "Fem_MechanicalMaterial" << "Fem_MaterialMechanicalNonlinear" << "Fem_BeamSection" @@ -119,6 +120,7 @@ Gui::MenuItem* Workbench::setupMenuBar() const << "Fem_SolverCalculix" << "Fem_SolverZ88" << "Fem_MeshNetgenFromShape" + << "Fem_MeshGmshFromShape" << "Fem_MechanicalMaterial" << "Fem_MaterialMechanicalNonlinear" << "Fem_BeamSection" diff --git a/src/Mod/Fem/InitGui.py b/src/Mod/Fem/InitGui.py index 369e21f596..4aa64f99c8 100644 --- a/src/Mod/Fem/InitGui.py +++ b/src/Mod/Fem/InitGui.py @@ -49,6 +49,7 @@ class FemWorkbench (Workbench): import _CommandRunSolver import _CommandPurgeResults import _CommandControlSolver + import _CommandMeshGmshFromShape import _CommandMeshNetgenFromShape import _CommandAnalysis import _CommandShellThickness diff --git a/src/Mod/Fem/_CommandMeshGmshFromShape.py b/src/Mod/Fem/_CommandMeshGmshFromShape.py new file mode 100644 index 0000000000..c7f628d2f6 --- /dev/null +++ b/src/Mod/Fem/_CommandMeshGmshFromShape.py @@ -0,0 +1,65 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "Command GMSH Mesh From Shape" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + +## @package CommandMeshGmshFromShape +# \ingroup FEM + +import FreeCAD +from FemCommands import FemCommands +import FreeCADGui +import FemGui +from PySide import QtCore + + +class _CommandMeshGmshFromShape(FemCommands): + # the Fem_MeshGmshFromShape command definition + def __init__(self): + super(_CommandMeshGmshFromShape, self).__init__() + self.resources = {'Pixmap': 'fem-fem-mesh-from-shape', + 'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGmshFromShape", "FEM mesh from shape by GMSH"), + 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGmshFromShape", "Create a FEM mesh from a shape by GMSH mesher")} + self.is_active = 'with_part_feature' + + def Activated(self): + FreeCAD.ActiveDocument.openTransaction("Create FEM mesh by GMSH") + FreeCADGui.addModule("FemGui") + sel = FreeCADGui.Selection.getSelection() + if (len(sel) == 1): + if(sel[0].isDerivedFrom("Part::Feature")): + mesh_obj_name = sel[0].Name + "_Mesh" + FreeCADGui.addModule("FemMeshGmsh") + FreeCADGui.doCommand("FemMeshGmsh.makeFemMeshGmsh('" + mesh_obj_name + "')") + FreeCADGui.doCommand("App.ActiveDocument.ActiveObject.Part = App.ActiveDocument." + sel[0].Name) + if FemGui.getActiveAnalysis(): + FreeCADGui.addModule("FemGui") + FreeCADGui.doCommand("FemGui.getActiveAnalysis().Member = FemGui.getActiveAnalysis().Member + [App.ActiveDocument.ActiveObject]") + FreeCADGui.doCommand("Gui.ActiveDocument.setEdit(App.ActiveDocument.ActiveObject.Name)") + + FreeCADGui.Selection.clearSelection() + + +if FreeCAD.GuiUp: + FreeCADGui.addCommand('Fem_MeshGmshFromShape', _CommandMeshGmshFromShape()) From c5216645ced83c9f8f57c9066b57259e2a2847a7 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:48:02 +0100 Subject: [PATCH 26/28] FEM: GMSH mesh tool, the GMSH tool class and a task panel --- src/Mod/Fem/App/CMakeLists.txt | 3 + src/Mod/Fem/CMakeLists.txt | 4 + src/Mod/Fem/FemGmshTools.py | 258 ++++++++++++++++++++++++ src/Mod/Fem/TaskPanelFemMeshGmsh.ui | 203 +++++++++++++++++++ src/Mod/Fem/_TaskPanelFemMeshGmsh.py | 170 ++++++++++++++++ src/Mod/Fem/_ViewProviderFemMeshGmsh.py | 9 +- 6 files changed, 641 insertions(+), 6 deletions(-) create mode 100644 src/Mod/Fem/FemGmshTools.py create mode 100644 src/Mod/Fem/TaskPanelFemMeshGmsh.ui create mode 100644 src/Mod/Fem/_TaskPanelFemMeshGmsh.py diff --git a/src/Mod/Fem/App/CMakeLists.txt b/src/Mod/Fem/App/CMakeLists.txt index 448a962217..f84b4a9966 100755 --- a/src/Mod/Fem/App/CMakeLists.txt +++ b/src/Mod/Fem/App/CMakeLists.txt @@ -87,6 +87,7 @@ SET(FemScripts_SRCS _FemSolverZ88.py _MechanicalMaterial.py _TaskPanelFemBeamSection.py + _TaskPanelFemMeshGmsh.py _TaskPanelFemShellThickness.py _TaskPanelFemSolverCalculix.py _TaskPanelMechanicalMaterial.py @@ -110,6 +111,7 @@ SET(FemScripts_SRCS FemBeamSection.py FemCommands.py FemConstraintSelfWeight.py + FemGmshTools.py FemInputWriter.py FemInputWriterCcx.py FemInputWriterZ88.py @@ -127,6 +129,7 @@ SET(FemScripts_SRCS TestFem.py z88DispReader.py TaskPanelFemBeamSection.ui + TaskPanelFemMeshGmsh.ui TaskPanelFemShellThickness.ui TaskPanelFemSolverCalculix.ui TaskPanelMechanicalMaterial.ui diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index b6e5c26c51..1d5636a81a 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -40,6 +40,10 @@ INSTALL( _FemMeshGmsh.py _ViewProviderFemMeshGmsh.py _CommandMeshGmshFromShape.py + _TaskPanelFemMeshGmsh.py + TaskPanelFemMeshGmsh.ui + + FemGmshTools.py FemBeamSection.py _FemBeamSection.py diff --git a/src/Mod/Fem/FemGmshTools.py b/src/Mod/Fem/FemGmshTools.py new file mode 100644 index 0000000000..f55999a053 --- /dev/null +++ b/src/Mod/Fem/FemGmshTools.py @@ -0,0 +1,258 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "Tools for the work with GMSH mesher" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + +## \addtogroup FEM +# @{ + +import FreeCAD +import Fem +import subprocess +import tempfile +from platform import system + + +# CONFIGURATION - EDIT THE FOLLOWING LINE TO MATCH YOUR GMSH BINARY +# gmsh_bin_linux = "/usr/bin/gmsh" +gmsh_bin_linux = "/usr/local/bin/gmsh" +gmsh_bin_windwos = "C:\\Daten\\gmsh-2.13.2-Windows\\gmsh.exe" +gmsh_bin_other = "/usr/bin/gmsh" +# END CONFIGURATION + + +class FemGmshTools(): + def __init__(self, gmsh_mesh_obj, analysis=None): + self.mesh_obj = gmsh_mesh_obj + if analysis: + self.analysis = analysis + # group meshing turned on + else: + self.analysis = None + # group meshing turned off + + # part to mesh + self.part_obj = self.mesh_obj.Part + + # clmax, ElementSizeMax: float, 0.0 = 1e+22 + self.clmax = self.mesh_obj.ElementSizeMax + if self.clmax == 0.0: + self.clmax = 1e+22 + + # clmin, ElementSizeMin: float + self.clmin = self.mesh_obj.ElementSizeMin + + # order, ElementOrder: ['Auto', '1st', '2nd'] + self.order = self.mesh_obj.ElementOrder + if self.order == '1st': + self.order = '1' + elif self.order == 'Auto' or self.order == '2nd': + self.order = '2' + else: + print('Error in order') + + # dimension, ElementDimension: ['Auto', '1D', '2D', '3D'] + self.dimension = self.mesh_obj.ElementDimension + + def create_mesh(self): + print("\nWe gone start GMSH FEM mesh run!") + print(' Part to mesh: Name --> ' + self.part_obj.Name + ', Label --> ' + self.part_obj.Label + ', ShapeType --> ' + self.part_obj.Shape.ShapeType) + print(' ElementSizeMax: ' + str(self.clmax)) + print(' ElementSizeMin: ' + str(self.clmin)) + print(' ElementOrder: ' + self.order) + self.get_dimension() + self.get_tmp_file_paths() + self.get_gmsh_command() + self.get_group_data() + self.write_part_file() + self.write_geo() + error = self.run_gmsh_with_geo() + self.read_and_set_new_mesh() + return error + + def get_dimension(self): + # Dimension + # GMSH uses the hightest availabe. + # A use case for not auto would be a surface (2D) mesh of a solid or other 3d shape + if self.dimension == 'Auto': + shty = self.part_obj.Shape.ShapeType + if shty == 'Solid' or shty == 'CompSolid': + # print('Found: ' + shty) + self.dimension = '3' + elif shty == 'Face' or shty == 'Shell': + # print('Found: ' + shty) + self.dimension = '2' + elif shty == 'Edge' or shty == 'Wire': + # print('Found: ' + shty) + self.dimension = '1' + elif shty == 'Vertex': + # print('Found: ' + shty) + FreeCAD.Console.PrintError("You can not mesh a Vertex.\n") + self.dimension = '0' + elif shty == 'Compound': + print('Found: ' + shty) + print('I do not know what is inside your Compound. Dimension was set to 3 anyway.') + # TODO check contents of Compound + # use dimension 3 on any shape works for 2D and 1d meshes as well ! + # but not in combination with sewfaces or connectfaces + self.dimension = '3' + else: + self.dimension = '0' + FreeCAD.Console.PrintError('Could not retrive Dimension from shape type. Please choose dimension.') + elif self.dimension == '3D': + self.dimension = '3' + elif self.dimension == '2D': + self.dimension = '2' + elif self.dimension == '1D': + self.dimension = '1' + else: + print('Error in dimension') + print(' ElementDimension: ' + self.dimension) + + def get_tmp_file_paths(self): + if system() == "Linux": + path_sep = "/" + elif system() == "Windows": + path_sep = "\\" + else: + path_sep = "/" + tmpdir = tempfile.gettempdir() + # geometry file + self.temp_file_geometry = tmpdir + path_sep + self.part_obj.Name + '_Geometry.brep' + print(' ' + self.temp_file_geometry) + # mesh file + self.mesh_name = self.part_obj.Name + '_Mesh_TmpGmsh' + self.temp_file_mesh = tmpdir + path_sep + self.mesh_name + '.unv' + print(' ' + self.temp_file_mesh) + # GMSH input file + self.temp_file_geo = tmpdir + path_sep + 'shape2mesh.geo' + print(' ' + self.temp_file_geo) + + def get_gmsh_command(self): + if system() == "Linux": + self.gmsh_bin = gmsh_bin_linux + elif system() == "Windows": + self.gmsh_bin = gmsh_bin_windwos + else: + self.gmsh_bin = gmsh_bin_other + self.gmsh_command = self.gmsh_bin + ' - ' + self.temp_file_geo # gmsh - /tmp/shape2mesh.geo + print(' ' + self.gmsh_command) + + def get_group_data(self): + if self.analysis: + print(' Group meshing.') + import FemMeshTools + self.group_elements = FemMeshTools.get_analysis_group_elements(self.analysis, self.part_obj) + print(self.group_elements) + else: + print(' NO group meshing.') + + def write_part_file(self): + self.part_obj.Shape.exportBrep(self.temp_file_geometry) + + def write_geo(self): + geo = open(self.temp_file_geo, "w") + geo.write('Merge "' + self.temp_file_geometry + '";\n') + geo.write("\n") + if self.analysis and self.group_elements: + print(' We gone have found elements to make mesh groups for!') + geo.write("// group data\n") + # we use the element name of FreeCAD which starts with 1 (example: 'Face1'), same as GMSH + for group in self.group_elements: + gdata = self.group_elements[group] + # print(gdata) + # geo.write("// " + group + "\n") + ele_nr = '' + if gdata[0].startswith('Solid'): + physical_type = 'Volume' + for ele in gdata: + ele_nr += (ele.lstrip('Solid') + ', ') + elif gdata[0].startswith('Face'): + physical_type = 'Surface' + for ele in gdata: + ele_nr += (ele.lstrip('Face') + ', ') + elif gdata[0].startswith('Edge') or gdata[0].startswith('Vertex'): + geo.write("// " + group + " group data not written. Edges or Vertexes group data not supported.\n") + print(' Groups for Edges or Vertexes reference shapes not handeled yet.') + if ele_nr: + ele_nr = ele_nr.rstrip(', ') + # print(ele_nr) + geo.write('Physical ' + physical_type + '("' + group + '") = {' + ele_nr + '};\n') + geo.write("\n") + geo.write("Mesh.CharacteristicLengthMax = " + str(self.clmax) + ";\n") + geo.write("Mesh.CharacteristicLengthMin = " + str(self.clmin) + ";\n") + geo.write("Mesh.ElementOrder = " + self.order + ";\n") + geo.write("//Mesh.HighOrderOptimize = 1;\n") # but does not really work, in GUI it does + geo.write("Mesh.Algorithm3D = 1;\n") + geo.write("Mesh.Algorithm = 2;\n") + geo.write("Mesh " + self.dimension + ";\n") + geo.write("Mesh.Format = 2;\n") # unv + if self.analysis and self.group_elements: + geo.write("// For each group save not only the elements but the nodes too.;\n") + geo.write("Mesh.SaveGroupsOfNodes = 1;\n") + geo.write("// Needed for Group meshing too, because for one material there is no group defined;\n") # belongs to Mesh.SaveAll but anly needed if there are groups + geo.write("// Ignore Physical definitions and save all elements;\n") + geo.write("Mesh.SaveAll = 1;\n") + geo.write("\n") + geo.write('Save "' + self.temp_file_mesh + '";\n') + geo.write("\n\n") + geo.write("//////////////////////////////////////////////////////////////////////\n") + geo.write("// GMSH documentation:\n") + geo.write("// http://gmsh.info/doc/texinfo/gmsh.html#Mesh\n") + geo.write("//\n") + geo.write("// We do not check if something went wrong, like negative jacobians etc. You can run GMSH manually yourself: \n") + geo.write("//\n") + geo.write("// to see full GMSH log, run in bash:\n") + geo.write("// " + self.gmsh_bin + " - " + self.temp_file_geo + "\n") + geo.write("//\n") + geo.write("// to run GMSH and keep file in GMSH GUI (with log), run in bash:\n") + geo.write("// " + self.gmsh_bin + " " + self.temp_file_geo + "\n") + geo.close + + def run_gmsh_with_geo(self): + self.error = False + comandlist = [self.gmsh_bin, '-', self.temp_file_geo] + # print(comandlist) + try: + p = subprocess.Popen(comandlist, shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, error = p.communicate() + # print(output) # stdout is still cut at some point but the warnings are in stderr and thus printed :-) + # print(error) + except: + error = 'Error executing: {}\n'.format(self.gmsh_command) + FreeCAD.Console.PrintError(error) + self.error = True + return error + + def read_and_set_new_mesh(self): + if not self.error: + fem_mesh = Fem.read(self.temp_file_mesh) + self.mesh_obj.FemMesh = fem_mesh + print(' The Part should have a pretty new FEM mesh!') + else: + print('No mesh was created.') + del self.temp_file_geometry + del self.temp_file_mesh + +# @} diff --git a/src/Mod/Fem/TaskPanelFemMeshGmsh.ui b/src/Mod/Fem/TaskPanelFemMeshGmsh.ui new file mode 100644 index 0000000000..48f738a8ac --- /dev/null +++ b/src/Mod/Fem/TaskPanelFemMeshGmsh.ui @@ -0,0 +1,203 @@ + + + GmshMesh + + + + 0 + 0 + 400 + 413 + + + + FEM Mesh by GMSH + + + + + + + 16777215 + 1677215 + + + + FEM Mesh Parameter + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + Mesh element dimension: + + + + + + + + + + Mesh element order: + + + + + + + + + + Max element size (0.0 = Auto): + + + + + + + + 0 + 0 + + + + + 80 + 20 + + + + 0.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1.000000000000000 + + + 1000000000.000000000000000 + + + mm + + + 2 + + + 0.000000000000000 + + + + + + + Min element size (0.0 = Auto): + + + + + + + + 0 + 0 + + + + + 80 + 20 + + + + 0.0 + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1.000000000000000 + + + 1000000000.000000000000000 + + + mm + + + 2 + + + 0.000000000000000 + + + + + + + + + + + + + 16777215 + 1677215 + + + + GMSH + + + + + + QFormLayout::AllNonFixedFieldsGrow + + + + + + + + 12 + + + + Time: + + + + + + + QTextEdit::NoWrap + + + + + + + + + + + + + + + Gui::InputField + QLineEdit +
Gui/InputField.h
+
+
+ + +
diff --git a/src/Mod/Fem/_TaskPanelFemMeshGmsh.py b/src/Mod/Fem/_TaskPanelFemMeshGmsh.py new file mode 100644 index 0000000000..8abd45fe4b --- /dev/null +++ b/src/Mod/Fem/_TaskPanelFemMeshGmsh.py @@ -0,0 +1,170 @@ +# *************************************************************************** +# * * +# * Copyright (c) 2016 - Bernd Hahnebach * +# * * +# * This program is free software; you can redistribute it and/or modify * +# * it under the terms of the GNU Lesser General Public License (LGPL) * +# * as published by the Free Software Foundation; either version 2 of * +# * the License, or (at your option) any later version. * +# * for detail see the LICENCE text file. * +# * * +# * This program is distributed in the hope that it will be useful, * +# * but WITHOUT ANY WARRANTY; without even the implied warranty of * +# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * +# * GNU Library General Public License for more details. * +# * * +# * You should have received a copy of the GNU Library General Public * +# * License along with this program; if not, write to the Free Software * +# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * +# * USA * +# * * +# *************************************************************************** + +__title__ = "_TaskPanelFemMeshGmsh" +__author__ = "Bernd Hahnebach" +__url__ = "http://www.freecadweb.org" + +## @package TaskPanelFemMeshGmsh +# \ingroup FEM + +import FreeCAD +import time +import _FemMeshGmsh +import FreeCADGui +from PySide import QtGui +from PySide import QtCore +from PySide.QtCore import Qt +from PySide.QtGui import QApplication + + +class _TaskPanelFemMeshGmsh: + '''The TaskPanel for editing References property of FemMeshGmsh objects and creation of new FEM mesh''' + def __init__(self, obj): + self.mesh_obj = obj + self.form = FreeCADGui.PySideUic.loadUi(FreeCAD.getHomePath() + "Mod/Fem/TaskPanelFemMeshGmsh.ui") + + self.Timer = QtCore.QTimer() + self.Timer.start(100) # 100 milli seconds + self.gmsh_runs = False + self.console_message_gmsh = '' + + QtCore.QObject.connect(self.form.if_max, QtCore.SIGNAL("valueChanged(double)"), self.max_changed) + QtCore.QObject.connect(self.form.if_min, QtCore.SIGNAL("valueChanged(double)"), self.min_changed) + QtCore.QObject.connect(self.form.cb_dimension, QtCore.SIGNAL("activated(int)"), self.choose_dimension) + QtCore.QObject.connect(self.form.cb_order, QtCore.SIGNAL("activated(int)"), self.choose_order) + QtCore.QObject.connect(self.Timer, QtCore.SIGNAL("timeout()"), self.update_timer_text) + + self.form.cb_dimension.addItems(_FemMeshGmsh._FemMeshGmsh.known_element_dimensions) + self.form.cb_order.addItems(_FemMeshGmsh._FemMeshGmsh.known_element_orders) + + self.get_mesh_params() + self.get_active_analysis() + self.update() + + def getStandardButtons(self): + return int(QtGui.QDialogButtonBox.Apply | QtGui.QDialogButtonBox.Close) + # show a apply and a close button + # def reject() is called on close button + # def clicked(self, button) is needed, to access the apply button + # def accept() in no longer needed, since there is no OK button + + def reject(self): + FreeCADGui.ActiveDocument.resetEdit() + FreeCAD.ActiveDocument.recompute() + return True + + def clicked(self, button): + if button == QtGui.QDialogButtonBox.Apply: + self.run_gmsh() + + def get_mesh_params(self): + self.clmax = self.mesh_obj.ElementSizeMax + self.clmin = self.mesh_obj.ElementSizeMin + self.order = self.mesh_obj.ElementOrder + self.dimension = self.mesh_obj.ElementDimension + + def set_mesh_params(self): + self.mesh_obj.ElementSizeMax = self.clmax + self.mesh_obj.ElementSizeMin = self.clmin + self.mesh_obj.ElementOrder = self.order + self.mesh_obj.ElementDimension = self.dimension + + def update(self): + 'fills the widgets' + self.form.if_max.setText("{} mm".format(self.clmax)) + self.form.if_min.setText("{} mm".format(self.clmin)) + index_dimension = self.form.cb_dimension.findText(self.dimension) + self.form.cb_dimension.setCurrentIndex(index_dimension) + index_order = self.form.cb_order.findText(self.order) + self.form.cb_order.setCurrentIndex(index_order) + + def console_log(self, message="", color="#000000"): + self.console_message_gmsh = self.console_message_gmsh + '{0:4.1f}: {2}
'.\ + format(time.time() - self.Start, color, message.encode('utf-8', 'replace')) + self.form.te_output.setText(self.console_message_gmsh) + self.form.te_output.moveCursor(QtGui.QTextCursor.End) + + def update_timer_text(self): + # print('timer1') + if self.gmsh_runs: + print('timer2') + # print('Time: {0:4.1f}: '.format(time.time() - self.Start)) + self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) + + def max_changed(self, value): + self.clmax = float(value) + + def min_changed(self, value): + self.clmin = float(value) + + def choose_dimension(self, index): + if index < 0: + return + self.form.cb_dimension.setCurrentIndex(index) + self.dimension = str(self.form.cb_dimension.itemText(index)) # form returns unicode + + def choose_order(self, index): + if index < 0: + return + self.form.cb_order.setCurrentIndex(index) + self.order = str(self.form.cb_order.itemText(index)) # form returns unicode + + def run_gmsh(self): + QApplication.setOverrideCursor(Qt.WaitCursor) + self.Start = time.time() + self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) + self.console_message_gmsh = '' + self.gmsh_runs = True + self.console_log("We gone start ...") + self.get_active_analysis() + self.set_mesh_params() + import FemGmshTools + gmsh_mesh = FemGmshTools.FemGmshTools(self.obj, self.analysis) + self.console_log("Start GMSH ...") + error = gmsh_mesh.create_mesh() + if error: + print(error) + self.console_log('GMSH had warnings ...') + self.console_log(error, '#FF0000') + else: + self.console_log('Clean run of GMSH') + self.console_log("GMSH done!") + self.form.l_time.setText('Time: {0:4.1f}: '.format(time.time() - self.Start)) + self.Timer.stop() + self.update() + QApplication.restoreOverrideCursor() + + def get_active_analysis(self): + import FemGui + self.analysis = FemGui.getActiveAnalysis() + if self.analysis: + for m in FemGui.getActiveAnalysis().Member: + if m.Name == self.mesh_obj.Name: + print(self.analysis.Name) + return + else: + # print('Mesh is not member of active analysis, means no group meshing') + self.analysis = None # no group meshing + else: + # print('No active analyis, means no group meshing') + self.analysis = None # no group meshing diff --git a/src/Mod/Fem/_ViewProviderFemMeshGmsh.py b/src/Mod/Fem/_ViewProviderFemMeshGmsh.py index bcae493989..981bfeed62 100644 --- a/src/Mod/Fem/_ViewProviderFemMeshGmsh.py +++ b/src/Mod/Fem/_ViewProviderFemMeshGmsh.py @@ -72,8 +72,7 @@ class _ViewProviderFemMeshGmsh: if FemGui.getActiveAnalysis().Document is FreeCAD.ActiveDocument: if self.Object in FemGui.getActiveAnalysis().Member: if not gui_doc.getInEdit(): - FreeCAD.Console.PrintError('TaskPanel test not yet implemented\n') - # gui_doc.setEdit(vobj.Object.Name) + gui_doc.setEdit(vobj.Object.Name) else: FreeCAD.Console.PrintError('Activate the analysis this mesh belongs to!\n') else: @@ -84,8 +83,7 @@ class _ViewProviderFemMeshGmsh: if m == self.Object: FemGui.setActiveAnalysis(o) print('Analysis the Mesh belongs too was activated.') - FreeCAD.Console.PrintError('TaskPanel test not yet implemented\n') - # gui_doc.setEdit(vobj.Object.Name) + gui_doc.setEdit(vobj.Object.Name) break else: FreeCAD.Console.PrintError('Active Analysis is not in active Document!\n') @@ -97,8 +95,7 @@ class _ViewProviderFemMeshGmsh: if m == self.Object: FemGui.setActiveAnalysis(o) print('Analysis the Mesh belongs too was activated.') - FreeCAD.Console.PrintError('TaskPanel test not yet implemented\n') - # gui_doc.setEdit(vobj.Object.Name) + gui_doc.setEdit(vobj.Object.Name) break else: print('Mesh GMSH object does not belong to an analysis. Group meshing will is deactivated.') From 4fdc94368c75f154d2c58a0acfe3023e4da45662 Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:48:05 +0100 Subject: [PATCH 27/28] FEM: GMSH mesh tool, add a pref page for gmsh binary path --- src/Mod/Fem/FemGmshTools.py | 43 ++-- src/Mod/Fem/Gui/AppFemGui.cpp | 2 + src/Mod/Fem/Gui/CMakeLists.txt | 5 + src/Mod/Fem/Gui/DlgSettingsFemGmsh.ui | 230 ++++++++++++++++++++++ src/Mod/Fem/Gui/DlgSettingsFemGmshImp.cpp | 69 +++++++ src/Mod/Fem/Gui/DlgSettingsFemGmshImp.h | 50 +++++ 6 files changed, 384 insertions(+), 15 deletions(-) create mode 100644 src/Mod/Fem/Gui/DlgSettingsFemGmsh.ui create mode 100644 src/Mod/Fem/Gui/DlgSettingsFemGmshImp.cpp create mode 100644 src/Mod/Fem/Gui/DlgSettingsFemGmshImp.h diff --git a/src/Mod/Fem/FemGmshTools.py b/src/Mod/Fem/FemGmshTools.py index f55999a053..a93c373650 100644 --- a/src/Mod/Fem/FemGmshTools.py +++ b/src/Mod/Fem/FemGmshTools.py @@ -34,14 +34,6 @@ import tempfile from platform import system -# CONFIGURATION - EDIT THE FOLLOWING LINE TO MATCH YOUR GMSH BINARY -# gmsh_bin_linux = "/usr/bin/gmsh" -gmsh_bin_linux = "/usr/local/bin/gmsh" -gmsh_bin_windwos = "C:\\Daten\\gmsh-2.13.2-Windows\\gmsh.exe" -gmsh_bin_other = "/usr/bin/gmsh" -# END CONFIGURATION - - class FemGmshTools(): def __init__(self, gmsh_mesh_obj, analysis=None): self.mesh_obj = gmsh_mesh_obj @@ -150,14 +142,35 @@ class FemGmshTools(): print(' ' + self.temp_file_geo) def get_gmsh_command(self): - if system() == "Linux": - self.gmsh_bin = gmsh_bin_linux - elif system() == "Windows": - self.gmsh_bin = gmsh_bin_windwos + self.gmsh_bin = None + gmsh_std_location = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Gmsh").GetBool("UseStandardGmshLocation") + if gmsh_std_location: + if system() == "Windows": + gmsh_path = FreeCAD.getHomePath() + "bin/gmsh.exe" + FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Gmsh").SetString("gmshBinaryPath", gmsh_path) + self.gmsh_bin = gmsh_path + elif system() == "Linux": + p1 = subprocess.Popen(['which', 'gmsh'], stdout=subprocess.PIPE) + if p1.wait() == 0: + gmsh_path = p1.stdout.read().split('\n')[0] + elif p1.wait() == 1: + error_message = "GMSH binary gmsh not found in standard system binary path. Please install gmsh or set path to binary in FEM preferences tab GMSH.\n" + # if FreeCAD.GuiUp: + # QtGui.QMessageBox.critical(None, "No GMSH binary ccx", error_message) + raise Exception(error_message) + self.gmsh_bin = gmsh_path else: - self.gmsh_bin = gmsh_bin_other - self.gmsh_command = self.gmsh_bin + ' - ' + self.temp_file_geo # gmsh - /tmp/shape2mesh.geo - print(' ' + self.gmsh_command) + if not self.gmsh_bin: + self.gmsh_bin = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Fem/Gmsh").GetString("gmshBinaryPath", "") + if not self.gmsh_bin: # in prefs not set, we will try to use something reasonable + if system() == "Linux": + self.gmsh_bin = "gmsh" + elif system() == "Windows": + self.gmsh_bin = FreeCAD.getHomePath() + "bin/gmsh.exe" + else: + self.gmsh_bin = "gmsh" + self.gmsh_bin = self.gmsh_bin + print(' ' + self.gmsh_bin) def get_group_data(self): if self.analysis: diff --git a/src/Mod/Fem/Gui/AppFemGui.cpp b/src/Mod/Fem/Gui/AppFemGui.cpp index 840f98aba3..e8bb5266d1 100644 --- a/src/Mod/Fem/Gui/AppFemGui.cpp +++ b/src/Mod/Fem/Gui/AppFemGui.cpp @@ -35,6 +35,7 @@ #include "PropertyFemMeshItem.h" #include "DlgSettingsFemGeneralImp.h" #include "DlgSettingsFemCcxImp.h" +#include "DlgSettingsFemGmshImp.h" #include "DlgSettingsFemZ88Imp.h" #include "ViewProviderFemMesh.h" #include "ViewProviderFemMeshShape.h" @@ -154,6 +155,7 @@ PyMODINIT_FUNC initFemGui() // register preferences pages new Gui::PrefPageProducer (QT_TRANSLATE_NOOP("QObject","FEM")); new Gui::PrefPageProducer (QT_TRANSLATE_NOOP("QObject","FEM")); + new Gui::PrefPageProducer (QT_TRANSLATE_NOOP("QObject","FEM")); new Gui::PrefPageProducer (QT_TRANSLATE_NOOP("QObject","FEM")); // add resources and reloads the translators diff --git a/src/Mod/Fem/Gui/CMakeLists.txt b/src/Mod/Fem/Gui/CMakeLists.txt index 661b7835b2..6c4dc26414 100755 --- a/src/Mod/Fem/Gui/CMakeLists.txt +++ b/src/Mod/Fem/Gui/CMakeLists.txt @@ -44,6 +44,7 @@ SOURCE_GROUP("Python" FILES ${Python_SRCS}) set(FemGui_MOC_HDRS DlgSettingsFemCcxImp.h DlgSettingsFemGeneralImp.h + DlgSettingsFemGmshImp.h DlgSettingsFemZ88Imp.h PropertyFemMeshItem.h TaskObjectName.h @@ -83,6 +84,7 @@ SOURCE_GROUP("Moc" FILES ${FemGui_MOC_SRCS}) set(FemGui_UIC_SRCS DlgSettingsFemCcx.ui DlgSettingsFemGeneral.ui + DlgSettingsFemGmsh.ui DlgSettingsFemZ88.ui TaskCreateNodeSet.ui TaskObjectName.ui @@ -125,6 +127,9 @@ SET(FemGui_DLG_SRCS DlgSettingsFemGeneral.ui DlgSettingsFemGeneralImp.cpp DlgSettingsFemGeneralImp.h + DlgSettingsFemGmsh.ui + DlgSettingsFemGmshImp.cpp + DlgSettingsFemGmshImp.h DlgSettingsFemZ88.ui DlgSettingsFemZ88Imp.cpp DlgSettingsFemZ88Imp.h diff --git a/src/Mod/Fem/Gui/DlgSettingsFemGmsh.ui b/src/Mod/Fem/Gui/DlgSettingsFemGmsh.ui new file mode 100644 index 0000000000..3be9f8bff2 --- /dev/null +++ b/src/Mod/Fem/Gui/DlgSettingsFemGmsh.ui @@ -0,0 +1,230 @@ + + + FemGui::DlgSettingsFemGmshImp + + + + 0 + 0 + 372 + 144 + + + + GMSH + + + + + + + + + 0 + 0 + + + + Qt::LeftToRight + + + GMSH + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + + QLayout::SetNoConstraint + + + + + + + Use standard gmsh binary path + + + true + + + UseStandardGmshLocation + + + Mod/Fem/Gmsh + + + + + + + GMSH binary + + + + + + + false + + + + 100 + 0 + + + + gmsh binary path + + + + + + + false + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + + 0 + 0 + + + + Leave blank to use default gmsh binary file + + + gmshBinaryPath + + + Mod/Fem/Gmsh + + + + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Gui::PrefCheckBox + QCheckBox +
Gui/PrefWidgets.h
+
+ + Gui::FileChooser + QWidget +
Gui/FileDialog.h
+
+ + Gui::PrefFileChooser + Gui::FileChooser +
Gui/PrefWidgets.h
+
+
+ + + + + + cb_gmsh_binary_std + toggled(bool) + l_gmsh_binary_path + setEnabled(bool) + + + 406 + 45 + + + 148 + 68 + + + + + cb_gmsh_binary_std + toggled(bool) + fc_gmsh_binary_path + setEnabled(bool) + + + 406 + 45 + + + 406 + 68 + + + + + cb_gmsh_binary_std + toggled(bool) + l_gmsh_binary_path + setDisabled(bool) + + + 406 + 45 + + + 148 + 68 + + + + + cb_gmsh_binary_std + toggled(bool) + fc_gmsh_binary_path + setDisabled(bool) + + + 406 + 45 + + + 406 + 68 + + + + +
diff --git a/src/Mod/Fem/Gui/DlgSettingsFemGmshImp.cpp b/src/Mod/Fem/Gui/DlgSettingsFemGmshImp.cpp new file mode 100644 index 0000000000..adbd5fb9aa --- /dev/null +++ b/src/Mod/Fem/Gui/DlgSettingsFemGmshImp.cpp @@ -0,0 +1,69 @@ +/*************************************************************************** + * Copyright (c) 2016 FreeCAD Developers * + * Author: Bernd Hahnebach * + * Based on src/Mod/Fem/Gui/DlgSettingsFemCcxImp.cpp * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#include "PreCompiled.h" + +#include "Gui/Application.h" +#include "DlgSettingsFemGmshImp.h" +#include + +using namespace FemGui; + +DlgSettingsFemGmshImp::DlgSettingsFemGmshImp( QWidget* parent ) + : PreferencePage( parent ) +{ + this->setupUi(this); +} + +DlgSettingsFemGmshImp::~DlgSettingsFemGmshImp() +{ + // no need to delete child widgets, Qt does it all for us +} + +void DlgSettingsFemGmshImp::saveSettings() +{ + cb_gmsh_binary_std->onSave(); + fc_gmsh_binary_path->onSave(); +} + +void DlgSettingsFemGmshImp::loadSettings() +{ + cb_gmsh_binary_std->onRestore(); + fc_gmsh_binary_path->onRestore(); +} + +/** + * Sets the strings of the subwidgets using the current language. + */ +void DlgSettingsFemGmshImp::changeEvent(QEvent *e) +{ + if (e->type() == QEvent::LanguageChange) { + } + else { + QWidget::changeEvent(e); + } +} + +#include "moc_DlgSettingsFemGmshImp.cpp" diff --git a/src/Mod/Fem/Gui/DlgSettingsFemGmshImp.h b/src/Mod/Fem/Gui/DlgSettingsFemGmshImp.h new file mode 100644 index 0000000000..33596da736 --- /dev/null +++ b/src/Mod/Fem/Gui/DlgSettingsFemGmshImp.h @@ -0,0 +1,50 @@ + /************************************************************************** + * Copyright (c) 2016 FreeCAD Developers * + * Author: Bernd Hahnebach * + * Based on src/Mod/Fem/Gui/DlgSettingsFemCcx.h * + * * + * This file is part of the FreeCAD CAx development system. * + * * + * This library is free software; you can redistribute it and/or * + * modify it under the terms of the GNU Library General Public * + * License as published by the Free Software Foundation; either * + * version 2 of the License, or (at your option) any later version. * + * * + * This library is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU Library General Public License for more details. * + * * + * You should have received a copy of the GNU Library General Public * + * License along with this library; see the file COPYING.LIB. If not, * + * write to the Free Software Foundation, Inc., 59 Temple Place, * + * Suite 330, Boston, MA 02111-1307, USA * + * * + ***************************************************************************/ + + +#ifndef FEMGUI_DLGSETTINGSFEMGMSHIMP_H +#define FEMGUI_DLGSETTINGSFEMGMSHIMP_H + +#include "ui_DlgSettingsFemGmsh.h" +#include + +namespace FemGui { + +class DlgSettingsFemGmshImp : public Gui::Dialog::PreferencePage, public Ui_DlgSettingsFemGmshImp +{ + Q_OBJECT + +public: + DlgSettingsFemGmshImp( QWidget* parent = 0 ); + ~DlgSettingsFemGmshImp(); + +protected: + void saveSettings(); + void loadSettings(); + void changeEvent(QEvent *e); +}; + +} // namespace FemGui + +#endif // FEMGUI_DLGSETTINGSFEMGMSHIMP_H From f326dc59a944e301eb85824463e2d1de14d0f67b Mon Sep 17 00:00:00 2001 From: Bernd Hahnebach Date: Tue, 22 Nov 2016 19:48:46 +0100 Subject: [PATCH 28/28] FEM: GMSH mesh tool, change icons for netgen and gmsh mesh to distingish them in toolbar --- src/Mod/Fem/Gui/Resources/Fem.qrc | 2 + .../icons/fem-fem-mesh-gmsh-from-shape.svg | 246 ++++++++++++++++++ .../icons/fem-fem-mesh-netgen-from-shape.svg | 246 ++++++++++++++++++ src/Mod/Fem/_CommandMeshGmshFromShape.py | 2 +- src/Mod/Fem/_CommandMeshNetgenFromShape.py | 2 +- 5 files changed, 496 insertions(+), 2 deletions(-) create mode 100644 src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-gmsh-from-shape.svg create mode 100644 src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-netgen-from-shape.svg diff --git a/src/Mod/Fem/Gui/Resources/Fem.qrc b/src/Mod/Fem/Gui/Resources/Fem.qrc index cffc4a2a73..7eb3d8a58d 100755 --- a/src/Mod/Fem/Gui/Resources/Fem.qrc +++ b/src/Mod/Fem/Gui/Resources/Fem.qrc @@ -1,6 +1,8 @@ icons/fem-fem-mesh-from-shape.svg + icons/fem-fem-mesh-gmsh-from-shape.svg + icons/fem-fem-mesh-netgen-from-shape.svg icons/fem-fem-mesh-create-node-by-poly.svg icons/fem-analysis.svg icons/fem-cfd-analysis.svg diff --git a/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-gmsh-from-shape.svg b/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-gmsh-from-shape.svg new file mode 100644 index 0000000000..d9fd5d8cf4 --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-gmsh-from-shape.svg @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + G + G + + diff --git a/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-netgen-from-shape.svg b/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-netgen-from-shape.svg new file mode 100644 index 0000000000..34c5bb60ef --- /dev/null +++ b/src/Mod/Fem/Gui/Resources/icons/fem-fem-mesh-netgen-from-shape.svg @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + N + N + + diff --git a/src/Mod/Fem/_CommandMeshGmshFromShape.py b/src/Mod/Fem/_CommandMeshGmshFromShape.py index c7f628d2f6..c279232880 100644 --- a/src/Mod/Fem/_CommandMeshGmshFromShape.py +++ b/src/Mod/Fem/_CommandMeshGmshFromShape.py @@ -38,7 +38,7 @@ class _CommandMeshGmshFromShape(FemCommands): # the Fem_MeshGmshFromShape command definition def __init__(self): super(_CommandMeshGmshFromShape, self).__init__() - self.resources = {'Pixmap': 'fem-fem-mesh-from-shape', + self.resources = {'Pixmap': 'fem-fem-mesh-gmsh-from-shape', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGmshFromShape", "FEM mesh from shape by GMSH"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshGmshFromShape", "Create a FEM mesh from a shape by GMSH mesher")} self.is_active = 'with_part_feature' diff --git a/src/Mod/Fem/_CommandMeshNetgenFromShape.py b/src/Mod/Fem/_CommandMeshNetgenFromShape.py index 27e1f11274..b44a161db5 100644 --- a/src/Mod/Fem/_CommandMeshNetgenFromShape.py +++ b/src/Mod/Fem/_CommandMeshNetgenFromShape.py @@ -37,7 +37,7 @@ class _CommandMeshNetgenFromShape(FemCommands): # the Fem_MeshNetgenFromShape command definition def __init__(self): super(_CommandMeshNetgenFromShape, self).__init__() - self.resources = {'Pixmap': 'fem-fem-mesh-from-shape', + self.resources = {'Pixmap': 'fem-fem-mesh-netgen-from-shape', 'MenuText': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "FEM mesh from shape by Netgen"), 'ToolTip': QtCore.QT_TRANSLATE_NOOP("Fem_MeshFromShape", "Create a FEM volume mesh from a solid or face shape by Netgen internal mesher")} self.is_active = 'with_part_feature'