Merge branch 'FreeCAD:master' into master

This commit is contained in:
Zolko-123
2021-07-18 16:54:29 +02:00
committed by GitHub
25 changed files with 1342 additions and 1102 deletions

View File

@@ -581,7 +581,7 @@ class _ViewProviderAxis:
t.string = self.getNumber(vobj,num)
num += 1
if hasattr(vobj,"BubblePosition"):
if vobj.BubblePosition == "Both":
if vobj.BubblePosition in ["Both","Arrow left","Arrow right","Bar left","Bar right"]:
if not alt:
num -= 1
alt = not alt
@@ -593,7 +593,11 @@ class _ViewProviderAxis:
if hasattr(vobj,"ShowLabel") and hasattr(vobj.Object,"Labels"):
if vobj.ShowLabel:
self.labels = coin.SoSeparator()
for i in range(len(vobj.Object.Shape.Edges)):
if hasattr(vobj.Object,"Limit") and vobj.Object.Limit.Value:
n = len(vobj.Object.Shape.Edges)/2
else:
n = len(vobj.Object.Shape.Edges)
for i in range(n):
if len(vobj.Object.Labels) > i:
if vobj.Object.Labels[i]:
import Draft

View File

@@ -1140,6 +1140,7 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent):
pairs = [["Mode"+str(i),"Mode"+str(i+1)] for i in range(1,len(WindowOpeningModes),2)]
self.invertPairs(pairs)
FreeCAD.ActiveDocument.recompute()
def invertHinge(self):
@@ -1147,6 +1148,8 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent):
pairs = [["Edge6","Edge8"],["Edge5","Edge7"]]
self.invertPairs(pairs)
self.invertOpening()
FreeCAD.ActiveDocument.recompute()
def invertPairs(self,pairs):
@@ -1166,7 +1169,6 @@ class _ViewProviderWindow(ArchComponent.ViewProviderComponent):
nparts.append(part)
if nparts != self.Object.WindowParts:
self.Object.WindowParts = nparts
FreeCAD.ActiveDocument.recompute()
else:
FreeCAD.Console.PrintWarning(translate("Arch","This window has no defined opening")+"\n")

View File

@@ -292,11 +292,11 @@ class Shape2DView(DraftObject):
if sh.Volume < 0:
sh.reverse()
c = sh.section(cutp)
if hasattr(obj,"InPlace"):
if not obj.InPlace:
c = self.getProjected(obj, c, proj)
faces = []
if (obj.ProjectionMode == "Cutfaces") and (sh.ShapeType == "Solid"):
if hasattr(obj,"InPlace"):
if not obj.InPlace:
c = self.getProjected(obj, c, proj)
wires = DraftGeomUtils.findWires(c.Edges)
for w in wires:
if w.isClosed():

View File

@@ -95,7 +95,7 @@ def display_external(internal_value,
if dim == 'Length':
q = App.Units.Quantity(internal_value, App.Units.Length)
if not unit:
if not decimals and showUnit:
if decimals == None and showUnit:
return q.UserString
conversion = q.getUserPreferred()[1]

View File

@@ -465,6 +465,9 @@ class ViewProviderDraft(object):
return ":/icons/Draft_N-Curve.svg"
elif tp in ("ShapeString"):
return ":/icons/Draft_ShapeString_tree.svg"
if hasattr(self.Object,"AutoUpdate") and not self.Object.AutoUpdate:
import TechDrawGui
return ":/icons/TechDraw_TreePageUnsync.svg"
return ":/icons/Draft_Draft.svg"
def claimChildren(self):

View File

@@ -133,6 +133,7 @@ SET(FemMesh_SRCS
femmesh/__init__.py
femmesh/femmesh2mesh.py
femmesh/gmshtools.py
femmesh/meshsetsgetter.py
femmesh/meshtools.py
)

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,7 @@ from .. import run
from .. import settings
from feminout import importCcxDatResults
from feminout import importCcxFrdResults
from femmesh import meshsetsgetter
from femtools import femutils
from femtools import membertools
@@ -60,14 +61,30 @@ class Prepare(run.Prepare):
def run(self):
global _inputFileName
self.pushStatus("Preparing input files...\n")
mesh_obj = membertools.get_mesh_to_solve(self.analysis)[0] # pre check done already
# get mesh set data
# TODO evaluate if it makes sense to add new task
# between check and prepare to the solver frame work
meshdatagetter = meshsetsgetter.MeshSetsGetter(
self.analysis,
self.solver,
mesh_obj,
membertools.AnalysisMember(self.analysis),
)
meshdatagetter.get_mesh_sets()
# write input file
w = writer.FemInputWriterCcx(
self.analysis,
self.solver,
membertools.get_mesh_to_solve(self.analysis)[0], # pre check has been done already
membertools.AnalysisMember(self.analysis),
self.directory
mesh_obj,
meshdatagetter.member,
self.directory,
meshdatagetter.mat_geo_sets
)
path = w.write_calculix_input_file()
path = w.write_solver_input()
# report to user if task succeeded
if path != "":
self.pushStatus("Write completed!")

View File

@@ -78,7 +78,7 @@ def write_constraint(f, femobj, disp_obj, ccxwriter):
elif not disp_obj.zFree:
f.write("{},3,3,{:.13G}\n".format(disp_obj.Name, disp_obj.zDisplacement))
if ccxwriter.beamsection_objects or ccxwriter.shellthickness_objects:
if ccxwriter.member.geos_beamsection or ccxwriter.member.geos_shellthickness:
if disp_obj.rotxFix:
f.write("{},4\n".format(disp_obj.Name))
elif not disp_obj.rotxFree:

View File

@@ -57,7 +57,10 @@ def get_after_write_constraint():
def write_meshdata_constraint(f, femobj, fix_obj, ccxwriter):
if (
ccxwriter.femmesh.Volumes
and (len(ccxwriter.shellthickness_objects) > 0 or len(ccxwriter.beamsection_objects) > 0)
and (
len(ccxwriter.member.geos_shellthickness) > 0
or len(ccxwriter.member.geos_beamsection) > 0
)
):
if len(femobj["NodesSolid"]) > 0:
f.write("*NSET,NSET={}Solid\n".format(fix_obj.Name))
@@ -79,7 +82,10 @@ def write_constraint(f, femobj, fix_obj, ccxwriter):
if (
ccxwriter.femmesh.Volumes
and (len(ccxwriter.shellthickness_objects) > 0 or len(ccxwriter.beamsection_objects) > 0)
and (
len(ccxwriter.member.geos_shellthickness) > 0
or len(ccxwriter.member.geos_beamsection) > 0
)
):
if len(femobj["NodesSolid"]) > 0:
f.write("*BOUNDARY\n")
@@ -101,7 +107,7 @@ def write_constraint(f, femobj, fix_obj, ccxwriter):
f.write(fix_obj.Name + ",1\n")
f.write(fix_obj.Name + ",2\n")
f.write(fix_obj.Name + ",3\n")
if ccxwriter.beamsection_objects or ccxwriter.shellthickness_objects:
if ccxwriter.member.geos_beamsection or ccxwriter.member.geos_shellthickness:
f.write(fix_obj.Name + ",4\n")
f.write(fix_obj.Name + ",5\n")
f.write(fix_obj.Name + ",6\n")

View File

@@ -43,14 +43,14 @@ from femmesh import meshtools
# as it is none standard constraint method compared to all other constraints
def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
if not ccxwriter.fluidsection_objects:
if not ccxwriter.member.geos_fluidsection:
return inpfile
# Fluid sections:
# fluidsection Liquid inlet outlet objs requires special element definition
# to fill ccxwriter.FluidInletoutlet_ele list the ccx_elset are needed
# thus this has to be after the creation of ccx_elsets
# different pipe cross sections will generate ccx_elsets
# thus this has to be after the creation of mat_geo_sets
# different pipe cross sections will generate mat_geo_sets
ccxwriter.FluidInletoutlet_ele = []
ccxwriter.fluid_inout_nodes_file = join(
@@ -76,8 +76,8 @@ def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
return fluidsec_obj
return None
def is_fluidsection_inoutlet_setnames_possible(ccx_elsets):
for ccx_elset in ccx_elsets:
def is_fluidsection_inoutlet_setnames_possible(mat_geo_sets):
for ccx_elset in mat_geo_sets:
if (
ccx_elset["ccx_elset"]
and "fluidsection_obj" in ccx_elset # fluid mesh
@@ -95,7 +95,7 @@ def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
# collect elementIDs for fluidsection Liquid inlet outlet objs
# if they have element data (happens if not "eall")
for ccx_elset in ccxwriter.ccx_elsets:
for ccx_elset in ccxwriter.mat_geo_sets:
fluidsec_obj = get_fluidsection_inoutlet_obj_if_setdata(ccx_elset)
if fluidsec_obj is None:
continue
@@ -118,9 +118,9 @@ def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
)
# create the correct element definition for fluidsection Liquid inlet outlet objs
# at least one "fluidsection_obj" needs to be in ccx_elsets and has the attributes
# at least one "fluidsection_obj" needs to be in mat_geo_sets and has the attributes
# TODO: what if there are other objs in elsets?
if is_fluidsection_inoutlet_setnames_possible(ccxwriter.ccx_elsets) is not None:
if is_fluidsection_inoutlet_setnames_possible(ccxwriter.mat_geo_sets) is not None:
# it is not distinguished if split input file
# for split input file the main file is just closed and reopend even if not needed
inpfile.close()
@@ -139,7 +139,7 @@ def handle_fluidsection_liquid_inlet_outlet(inpfile, ccxwriter):
# split method into separate methods and move some part into base writer
# see also method handle_fluidsection_liquid_inlet_outlet
def write_constraints_fluidsection(f, ccxwriter):
if not ccxwriter.fluidsection_objects:
if not ccxwriter.member.geos_fluidsection:
return
if ccxwriter.analysis_type not in ["thermomech"]:
return
@@ -158,7 +158,7 @@ def write_constraints_fluidsection(f, ccxwriter):
)
# get nodes
ccxwriter.get_constraints_fluidsection_nodes()
for femobj in ccxwriter.fluidsection_objects:
for femobj in ccxwriter.member.geos_fluidsection:
# femobj --> dict, FreeCAD document object is femobj["Object"]
fluidsection_obj = femobj["Object"]
f.write("** " + fluidsection_obj.Label + "\n")

View File

@@ -32,7 +32,7 @@ def write_femelement_geometry(f, ccxwriter):
f.write("\n{}\n".format(59 * "*"))
f.write("** Sections\n")
for ccx_elset in ccxwriter.ccx_elsets:
for ccx_elset in ccxwriter.mat_geo_sets:
if ccx_elset["ccx_elset"]:
elsetdef = "ELSET={}, ".format(ccx_elset["ccx_elset_name"])
material = "MATERIAL={}".format(ccx_elset["mat_obj_name"])

View File

@@ -42,16 +42,16 @@ def write_femelement_material(f, ccxwriter):
and not ccxwriter.solver_obj.ThermoMechSteadyState
):
return True
if ccxwriter.centrif_objects:
if ccxwriter.member.cons_centrif:
return True
if ccxwriter.selfweight_objects:
if ccxwriter.member.cons_selfweight:
return True
return False
f.write("\n{}\n".format(59 * "*"))
f.write("** Materials\n")
f.write("** see information about units at file end\n")
for femobj in ccxwriter.material_objects:
for femobj in ccxwriter.member.mats_linear:
# femobj --> dict, FreeCAD document object is femobj["Object"]
mat_obj = femobj["Object"]
mat_info_name = mat_obj.Material["Name"]
@@ -107,7 +107,7 @@ def write_femelement_material(f, ccxwriter):
# nonlinear material properties
if ccxwriter.solver_obj.MaterialNonlinearity == "nonlinear":
for nlfemobj in ccxwriter.material_nonlinear_objects:
for nlfemobj in ccxwriter.member.mats_nonlinear:
# femobj --> dict, FreeCAD document object is nlfemobj["Object"]
nl_mat_obj = nlfemobj["Object"]
if nl_mat_obj.LinearBaseMaterial == mat_obj:

View File

@@ -31,14 +31,17 @@ import six
def write_femelement_matgeosets(f, ccxwriter):
# write ccx_elsets to file
# write mat_geo_sets to file
f.write("\n{}\n".format(59 * "*"))
f.write("** Element sets for materials and FEM element type (solid, shell, beam, fluid)\n")
for ccx_elset in ccxwriter.ccx_elsets:
f.write("*ELSET,ELSET=" + ccx_elset["ccx_elset_name"] + "\n")
for ccx_elset in ccxwriter.mat_geo_sets:
f.write("*ELSET,ELSET={}\n".format(ccx_elset["ccx_elset_name"]))
# use six to be sure to be Python 2.7 and 3.x compatible
if isinstance(ccx_elset["ccx_elset"], six.string_types):
f.write(ccx_elset["ccx_elset"] + "\n")
f.write("{}\n".format(ccx_elset["ccx_elset"]))
else:
for elid in ccx_elset["ccx_elset"]:
f.write(str(elid) + ",\n")

View File

@@ -48,7 +48,7 @@ def write_mesh(ccxwriter):
)
# Check to see if fluid sections are in analysis and use D network element type
if ccxwriter.fluidsection_objects:
if ccxwriter.member.geos_fluidsection:
meshtools.write_D_network_element_to_inputfile(ccxwriter.femmesh_file)
inpfile = codecs.open(ccxwriter.file_name, "w", encoding="utf-8")
@@ -65,7 +65,7 @@ def write_mesh(ccxwriter):
)
# Check to see if fluid sections are in analysis and use D network element type
if ccxwriter.fluidsection_objects:
if ccxwriter.member.geos_fluidsection:
# inpfile is closed
meshtools.write_D_network_element_to_inputfile(ccxwriter.femmesh_file)

View File

@@ -31,9 +31,9 @@ def write_step_output(f, ccxwriter):
f.write("\n{}\n".format(59 * "*"))
f.write("** Outputs --> frd file\n")
if (
ccxwriter.beamsection_objects
or ccxwriter.shellthickness_objects
or ccxwriter.fluidsection_objects
ccxwriter.member.geos_beamsection
or ccxwriter.member.geos_shellthickness
or ccxwriter.member.geos_fluidsection
):
if ccxwriter.solver_obj.BeamShellResultOutput3D is False:
f.write("*NODE FILE, OUTPUT=2d\n")
@@ -43,13 +43,13 @@ def write_step_output(f, ccxwriter):
f.write("*NODE FILE\n")
# MPH write out nodal temperatures if thermomechanical
if ccxwriter.analysis_type == "thermomech":
if not ccxwriter.fluidsection_objects:
if not ccxwriter.member.geos_fluidsection:
f.write("U, NT\n")
else:
f.write("MF, PS\n")
else:
f.write("U\n")
if not ccxwriter.fluidsection_objects:
if not ccxwriter.member.geos_fluidsection:
f.write("*EL FILE\n")
if ccxwriter.solver_obj.MaterialNonlinearity == "nonlinear":
f.write("S, E, PEEQ\n")
@@ -58,11 +58,11 @@ def write_step_output(f, ccxwriter):
# dat file
# reaction forces: freecadweb.org/tracker/view.php?id=2934
if ccxwriter.fixed_objects:
if ccxwriter.member.cons_fixed:
f.write("** outputs --> dat file\n")
# reaction forces for all Constraint fixed
f.write("** reaction forces for Constraint fixed\n")
for femobj in ccxwriter.fixed_objects:
for femobj in ccxwriter.member.cons_fixed:
# femobj --> dict, FreeCAD document object is femobj["Object"]
fix_obj_name = femobj["Object"].Name
f.write("*NODE PRINT, NSET={}, TOTALS=ONLY\n".format(fix_obj_name))

View File

@@ -42,7 +42,7 @@ from . import write_constraint_fixed as con_fixed
from . import write_constraint_fluidsection as con_fluidsection
from . import write_constraint_force as con_force
from . import write_constraint_heatflux as con_heatflux
from . import write_constraint_initialtemperature as con_initialtemp
from . import write_constraint_initialtemperature as con_itemp
from . import write_constraint_planerotation as con_planerotation
from . import write_constraint_pressure as con_pressure
from . import write_constraint_sectionprint as con_sectionprint
@@ -110,7 +110,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
solver_obj,
mesh_obj,
member,
dir_name=None
dir_name=None,
mat_geo_sets=None
):
writerbase.FemInputWriter.__init__(
self,
@@ -118,7 +119,8 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
solver_obj,
mesh_obj,
member,
dir_name
dir_name,
mat_geo_sets
)
self.mesh_name = self.mesh_object.Name
self.file_name = join(self.dir_name, self.mesh_name + ".inp")
@@ -128,17 +130,14 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# ********************************************************************************************
# write calculix input
def write_calculix_input_file(self):
def write_solver_input(self):
FreeCAD.Console.PrintMessage("Get mesh sets.\n")
time_start = time.process_time()
self.get_mesh_sets()
time_getsets = time.process_time()
FreeCAD.Console.PrintMessage(
"Start writing CalculiX input file to: {}\n"
.format(self.file_name)
)
if self.solver_obj.SplitInputWriter is True:
FreeCAD.Console.PrintMessage("Split input file.\n")
self.split_inpfile = True
@@ -152,48 +151,48 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# element sets for materials and element geometry
write_femelement_matgeosets.write_femelement_matgeosets(inpfile, self)
# some fluidsection objs need special treatment, ccx_elsets are needed for this
# some fluidsection objs need special treatment, mat_geo_sets are needed for this
inpfile = con_fluidsection.handle_fluidsection_liquid_inlet_outlet(inpfile, self)
# element sets constraints
self.write_constraints_meshsets(inpfile, self.centrif_objects, con_centrif)
self.write_constraints_meshsets(inpfile, self.member.cons_centrif, con_centrif)
# node sets
self.write_constraints_meshsets(inpfile, self.fixed_objects, con_fixed)
self.write_constraints_meshsets(inpfile, self.displacement_objects, con_displacement)
self.write_constraints_meshsets(inpfile, self.planerotation_objects, con_planerotation)
self.write_constraints_meshsets(inpfile, self.transform_objects, con_transform)
self.write_constraints_meshsets(inpfile, self.temperature_objects, con_temperature)
self.write_constraints_meshsets(inpfile, self.member.cons_fixed, con_fixed)
self.write_constraints_meshsets(inpfile, self.member.cons_displacement, con_displacement)
self.write_constraints_meshsets(inpfile, self.member.cons_planerotation, con_planerotation)
self.write_constraints_meshsets(inpfile, self.member.cons_transform, con_transform)
self.write_constraints_meshsets(inpfile, self.member.cons_temperature, con_temperature)
# surface sets
self.write_constraints_meshsets(inpfile, self.contact_objects, con_contact)
self.write_constraints_meshsets(inpfile, self.tie_objects, con_tie)
self.write_constraints_meshsets(inpfile, self.sectionprint_objects, con_sectionprint)
self.write_constraints_meshsets(inpfile, self.member.cons_contact, con_contact)
self.write_constraints_meshsets(inpfile, self.member.cons_tie, con_tie)
self.write_constraints_meshsets(inpfile, self.member.cons_sectionprint, con_sectionprint)
# materials and fem element types
write_femelement_material.write_femelement_material(inpfile, self)
self.write_constraints_propdata(inpfile, self.initialtemperature_objects, con_initialtemp)
self.write_constraints_propdata(inpfile, self.member.cons_initialtemperature, con_itemp)
write_femelement_geometry.write_femelement_geometry(inpfile, self)
# constraints independent from steps
self.write_constraints_propdata(inpfile, self.planerotation_objects, con_planerotation)
self.write_constraints_propdata(inpfile, self.contact_objects, con_contact)
self.write_constraints_propdata(inpfile, self.tie_objects, con_tie)
self.write_constraints_propdata(inpfile, self.transform_objects, con_transform)
self.write_constraints_propdata(inpfile, self.member.cons_planerotation, con_planerotation)
self.write_constraints_propdata(inpfile, self.member.cons_contact, con_contact)
self.write_constraints_propdata(inpfile, self.member.cons_tie, con_tie)
self.write_constraints_propdata(inpfile, self.member.cons_transform, con_transform)
# step equation
write_step_equation.write_step_equation(inpfile, self)
# constraints dependent from steps
self.write_constraints_propdata(inpfile, self.fixed_objects, con_fixed)
self.write_constraints_propdata(inpfile, self.displacement_objects, con_displacement)
self.write_constraints_propdata(inpfile, self.sectionprint_objects, con_sectionprint)
self.write_constraints_propdata(inpfile, self.selfweight_objects, con_selfweight)
self.write_constraints_propdata(inpfile, self.centrif_objects, con_centrif)
self.write_constraints_meshsets(inpfile, self.force_objects, con_force)
self.write_constraints_meshsets(inpfile, self.pressure_objects, con_pressure)
self.write_constraints_propdata(inpfile, self.temperature_objects, con_temperature)
self.write_constraints_meshsets(inpfile, self.heatflux_objects, con_heatflux)
self.write_constraints_propdata(inpfile, self.member.cons_fixed, con_fixed)
self.write_constraints_propdata(inpfile, self.member.cons_displacement, con_displacement)
self.write_constraints_propdata(inpfile, self.member.cons_sectionprint, con_sectionprint)
self.write_constraints_propdata(inpfile, self.member.cons_selfweight, con_selfweight)
self.write_constraints_propdata(inpfile, self.member.cons_centrif, con_centrif)
self.write_constraints_meshsets(inpfile, self.member.cons_force, con_force)
self.write_constraints_meshsets(inpfile, self.member.cons_pressure, con_pressure)
self.write_constraints_propdata(inpfile, self.member.cons_temperature, con_temperature)
self.write_constraints_meshsets(inpfile, self.member.cons_heatflux, con_heatflux)
con_fluidsection.write_constraints_fluidsection(inpfile, self)
# output and step end
@@ -206,19 +205,10 @@ class FemInputWriterCcx(writerbase.FemInputWriter):
# close file
inpfile.close()
setstime = round((time_getsets - time_start), 3)
writetime = round((time.process_time() - time_getsets), 3)
all_time = round((setstime + writetime), 3)
FreeCAD.Console.PrintMessage(
"Getting mesh sets or groups time: {} seconds \n".format(setstime)
)
writetime = round((time.process_time() - time_start), 3)
FreeCAD.Console.PrintMessage(
"Writing time CalculiX input file: {} seconds \n".format(writetime)
)
FreeCAD.Console.PrintMessage(
"Overall time CalculiX input file: {} seconds \n\n"
.format(all_time)
)
# return
if self.femelement_count_test is True:

View File

@@ -84,7 +84,7 @@ class Prepare(run.Prepare):
FreeCAD.Console.PrintLog("Machine testmode: {}\n".format(self.testmode))
w = writer.Writer(self.solver, self.directory)
try:
w.write()
w.write_solver_input()
self.checkHandled(w)
except writer.WriteError as e:
self.report.error(str(e))

View File

@@ -79,7 +79,7 @@ class Writer(object):
def getHandledConstraints(self):
return self._handledObjects
def write(self):
def write_solver_input(self):
self._handleRedifinedConstants()
self._handleSimulation()
self._handleHeat()

File diff suppressed because it is too large Load Diff

View File

@@ -61,7 +61,7 @@ class Prepare(run.Prepare):
membertools.AnalysisMember(self.analysis),
self.directory
)
path = w.write_z88_input()
path = w.write_solver_input()
# report to user if task succeeded
if path is not None:
self.pushStatus("Write completed!")

View File

@@ -63,7 +63,7 @@ class FemInputWriterZ88(writerbase.FemInputWriter):
"FemInputWriterZ88 --> self.file_name --> " + self.file_name + "\n"
)
def write_z88_input(self):
def write_solver_input(self):
timestart = time.process_time()
FreeCAD.Console.PrintMessage("Write z88 input files to: {}\n".format(self.dir_name))
if not self.femnodes_mesh:

View File

@@ -487,7 +487,10 @@ class _TaskPanel:
"May try the following in Python console:\n"
"from FreeCAD import Units\n"
"Units.Quantity('{}')\n"
.format(self.material["ThermalConductivity"], self.material["ThermalConductivity"])
.format(
self.material["ThermalConductivity"],
self.material["ThermalConductivity"]
)
)
self.material["ThermalConductivity"] = "0 W/m/K"
if "ThermalConductivity" not in str(Units.Unit(self.material["ThermalConductivity"])):

View File

@@ -366,6 +366,20 @@ class FemToolsCcx(QtCore.QRunnable, QtCore.QObject):
self.set_inp_file_name()
def write_inp_file(self):
# get mesh set data
# TODO use separate method for getting the mesh set data
from femmesh import meshsetsgetter
meshdatagetter = meshsetsgetter.MeshSetsGetter(
self.analysis,
self.solver,
self.mesh,
membertools.AnalysisMember(self.analysis),
)
# save the sets into the member objects of the instanz meshdatagetter
meshdatagetter.get_mesh_sets()
# write input file
import femsolver.calculix.writer as iw
self.inp_file_name = ""
try:
@@ -373,10 +387,11 @@ class FemToolsCcx(QtCore.QRunnable, QtCore.QObject):
self.analysis,
self.solver,
self.mesh,
self.member,
self.working_dir
meshdatagetter.member,
self.working_dir,
meshdatagetter.mat_geo_sets
)
self.inp_file_name = inp_writer.write_calculix_input_file()
self.inp_file_name = inp_writer.write_solver_input()
except Exception:
FreeCAD.Console.PrintError(
"Unexpected error when writing CalculiX input file: {}\n"

View File

@@ -37,9 +37,11 @@ if sys.version_info.major >= 3:
unicode = str
# ************************************************************************************************
# ************************************************************************************************
class MaterialEditor:
def __init__(self, obj=None, prop=None, material=None, card_path=''):
def __init__(self, obj=None, prop=None, material=None, card_path=""):
"""Initializes, optionally with an object name and a material property
name to edit, or directly with a material dictionary."""
@@ -139,7 +141,7 @@ class MaterialEditor:
def implementModel(self):
'''implements the model with the material attribute structure.'''
"""implements the model with the material attribute structure."""
p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material")
widget = self.widget
@@ -163,13 +165,13 @@ class MaterialEditor:
for properName in group[gg]:
pp = properName # property name
item = QtGui.QStandardItem(pp)
item.setToolTip(group[gg][properName]['Description'])
item.setToolTip(group[gg][properName]["Description"])
self.internalprops.append(pp)
it = QtGui.QStandardItem()
it.setToolTip(group[gg][properName]['Description'])
it.setToolTip(group[gg][properName]["Description"])
tt = group[gg][properName]['Type']
tt = group[gg][properName]["Type"]
itType = QtGui.QStandardItem(tt)
top.appendRow([item, it, itType])
@@ -180,9 +182,9 @@ class MaterialEditor:
def updateMatParamsInTree(self, data):
'''updates the contents of the editor with the given dictionary
"""updates the contents of the editor with the given dictionary
the material property keys where added to the editor already
not known material property keys will be added to the user defined group'''
not known material property keys will be added to the user defined group"""
# print(data)
model = self.widget.treeView.model()
@@ -223,8 +225,8 @@ class MaterialEditor:
return
self.card_path = self.widget.ComboMaterial.itemData(index)
FreeCAD.Console.PrintMessage(
'choose_material in material editor:\n'
' {}\n'.format(self.card_path)
"choose_material in material editor:\n"
" {}\n".format(self.card_path)
)
if os.path.isfile(self.card_path):
from importFCMat import read
@@ -234,11 +236,11 @@ class MaterialEditor:
# the card could be updated the dict not
self.widget.ComboMaterial.setCurrentIndex(index) # set after tree params
else:
FreeCAD.Console.PrintError('material card not found: {}\n'.format(self.card_path))
FreeCAD.Console.PrintError("material card not found: {}\n".format(self.card_path))
def updateCardsInCombo(self):
'''updates the contents of the materials combo with existing material cards'''
"""updates the contents of the materials combo with existing material cards"""
mat_prefs = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Material/Cards")
sort_by_resources = mat_prefs.GetBool("SortByResources", False)
@@ -260,13 +262,13 @@ class MaterialEditor:
a_path = card_names_tmp[a_name]
card_name_list.append([a_name, a_path, self.icons[a_path]])
card_name_list.insert(0, [None, '', ''])
card_name_list.insert(0, [None, "", ""])
for mat in card_name_list:
self.widget.ComboMaterial.addItem(QtGui.QIcon(mat[2]), mat[0], mat[1])
def openProductURL(self):
'''opens the contents of the ProductURL field in an external browser.'''
"""opens the contents of the ProductURL field in an external browser."""
model = self.widget.treeView.model()
item = model.findItems(translate("Material", "Product URL"),
@@ -340,8 +342,8 @@ class MaterialEditor:
def deleteCustomProperty(self, key=None):
'''Deletes a custom property from the editor,
or deletes the value of an internal property.'''
"""Deletes a custom property from the editor,
or deletes the value of an internal property."""
widget = self.widget
treeView = widget.treeView
@@ -377,8 +379,8 @@ class MaterialEditor:
def onClickTree(self, index):
'''Checks if the current item is a custom or an internal property,
and enable the delete property or delete value button.'''
"""Checks if the current item is a custom or an internal property,
and enable the delete property or delete value button."""
widget = self.widget
buttonDeleteProperty = widget.ButtonDeleteProperty
@@ -428,18 +430,18 @@ class MaterialEditor:
# since text(0) could be translated
matkey = self.collapseKey(str(kk))
matvalue = unicode(ii)
if matvalue or (matkey == 'Name'):
if matvalue or (matkey == "Name"):
# use only keys which are not empty and the name even if empty
d[matkey] = matvalue
# self.outputDict(d)
return d
def outputDict(self, d):
print('MaterialEditor dictionary')
print("MaterialEditor dictionary")
for param in d:
print(' {} : {}'.format(param, d[param]))
print(" {} : {}".format(param, d[param]))
'''
"""
def setTexture(self, pattern):
"displays a texture preview if needed"
self.widget.PreviewVector.hide()
@@ -453,7 +455,7 @@ class MaterialEditor:
if pattern:
self.widget.PreviewVector.setPixmap(QtGui.QPixmap(pattern))
self.widget.PreviewVector.show()
'''
"""
def updatePreviews(self, mat=None):
"updates the preview images from the content of the editor"
@@ -505,9 +507,9 @@ class MaterialEditor:
"Opens a FCMat file"
filetuple = QtGui.QFileDialog.getOpenFileName(
QtGui.QApplication.activeWindow(),
'Open FreeCAD Material file',
"Open FreeCAD Material file",
self.directory,
'*.FCMat'
"*.FCMat"
)
self.card_path = filetuple[0]
index = self.widget.ComboMaterial.findData(self.card_path)
@@ -518,8 +520,8 @@ class MaterialEditor:
if os.path.isfile(self.card_path):
if index == -1:
FreeCAD.Console.PrintMessage(
'Card path: {} not found in known cards.'
'The material parameter only are loaded.\n'
"Card path: {} not found in known cards."
"The material parameter only are loaded.\n"
.format(self.card_path)
)
from importFCMat import read
@@ -548,9 +550,9 @@ class MaterialEditor:
name = "Material"
filetuple = QtGui.QFileDialog.getSaveFileName(
QtGui.QApplication.activeWindow(),
'Save FreeCAD Material file',
self.directory + '/' + name + '.FCMat',
'*.FCMat'
"Save FreeCAD Material file",
self.directory + "/" + name + ".FCMat",
"*.FCMat"
)
# a tuple of two empty strings returns True, so use the filename directly
filename = filetuple[0]
@@ -571,9 +573,11 @@ class MaterialEditor:
return self.widget.exec_()
# ************************************************************************************************
# ************************************************************************************************
class MaterialsDelegate(QtGui.QStyledItemDelegate):
'''provides display and editing facilities for data items from a model.'''
"""provides display and editing facilities for data items from a model."""
def __init__(self):
""
@@ -582,7 +586,7 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate):
def createEditor(self, parent, option, index):
'''returns the widget used to change data from the model.'''
"""returns the widget used to change data from the model."""
model = index.model()
column = index.column()
@@ -628,16 +632,16 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate):
def setEditorData(self, editor, index):
'''provides the widget with data to manipulate.'''
"""provides the widget with data to manipulate."""
Type = editor.property('Type')
Type = editor.property("Type")
model = index.model()
item = model.itemFromIndex(index)
print("item1={}".format(item.text()))
if Type == "Color":
color = editor.property('color')
color = editor.property("color")
color = tuple([v/255.0 for v in color.getRgb()])
item.setText(str(color))
@@ -649,16 +653,33 @@ class MaterialsDelegate(QtGui.QStyledItemDelegate):
else:
super(MaterialsDelegate, self).setEditorData(editor, index)
print("item2={}".format(item.text()))
ui = FreeCADGui.UiLoader()
# ************************************************************************************************
# ************************************************************************************************
def matProperWidget(parent=None, matproperty=None, Type="String", Value=None,
minimum=None, maximum=None, stepsize=None, precision=None):
minimum=None, maximum=None, stepsize=None, precision=12):
'''customs widgets for the material stuff.'''
"""customs widgets for the material stuff."""
# FIXME
# Workaround for problem from here:
# https://forum.freecadweb.org/viewtopic.php?f=18&t=56912&start=20#p516811
# set precision to 12
# Better would be a similar system like used in FEM material task panel
# if the value in the InputField has not changed the data is not changed
# why does the value changes if the user clicks in
# the value and unit should exact stay as it is displayed before the user
# clicks in the field
# the user defined properties are of Type String and thus uses a "Gui::PrefLineEdit"
print(matproperty)
print(Type)
print(Value)
ui = FreeCADGui.UiLoader()
if Type == "String":
@@ -675,23 +696,31 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None,
lineEdit = widget.children()[1]
lineEdit.setText(Value)
elif Type == "Quantity":
elif Type == "Quantity" or Type == "Float":
widget = ui.createWidget("Gui::InputField")
# print(matproperty)
if hasattr(FreeCAD.Units, matproperty):
unit = getattr(FreeCAD.Units, matproperty)
quantity = FreeCAD.Units.Quantity(1, unit)
widget.setProperty('unit', quantity.getUserPreferred()[2])
widget.setProperty("unit", quantity.getUserPreferred()[2])
else:
FreeCAD.Console.PrintError('Not known unit for property: {}\n'.format(matproperty))
FreeCAD.Console.PrintWarning(
"Not known unit for property: {}. Probably the Quantity does not have a unit.\n"
.format(matproperty)
)
# the Gui::InputField is used for Floats too, because of the diggits
elif Type == "Integer":
widget = ui.createWidget("Gui::UIntSpinBox")
elif Type == "Float":
# elif Type == "Float":
widget = ui.createWidget("Gui::PrefDoubleSpinBox")
# widget = ui.createWidget("Gui::PrefDoubleSpinBox")
# has only 2 diggits precision, but for example RelativePermittivity needs much more
# see material card for Air, thus Workaround
# a "Gui::InputField" without unit is used
elif Type == "Enumerator":
@@ -700,7 +729,7 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None,
elif Type == "Boolean":
widget = ui.createWidget("Gui::PrefComboBox")
widget.insertItems(0, ['', 'False', 'True'])
widget.insertItems(0, ["", "False", "True"])
elif Type == "Vector":
@@ -713,22 +742,22 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None,
value = string2tuple(Value)
color = QtGui.QColor()
color.setRgb(value[0], value[1], value[2], value[3])
widget.setProperty('color', color)
widget.setProperty("color", color)
else:
widget = QtGui.QLineEdit()
if minimum is not None:
widget.setProperty('minimum', minimum)
widget.setProperty("minimum", minimum)
if maximum is not None:
widget.setProperty('maximum', maximum)
widget.setProperty("maximum", maximum)
if stepsize is not None:
widget.setProperty('stepsize', stepsize)
widget.setProperty("stepsize", stepsize)
if precision is not None:
widget.setProperty('precision', precision)
widget.setProperty("precision", precision)
widget.setProperty('Type', Type)
widget.setProperty("Type", Type)
widget.setParent(parent)
@@ -738,7 +767,7 @@ def matProperWidget(parent=None, matproperty=None, Type="String", Value=None,
def string2tuple(string):
"provisionally"
value = string[1:-1]
value = value.split(',')
value = value.split(",")
value = [int(float(v)*255) for v in value]
value = tuple(value)
return value
@@ -775,26 +804,28 @@ def editMaterial(material=None, card_path=None):
return {}
'''
# ************************************************************************************************
# ************************************************************************************************
"""
# some examples how to open the material editor in Python:
import MaterialEditor
MaterialEditor.openEditor()
doc = FreeCAD.open(
FreeCAD.ConfigGet("AppHomePath") + 'data/examples/FemCalculixCantilever3D.FCStd'
FreeCAD.ConfigGet("AppHomePath") + "data/examples/FemCalculixCantilever3D.FCStd"
)
import MaterialEditor
MaterialEditor.openEditor('SolidMaterial', 'Material')
MaterialEditor.openEditor("SolidMaterial", "Material")
import MaterialEditor
MaterialEditor.editMaterial({
'Density': '1234.0 kg/m^3',
'Name': 'My-Material-Data',
'PoissonRatio': '0.66',
'YoungsModulus': '123456 MPa'
"Density": "1234.0 kg/m^3",
"Name": "My-Material-Data",
"PoissonRatio": "0.66",
"YoungsModulus": "123456 MPa"
})
import MaterialEditor
MaterialEditor.editMaterial('ABS')
MaterialEditor.editMaterial("ABS")
'''
"""