Skip to content

[WIP] Boundary update with testcases - #27

Open
bigfooted wants to merge 4 commits into
developfrom
new_fixed_strain
Open

[WIP] Boundary update with testcases#27
bigfooted wants to merge 4 commits into
developfrom
new_fixed_strain

Conversation

@bigfooted

@bigfooted bigfooted commented Sep 6, 2026

Copy link
Copy Markdown
Collaborator

Proposed Changes

Modify 2D table edges to better follow curved boundaries
add fixed strain rate testcase
add CH4 premixed testcase

To do for this PR:
regression test the new cases

Related Work

PR Checklist

Put an X by all that apply. You can fill this out after submitting the PR. If you have any questions, don't hesitate to ask! We want to help. These are a guide for you to know what the reviewers will be looking for in your contribution.

  • I am submitting my contribution to the develop branch.
  • I have updated the list of python modules in required_packages.txt and environment.yml, if necessary.
  • I have properly commented my changes.
  • I used the pre-commit hook to prevent dirty commits and used pre-commit run --all to format old commits.
  • I have updated the documentation, if necessary.
  • I have added a test case that demonstrates my contribution, if necessary.

@bigfooted

Copy link
Copy Markdown
Collaborator Author

flamelet_table_h2 was not working anymore, still has to be updated and checked.

@EvertBunschoten EvertBunschoten left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very nice! Thank you also for doing some clean up in other parts of the code and the test cases. I especially like the extensive visualization functions that have been added to the table generator. Overall, I think some of the functions can be made shorter and there is still one bug where the table plots are not actually visualized when specifying show=True.

Comment on lines +268 to +287
def ClampSourceTerms(self, species_list:list[str], pv_frac:float=0.99, abs_tol:float=1e-3):
"""Clamp source terms of selected species to zero near the burnt (high-PV) boundary.

For each table level the per-level progress variable maximum is computed. At every node
where PV >= ``pv_frac * PV_max`` the net, positive, and negative source terms
(``Y_dot_net-<sp>``, ``Y_dot_pos-<sp>``, ``Y_dot_neg-<sp>``) of each species in
``species_list`` are set to zero when their absolute value is below ``abs_tol``.
In addition, the production terms are clipped to be non-negative and the consumption
terms non-positive over all nodes, as SU2 evaluates the species source as
``source_prod + source_cons * y_aux``.

Call this method after :meth:`generateTable` and before :meth:`writeSU2Table`.

:param species_list: species names to clamp (e.g. ``['CO', 'H2']``).
:type species_list: list[str]
:param pv_frac: fraction of the PV maximum above which clamping is applied, defaults to 0.99
:type pv_frac: float, optional
:param abs_tol: source terms with an absolute value below this are set to zero, defaults to 1e-3
:type abs_tol: float, optional
:raises Exception: if the table data have not been generated yet.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to make this functionality independent of the order of operation, similar to how smoothing is applied.

data_level = self._data_in_table[iLevel]
pv_nodes = data_level[name_pv].to_numpy(dtype=float)
pv_max = pv_max_global if pv_is_level_cv else np.max(pv_nodes)
nodes_near_products = pv_nodes >= pv_frac * pv_max

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why only apply this to the burnt side? Would it be possible to apply clamping to the premixed side as well?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, but for burner stabilized flames the source term does not have to be zero on the burner surface.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use the EquilibriumSolver to calculate the value of the progress variable of the premixed reactants and products. The clamping should not affect the source terms there, since the value of the progress variable at the inflow of the burner-stabilized flamelet solutions is higher than the reactant progress variable.

Comment on lines +621 to +644
def __polylineIntersection(self, polyline_a:np.ndarray[float], polyline_b:np.ndarray[float]):
"""Locate the last point at which two polylines cross.

:return: the crossing point with the index of the crossed segment in each polyline, or None.
:rtype: tuple
"""
crossing = None
for iSegment in range(len(polyline_a) - 1):
start_a = polyline_a[iSegment]
direction_a = polyline_a[iSegment + 1] - start_a
for jSegment in range(len(polyline_b) - 1):
start_b = polyline_b[jSegment]
direction_b = polyline_b[jSegment + 1] - start_b

determinant = direction_a[0]*direction_b[1] - direction_a[1]*direction_b[0]
if abs(determinant) < np.finfo(float).eps:
continue

offset = start_b - start_a
along_a = (offset[0]*direction_b[1] - offset[1]*direction_b[0])/determinant
along_b = (offset[0]*direction_a[1] - offset[1]*direction_a[0])/determinant
if 0 <= along_a <= 1 and 0 <= along_b <= 1:
crossing = (start_a + along_a*direction_a, iSegment, jSegment)
return crossing

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function can be made a static method, for example under Common/Interpolators.py

Comment on lines +686 to +687
if not show:
plt.close(fig)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not show:
plt.close(fig)
if show:
plt.show()
if else:
plt.close(fig)

Comment on lines +512 to +524
if not table_is_generated:
self._processTableLevels()
if self._fluid_data_interpolator is None:
self._defineFluidDataInterpolator()
self._checkTableLevelIndex(level_index)

if table_is_generated:
table_nodes = self._table_nodes[level_index]
connectivity = self._table_connectivity[level_index]
hull_nodes = self._table_hullnodes[level_index]
data_level = self._data_in_table[level_index]
else:
table_nodes, connectivity, hull_nodes, data_level = self.meshTableLevel(level_index)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if not table_is_generated:
self._processTableLevels()
if self._fluid_data_interpolator is None:
self._defineFluidDataInterpolator()
self._checkTableLevelIndex(level_index)
if table_is_generated:
table_nodes = self._table_nodes[level_index]
connectivity = self._table_connectivity[level_index]
hull_nodes = self._table_hullnodes[level_index]
data_level = self._data_in_table[level_index]
else:
table_nodes, connectivity, hull_nodes, data_level = self.meshTableLevel(level_index)
if table_is_generated:
table_nodes = self._table_nodes[level_index]
connectivity = self._table_connectivity[level_index]
hull_nodes = self._table_hullnodes[level_index]
data_level = self._data_in_table[level_index]
else:
self._processTableLevels()
if self._fluid_data_interpolator is None:
self._defineFluidDataInterpolator()
self._checkTableLevelIndex(level_index)
table_nodes, connectivity, hull_nodes, data_level = self.meshTableLevel(level_index)

Comment on lines +537 to +543
fig, ax = plt.subplots(figsize=(10, 10))
ax.triplot(x_nodes, y_nodes, connectivity, linewidth=0.5)
ax.plot(x_nodes[hull_nodes], y_nodes[hull_nodes], 'ko', ms=3, label="Perimiter nodes")
ax.set_xlabel(self._table_cv_names[0], fontsize=14)
ax.set_ylabel(self._table_cv_names[1], fontsize=14)
ax.set_title(title, fontsize=14)
ax.legend(fontsize=12)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could these blocks be moved to static functions? The plotting data, labels, etc, could be passed through a dictionary.

triangulation = mtri.Triangulation(x_nodes, y_nodes, connectivity)
fig, ax = plt.subplots(figsize=(10, 7), constrained_layout=True)
colormesh = ax.tripcolor(triangulation, data_level[var_to_plot].to_numpy(dtype=float), \
shading='gouraud', cmap='inferno')

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we define the colormap through a setter function, we can keep the colormap consistent between plotting functions.

raise Exception("Boundary polyline should be provided as an array with %i columns" % len(self.__mesh_along_coords))
if len(polyline) < 3:
raise Exception("Boundary polyline should describe at least three points")
self.__boundary_polyline = polyline

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be one more check here for if the point cloud contains unique points.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants