diff --git a/src/Mod/Fem/CMakeLists.txt b/src/Mod/Fem/CMakeLists.txt index 861895269c..72fbd73c8c 100755 --- a/src/Mod/Fem/CMakeLists.txt +++ b/src/Mod/Fem/CMakeLists.txt @@ -139,6 +139,7 @@ SET(FemObjects_SRCS femobjects/base_fempythonobject.py femobjects/constant_vacuumpermittivity.py femobjects/constraint_bodyheatsource.py + femobjects/constraint_centrif.py femobjects/constraint_electrostaticpotential.py femobjects/constraint_flowvelocity.py femobjects/constraint_initialflowvelocity.py @@ -493,6 +494,7 @@ SET(FemGuiViewProvider_SRCS femviewprovider/view_base_femobject.py femviewprovider/view_constant_vacuumpermittivity.py femviewprovider/view_constraint_bodyheatsource.py + femviewprovider/view_constraint_centrif.py femviewprovider/view_constraint_electrostaticpotential.py femviewprovider/view_constraint_flowvelocity.py femviewprovider/view_constraint_initialflowvelocity.py diff --git a/src/Mod/Fem/ObjectsFem.py b/src/Mod/Fem/ObjectsFem.py index 885025f69a..fd7c380540 100644 --- a/src/Mod/Fem/ObjectsFem.py +++ b/src/Mod/Fem/ObjectsFem.py @@ -98,6 +98,21 @@ def makeConstraintBodyHeatSource( return obj +def makeConstraintCentrif( + doc, + name="ConstraintCentrif" +): + """makeConstraintCentrif(document, [name]): + creates a centrif object to define centrifugal body load constraint""" + obj = doc.addObject("Fem::ConstraintPython", name) + from femobjects import constraint_centrif + constraint_centrif.ConstraintCentrif(obj) + if FreeCAD.GuiUp: + from femviewprovider import view_constraint_centrif + view_constraint_centrif.VPConstraintCentrif(obj.ViewObject) + return obj + + def makeConstraintContact( doc, name="ConstraintContact" diff --git a/src/Mod/Fem/femmesh/meshtools.py b/src/Mod/Fem/femmesh/meshtools.py index 02fe33205e..993483a5f9 100644 --- a/src/Mod/Fem/femmesh/meshtools.py +++ b/src/Mod/Fem/femmesh/meshtools.py @@ -734,6 +734,7 @@ def get_elset_short_name( obj, i ): + # ATM for CalculiX needed for all objects which will write element sets into solver input file from femtools.femutils import is_of_type if is_of_type(obj, "Fem::MaterialCommon"): return "M" + str(i) @@ -745,6 +746,8 @@ def get_elset_short_name( return "F" + str(i) elif is_of_type(obj, "Fem::ElementGeometry2D"): return "S" + str(i) + elif is_of_type(obj, "Fem::ConstraintCentrif"): + return "C" + str(i) else: FreeCAD.Console.PrintError( "Error in creating short elset name " diff --git a/src/Mod/Fem/femobjects/constraint_centrif.py b/src/Mod/Fem/femobjects/constraint_centrif.py new file mode 100644 index 0000000000..3c732ed0d5 --- /dev/null +++ b/src/Mod/Fem/femobjects/constraint_centrif.py @@ -0,0 +1,57 @@ +# *************************************************************************** +# * Copyright (c) 2021 Bernd Hahnebach * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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__ = "FreeCAD FEM constraint centrif document object" +__author__ = "Bernd Hahnebach" +__url__ = "https://www.freecadweb.org" + +## @package constraint_centrif +# \ingroup FEM +# \brief constraint centrif object + +from . import base_fempythonobject + + +class ConstraintCentrif(base_fempythonobject.BaseFemPythonObject): + """ + The ConstraintCentrif object + """ + + Type = "Fem::ConstraintCentrif" + + def __init__(self, obj): + super(ConstraintCentrif, self).__init__(obj) + + obj.addProperty( + "App::PropertyFrequency", + "RotationFrequency", + "Constraint CENTRIF", + "set rotation frequency frot" + ) + + obj.addProperty( + "App::PropertyLinkSubList", + "RotationAxis", + "Constraint CENTRIF", + "set line as axis of rotation" + ) diff --git a/src/Mod/Fem/femsolver/calculix/writer.py b/src/Mod/Fem/femsolver/calculix/writer.py index 64492c773f..c65c2d6d20 100644 --- a/src/Mod/Fem/femsolver/calculix/writer.py +++ b/src/Mod/Fem/femsolver/calculix/writer.py @@ -31,6 +31,7 @@ __url__ = "https://www.freecadweb.org" # import io import codecs +import math import os import six import sys @@ -150,6 +151,9 @@ class FemInputWriterCcx(writerbase.FemInputWriter): # some fluidsection objs need special treatment, ccx_elsets are needed for this inpfile_main = self.handle_fluidsection_liquid_inlet_outlet(inpfile_main) + # element sets constraints + self.write_element_sets_constraints_centrif(inpfile_main) + # node sets and surface sets self.write_node_sets_constraints_fixed(inpfile_main) self.write_node_sets_constraints_displacement(inpfile_main) @@ -180,6 +184,7 @@ class FemInputWriterCcx(writerbase.FemInputWriter): self.write_constraints_displacement(inpfile_main) self.write_constraints_sectionprint(inpfile_main) self.write_constraints_selfweight(inpfile_main) + self.write_constraints_centrif(inpfile_main) self.write_constraints_force(inpfile_main) self.write_constraints_pressure(inpfile_main) self.write_constraints_temperature(inpfile_main) @@ -791,6 +796,77 @@ class FemInputWriterCcx(writerbase.FemInputWriter): # different element sets for different density # are written in the material element sets already + # ******************************************************************************************** + # constraints centrif + def write_element_sets_constraints_centrif(self, f): + self.write_constraints_sets( + f, + femobjs=self.centrif_objects, + analysis_types=["buckling", "static", "thermomech"], + sets_getter_method=self.get_constraints_centrif_elements, + write_name="constraints_centrif_element_sets", + sets_writer_method=self.write_element_sets_elements_constraints_centrif, + caller_method_name=sys._getframe().f_code.co_name, + ) + + def write_constraints_centrif(self, f): + self.write_constraints_data( + f, + femobjs=self.centrif_objects, + analysis_types="all", # write for all analysis types + constraint_title_name="Centrif Constraints", + constraint_writer_method=self.constraint_centrif_writer, + caller_method_name=sys._getframe().f_code.co_name, + ) + + def write_element_sets_elements_constraints_centrif(self, f, femobj, centrif_obj): + f.write("*ELSET,ELSET={}\n".format(centrif_obj.Name)) + # use six to be sure to be Python 2.7 and 3.x compatible + if isinstance(femobj["FEMElements"], six.string_types): + f.write("{}\n".format(femobj["FEMElements"])) + else: + for e in femobj["FEMElements"]: + f.write("{},\n".format(e)) + + def constraint_centrif_writer(self, f, femobj, centrif_obj): + + # get some data from the centrif_obj + refobj = centrif_obj.RotationAxis[0][0] + subobj = centrif_obj.RotationAxis[0][1][0] + axis = refobj.Shape.getElement(subobj) + + if axis.Curve.TypeId == "Part::GeomLine": + axiscopy = axis.copy() # apply global placement to copy + axiscopy.Placement = refobj.getGlobalPlacement() + direction = axiscopy.Curve.Direction + location = axiscopy.Curve.Location + else: # no line found, set default + # TODO: No test at all in the writer + # they should all be before in prechecks + location = FreeCAD.Vector(0., 0., 0.) + direction = FreeCAD.Vector(0., 0., 1.) + + # write to file + f.write("*DLOAD\n") + # Why {:.13G} ... + # ccx uses F20.0 FORTRAN input fields, see in dload.f in ccx's source + # https://forum.freecadweb.org/viewtopic.php?f=18&t=22759&#p176578 + # example "{:.13G}".format(math.sqrt(2.)*-1e100) and count chars + f.write( + "{},CENTRIF,{:.13G},{:.13G},{:.13G},{:.13G},{:.13G},{:.13G},{:.13G}\n" + .format( + centrif_obj.Name, + (2. * math.pi * float(centrif_obj.RotationFrequency.getValueAs("1/s"))) ** 2, + location.x, + location.y, + location.z, + direction.x, + direction.y, + direction.z + ) + ) + f.write("\n") + # ******************************************************************************************** # constraints force def write_constraints_force(self, f): @@ -1304,6 +1380,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter): return True if self.analysis_type == "thermomech" and not self.solver_obj.ThermoMechSteadyState: return True + if self.centrif_objects: + return True if self.selfweight_objects: return True return False diff --git a/src/Mod/Fem/femsolver/writerbase.py b/src/Mod/Fem/femsolver/writerbase.py index c62fdd1894..b5be6a2dec 100644 --- a/src/Mod/Fem/femsolver/writerbase.py +++ b/src/Mod/Fem/femsolver/writerbase.py @@ -60,6 +60,7 @@ class FemInputWriter(): self.fluidsection_objects = member.geos_fluidsection self.shellthickness_objects = member.geos_shellthickness # constraints + self.centrif_objects = member.cons_centrif self.contact_objects = member.cons_contact self.displacement_objects = member.cons_displacement self.fixed_objects = member.cons_fixed @@ -456,9 +457,20 @@ class FemInputWriter(): face_table = self.mesh_object.FemMesh.getccxVolumesByFace(ho) femobj["HeatFluxFaceTable"].append((elem_info, face_table)) + # ******************************************************************************************** # ******************************************************************************************** - # element sets + # element sets constraints + def get_constraints_centrif_elements(self): + # get element ids and write them into the femobj + if len(self.centrif_objects) == 1 and not self.centrif_objects[0]["Object"].References: + self.centrif_objects[0]["FEMElements"] = self.ccx_evolumes + else: + self.get_solid_element_sets(self.centrif_objects) + + # ******************************************************************************************** + # ******************************************************************************************** + # element sets material and element geometry def get_solid_element_sets(self, femobjs): # get element ids and write them into the femobj all_found = False diff --git a/src/Mod/Fem/femtest/app/test_object.py b/src/Mod/Fem/femtest/app/test_object.py index e899901e68..b3d710bc0f 100644 --- a/src/Mod/Fem/femtest/app/test_object.py +++ b/src/Mod/Fem/femtest/app/test_object.py @@ -233,6 +233,10 @@ class TestObjectType(unittest.TestCase): "Fem::ConstraintSelfWeight", type_of_obj(ObjectsFem.makeConstraintSelfWeight(doc)) ) + self.assertEqual( + "Fem::ConstraintCentrif", + type_of_obj(ObjectsFem.makeConstraintCentrif(doc)) + ) self.assertEqual( "Fem::ConstraintTemperature", type_of_obj(ObjectsFem.makeConstraintTemperature(doc)) @@ -442,6 +446,10 @@ class TestObjectType(unittest.TestCase): ObjectsFem.makeConstraintSelfWeight(doc), "Fem::ConstraintSelfWeight" )) + self.assertTrue(is_of_type( + ObjectsFem.makeConstraintCentrif(doc), + "Fem::ConstraintCentrif" + )) self.assertTrue(is_of_type( ObjectsFem.makeConstraintTemperature(doc), "Fem::ConstraintTemperature" @@ -871,6 +879,21 @@ class TestObjectType(unittest.TestCase): "Fem::ConstraintSelfWeight" )) + # ConstraintCentrif + constraint_centrif = ObjectsFem.makeConstraintCentrif(doc) + self.assertTrue(is_derived_from( + constraint_centrif, + "App::DocumentObject" + )) + self.assertTrue(is_derived_from( + constraint_centrif, + "Fem::ConstraintPython" + )) + self.assertTrue(is_derived_from( + constraint_centrif, + "Fem::ConstraintCentrif" + )) + # ConstraintTemperature constraint_temperature = ObjectsFem.makeConstraintTemperature(doc) self.assertTrue(is_derived_from( @@ -1415,6 +1438,11 @@ class TestObjectType(unittest.TestCase): doc ).isDerivedFrom("Fem::ConstraintPython") ) + self.assertTrue( + ObjectsFem.makeConstraintCentrif( + doc + ).isDerivedFrom("Fem::ConstraintPython") + ) self.assertTrue( ObjectsFem.makeConstraintTemperature( doc @@ -1595,6 +1623,7 @@ def create_all_fem_objects_doc( analysis.addObject(ObjectsFem.makeConstraintPulley(doc)) analysis.addObject(ObjectsFem.makeConstraintSectionPrint(doc)) analysis.addObject(ObjectsFem.makeConstraintSelfWeight(doc)) + analysis.addObject(ObjectsFem.makeConstraintCentrif(doc)) analysis.addObject(ObjectsFem.makeConstraintTemperature(doc)) analysis.addObject(ObjectsFem.makeConstraintTie(doc)) analysis.addObject(ObjectsFem.makeConstraintTransform(doc)) diff --git a/src/Mod/Fem/femtools/membertools.py b/src/Mod/Fem/femtools/membertools.py index 0d25d6a663..3f1f028b50 100644 --- a/src/Mod/Fem/femtools/membertools.py +++ b/src/Mod/Fem/femtools/membertools.py @@ -188,6 +188,10 @@ class AnalysisMember(): [{"Object":shell_thickness_obj, "xxxxxxxx":value}, {}, ...] constraints: + constraints_centrif : list of dictionaries + list of centrifs for the analysis. + [{"Object":centrif_obj, "xxxxxxxx":value}, {}, ...] + constraints_contact : list of dictionaries list of contact constraints from the analysis. [{"Object":contact_obj, "xxxxxxxx":value}, {}, ...] @@ -275,6 +279,9 @@ class AnalysisMember(): ) # constraints + self.cons_centrif = self.get_several_member( + "Fem::ConstraintCentrif" + ) self.cons_contact = self.get_several_member( "Fem::ConstraintContact" ) diff --git a/src/Mod/Fem/femviewprovider/view_constraint_centrif.py b/src/Mod/Fem/femviewprovider/view_constraint_centrif.py new file mode 100644 index 0000000000..f68ad42916 --- /dev/null +++ b/src/Mod/Fem/femviewprovider/view_constraint_centrif.py @@ -0,0 +1,40 @@ +# *************************************************************************** +# * Copyright (c) 2021 Bernd Hahnebach * +# * * +# * This file is part of the FreeCAD CAx development system. * +# * * +# * 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__ = "FreeCAD FEM constraint centrif ViewProvider for the document object" +__author__ = "Bernd Hahnebach" +__url__ = "https://www.freecadweb.org" + +## @package view_constraint_centrif +# \ingroup FEM +# \brief view provider for constraint centrif object + +from . import view_base_femconstraint + + +class VPConstraintCentrif(view_base_femconstraint.VPBaseFemConstraint): + """ + A View Provider for the ConstraintCentrif object + """ + + pass