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
58 changes: 58 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
name: Test all platforms

on: [ pull_request, workflow_dispatch ]

jobs:
test:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest, macos-13, macos-latest, windows-latest ]
python-version: [ "3.9", "3.10", "3.11", "3.12", "3.13" ]

runs-on: ${{ matrix.os }}

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Linux packages for Qt5/Qt6 support and start Xvfb
if: runner.os == 'Linux'
uses: pyvista/setup-headless-display-action@v3
with:
qt: true

- name: Linux OpenCL support
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y pocl-opencl-icd ocl-icd-opencl-dev gcc clinfo
clinfo

- name : Windows OpenCL support
if: runner.os == 'Windows'
run: |
choco install opencl-intel-cpu-runtime --no-progress --yes

- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}

- name: Install dependencies
run: |
python -m pip install --upgrade pip
python -m pip install setuptools>=40.8.0 wheel pytest
python -m pip install .
python -m pip freeze --all

- name: Validate OpenCL
if: matrix.os != 'macos-latest' # no OpenCL device in macOS runners since macos-14
run: |
python -c "from pytissueoptics.rayscattering.opencl import OPENCL_OK; assert OPENCL_OK"

- name: Run tests
env:
PTO_CI_MODE: 1
run: |
python -m pytest -v
6 changes: 6 additions & 0 deletions pytissueoptics/rayscattering/opencl/config/CLConfig.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ def _load(self):
with open(OPENCL_CONFIG_PATH, "r") as f:
self._config = json.load(f)

if os.getenv("PTO_CI_MODE", "0") == "1":
warnings.warn("Using default OpenCL configuration for CI mode.")
self.DEVICE_INDEX = 0
self.N_WORK_UNITS = 128
self.MAX_MEMORY_MB = 1024

def _assertExists(self):
if not os.path.exists(OPENCL_CONFIG_PATH):
warnings.warn("No OpenCL config file found. Creating a new one.")
Expand Down
28 changes: 19 additions & 9 deletions pytissueoptics/rayscattering/tests/opencl/config/testCLConfig.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import tempfile
import unittest
from unittest.mock import patch

from pytissueoptics.rayscattering.opencl import OPENCL_OK
from pytissueoptics.rayscattering.opencl.config import CLConfig as clc
Expand All @@ -25,11 +26,17 @@ def testGivenNoConfigFile_shouldWarnAndCreateANewOne(self):
self.assertTrue(os.path.exists(clc.OPENCL_CONFIG_PATH))

@tempConfigPath
def testGivenNewConfigFile_shouldHaveDefaultValues(self):
def testGivenNewConfigFile_shouldHaveDefaultsFromEnvironment(self):
with self.assertWarns(UserWarning):
config = clc.CLConfig()
self.assertEqual(None, config.N_WORK_UNITS)
self.assertEqual(None, config.MAX_MEMORY_MB)
if os.getenv("PTO_CI_MODE", "0") == "1":
self.assertEqual(0, config.DEVICE_INDEX)
self.assertEqual(128, config.N_WORK_UNITS)
self.assertEqual(1024, config.MAX_MEMORY_MB)
else:
self.assertEqual(None, config.DEVICE_INDEX)
self.assertEqual(None, config.N_WORK_UNITS)
self.assertEqual(None, config.MAX_MEMORY_MB)
self.assertEqual(1000, config.IPP_TEST_N_PHOTONS)
self.assertEqual(0.20, config.BATCH_LOAD_FACTOR)

Expand All @@ -46,7 +53,8 @@ def testGivenMaxMemoryNotSet_whenValidate_shouldWarnAndSetMaxMemory(self):
with open(clc.OPENCL_CONFIG_PATH, "w") as f:
f.write('{"DEVICE_INDEX": 0, "N_WORK_UNITS": 100, "MAX_MEMORY_MB": null, '
'"IPP_TEST_N_PHOTONS": 1000, "BATCH_LOAD_FACTOR": 0.2}')
config = clc.CLConfig()
with patch("os.getenv", return_value=None):
config = clc.CLConfig()
with self.assertWarns(UserWarning):
config.validate()
self.assertIsNotNone(config.MAX_MEMORY_MB)
Expand All @@ -68,8 +76,10 @@ def testGivenFileWithAParameterBelowOrEqualToZero_whenValidate_shouldResetDefaul
with open(clc.OPENCL_CONFIG_PATH, "w") as f:
f.write('{"DEVICE_INDEX": 0, "N_WORK_UNITS": 100, "MAX_MEMORY_MB": 0, '
'"IPP_TEST_N_PHOTONS": 1000, "BATCH_LOAD_FACTOR": 0.2}')
config = clc.CLConfig()
with self.assertRaises(ValueError):
config.validate()
config = clc.CLConfig()
self.assertIsNone(config.MAX_MEMORY_MB)

with patch("os.getenv", return_value=None):
config = clc.CLConfig()
with self.assertRaises(ValueError):
config.validate()
config = clc.CLConfig()
self.assertIsNone(config.MAX_MEMORY_MB)