How to replicate BaramMesh results using NextFOAM/OpenFOAM from the command line
Quote from Christoforos Lefkiou on June 4, 2026, 11:54 pmI am trying to automate mesh generation for multiple ship hulls using NextFOAM/OpenFOAM directly, replicating what BaramMesh does through the GUI.
I exported a case from BaramMesh and copied the
snappyHexMeshDict,blockMeshDict, and all settings to my OpenFOAM template. However, my mesh has ~1.3M cells while BARAM produces ~1.6M cells with noticeably better edge refinement on the hull surface.After investigation I found:
- The
blockMeshDictis identical (30x12x12 background mesh)- All
snappyHexMeshDictsettings are the same (refinement levels, layer settings, quality controls)- The only difference is the feature edge file
hull.obj— BARAM generates one with 1291 edges, whilesurfaceFeatureExtractwithincludedAngle 150gives only 908 edgesThere is no
surfaceFeatureExtractDictin the BARAM-exported case, meaning BARAM does not usesurfaceFeatureExtractat all. Thehull.objappears to be generated internally by BARAM through Python/VTK.My question: How does BaramMesh generate the feature edge file (
hull.obj)? Is it usingsurfacePatch, VTK feature edge extraction, or something else?And the most ipmportant question, what is the correct way to replicate this from the command line to get consistent results?
Any insight into BARAM's internal preprocessing pipeline would be greatly appreciated.
I am trying to automate mesh generation for multiple ship hulls using NextFOAM/OpenFOAM directly, replicating what BaramMesh does through the GUI.
I exported a case from BaramMesh and copied the snappyHexMeshDict, blockMeshDict, and all settings to my OpenFOAM template. However, my mesh has ~1.3M cells while BARAM produces ~1.6M cells with noticeably better edge refinement on the hull surface.
After investigation I found:
- The
blockMeshDictis identical (30x12x12 background mesh) - All
snappyHexMeshDictsettings are the same (refinement levels, layer settings, quality controls) - The only difference is the feature edge file
hull.obj— BARAM generates one with 1291 edges, whilesurfaceFeatureExtractwithincludedAngle 150gives only 908 edges
There is no surfaceFeatureExtractDict in the BARAM-exported case, meaning BARAM does not use surfaceFeatureExtract at all. The hull.obj appears to be generated internally by BARAM through Python/VTK.
My question: How does BaramMesh generate the feature edge file (hull.obj)? Is it using surfacePatch, VTK feature edge extraction, or something else?
And the most ipmportant question, what is the correct way to replicate this from the command line to get consistent results?
Any insight into BARAM's internal preprocessing pipeline would be greatly appreciated.
Quote from Jake on June 5, 2026, 12:09 pmHi, Christoforos.
Excellent troubleshooting—you hit the nail on the head.
BARAM Mesh utilizes vtkFeatureEdges from VTK.Regarding your second question on how to replicate this from the command line: because vtkFeatureEdges is a library class rather than a standalone OpenFOAM utility, there is no out-of-the-box CLI command to trigger it.
However, the most robust way to replicate BARAM's exact edge extraction pipeline is to write a standalone Python script using the vtk Python package. You can easily run this script from the command line right before you execute blockMesh and snappyHexMesh.
To get the exact parameters and logic BARAM uses, I highly recommend looking at the BARAM source code. Specifically, the Python method "_writeFeatureFile()". You can essentially lift the logic from that method to create your own automated CLI script.
Best regards,
Jake
Hi, Christoforos.
Excellent troubleshooting—you hit the nail on the head.
BARAM Mesh utilizes vtkFeatureEdges from VTK.
Regarding your second question on how to replicate this from the command line: because vtkFeatureEdges is a library class rather than a standalone OpenFOAM utility, there is no out-of-the-box CLI command to trigger it.
However, the most robust way to replicate BARAM's exact edge extraction pipeline is to write a standalone Python script using the vtk Python package. You can easily run this script from the command line right before you execute blockMesh and snappyHexMesh.
To get the exact parameters and logic BARAM uses, I highly recommend looking at the BARAM source code. Specifically, the Python method "_writeFeatureFile()". You can essentially lift the logic from that method to create your own automated CLI script.
Best regards,
Jake
Quote from Christoforos Lefkiou on June 5, 2026, 3:40 pmGood morning Jake,
Thank you for your reply. Your approach is correct and on-point.
Based on your answer, I have built a python script that can help other users too. Of course, one has to adjust it accordingly to their needs. For future references, I uploaded it here - the system doesnt allow me to upload python files (.py) so I will upload the text below:
import pyvista as pv
import sysstl_file = sys.argv[1]
obj_file = sys.argv[2]# Bounding box from blockMeshDict
bbox_min = (-21, 0, -7)
bbox_max = (14, 14, 7)mesh = pv.read(stl_file)
# Feature edges - exactly as BARAM does it
edges = mesh.extract_feature_edges(
boundary_edges=True,
non_manifold_edges=False,
feature_angle=30,
feature_edges=True,
manifold_edges=False
)# Add bounding box plane intersections
all_edges = [edges]
planes = [
((bbox_min[0], 0, 0), (-1, 0, 0)),
((bbox_max[0], 0, 0), (1, 0, 0)),
((0, bbox_min[1], 0), (0, -1, 0)),
((0, bbox_max[1], 0), (0, 1, 0)),
((0, 0, bbox_min[2]), (0, 0, -1)),
((0, 0, bbox_max[2]), (0, 0, 1)),
]for origin, normal in planes:
try:
cut = mesh.slice(normal=normal, origin=origin)
if cut.n_cells > 0:
all_edges.append(cut)
except:
passcombined = pv.merge(all_edges)
points = combined.points
lines = combined.lines.reshape(-1, 3)[:, 1:]with open(obj_file, "w") as f:
for pt in points:
f.write(f"v {pt[0]:.10f} {pt[1]:.10f} {pt[2]:.10f}\n")
for l in lines:
f.write(f"l {l[0]+1} {l[1]+1}\n")print(f"Written {len(lines)} edges to {obj_file}")
Best regards,
Christoforos
Good morning Jake,
Thank you for your reply. Your approach is correct and on-point.
Based on your answer, I have built a python script that can help other users too. Of course, one has to adjust it accordingly to their needs. For future references, I uploaded it here - the system doesnt allow me to upload python files (.py) so I will upload the text below:
import pyvista as pv
import sys
stl_file = sys.argv[1]
obj_file = sys.argv[2]
# Bounding box from blockMeshDict
bbox_min = (-21, 0, -7)
bbox_max = (14, 14, 7)
mesh = pv.read(stl_file)
# Feature edges - exactly as BARAM does it
edges = mesh.extract_feature_edges(
boundary_edges=True,
non_manifold_edges=False,
feature_angle=30,
feature_edges=True,
manifold_edges=False
)
# Add bounding box plane intersections
all_edges = [edges]
planes = [
((bbox_min[0], 0, 0), (-1, 0, 0)),
((bbox_max[0], 0, 0), (1, 0, 0)),
((0, bbox_min[1], 0), (0, -1, 0)),
((0, bbox_max[1], 0), (0, 1, 0)),
((0, 0, bbox_min[2]), (0, 0, -1)),
((0, 0, bbox_max[2]), (0, 0, 1)),
]
for origin, normal in planes:
try:
cut = mesh.slice(normal=normal, origin=origin)
if cut.n_cells > 0:
all_edges.append(cut)
except:
pass
combined = pv.merge(all_edges)
points = combined.points
lines = combined.lines.reshape(-1, 3)[:, 1:]
with open(obj_file, "w") as f:
for pt in points:
f.write(f"v {pt[0]:.10f} {pt[1]:.10f} {pt[2]:.10f}\n")
for l in lines:
f.write(f"l {l[0]+1} {l[1]+1}\n")
print(f"Written {len(lines)} edges to {obj_file}")
Best regards,
Christoforos