Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add recirculation boundary function #3870

Merged
merged 12 commits into from
Nov 13, 2023
59 changes: 59 additions & 0 deletions _unittest/test_98_Icepak.py
Original file line number Diff line number Diff line change
Expand Up @@ -1278,3 +1278,62 @@ def test_68_mesh_priority_3d_comp(self, add_app):
assert app.mesh.add_priority(entity_type=2, comp_name="all_3d_objects1", priority=2)

app.close_project(name="3d_comp_mesh_prio_test", save_project=False)

def test_69_recirculation_boundary(self):
box = self.aedtapp.modeler.create_box([5, 5, 5], [1, 2, 3], "BlockBoxEmpty", "copper")
box.solve_inside = False
assert not self.aedtapp.assign_recirculation_opening(
[box.top_face_x, box.bottom_face_x, box.bottom_face_y], box.top_face_x, flow_assignment="10kg_per_s_m2"
)
assert self.aedtapp.assign_recirculation_opening(
[box.top_face_x, box.bottom_face_x], box.top_face_x, conductance_external_temperature="25cel"
)
assert self.aedtapp.assign_recirculation_opening(
[box.top_face_x, box.bottom_face_x], box.top_face_x, start_time="0s"
)
self.aedtapp.solution_type = "Transient"
assert self.aedtapp.assign_recirculation_opening([box.top_face_x, box.bottom_face_x], box.top_face_x)
assert self.aedtapp.assign_recirculation_opening([box.top_face_x.id, box.bottom_face_x.id], box.top_face_x.id)
assert not self.aedtapp.assign_recirculation_opening(
[box.top_face_x.id, box.bottom_face_x.id],
box.top_face_x.id,
thermal_specification="Conductance",
flow_direction=[1],
)
temp_dict = {"Function": "Square Wave", "Values": ["1cel", "0s", "1s", "0.5s", "0cel"]}
flow_dict = {"Function": "Sinusoidal", "Values": ["0kg_per_s_m2", 1, 1, "1s"]}
recirc = self.aedtapp.assign_recirculation_opening(
[box.top_face_x.id, box.bottom_face_x.id],
box.top_face_x.id,
thermal_specification="Temperature",
assignment_value=temp_dict,
flow_assignment=flow_dict,
)
assert recirc
assert recirc.update()
self.aedtapp.solution_type = "SteadyState"
assert not self.aedtapp.assign_recirculation_opening(
[box.top_face_x.id, box.bottom_face_x.id],
box.top_face_x.id,
thermal_specification="Temperature",
assignment_value=temp_dict,
flow_assignment=flow_dict,
)
assert not self.aedtapp.assign_recirculation_opening(
[box.top_face_x.id, box.bottom_face_x.id],
box.top_face_x.id,
thermal_specification="Temperature",
flow_direction="Side",
)
assert self.aedtapp.assign_recirculation_opening(
[box.top_face_x.id, box.bottom_face_x.id],
box.top_face_x.id,
thermal_specification="Temperature",
flow_direction=[0, 1, 0],
)
assert not self.aedtapp.assign_recirculation_opening(
[box.top_face_x.id, box.bottom_face_x.id],
box.top_face_x.id,
thermal_specification="Temperature",
flow_assignment=flow_dict,
)
179 changes: 179 additions & 0 deletions pyaedt/icepak.py
Original file line number Diff line number Diff line change
Expand Up @@ -4869,3 +4869,182 @@
raise SystemExit
except (GrpcApiError, SystemExit):
return None

@pyaedt_function_handler()
def assign_recirculation_opening(self, face_list, extract_face, thermal_specification="Temperature",
assignment_value="0cel", conductance_external_temperature=None,
flow_specification="Mass Flow", flow_assignment="0kg_per_s_m2",
flow_direction=None, start_time=None, end_time=None, boundary_name=None):
"""Assign recirculation faces.

Parameters
----------
face_list : list
List of modeler.cad.elements3d.FacePrimitive or of integers
containing faces ids.
extract_face : modeler.cad.elements3d.FacePrimitive, int
Face of the face on the extract side.
thermal_specification : str, optional
Type of the thermal assignment across the two recirculation
faces. Options are ``"Conductance"``, ``"Heat Input"`` and
``"Temperature"``. Default is ``"Temperature"``.
assignment_value : str or dict, optional
String with value and units of the thermal assignment. For a
transient assignment, a dictionary can be used. The dictionary
should contain two keys: ``"Function"`` and ``"Values"``.
- For the ``"Function"`` key, acceptable values are
``"Exponential"``, ``"Linear"``, ``"Piecewise Linear"``,
``"Power Law"``, ``"Sinusoidal"``, and ``"Square Wave"``.
- For the ``"Values"`` key, a list of strings containing the
parameters required by the ``"Function"`` key selection. For
example, when``"Linear"`` is set as the ``"Function"`` key, two
parameters are required: the value of the variable at t=0 and the
slope of the line. For the parameters required by each
``"Function"`` key selection, see the Icepak documentation.
The parameters must contain the units where needed.
The default value is ``"0cel"``.
conductance_external_temperature : str, optional
External temperature value, needed if ``thermal_specification``
is set to ``"Conductance"``. Default is ``None``.
flow_specification : str, optional
Flow specification for the recirculation zone. Available
options are: ``"Mass Flow"``, ``"Mass Flux"``, and
``"Volume Flow"``. The default value is ``"Mass Flow"``.
flow_assignment : str or dict, optional
String with value and units of the flow assignment. For a
transient assignment, a dictionary can be used. The dictionary
should contain two keys: ``"Function"`` and ``"Values"``.
- For the ``"Function"`` key, acceptable values are
``"Exponential"``, ``"Linear"``, ``"Piecewise Linear"``,
``"Power Law"``, ``"Sinusoidal"``, and ``"Square Wave"``.
- For the ``"Values"`` key, a list of strings containing the
parameters required by the ``"Function"`` key selection. For
example, when``"Linear"`` is set as the ``"Function"`` key, two
parameters are required: the value of the variable at t=0 and the
slope of the line. For the parameters required by each
``"Function"`` key selection, see the Icepak documentation.
The parameters must contain the units where needed.
The default value is ``"0kg_per_s_m2"``.
flow_direction : list, optional
Flow direction enforced at the recirculation zone. The default value
is ``None`` in which case the normal direction is used.
start_time : str, optional
Start of the time interval. Relevant only if the simulation is
transient. The default value is ``"0s"``.
end_time : str, optional
End of the time interval. Relevant only if the simulation is
transient. The default value is ``"0s"``.
boundary_name : str, optional
Name of the recirculation boundary. The default is ``None``, in
which case the boundary is automatically generated.

Returns
-------
:class:`pyaedt.modules.Boundary.BoundaryObject`
Boundary object when successful or ``None`` when failed.

References
----------

>>> oModule.AssignRecircBoundary

Examples
--------
>>> from pyaedt import Icepak
>>> ipk = Icepak()
>>> ipk.solution_type = "Transient"
>>> box = ipk.modeler.create_box([5, 5, 5], [1, 2, 3], "BlockBoxEmpty", "copper")
>>> box.solve_inside = False
>>> recirc = ipk.assign_recirculation_opening([box.top_face_x, box.bottom_face_x], box.top_face_x,
>>> flow_assignment="10kg_per_s_m2")

"""
if not len(face_list) == 2:
self.logger.error("Recirculation boundary condition must be assigned to two faces.")
return False
if conductance_external_temperature is not None and thermal_specification is not "Conductance":
self.logger.warning(

Check warning on line 4966 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L4962-L4966

Added lines #L4962 - L4966 were not covered by tests
'``conductance_external_temperature`` will not have any effect unless the ``thermal_specification`` '
'is ``"Conductance"``.')
if conductance_external_temperature is not None and thermal_specification is not "Conductance":
self.logger.warning(

Check warning on line 4970 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L4969-L4970

Added lines #L4969 - L4970 were not covered by tests
'``conductance_external_temperature`` needs to be specified when ``thermal_specification`` '
'is ``"Conductance"``. Setting ``conductance_external_temperature`` to ``"AmbientTemp"``.')
if (start_time is not None or end_time is not None) and not self.solution_type == "Transient":
self.logger.warning(

Check warning on line 4974 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L4973-L4974

Added lines #L4973 - L4974 were not covered by tests
'``start_time`` and ``end_time`` will not have any effect unless for steady-state simulations.')
elif self.solution_type == "Transient" and not (start_time and end_time):
self.logger.warning(

Check warning on line 4977 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L4976-L4977

Added lines #L4976 - L4977 were not covered by tests
'``start_time`` and ``end_time`` should be declared for transient simulations. Setting them to "0s".')
start_time = "0s"
end_time = "0s"
assignment_dict = {

Check warning on line 4981 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L4979-L4981

Added lines #L4979 - L4981 were not covered by tests
"Conductance": "Conductance",
"Heat Input": "Heat Flow",
"Temperature": "Temperature Change"
}
props = {}
if not isinstance(face_list[0], int):
face_list = [f.id for f in face_list]
props["Faces"] = face_list
if isinstance(extract_face, int):
extract_face = [extract_face]

Check warning on line 4991 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L4986-L4991

Added lines #L4986 - L4991 were not covered by tests
else:
extract_face = [extract_face.id]
props["ExtractFace"] = extract_face
props["Thermal Condition"] = thermal_specification
if isinstance(assignment_value, dict):
if not self.solution_type == "Transient":
self.logger.error("Transient assignment is supported only in transient designs.")
return None
assignment = self._parse_variation_data(

Check warning on line 5000 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L4993-L5000

Added lines #L4993 - L5000 were not covered by tests
assignment_dict[thermal_specification],
"Transient",
variation_value=assignment_value["Values"],
function=assignment_value["Function"],
)
props.update(assignment)

Check warning on line 5006 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L5006

Added line #L5006 was not covered by tests
else:
props[assignment_dict[thermal_specification]] = assignment_value
if thermal_specification == "Conductance":
props["External Temp"] = conductance_external_temperature
if isinstance(flow_assignment, dict):
lorenzovecchietti marked this conversation as resolved.
Show resolved Hide resolved
if not self.solution_type == "Transient":
self.logger.error("Transient assignment is supported only in transient designs.")
return None
assignment = self._parse_variation_data(

Check warning on line 5015 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L5008-L5015

Added lines #L5008 - L5015 were not covered by tests
flow_specification + " Rate",
"Transient",
variation_value=flow_assignment["Values"],
function=flow_assignment["Function"],
)
props.update(assignment)

Check warning on line 5021 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L5021

Added line #L5021 was not covered by tests
else:
props[flow_specification + " Rate"] = flow_assignment
if flow_direction is None:
props["Supply Flow Direction"] = "Normal"

Check warning on line 5025 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L5023-L5025

Added lines #L5023 - L5025 were not covered by tests
else:
props["Supply Flow Direction"] = "Specified"
if not (isinstance(flow_direction, list)):
self.logger.error("``flow_direction`` can be only ``None`` or a list of strings or floats.")
return False
elif len(flow_direction) != 3:
self.logger.error("``flow_direction`` must have only three components.")
return False
for direction, val in zip(["X", "Y", "Z"], flow_direction):
props[direction] = str(val)
if self.solution_type == "Transient":
props["Start"] = start_time
props["End"] = end_time
if not boundary_name:
boundary_name = generate_unique_name("Recirculating")

Check warning on line 5040 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L5027-L5040

Added lines #L5027 - L5040 were not covered by tests

bound = BoundaryObject(self, boundary_name, props, "Recirculating")
try:
if bound.create():
self._boundaries[bound.name] = bound
return bound

Check warning on line 5046 in pyaedt/icepak.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/icepak.py#L5042-L5046

Added lines #L5042 - L5046 were not covered by tests
else: # pragma: no cover
raise SystemExit
except (GrpcApiError, SystemExit): # pragma: no cover
return None
4 changes: 4 additions & 0 deletions pyaedt/modules/Boundary.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,8 @@
self._app.oboundary.AssignStationaryWallBoundary(self._get_args())
elif bound_type == "Symmetry Wall":
self._app.oboundary.AssignSymmetryWallBoundary(self._get_args())
elif bound_type == "Recirculating":
self._app.oboundary.AssignRecircBoundary(self._get_args())

Check warning on line 560 in pyaedt/modules/Boundary.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/modules/Boundary.py#L560

Added line #L560 was not covered by tests
elif bound_type == "Resistance":
self._app.oboundary.AssignResistanceBoundary(self._get_args())
elif bound_type == "Conducting Plate":
Expand Down Expand Up @@ -728,6 +730,8 @@
self._app.oboundary.EditStationaryWallBoundary(self._boundary_name, self._get_args()) # pragma: no cover
elif bound_type == "Symmetry Wall":
self._app.oboundary.EditSymmetryWallBoundary(self._boundary_name, self._get_args()) # pragma: no cover
elif bound_type == "Recirculating":
self._app.oboundary.EditRecircBoundary(self._boundary_name, self._get_args())

Check warning on line 734 in pyaedt/modules/Boundary.py

View check run for this annotation

Codecov / codecov/patch

pyaedt/modules/Boundary.py#L734

Added line #L734 was not covered by tests
elif bound_type == "Resistance":
self._app.oboundary.EditResistanceBoundary(self._boundary_name, self._get_args()) # pragma: no cover
elif bound_type == "Conducting Plate":
Expand Down
Loading