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
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ A Python library for interpolating physical field data (electromagnetic forces,
- **Support for multiple load types**:
- EM forces (3-component vector fields)
- Heat flux (scalar fields)
- Heat generation (volumetric)
- Heat Transfer Coefficient + bulk fluid temperature (convection BCs)
- **Export to ANSYS APDL**: Direct export of interpolated results in APDL format
- **Visualization**: Built-in VTK export for ParaView or PyVista visualization
- **Efficient**: KDTree-based spatial queries for fast neighbor searches
Expand Down Expand Up @@ -62,9 +64,10 @@ interpolator.build_vtk_output(outdir="vtk_output")

Complete working examples with sample data are available in the [`doc/`](doc/) folder:

- **[Heat Flux Example](doc/heat_flux/)**: Scalar field interpolation using the AVERAGE kernel
- **[Heat Generation Example](doc/heat_gen/)**: Volumetric heat generation using the CLOSEST kernel
- **[EM Force Example](doc/em_force/)**: Vector field interpolation with glyph visualization
- **[Heat Flux Example](doc/heat_flux/heat_flux.ipynb)**: Scalar field interpolation using the AVERAGE kernel
- **[Heat Generation Example](doc/heat_gen/heat_gen.ipynb)**: Volumetric heat generation using the CLOSEST kernel
- **[EM Force Example](doc/em_force/em_force.ipynb)**: Vector field interpolation with glyph visualization
- **[HTC Example](doc/htc/htc.ipynb)**: Convection boundary condition interpolation (HTC + bulk fluid temperature)

Each example includes:
- Sample mesh files
Expand Down Expand Up @@ -99,6 +102,7 @@ A value is assigned to each destination point based on source neighbours
interpreted as force densities and will be multiplied by the volume.
- `HEAT_FLUX`: Scalar fields for surface heat flux
- `HEAT_GEN`: Scalar fields for volumetric heat generation
- `HTC`: 2-component convection boundary condition — Heat Transfer Coefficient and bulk fluid (reference) temperature. Exported as `SFE,,CONV,1` and `SFE,,CONV,2` in APDL.

## File Format

Expand Down
76 changes: 76 additions & 0 deletions doc/htc/destination_mesh.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
Node_ID X Y Z
101 0.25 0.33 0.00
102 0.25 1.00 0.00
103 0.25 1.67 0.00
104 0.25 2.33 0.00
105 0.25 3.00 0.00
106 0.25 3.67 0.00
107 0.25 4.34 0.00
108 0.25 5.00 0.00
109 0.25 5.67 0.00
110 0.25 6.34 0.00
111 0.25 7.00 0.00
112 0.25 7.67 0.00
113 0.25 8.34 0.00
114 0.25 9.00 0.00
115 0.25 9.67 0.00
116 0.75 0.33 0.00
117 0.75 1.00 0.00
118 0.75 1.67 0.00
119 0.75 2.33 0.00
120 0.75 3.00 0.00
121 0.75 3.67 0.00
122 0.75 4.34 0.00
123 0.75 5.00 0.00
124 0.75 5.67 0.00
125 0.75 6.34 0.00
126 0.75 7.00 0.00
127 0.75 7.67 0.00
128 0.75 8.34 0.00
129 0.75 9.00 0.00
130 0.75 9.67 0.00
131 1.25 0.33 0.00
132 1.25 1.00 0.00
133 1.25 1.67 0.00
134 1.25 2.33 0.00
135 1.25 3.00 0.00
136 1.25 3.67 0.00
137 1.25 4.34 0.00
138 1.25 5.00 0.00
139 1.25 5.67 0.00
140 1.25 6.34 0.00
141 1.25 7.00 0.00
142 1.25 7.67 0.00
143 1.25 8.34 0.00
144 1.25 9.00 0.00
145 1.25 9.67 0.00
146 1.75 0.33 0.00
147 1.75 1.00 0.00
148 1.75 1.67 0.00
149 1.75 2.33 0.00
150 1.75 3.00 0.00
151 1.75 3.67 0.00
152 1.75 4.34 0.00
153 1.75 5.00 0.00
154 1.75 5.67 0.00
155 1.75 6.34 0.00
156 1.75 7.00 0.00
157 1.75 7.67 0.00
158 1.75 8.34 0.00
159 1.75 9.00 0.00
160 1.75 9.67 0.00
161 2.25 0.33 0.00
162 2.25 1.00 0.00
163 2.25 1.67 0.00
164 2.25 2.33 0.00
165 2.25 3.00 0.00
166 2.25 3.67 0.00
167 2.25 4.34 0.00
168 2.25 5.00 0.00
169 2.25 5.67 0.00
170 2.25 6.34 0.00
171 2.25 7.00 0.00
172 2.25 7.67 0.00
173 2.25 8.34 0.00
174 2.25 9.00 0.00
175 2.25 9.67 0.00
268 changes: 268 additions & 0 deletions doc/htc/htc.ipynb

Large diffs are not rendered by default.

31 changes: 31 additions & 0 deletions doc/htc/source_data/htc_data.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Node_ID X Y Z HTC Tref
1 0.50 0.50 0.00 150.00 310.00
2 0.50 1.50 0.00 155.00 312.00
3 0.50 2.50 0.00 162.00 315.00
4 0.50 3.50 0.00 170.00 318.00
5 0.50 4.50 0.00 178.00 320.00
6 0.50 5.50 0.00 185.00 322.00
7 0.50 6.50 0.00 190.00 325.00
8 0.50 7.50 0.00 196.00 328.00
9 0.50 8.50 0.00 200.00 330.00
10 0.50 9.50 0.00 205.00 332.00
11 1.50 0.50 0.00 158.00 311.00
12 1.50 1.50 0.00 163.00 313.00
13 1.50 2.50 0.00 169.00 316.00
14 1.50 3.50 0.00 177.00 319.00
15 1.50 4.50 0.00 184.00 321.00
16 1.50 5.50 0.00 191.00 323.00
17 1.50 6.50 0.00 198.00 326.00
18 1.50 7.50 0.00 204.00 329.00
19 1.50 8.50 0.00 209.00 331.00
20 1.50 9.50 0.00 214.00 333.00
21 2.50 0.50 0.00 165.00 312.00
22 2.50 1.50 0.00 170.00 314.00
23 2.50 2.50 0.00 176.00 317.00
24 2.50 3.50 0.00 183.00 320.00
25 2.50 4.50 0.00 190.00 322.00
26 2.50 5.50 0.00 197.00 324.00
27 2.50 6.50 0.00 204.00 327.00
28 2.50 7.50 0.00 210.00 330.00
29 2.50 8.50 0.00 215.00 332.00
30 2.50 9.50 0.00 220.00 334.00
3 changes: 3 additions & 0 deletions src/interpcore/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class INTERPOLATED_LOAD_TYPE(Enum):
EM_FORCE = "EM-Force"
HEAT_FLUX = "Heat Flux"
HEAT_GEN = "Heat Generation"
HTC = "Heat Transfer Coefficient"


class INTERPOLATION_KERNEL(Enum):
Expand Down Expand Up @@ -85,5 +86,7 @@ def __post_init__(self):
self.num_components = 1
elif self.interpolated_load == INTERPOLATED_LOAD_TYPE.HEAT_GEN:
self.num_components = 1
elif self.interpolated_load == INTERPOLATED_LOAD_TYPE.HTC:
self.num_components = 2
else:
raise ValueError(f"Unsupported load type: {self.interpolated_load}")
5 changes: 5 additions & 0 deletions src/interpcore/interpolator.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,5 +243,10 @@ def _select_template(interpolated_load: INTERPOLATED_LOAD_TYPE) -> list[str]:
return [
"BFE, {}, HGEN,, {}\n",
]
elif interpolated_load == INTERPOLATED_LOAD_TYPE.HTC:
return [
"SFE, {},, CONV, 1, {}\n", # HTC
"SFE, {},, CONV, 2, {}\n", # TEMP
]
else:
raise NotImplementedError(f"Unsupported load type: {interpolated_load}")
103 changes: 103 additions & 0 deletions tests/test_interpolator.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,20 @@ def sample_config_heat_gen():
)


@pytest.fixture
def sample_config_htc():
"""Create a sample configuration for HTC interpolation"""
return InterpolationConfig(
method=QUERY_TYPE.K,
param=3,
max_distance=2.0,
coincidence_tolerance=1e-6,
kernel=INTERPOLATION_KERNEL.DISTANCE_WEIGHTED,
multithread=False,
interpolated_load=INTERPOLATED_LOAD_TYPE.HTC,
)


@pytest.fixture
def create_sample_mesh_files(temp_dir):
"""Create sample mesh and data files for testing"""
Expand Down Expand Up @@ -156,6 +170,38 @@ def create_sample_heat_gen_files(temp_dir):
}


@pytest.fixture
def create_sample_htc_files(temp_dir):
"""Create sample mesh and HTC data files for testing"""
# Create destination mesh file
dest_mesh = temp_dir / "destination_mesh.txt"
dest_content = """Node_ID X Y Z
501 0.0 0.0 0.0
502 1.0 0.0 0.0
503 2.0 0.0 0.0
504 0.0 1.0 0.0
"""
dest_mesh.write_text(dest_content)

# Create source data folder
src_folder = temp_dir / "htc_data"
src_folder.mkdir()

# Create source data file with HTC and reference temperature (2 components)
src_file = src_folder / "htc_001.txt"
src_content = """Node_ID X Y Z HTC Tref
1 0.5 0.5 0.0 250.0 300.0
2 1.5 0.5 0.0 300.0 310.0
3 0.5 1.5 0.0 275.0 305.0
"""
src_file.write_text(src_content)

return {
"dest_mesh": str(dest_mesh),
"src_folder": str(src_folder),
}


class TestInterpolator:
"""Tests for Interpolator class"""

Expand Down Expand Up @@ -267,6 +313,25 @@ def test_interpolate_all_with_em_force(
result = interpolator.interpolated_results["force_001"]
assert result["interpolated"].shape[1] == 3 # EM force has 3 components

def test_interpolate_all_with_htc(self, create_sample_htc_files, sample_config_htc):
"""Test interpolation with HTC data (2 components: HTC and Tref)"""
file_idx = {"ids": 0, "dest_x": 1, "src_x": 1, "val": 4}
interpolator = Interpolator(
path_to_src_folder=create_sample_htc_files["src_folder"],
path_to_dest_mesh=create_sample_htc_files["dest_mesh"],
config=sample_config_htc,
file_idx=file_idx,
)

interpolator.interpolate_all()

assert interpolator.interpolated_results is not None
result = interpolator.interpolated_results["htc_001"]
assert "interpolated" in result
assert "unmapped" in result
assert result["interpolated"].shape[0] > 0
assert result["interpolated"].shape[1] == 2 # HTC has 2 components

def test_export_to_ansys_without_interpolation(
self, create_sample_mesh_files, sample_config_heat_flux, temp_dir
):
Expand Down Expand Up @@ -371,6 +436,34 @@ def test_export_to_ansys_heat_gen(
assert "HGEN" in content
assert "BF" in content

def test_export_to_ansys_htc(
self, create_sample_htc_files, sample_config_htc, temp_dir
):
"""Test exporting HTC results to ANSYS format"""
file_idx = {"ids": 0, "dest_x": 1, "src_x": 1, "val": 4}
interpolator = Interpolator(
path_to_src_folder=create_sample_htc_files["src_folder"],
path_to_dest_mesh=create_sample_htc_files["dest_mesh"],
config=sample_config_htc,
file_idx=file_idx,
)

interpolator.interpolate_all()

output_dir = temp_dir / "output"
output_dir.mkdir()
interpolator.export_to_ansys(output_dir)

# Check that output file was created
output_files = list(output_dir.glob("interpolated_*.txt"))
assert len(output_files) == 1
assert output_files[0].name == "interpolated_htc_001.txt"

# Check file content format (should have CONV)
content = output_files[0].read_text()
assert "CONV" in content
assert "SFE" in content

def test_build_vtk_output_without_interpolation(
self, create_sample_mesh_files, sample_config_heat_flux
):
Expand Down Expand Up @@ -500,6 +593,16 @@ def test_select_template_heat_gen(self):
assert "HGEN" in templates[0]
assert "BFE" in templates[0]

def test_select_template_htc(self):
"""Test template selection for HTC"""
templates = _select_template(INTERPOLATED_LOAD_TYPE.HTC)

assert len(templates) == 2
assert "CONV" in templates[0]
assert "SFE" in templates[0]
assert "CONV" in templates[1]
assert "SFE" in templates[1]

def test_select_template_unsupported_type(self):
"""Test that unsupported load types raise NotImplementedError"""

Expand Down
Loading