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_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'] print("Constraint pressure: " + femobj['Object'].Name) 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'])
def get_material_elements(self): # it only works if either Volumes or Shellthicknesses or Beamsections are in the material objects # it means it does not work for mixed meshes and multiple materials, this is checked in check_prerequisites # the femelement_table is only calculated for the highest dimension in get_femelement_table FreeCAD.Console.PrintMessage('Materials\n') if self.femmesh.Volumes: # we only could do this for volumes, if a mesh contains volumes we're going to use them in the analysis # but a mesh could contain the element faces of the volumes as faces and the edges of the faces as edges, # there we have to check of some geometric objects all_found = False if self.femmesh.GroupCount: all_found = FemMeshTools.get_femelement_sets_from_group_data(self.femmesh, self.material_objects) FreeCAD.Console.PrintMessage(all_found) FreeCAD.Console.PrintMessage('\n') if all_found is False: if not self.femelement_table: self.femelement_table = FemMeshTools.get_femelement_table(self.femmesh) # we're going to 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) control = FemMeshTools.get_femelement_sets(self.femmesh, self.femelement_table, self.material_objects, self.femnodes_ele_table) if (self.femelement_count_test is True) and (control is False): # we only need to set it, if it is still True self.femelement_count_test = False if self.shellthickness_objects: if not self.femelement_faces_table: self.femelement_faces_table = FemMeshTools.get_femelement_faces_table(self.femmesh) FemMeshTools.get_femelement_sets(self.femmesh, self.femelement_faces_table, self.material_objects) if self.beamsection_objects or self.fluidsection_objects: if not self.femelement_edges_table: self.femelement_edges_table = FemMeshTools.get_femelement_edges_table(self.femmesh) FemMeshTools.get_femelement_sets(self.femmesh, self.femelement_edges_table, self.material_objects)
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"] = meshtools.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 = meshtools.get_femelement_table( self.femmesh) if not self.femnodes_ele_table: self.femnodes_ele_table = meshtools.get_femnodes_ele_table( self.femnodes_mesh, self.femelement_table) for femobj in self.pressure_objects: # femobj --> dict, FreeCAD document object is femobj["Object"] FreeCAD.Console.PrintMessage("Constraint pressure: " + femobj["Object"].Name + "\n") pressure_faces = meshtools.get_pressure_obj_faces( self.femmesh, self.femelement_table, self.femnodes_ele_table, femobj) femobj["PressureFaces"] = [(femobj["Object"].Name + ": face load", pressure_faces)] FreeCAD.Console.PrintLog("{}\n".format(femobj["PressureFaces"]))
def get_material_elements(self): # it only works if either Volumes or Shellthicknesses or Beamsections are in the material objects # it means it does not work for mixed meshes and multiple materials, this is checked in check_prerequisites print("Materials") if self.femmesh.Volumes: # we only could do this for volumes, if a mesh contains volumes we're going to use them in the analysis # but a mesh could contain the element faces of the volumes as faces and the edges of the faces as edges, # there we have to check of some geometric objects all_found = False if self.femmesh.GroupCount: all_found = FemMeshTools.get_femelement_sets_from_group_data(self.femmesh, self.material_objects) print(all_found) if all_found is False: if not self.femelement_table: self.femelement_table = FemMeshTools.get_femelement_table(self.femmesh) # we're going to 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) if self.shellthickness_objects: 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) if self.beamsection_objects or self.fluidsection_objects: 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)
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_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'] FreeCAD.Console.PrintMessage("Constraint pressure: " + femobj['Object'].Name + '\n') 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)] FreeCAD.Console.PrintMessage(femobj['PressureFaces']) FreeCAD.Console.PrintMessage('\n')
def get_solid_element_sets(self, femobjs): # get element ids and write them into the femobj all_found = False if self.femmesh.GroupCount: all_found = meshtools.get_femelement_sets_from_group_data( self.femmesh, femobjs) FreeCAD.Console.PrintMessage(all_found) FreeCAD.Console.PrintMessage("\n") if all_found is False: if not self.femelement_table: self.femelement_table = meshtools.get_femelement_table( self.femmesh) # we're going to 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 = meshtools.get_femnodes_ele_table( self.femnodes_mesh, self.femelement_table) control = meshtools.get_femelement_sets(self.femmesh, self.femelement_table, femobjs, self.femnodes_ele_table) # we only need to set it, if it is still True if (self.femelement_count_test is True) and (control is False): self.femelement_count_test = False
def get_constraints_tie_faces(self): if not self.femnodes_mesh: self.femnodes_mesh = self.femmesh.Nodes if not self.femelement_table: self.femelement_table = meshtools.get_femelement_table( self.femmesh) if not self.femnodes_ele_table: self.femnodes_ele_table = meshtools.get_femnodes_ele_table( self.femnodes_mesh, self.femelement_table) for femobj in self.tie_objects: # femobj --> dict, FreeCAD document object is femobj["Object"] print_obj_info(femobj["Object"]) slave_faces, master_faces = meshtools.get_tie_obj_faces( self.femmesh, self.femelement_table, self.femnodes_ele_table, femobj) # [ele_id, ele_face_id], [ele_id, ele_face_id], ...] # whereas the ele_face_id might be ccx specific femobj["TieSlaveFaces"] = slave_faces femobj["TieMasterFaces"] = master_faces
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"] = meshtools.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 = meshtools.get_femelement_table(self.femmesh) if not self.femnodes_ele_table: self.femnodes_ele_table = meshtools.get_femnodes_ele_table( self.femnodes_mesh, self.femelement_table ) for femobj in self.pressure_objects: # femobj --> dict, FreeCAD document object is femobj["Object"] print_obj_info(femobj["Object"]) pressure_faces = meshtools.get_pressure_obj_faces( self.femmesh, self.femelement_table, self.femnodes_ele_table, femobj ) # the data model is for compatibility reason with depreciated version # get_pressure_obj_faces_depreciated returns the face ids in a tuple per ref_shape # some_string was the reference_shape_element_string in depreciated method # [(some_string, [ele_id, ele_face_id], [ele_id, ele_face_id], ...])] some_string = "{}: face load".format(femobj["Object"].Name) femobj["PressureFaces"] = [(some_string, pressure_faces)] FreeCAD.Console.PrintLog("{}\n".format(femobj["PressureFaces"]))
def get_constraints_contact_faces(self): if not self.member.cons_contact: return if not self.femnodes_mesh: self.femnodes_mesh = self.femmesh.Nodes if not self.femelement_table: self.femelement_table = meshtools.get_femelement_table( self.femmesh) if not self.femnodes_ele_table: self.femnodes_ele_table = meshtools.get_femnodes_ele_table( self.femnodes_mesh, self.femelement_table) for femobj in self.member.cons_contact: # femobj --> dict, FreeCAD document object is femobj["Object"] print_obj_info(femobj["Object"]) contact_slave_faces, contact_master_faces = meshtools.get_contact_obj_faces( self.femmesh, self.femelement_table, self.femnodes_ele_table, femobj) # [ele_id, ele_face_id], [ele_id, ele_face_id], ...] # whereas the ele_face_id might be ccx specific femobj["ContactSlaveFaces"] = contact_slave_faces femobj["ContactMasterFaces"] = contact_master_faces
def setUpInput(doc, mesh, analysis): analysis = doc.getObject("Analysis") # create connextivity array elnodes for mapping local node number -> global node number elnodes = np.array([mesh.getElementNodes(el) for el in mesh.Volumes ]) # elnodes[elementIndex] = [node1,...,Node10] elo = dict(zip(mesh.Volumes, range(len( mesh.Volumes)))) # elo : {elementNumber : elementIndex} # create nodal coordinate array nocoord for node number -> (x,y,z) nocoord = np.asarray(mesh.Nodes.values() ) # nocoord[nodeIndex] = [x-coord, y-coord, z-coord] # create element material array: materialbyElement maps element number -> E, nu materials_lin = gsm(analysis, 'Fem::Material') fiwc = iw(analysis, doc.CalculiXccxTools, doc.FEMMeshGmsh, materials_lin, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None, None) fiwc.get_material_elements() materialbyElement = [] po_keys = [] # parentobject[el] = parent material object for element el po_values = [] counter = 0 for object in fiwc.material_objects: E = float( App.Units.Quantity( object['Object'].Material['YoungsModulus']).getValueAs('MPa')) Nu = float(object['Object'].Material['PoissonRatio']) for el in object['FEMElements']: po_keys.append(el) po_values.append(object['Object'].Name) counter += 1 materialbyElement.append([ el, E, Nu ]) # materialbyElement[elementIndex] = [elementNumber, E, Nu] parentobject = dict(zip(po_keys, po_values)) # determine elements connected to a node using FC API fet = mt.get_femelement_table( mesh ) # fet is dictionary: { elementid : [ nodeid, nodeid, ... , nodeid ] } net = mt.get_femnodes_ele_table( mesh.Nodes, fet ) # net is dictionary: {nodeID : [[eleID, NodePosition], [], ...], nodeID : [[], [], ...], ...} # set up interface element connectivity nodecount = len(nocoord) twins = {} # twins : {oldnode : [newnode, face number]} interface_elements = [] for obj in App.ActiveDocument.Objects: if obj.Name == "BooleanFragments": num_BF_els = len(App.ActiveDocument.BooleanFragments.Objects) num_Mat_obs = len(fiwc.material_objects) if num_BF_els != num_Mat_obs: print( "Each BooleanFragment element needs its own material object" ) raise SystemExit() shapecontacts = [] tk = [] tv = [] contactnum = 0 # number of contact faces between BooleanFragment elements for index, obj1 in enumerate(obj.Objects): for obj1face in obj1.Shape.Faces: el1faces = np.asarray(mesh.getFacesByFace(obj1face)) for obj2 in obj.Objects[index + 1:]: for obj2face in obj2.Shape.Faces: el2faces = np.asarray( mesh.getFacesByFace(obj2face)) contact = np.intersect1d( el1faces, el2faces ) # all volume element contact faces between obj1 and obj2 if contact != []: contactnum += 1 npflist = [] shapecontacts.append( contact ) # all volume element contact faces for contactface in contact: npflist.append( mesh.getElementNodes(contactface) ) # all nodes at the contact between obj1 and obj2 # flatten npflist and remove duplicate nodes cn = list( set([ node for npf in npflist for node in npf ])) cn.sort() for node in cn: if node not in tk: nodecount += 1 tk.append( int(node) ) # add an existing contact node to interface dict tv.append( [nodecount, contactnum] ) # add a new contact node (nodecount) to interface dict and the contact (contactnum) it is a member of nocoord = np.append( nocoord, [nocoord[node - 1]], axis=0 ) # add coordinates for new nodes twins = dict(zip(tk, tv)) # twins : {oldnode : [newnode, face number]} print("\nInterface twins: {}".format(twins)) for facecontacts in shapecontacts: for face in facecontacts: nodeset1 = list(mesh.getElementNodes(face)) nodeset2 = [] for node in mesh.getElementNodes(face): nodeset2.append(twins[node][0]) interface_elements.append( nodeset1 + nodeset2 ) # interface_elements[index] = [oldnode1,..,oldnode6, newnode1,..,newnode6] interface_elements = np.asarray( interface_elements ) # add interface elements for the face between obj1 and obj2 print("number of interface elements: {}".format(len(interface_elements))) for ie in interface_elements: print(ie) # reconnect volume elements to new interface nodes if interface_elements != []: membership = [""] * contactnum shiftelements = [] # reconnected elements for node in twins: if membership[twins[node][1] - 1] == "": membership[twins[node][1] - 1] = parentobject[net[node][0][ 0]] # elements that will stay with old nodes are in membership material object for element in net[node]: elnum = element[0] # element number if parentobject[elnum] != membership[ twins[node][1] - 1]: # reconnect element to new nodes nonum = int( math.log(element[1], 2) ) # local node number from binary node number net[node][1] shiftelements.append(elo[elnum]) elnodes[elo[elnum]][nonum] = twins[node][ 0] # connect element to new nodes noce = np.zeros((len(nocoord)), dtype=np.int16) for inno in range(len(nocoord)): i, j = np.where(elnodes == inno + 1) noce[inno] = len(i) # create boundary condition array dispfaces dispfaces = [] for obj in App.ActiveDocument.Objects: if obj.isDerivedFrom('Fem::ConstraintDisplacement'): bcnodes = [] bctype = [obj.xFree, obj.yFree, obj.zFree] bcvalue = [obj.xDisplacement, obj.yDisplacement, obj.zDisplacement] for part, boundaries in obj.References: for boundary in boundaries: ref = part.Shape.getElement(boundary) if type(ref) == Part.Vertex: bc = mesh.getNodesByVertex(ref) for bcn in bc: bcnodes.append(bcn) elif type(ref) == Part.Edge: bc = mesh.getNodesByEdge(ref) for bcn in bc: bcnodes.append(bcn) elif type(ref) == Part.Face: bc = mesh.getNodesByFace(ref) for bcn in bc: if bcn not in twins: bcnodes.append(bcn) else: print("No Boundaries Found") edge = list(set(bc) & set(twins)) interior = list(set(bc) - set(twins)) #print("\nset(bc) {}, \nset(twins) {}, \nedge of boundary: {}, \ninterior of boundary: {}".format(bc, twins, edge, interior)) for node in edge: for elem in net[node]: elnum = elo[elem[0]] if list(set(elnodes[elnum]) & set(interior)) != []: if elnum in shiftelements: bcnodes.append(twins[node][0]) else: bcnodes.append(node) bcnodes = list( dict.fromkeys(bcnodes)) #remove duplicates in bcnodes if bcnodes != []: dispfaces.append([bcnodes, bctype, bcvalue]) # create loaded faces and their global node numbers loadfaces_keys = [] loadfaces_values = [] for obj in App.ActiveDocument.Objects: if obj.isDerivedFrom('Fem::ConstraintPressure'): if obj.Reversed: sign = 1 else: sign = -1 for part, boundaries in obj.References: for boundary in boundaries: ref = part.Shape.getElement(boundary) if type(ref) == Part.Face: for faceID in mesh.getFacesByFace(ref): loadfaces_keys.append(faceID) loadfaces_values.append([ list(mesh.getElementNodes(faceID)), sign * obj.Pressure ]) else: print("No Faces with Pressure Loads") loadfaces = dict(zip(loadfaces_keys, loadfaces_values)) # re-order element nodes for el in elnodes: temp = el[1] el[1] = el[2] el[2] = temp temp = el[4] el[4] = el[6] el[6] = temp temp = el[8] el[8] = el[9] el[9] = temp return elnodes, nocoord, dispfaces, loadfaces, materialbyElement, interface_elements, noce