Fem: Add electrostatic concentrated load

This commit is contained in:
marioalexis
2025-11-08 10:19:03 -03:00
committed by Max Wilfinger
parent 47d1913544
commit f44af0929f
5 changed files with 88 additions and 3 deletions

View File

@@ -164,6 +164,16 @@
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="ckb_concentrated">
<property name="visible">
<bool>false</bool>
</property>
<property name="text">
<string>Concentrated</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>

View File

@@ -159,6 +159,7 @@ class MeshSetsGetter:
self.get_constraints_temperature_nodes()
self.get_constraints_initialtemperature_nodes()
self.get_constraints_electrostatic_nodes()
self.get_constraints_electricchargedensity_nodes()
# constraints sets with constraint data
self.get_constraints_force_nodeloads()
@@ -289,6 +290,18 @@ class MeshSetsGetter:
self.femmesh, femobj
)
def get_constraints_electricchargedensity_nodes(self):
if not self.member.cons_electricchargedensity:
return
# get nodes
for femobj in self.member.cons_electricchargedensity:
# femobj --> dict, FreeCAD document object is femobj["Object"]
if femobj["Object"].Concentrated:
print_obj_info(femobj["Object"])
femobj["Nodes"] = meshtools.get_femnodes_by_femobj_with_references(
self.femmesh, femobj
)
def get_constraints_force_nodeloads(self):
if not self.member.cons_force:
return

View File

@@ -31,6 +31,7 @@ __url__ = "https://www.freecad.org"
from FreeCAD import Units
from FreeCAD import Base
from . import base_fempythonobject
@@ -77,6 +78,15 @@ class ConstraintElectricChargeDensity(base_fempythonobject.BaseFemPythonObject):
value="0 C",
)
)
prop.append(
_PropHelper(
type="App::PropertyBool",
name="Concentrated",
group="Electric Charge Density",
doc="Use concentrated charges at the nodes",
value=False,
)
)
prop.append(
_PropHelper(
type="App::PropertyEnumeration",
@@ -89,6 +99,23 @@ class ConstraintElectricChargeDensity(base_fempythonobject.BaseFemPythonObject):
return prop
def onDocumentRestored(self, obj):
print("restored", obj.Name)
# update old project with new properties
for prop in self._get_properties():
try:
obj.getPropertyByName(prop.name)
except Base.PropertyError:
prop.add_to_object(obj)
def onChanged(self, obj, prop):
print("change", prop)
if prop == "Mode":
if obj.Mode == "Total Source":
obj.setPropertyStatus("Concentrated", "-ReadOnly")
else:
obj.setPropertyStatus("Concentrated", "ReadOnly")
def get_total_source_density(self, obj):
"""
Calculate density for `Total Source` mode.

View File

@@ -43,6 +43,12 @@ def write_meshdata_constraint(f, femobj, den_obj, ccxwriter):
if ccxwriter.solver_obj.ElectromagneticMode != "electrostatic":
return
if den_obj.Concentrated and den_obj.Mode == "Total Source":
f.write(f"*NSET,NSET={den_obj.Name}\n")
for n in femobj["Nodes"]:
f.write(f"{n},\n")
return
if den_obj.Mode in ["Source", "Total Source"]:
f.write(f"*ELSET,ELSET={den_obj.Name}\n")
for refs, surf, is_sub_el in femobj["ChargeDensityElements"]:
@@ -73,6 +79,14 @@ def write_constraint(f, femobj, den_obj, ccxwriter):
if ccxwriter.solver_obj.ElectromagneticMode != "electrostatic":
return
if den_obj.Concentrated and den_obj.Mode == "Total Source":
nodes = len(femobj["Nodes"])
node_charge = den_obj.TotalCharge.getValueAs("C").Value / nodes
f.write("*CFLUX\n")
f.write("{},11,{:.13G}\n".format(den_obj.Name, node_charge))
f.write("\n")
return
match den_obj.Mode:
case "Source":
density = den_obj.SourceChargeDensity

View File

@@ -71,11 +71,16 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
QtCore.SIGNAL("currentIndexChanged(int)"),
self.mode_changed,
)
QtCore.QObject.connect(
self.parameter_widget.ckb_concentrated,
QtCore.SIGNAL("toggled(bool)"),
self.concentrated_changed,
)
# geometry selection widget
# start with Solid in list!
self.selection_widget = selection_widgets.GeometryElementsSelection(
obj.References, ["Solid", "Face", "Edge"], False, False
obj.References, ["Solid", "Face", "Edge", "Vertex"], False, False
)
# form made from param and selection widget
@@ -109,6 +114,7 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
self.obj.InterfaceChargeDensity = self.interface_charge_density
self.obj.TotalCharge = self.total_charge
self.obj.Mode = self.mode
self.obj.Concentrated = self.concentrated
self.selection_widget.finish_selection()
self.restore_visibility()
@@ -129,6 +135,8 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
self.source_charge_density = self.obj.SourceChargeDensity
self.interface_charge_density = self.obj.InterfaceChargeDensity
self.total_charge = self.obj.TotalCharge
self.concentrated = self.obj.Concentrated
FreeCADGui.ExpressionBinding(self.parameter_widget.qsb_source_charge_density).bind(
self.obj, "SourceChargeDensity"
)
@@ -155,6 +163,10 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
self.parameter_widget.cb_mode.setCurrentIndex(index)
self.mode_changed(index)
self.parameter_widget.ckb_concentrated.setChecked(self.concentrated)
if self.mode == "Total Source":
self.parameter_widget.ckb_concentrated.setVisible(True)
def source_charge_density_changed(self, base_quantity_value):
self.source_charge_density = base_quantity_value
@@ -166,6 +178,15 @@ class _TaskPanel(base_femtaskpanel._BaseTaskPanel):
def mode_changed(self, index):
self.mode = self.mode_enum[index]
if self.mode in ["Total Interface", "Total Source"]:
index = 2
match self.mode:
case "Total Interface":
index = 2
self.parameter_widget.ckb_concentrated.setVisible(False)
case "Total Source":
index = 2
self.parameter_widget.ckb_concentrated.setVisible(True)
self.parameter_widget.sw_mode.setCurrentIndex(index)
def concentrated_changed(self, value):
self.concentrated = value