diff --git a/.arcconfig b/.arcconfig new file mode 100644 index 000000000..caca558ab --- /dev/null +++ b/.arcconfig @@ -0,0 +1,3 @@ +{ + "phabricator.uri" : "http://pha.geofinder.eu/" +} diff --git a/src/Mod/Fem/FemBeamSection.py b/src/Mod/Fem/FemBeamSection.py index dd8008608..20ad7b477 100644 --- a/src/Mod/Fem/FemBeamSection.py +++ b/src/Mod/Fem/FemBeamSection.py @@ -1,24 +1,24 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2015 - 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 * -#* * -#*************************************************************************** +# *************************************************************************** +# * * +# * Copyright (c) 2015 - 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 * +# * * +# *************************************************************************** import FreeCAD diff --git a/src/Mod/Fem/FemBeamSection.ui b/src/Mod/Fem/FemBeamSection.ui index 749b71e11..9fc09d32e 100644 --- a/src/Mod/Fem/FemBeamSection.ui +++ b/src/Mod/Fem/FemBeamSection.ui @@ -46,13 +46,13 @@ - Reference + References - Leave reference blank + Leave references blank diff --git a/src/Mod/Fem/FemShellThickness.py b/src/Mod/Fem/FemShellThickness.py index 16b02c8fd..f0e2c2c95 100644 --- a/src/Mod/Fem/FemShellThickness.py +++ b/src/Mod/Fem/FemShellThickness.py @@ -1,24 +1,24 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2015 - 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 * -#* * -#*************************************************************************** +# *************************************************************************** +# * * +# * Copyright (c) 2015 - 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 * +# * * +# *************************************************************************** import FreeCAD diff --git a/src/Mod/Fem/FemShellThickness.ui b/src/Mod/Fem/FemShellThickness.ui index 2a0a2eef6..daf305943 100644 --- a/src/Mod/Fem/FemShellThickness.ui +++ b/src/Mod/Fem/FemShellThickness.ui @@ -46,13 +46,13 @@ - Reference + References - Leave reference blank + Leave references blank diff --git a/src/Mod/Fem/MechanicalMaterial.py b/src/Mod/Fem/MechanicalMaterial.py index 778e2946f..4e7f04e6a 100644 --- a/src/Mod/Fem/MechanicalMaterial.py +++ b/src/Mod/Fem/MechanicalMaterial.py @@ -1,24 +1,24 @@ -#*************************************************************************** -#* * -#* Copyright (c) 2013 - Juergen Riegel * -#* * -#* 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 * -#* * -#*************************************************************************** +# *************************************************************************** +# * * +# * Copyright (c) 2013 - Juergen Riegel * +# * * +# * 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 * +# * * +# *************************************************************************** import FreeCAD @@ -134,14 +134,14 @@ class _MechanicalMaterialTaskPanel: QtCore.QObject.connect(self.form.input_fd_young_modulus, QtCore.SIGNAL("valueChanged(double)"), self.ym_changed) QtCore.QObject.connect(self.form.spinBox_poisson_ratio, QtCore.SIGNAL("valueChanged(double)"), self.pr_changed) QtCore.QObject.connect(self.form.input_fd_density, QtCore.SIGNAL("valueChanged(double)"), self.density_changed) - self.previous_material = self.obj.Material + self.material = self.obj.Material self.import_materials() - previous_mat_path = self.get_material_path(self.previous_material) + previous_mat_path = self.get_material_path(self.material) if not previous_mat_path: print "Previously used material cannot be found in material directories. Using transient material." - material_name = self.get_material_name(self.previous_material) + material_name = self.get_material_name(self.material) if material_name != 'None': - self.add_transient_material(self.previous_material) + self.add_transient_material(self.material) index = self.form.cb_materials.findData(material_name) else: index = self.form.cb_materials.findText(material_name) @@ -151,11 +151,11 @@ class _MechanicalMaterialTaskPanel: self.choose_material(index) def accept(self): + self.obj.Material = self.material FreeCADGui.ActiveDocument.resetEdit() + FreeCAD.ActiveDocument.recompute() def reject(self): - self.obj.Material = self.previous_material - print "Reverting to material:" FreeCADGui.ActiveDocument.resetEdit() def goMatWeb(self): @@ -164,44 +164,44 @@ class _MechanicalMaterialTaskPanel: def ym_changed(self, value): import Units - old_ym = Units.Quantity(self.obj.Material['YoungsModulus']) + old_ym = Units.Quantity(self.material['YoungsModulus']) if old_ym != value: - material = self.obj.Material + material = self.material # FreeCAD uses kPa internall for Stress material['YoungsModulus'] = unicode(value) + " kPa" - self.obj.Material = material + self.material = material def density_changed(self, value): import Units - old_density = Units.Quantity(self.obj.Material['Density']) + old_density = Units.Quantity(self.material['Density']) if old_density != value: - material = self.obj.Material + material = self.material material['Density'] = unicode(value) + " kg/mm^3" - self.obj.Material = material + self.material = material def pr_changed(self, value): import Units - old_pr = Units.Quantity(self.obj.Material['PoissonRatio']) + old_pr = Units.Quantity(self.material['PoissonRatio']) if old_pr != value: - material = self.obj.Material + material = self.material material['PoissonRatio'] = unicode(value) - self.obj.Material = material + self.material = material def choose_material(self, index): if index < 0: return mat_file_path = self.form.cb_materials.itemData(index) - self.obj.Material = self.materials[mat_file_path] + self.material = self.materials[mat_file_path] self.form.cb_materials.setCurrentIndex(index) - self.set_mat_params_in_combo_box(self.obj.Material) + self.set_mat_params_in_combo_box(self.material) gen_mat_desc = "" - if 'Description' in self.obj.Material: - gen_mat_desc = self.obj.Material['Description'] + if 'Description' in self.material: + gen_mat_desc = self.material['Description'] self.form.l_mat_description.setText(gen_mat_desc) def get_material_name(self, material): - if 'Name' in self.previous_material: - return self.previous_material['Name'] + if 'Name' in self.material: + return self.material['Name'] else: return 'None' diff --git a/src/Mod/Fem/TestFem.py b/src/Mod/Fem/TestFem.py index 7589ec571..b81131c41 100644 --- a/src/Mod/Fem/TestFem.py +++ b/src/Mod/Fem/TestFem.py @@ -28,6 +28,7 @@ import Fem import FemTools import FreeCAD import MechanicalAnalysis +import MechanicalMaterial import csv import tempfile import unittest @@ -89,7 +90,7 @@ class FemTest(unittest.TestCase): self.active_doc.recompute() def create_new_material(self): - self.new_material_object = self.active_doc.addObject("App::MaterialObjectPython", 'MechanicalMaterial') + self.new_material_object = MechanicalMaterial.makeMechanicalMaterial('MechanicalMaterial') mat = self.new_material_object.Material mat['Name'] = "Steel" mat['YoungsModulus'] = "200000 MPa" diff --git a/src/Mod/Fem/ccxInpWriter.py b/src/Mod/Fem/ccxInpWriter.py index f4811f5cb..a3b49ada1 100644 --- a/src/Mod/Fem/ccxInpWriter.py +++ b/src/Mod/Fem/ccxInpWriter.py @@ -203,7 +203,7 @@ class inp_writer: elsetdef = 'ELSET=' + ccx_elset['ccx_elset_name'] + ', ' material = 'MATERIAL=' + ccx_elset['ccx_mat_name'] setion_def = '*BEAM SECTION, ' + elsetdef + material + ', SECTION=RECT\n' - setion_geo = str(beamsec_obj.Hight.getValueAs('mm')) + ', ' + str(beamsec_obj.Width.getValueAs('mm')) + '\n' + setion_geo = str(beamsec_obj.Height.getValueAs('mm')) + ', ' + str(beamsec_obj.Width.getValueAs('mm')) + '\n' f.write(setion_def) f.write(setion_geo) elif 'shellthickness_obj'in ccx_elset: # shell mesh @@ -511,7 +511,7 @@ class inp_writer: def get_ccx_elsets_single_mat_multiple_beam(self): mat_obj = self.material_objects[0]['Object'] - self.get_beamsection_element_sets() + self.get_femelement_sets(self.beamsection_objects) for beamsec_data in self.beamsection_objects: beamsec_obj = beamsec_data['Object'] ccx_elset = {} @@ -524,7 +524,7 @@ class inp_writer: def get_ccx_elsets_single_mat_multiple_shell(self): mat_obj = self.material_objects[0]['Object'] - self.get_shellthickness_element_sets() + self.get_femelement_sets(self.shellthickness_objects) for shellth_data in self.shellthickness_objects: shellth_obj = shellth_data['Object'] ccx_elset = {} @@ -537,7 +537,7 @@ class inp_writer: def get_ccx_elsets_multiple_mat_single_beam(self): beamsec_obj = self.beamsection_objects[0]['Object'] - self.get_material_element_sets() + self.get_femelement_sets(self.material_objects) for mat_data in self.material_objects: mat_obj = mat_data['Object'] ccx_elset = {} @@ -550,7 +550,7 @@ class inp_writer: def get_ccx_elsets_multiple_mat_single_shell(self): shellth_obj = self.shellthickness_objects[0]['Object'] - self.get_material_element_sets() + self.get_femelement_sets(self.material_objects) for mat_data in self.material_objects: mat_obj = mat_data['Object'] ccx_elset = {} @@ -562,7 +562,7 @@ class inp_writer: self.ccx_elsets.append(ccx_elset) def get_ccx_elsets_multiple_mat_solid(self): - self.get_material_element_sets() + self.get_femelement_sets(self.material_objects) for mat_data in self.material_objects: mat_obj = mat_data['Object'] ccx_elset = {} @@ -573,8 +573,8 @@ class inp_writer: self.ccx_elsets.append(ccx_elset) def get_ccx_elsets_multiple_mat_multiple_beam(self): - self.get_beamsection_element_sets() - self.get_material_element_sets() + self.get_femelement_sets(self.beamsection_objects) + self.get_femelement_sets(self.material_objects) for beamsec_data in self.beamsection_objects: beamsec_obj = beamsec_data['Object'] for mat_data in self.material_objects: @@ -592,8 +592,8 @@ class inp_writer: self.ccx_elsets.append(ccx_elset) def get_ccx_elsets_multiple_mat_multiple_shell(self): - self.get_shellthickness_element_sets() - self.get_material_element_sets() + self.get_femelement_sets(self.shellthickness_objects) + self.get_femelement_sets(self.material_objects) for shellth_data in self.shellthickness_objects: shellth_obj = shellth_data['Object'] for mat_data in self.material_objects: @@ -610,102 +610,55 @@ class inp_writer: ccx_elset['ccx_mat_name'] = mat_obj.Material['Name'][:80] self.ccx_elsets.append(ccx_elset) - def get_material_element_sets(self): - # get femelements for reference shapes of each material_obj - FreeCAD.Console.PrintError('Multiple materials defined, this could result in a broken CalculiX input file!\n') - # TODO get the elset nodeids and write them to mat_data['FEMElements'] - # if not hasattr(self, 'fem_element_table'): - # self.fem_element_table = getFemElementTable(self.mesh_object.FemMesh) - for mat_data_i, mat_data in enumerate(self.material_objects): - mat_data['ShortName'] = 'Mat' + str(mat_data_i) # unique short ccx_identifier - # mat_obj = mat_data['Object'] - mat_data['FEMElements'] = self.ccx_eall - - def get_beamsection_element_sets(self): - # get femelements for reference shapes of each beamsec_obj + def get_femelement_sets(self, fem_objects): + # get femelements for reference shapes of each obj.References if not hasattr(self, 'fem_element_table'): self.fem_element_table = getFemElementTable(self.mesh_object.FemMesh) - count_femelements_beamsection = 0 - referenced_femelements_beamsection = [] - has_remaining_femelements_beamsection = None - for beamsec_data_i, beamsec_data in enumerate(self.beamsection_objects): - beamsec_data['ShortName'] = 'Beam' + str(beamsec_data_i) # unique short ccx_identifier - beamsec_obj = beamsec_data['Object'] - if beamsec_obj.References: + count_femelements = 0 + referenced_femelements = [] + has_remaining_femelements = None + for fem_object_i, fem_object in enumerate(fem_objects): + obj = fem_object['Object'] + fem_object['ShortName'] = get_ccx_elset_short_name(obj, fem_object_i) # unique short ccx_identifier + if obj.References: ref_shape_femelements = [] - for ref in beamsec_obj.References: - nodeids = [] - elemids = [] + for ref in obj.References: + femnodes = [] + femelements = [] r = ref[0].Shape.getElement(ref[1]) + print(' ReferenceShape : ', r.ShapeType, ', ', ref[0].Name, ', ', ref[0].Label, ' --> ', ref[1]) if r.ShapeType == 'Edge': - # print(' BeamSectionReferenceEdge : ', ref[0].Name, ', ', ref[0].Label, ' --> ', ref[1]) - nodeids = self.mesh_object.FemMesh.getNodesByEdge(r) - elemids = getFemElementsByNodes(self.fem_element_table, nodeids) + femnodes = self.mesh_object.FemMesh.getNodesByEdge(r) + elif r.ShapeType == 'Face': + femnodes = self.mesh_object.FemMesh.getNodesByFace(r) + elif r.ShapeType == 'Solid': + # femnodes = self.mesh_object.FemMesh.getNodesBySolid(r) --> TODO + FreeCAD.Console.PrintError('Solid Reference Shapes, CalculiX input file may be broken!\n') + fem_object['FEMElements'] = self.ccx_eall + return else: - print(' No Edge, but BeamSection needs Edges as reference shapes!') - ref_shape_femelements += elemids - referenced_femelements_beamsection += elemids - count_femelements_beamsection += len(elemids) - beamsec_data['FEMElements'] = ref_shape_femelements + print(' No Edge, Face or Solid as reference shapes!') + femelements = getFemElementsByNodes(self.fem_element_table, femnodes) + ref_shape_femelements += femelements + referenced_femelements += femelements + count_femelements += len(femelements) + fem_object['FEMElements'] = ref_shape_femelements else: - has_remaining_femelements_beamsection = beamsec_obj.Name - # get remaining femelements for the beamsection objects - if has_remaining_femelements_beamsection: - remaining_femelements_beamsection = [] + has_remaining_femelements = obj.Name + # get remaining femelements for the fem_objects + if has_remaining_femelements: + remaining_femelements = [] for elemid in self.fem_element_table: - if elemid not in referenced_femelements_beamsection: - remaining_femelements_beamsection.append(elemid) - count_femelements_beamsection += len(remaining_femelements_beamsection) - for beamsec_data in self.beamsection_objects: - beamsec_obj = beamsec_data['Object'] - if beamsec_obj.Name == has_remaining_femelements_beamsection: - beamsec_data['FEMElements'] = sorted(remaining_femelements_beamsection) + if elemid not in referenced_femelements: + remaining_femelements.append(elemid) + count_femelements += len(remaining_femelements) + for fem_object in fem_objects: + obj = fem_object['Object'] + if obj.Name == has_remaining_femelements: + fem_object['FEMElements'] = sorted(remaining_femelements) # check if all worked out well - if not femelements_count_ok(self.fem_element_table, count_femelements_beamsection): - FreeCAD.Console.PrintError('Error in BeamSection -- > femelements_count_ok failed!\n') - - def get_shellthickness_element_sets(self): - # get femelements for reference shapes of each shellth_obj - if not hasattr(self, 'fem_element_table'): - self.fem_element_table = getFemElementTable(self.mesh_object.FemMesh) - count_femelements_shellthickness = 0 - referenced_femelements_shellthickness = [] - has_remaining_femelements_shellthickness = None - for shellth_data_i, shellth_data in enumerate(self.shellthickness_objects): - shellth_data['ShortName'] = 'Shell' + str(shellth_data_i) # unique short ccx_identifier - shellth_obj = shellth_data['Object'] - if shellth_obj.References: - ref_shape_femelements = [] - for ref in shellth_obj.References: - nodeids = [] - elemids = [] - r = ref[0].Shape.getElement(ref[1]) - if r.ShapeType == 'Face': - # print(' ShellThicknessReferenceFace : ', ref[0].Name, ', ', ref[0].Label, ' --> ', ref[1]) - nodeids = self.mesh_object.FemMesh.getNodesByFace(r) - elemids = getFemElementsByNodes(self.fem_element_table, nodeids) - else: - print(' No Face, but ShellThickness needs Faces as reference shapes!') - ref_shape_femelements += elemids - referenced_femelements_shellthickness += elemids - count_femelements_shellthickness += len(elemids) - shellth_data['FEMElements'] = ref_shape_femelements - else: - has_remaining_femelements_shellthickness = shellth_obj.Name - # get remaining femelements for the shellthickness objects - if has_remaining_femelements_shellthickness: - remaining_femelements_shellthickness = [] - for elemid in self.fem_element_table: - if elemid not in referenced_femelements_shellthickness: - remaining_femelements_shellthickness.append(elemid) - count_femelements_shellthickness += len(remaining_femelements_shellthickness) - for shellth_data in self.shellthickness_objects: - shellth_obj = shellth_data['Object'] - if shellth_obj.Name == has_remaining_femelements_shellthickness: - shellth_data['FEMElements'] = sorted(remaining_femelements_shellthickness) - # check if all worked out well - if not femelements_count_ok(self.fem_element_table, count_femelements_shellthickness): - FreeCAD.Console.PrintError('Error in ShellThickness -- > femelements_count_ok failed!\n') + if not femelements_count_ok(self.fem_element_table, count_femelements): + FreeCAD.Console.PrintError('Error in get_femelement_sets -- > femelements_count_ok failed!\n') # Helpers @@ -812,3 +765,14 @@ def get_ccx_elset_solid_name(mat_name, solid_name=None, mat_short_name=None): return mat_short_name + solid_name else: return mat_name + solid_name + + +def get_ccx_elset_short_name(obj, i): + if hasattr(obj, "Proxy") and obj.Proxy.Type == 'MechanicalMaterial': + return 'Mat' + str(i) + elif hasattr(obj, "Proxy") and obj.Proxy.Type == 'FemBeamSection': + return 'Beam' + str(i) + elif hasattr(obj, "Proxy") and obj.Proxy.Type == 'FemShellThickness': + return 'Shell' + str(i) + else: + print 'Error: ', obj.Name, ' --> ', obj.Proxy.Type