Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions .github/workflows/ci_conda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,29 @@ on: [pull_request, push]

jobs:
run-tests:
name: run-tests (fenics-dolfinx v${{ matrix.dolfinx }})
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
dolfinx: ['0.9.0', '0.10.0']

steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v6

- name: Set up Conda
uses: conda-incubator/setup-miniconda@v3
with:
activate-environment: myenv
miniforge-version: latest
# use-mamba: true
channels: conda-forge

- name: Create Conda environment
shell: bash -l {0}
run: |
conda install -c conda-forge fenics-dolfinx=0.9.0 pyvista
conda install -c conda-forge fenics-dolfinx=${{ matrix.dolfinx }} pyvista

- name: Install local package and dependencies
shell: bash -l {0}
Expand Down
8 changes: 6 additions & 2 deletions .github/workflows/ci_docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@ jobs:
strategy:
fail-fast: false
matrix:
container_version: [v0.9.0, nightly]
container_version: [v0.9.0, v0.10.0, nightly]
container: dolfinx/dolfinx:${{ matrix.container_version }}
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v6

- name: Configure git safe directory
run: |
git config --global --add safe.directory '*'

- name: Install local package and dependencies
run: |
Expand Down
2 changes: 1 addition & 1 deletion src/foam2dolfinx/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@

from .open_foam_reader import OpenFOAMReader, find_closest_value

__all__ = ["OpenFOAMReader, find_closest_value"]
__all__ = ["OpenFOAMReader", "find_closest_value"]
74 changes: 69 additions & 5 deletions src/foam2dolfinx/open_foam_reader.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,26 +168,30 @@ def _create_dolfinx_mesh(self, subdomain: str | None = "default"):
)
degree = 1 # Set polynomial degree
cell = ufl.Cell(shape)
# ufl.Cell.cellname became a property after dolfinx v0.10
cell_name = cell.cellname() if callable(cell.cellname) else cell.cellname
self.mesh_vector_element = basix.ufl.element(
"Lagrange", cell.cellname(), degree, shape=(3,)
"Lagrange", cell_name, degree, shape=(3,)
)
self.mesh_scalar_element = basix.ufl.element(
"Lagrange", cell.cellname(), degree, shape=()
"Lagrange", cell_name, degree, shape=()
)

# Create dolfinx Mesh
mesh_ufl = ufl.Mesh(self.mesh_vector_element)
mesh_ufl = ufl.Mesh(
basix.ufl.element("Lagrange", cell_name, degree, shape=(3,))
)
self.dolfinx_meshes_dict[subdomain] = create_mesh(
comm=MPI.COMM_WORLD,
cells=self.connectivities_dict[subdomain],
x=self.OF_meshes_dict[subdomain].points,
e=mesh_ufl,
)

def create_dolfinx_function(
def create_dolfinx_function_with_cell_data(
self, t: float, name: str = "U", subdomain: str | None = "default"
) -> dolfinx.fem.Function:
"""Creates a dolfinx.fem.Function from the OpenFOAM file.
"""Creates a dolfinx.fem.Function from the OpenFOAM file using cell data.

Args:
t: timestamp of the data to read
Expand All @@ -202,6 +206,66 @@ def create_dolfinx_function(
# read the OpenFOAM data in the filename provided
self._read_with_pyvista(t=t, subdomain=subdomain)

# test if name is in the cell data of the OF mesh
if name not in self.OF_meshes_dict[subdomain].cell_data.keys():
raise ValueError(
f"Function name: {name} not found in the subdomain: {subdomain}, "
"in the OpenFOAM file. "
f"Available functions in subdomain: {subdomain} : "
f"{self.OF_meshes_dict[subdomain].cell_data.keys()}"
)

# create the dolfinx mesh
if subdomain not in self.dolfinx_meshes_dict:
self._create_dolfinx_mesh(subdomain=subdomain)

mesh = self.dolfinx_meshes_dict[subdomain]

if name == "U":
element = basix.ufl.element("DG", mesh.topology.cell_name(), 0, shape=(3,))
else:
element = basix.ufl.element("DG", mesh.topology.cell_name(), 0, shape=())

function_space = dolfinx.fem.functionspace(mesh, element)
u = dolfinx.fem.Function(function_space)

# Assign values in OF_mesh to dolfinx_mesh
assert hasattr(self.OF_meshes_dict[subdomain], "cell_data")
u.x.array[:] = (
self.OF_meshes_dict[subdomain]
.cell_data[name][mesh.topology.original_cell_index]
.flatten()
)

return u

def create_dolfinx_function_with_point_data(
self, t: float, name: str = "U", subdomain: str | None = "default"
) -> dolfinx.fem.Function:
"""Creates a dolfinx.fem.Function from the OpenFOAM file using point data.

Args:
t: timestamp of the data to read
name: Name of the field in the OpenFOAM file, defaults to "U" for velocity
subdomain: Name of the subdmain in the OpenFOAM file, from which a field is
extracted

Returns:
the dolfinx function
"""

# read the OpenFOAM data in the filename provided
self._read_with_pyvista(t=t, subdomain=subdomain)

# test if name is in the cell data of the OF mesh
if name not in self.OF_meshes_dict[subdomain].cell_data.keys():
raise ValueError(
f"Function name: {name} not found in the subdomain: {subdomain}, "
"in the OpenFOAM file. "
f"Available functions in subdomain: {subdomain} : "
f"{self.OF_meshes_dict[subdomain].cell_data.keys()}"
)

# create the dolfinx mesh
if subdomain not in self.dolfinx_meshes_dict:
self._create_dolfinx_mesh(subdomain=subdomain)
Expand Down
8 changes: 6 additions & 2 deletions test/test_create_dolfinx_mesh.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import re

import numpy as np
import pytest
from pyvista import examples
import re

from foam2dolfinx import OpenFOAMReader

Expand All @@ -19,7 +20,10 @@ def test_error_rasied_when_using_mixed_topology_mesh():
# Create a 400x8 array filled with random values
my_reader.OF_cells_dict["default"] = rng.random((400, 8))

error_message = "Cell type: 1, not supported, please use either 12 (hexahedron) or 10 (tetrahedron) cells in OF mesh"
error_message = (
"Cell type: 1, not supported, please use either 12 (hexahedron) "
"or 10 (tetrahedron) cells in OF mesh"
)
pattern = re.escape(error_message)

with pytest.raises(
Expand Down
59 changes: 59 additions & 0 deletions test/test_create_function.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import re
import zipfile
from pathlib import Path

import pytest

from foam2dolfinx import OpenFOAMReader


def test_not_finding_function_cell_data(tmpdir):
zip_path = Path("test/data/test_2Regions.zip")
extract_path = Path(tmpdir) / "test_2Regions"

# Unzip the file
with zipfile.ZipFile(zip_path, "r") as zip_ref:
zip_ref.extractall(extract_path)

# Construct the path to the .foam file
foam_file = extract_path / "test_2Regions/pv.foam"

# read the .foam file
my_of_reader = OpenFOAMReader(filename=str(foam_file), cell_type=12)

with pytest.raises(
ValueError,
match=re.escape(
"Function name: coucou not found in the subdomain: solid, in the OpenFOAM file. "
"Available functions in subdomain: solid : ['T']"
),
):
my_of_reader.create_dolfinx_function_with_cell_data(
t=20.0, subdomain="solid", name="coucou"
)


def test_not_finding_function_point_data(tmpdir):
zip_path = Path("test/data/test_2Regions.zip")
extract_path = Path(tmpdir) / "test_2Regions"

# Unzip the file
with zipfile.ZipFile(zip_path, "r") as zip_ref:
zip_ref.extractall(extract_path)

# Construct the path to the .foam file
foam_file = extract_path / "test_2Regions/pv.foam"

# read the .foam file
my_of_reader = OpenFOAMReader(filename=str(foam_file), cell_type=12)

with pytest.raises(
ValueError,
match=re.escape(
"Function name: coucou not found in the subdomain: solid, in the OpenFOAM file. "
"Available functions in subdomain: solid : ['T']"
),
):
my_of_reader.create_dolfinx_function_with_point_data(
t=20.0, subdomain="solid", name="coucou"
)
60 changes: 48 additions & 12 deletions test/test_example.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from foam2dolfinx import OpenFOAMReader
import dolfinx
from pyvista import examples
import zipfile
from pathlib import Path

import dolfinx
from pyvista import examples

from foam2dolfinx import OpenFOAMReader


def test_reading_and_writing_cavity_example():
my_of_reader = OpenFOAMReader(filename=examples.download_cavity(load=False))
vel = my_of_reader.create_dolfinx_function(t=2.5)
vel = my_of_reader.create_dolfinx_function_with_point_data(t=2.5)

assert isinstance(vel, dolfinx.fem.Function)

Expand All @@ -28,8 +30,8 @@ def test_baby_example(tmpdir):
# read the .foam file
my_of_reader = OpenFOAMReader(filename=str(foam_file), cell_type=10)

vel = my_of_reader.create_dolfinx_function(t=time, name="U")
T = my_of_reader.create_dolfinx_function(t=time, name="T")
vel = my_of_reader.create_dolfinx_function_with_point_data(t=time, name="U")
T = my_of_reader.create_dolfinx_function_with_point_data(t=time, name="T")

assert isinstance(vel, dolfinx.fem.Function)
assert isinstance(T, dolfinx.fem.Function)
Expand All @@ -51,10 +53,44 @@ def test_hot_room(tmpdir):
# read the .foam file
my_of_reader = OpenFOAMReader(filename=str(foam_file), cell_type=12)

vel = my_of_reader.create_dolfinx_function(t=time, name="U")
T = my_of_reader.create_dolfinx_function(t=time, name="T")
nut = my_of_reader.create_dolfinx_function(t=time, name="nut")
vel_point = my_of_reader.create_dolfinx_function_with_point_data(t=time, name="U")
T_point = my_of_reader.create_dolfinx_function_with_point_data(t=time, name="T")
nut_point = my_of_reader.create_dolfinx_function_with_point_data(t=time, name="nut")

assert isinstance(vel, dolfinx.fem.Function)
assert isinstance(T, dolfinx.fem.Function)
assert isinstance(nut, dolfinx.fem.Function)
vel_cell = my_of_reader.create_dolfinx_function_with_cell_data(t=time, name="U")
T_cell = my_of_reader.create_dolfinx_function_with_cell_data(t=time, name="T")
nut_cell = my_of_reader.create_dolfinx_function_with_cell_data(t=time, name="nut")

assert isinstance(vel_point, dolfinx.fem.Function)
assert isinstance(T_point, dolfinx.fem.Function)
assert isinstance(nut_point, dolfinx.fem.Function)
assert isinstance(vel_cell, dolfinx.fem.Function)
assert isinstance(T_cell, dolfinx.fem.Function)
assert isinstance(nut_cell, dolfinx.fem.Function)


def test_mesh_created_when_not_in_dict(tmpdir):
zip_path = Path("test/data/test_2Regions.zip")
extract_path = Path(tmpdir) / "test_2Regions"

# Unzip the file
with zipfile.ZipFile(zip_path, "r") as zip_ref:
zip_ref.extractall(extract_path)

# Construct the path to the .foam file
foam_file = extract_path / "test_2Regions/pv.foam"

# read the .foam file
my_of_reader = OpenFOAMReader(filename=str(foam_file), cell_type=12)

my_of_reader.create_dolfinx_function_with_cell_data(
t=20.0, subdomain="fluid", name="T"
)

assert len(my_of_reader.dolfinx_meshes_dict) == 1

my_of_reader.create_dolfinx_function_with_cell_data(
t=20.0, subdomain="solid", name="T"
)

assert len(my_of_reader.dolfinx_meshes_dict) == 2
5 changes: 4 additions & 1 deletion test/test_read_with_pyvista.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ def test_error_rasied_when_subdomain_is_not_given_in_multidomain_case(tmpdir):

with pytest.raises(
ValueError,
match="Subdomain None not found in the OpenFOAM file\. Available subdomains: \['defaultRegion', 'fluid', 'solid']",
match=(
r"Subdomain None not found in the OpenFOAM file\. "
r"Available subdomains: \['defaultRegion', 'fluid', 'solid']"
),
):
my_of_reader._read_with_pyvista(t=20.0, subdomain=None)

Expand Down
Loading