Skip to content

Commit b08498a

Browse files
authored
Merge pull request #144 from DCC-Lab/jlb/improve-readme
Improve README
2 parents 50c4e76 + 052e7ba commit b08498a

4 files changed

Lines changed: 101 additions & 144 deletions

File tree

.github/workflows/test-coverage.yaml

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
name: Test Coverage
22

33
on:
4-
pull_request:
5-
push:
6-
branches:
7-
- main
8-
workflow_dispatch:
4+
pull_request:
5+
push:
6+
branches:
7+
- main
8+
workflow_dispatch:
99

1010
jobs:
1111
test:
@@ -40,7 +40,9 @@ jobs:
4040
env:
4141
PTO_CI_MODE: 1
4242
run: |
43-
pytest -v --cov=pytissueoptics --cov-report=xml --cov-report=html
43+
pytest --cov --cov-branch --cov-report=term --cov-report=xml
4444
4545
- name: Upload coverage report
46-
uses: codecov/codecov-action@v4
46+
uses: codecov/codecov-action@v5
47+
with:
48+
token: ${{ secrets.CODECOV_TOKEN }}

.github/workflows/tests.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ on:
55
push:
66
branches:
77
- main
8+
schedule:
9+
- cron: "0 20 * * 4" # Every Thursday @ 20:00 UTC (15:00 EST)
810
workflow_dispatch:
911

1012
jobs:

README.md

Lines changed: 90 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,31 @@
1-
21
<h1 align="center"><b>PyTissueOptics</b></h1>
2+
<p align="center"><i>A hardware-accelerated Python module to simulate light transport in arbitrarily complex 3D media with ease.</i></p>
3+
<img src="https://raw.githubusercontent.com/DCC-Lab/PyTissueOptics/main/assets/banner.png" />
34

4-
<p align="center"><i>Monte Carlo simulations of light transport made easy.</i></p>
5-
<p align="center">
6-
<img src="https://raw.githubusercontent.com/DCC-Lab/PyTissueOptics/main/docs/README.assets/pytissue-demo-banenr.jpg" />
7-
</p>
5+
[![Tests](https://github.com/DCC-Lab/pytissueoptics/actions/workflows/tests.yaml/badge.svg)](https://github.com/DCC-Lab/pytissueoptics/actions/workflows/tests.yaml) [![codecov](https://codecov.io/gh/DCC-Lab/pytissueoptics/branch/main/graph/badge.svg)](https://codecov.io/gh/DCC-Lab/pytissueoptics) [![CodeFactor](https://www.codefactor.io/repository/github/DCC-Lab/pytissueoptics/badge)](https://www.codefactor.io/repository/github/DCC-Lab/pytissueoptics) [![License](https://img.shields.io/github/license/DCC-Lab/pytissueoptics.svg)](LICENSE)
86

9-
This python package is an object-oriented implementation of Monte Carlo modeling for light transport in diffuse media.
10-
The package is very **easy to set up and use**, and its mesh-based approach makes it a **polyvalent** tool to simulate light transport in arbitrarily complex scenes.
11-
The package offers both a native Python implementation and a hardware-accelerated version using OpenCL.
7+
This python package is a fast and flexible implementation of Monte Carlo modeling for light transport in diffuse media.
8+
The package is **easy to set up and use**, and its mesh-based approach makes it a polyvalent tool to simulate
9+
light transport in **arbitrarily complex scenes**. The package offers both a native Python implementation
10+
and a **hardware-accelerated** version using OpenCL which supports most GPUs and CPUs.
1211

13-
As discussed in the [why use this package](#why-use-this-package) section, computation time isn't the only variable at play. This code is **easy to understand**, **easily scalable** and **very simple to modify** for your need. It was designed with **research and education** in mind.
12+
Designed with **research and education** in mind, the code aims to be clear, modular, and easy to extend for a wide range of applications.
1413

1514
## Notable features
16-
- Arbitrarily complex 3D environments.
17-
- Import external 3D models (.OBJ).
18-
- Great data visualization with `Mayavi`.
19-
- Multi-layered tissues.
20-
- Hardware acceleration with `OpenCL`.
21-
- Accurate Fresnel reflection and refraction with surface smoothing.
22-
- Discard 3D data (auto-binning to 2D views).
23-
- Independent 3D graphics framework under `scene`.
24-
25-
## Table of Contents
26-
- [Installation](#installation)
27-
- [Getting Started](#getting-started)
28-
- [Hardware Acceleration](#hardware-acceleration)
29-
- [Why Use This Package](#why-use-this-package)
30-
- [Examples](#examples)
15+
- Supports arbitrarily complex **mesh-based** 3D environments.
16+
- **Normal smoothing** for accurate modeling of curved surfaces like lenses.
17+
- Per-photon data points of deposited energy, fluence rate and intersection events.
18+
- **Hardware accelerated** with `OpenCL` using [PyOpenCL](https://github.com/inducer/pyopencl).
19+
- Photon traces & detectors.
20+
- Import **external 3D models** (`.OBJ`).
21+
- Many 3D visualization options built with [Mayavi](https://github.com/enthought/mayavi).
22+
- Low memory mode with auto-binning to 2D views.
23+
- **Reusable graphics framework** to kickstart other raytracing projects like [SensorSim](https://github.com/JLBegin/SensorSim).
3124

3225
## Installation
33-
Requires Python >=3.9 installed on the device.
34-
35-
### Installing the latest release
36-
> Currently, this `pip` version is outdated. We recommend installing the development version.
37-
```shell
38-
python -m pip install --upgrade pip
39-
python -m pip install --upgrade pytissueoptics
40-
```
26+
Requires Python 3.9+ installed.
4127

42-
### Installing the development version
28+
> Currently, the `pip` version is outdated. We recommend installing the development version.
4329
1. Clone the repository.
4430
2. Create a virtual environment inside the repository with `python -m venv venv`.
4531
3. Activate the virtual environment.
@@ -49,80 +35,30 @@ python -m pip install --upgrade pytissueoptics
4935
5. Install the package requirements with `python -m pip install -e .[dev]`.
5036

5137
## Getting started
52-
A command-line interface is available to help you run examples and tests.
53-
```shell
54-
python -m pytissueoptics --help
55-
python -m pytissueoptics --list
56-
python -m pytissueoptics --examples 1,2,3
57-
python -m pytissueoptics --tests
58-
```
5938

60-
To launch a simple simulation on your own, follow these steps.
61-
1. Import the `pytissueoptics` module
62-
2. Define the following objects:
63-
- `scene`: a `ScatteringScene` object, which defines the scene and the optical properties of the media, or use a pre-defined scene from the `samples` module. The scene takes in a list of `Solid` as its argument. These `Solid` will have a `ScatteringMaterial` and a position. This is clear in the examples below.
64-
- `source`: a `Source` object, which defines the source of photons.
65-
- `logger`: an `EnergyLogger` object, which logs the simulation progress ('keep3D=False' can be set to auto-bin to 2D views).
66-
3. Propagate the photons in your `scene` with `source.propagate`.
67-
4. Define a `Viewer` object and display the results by calling the desired methods. It offers various visualizations of the experiment as well as a statistics report.
68-
69-
Here's what it might look like:
70-
```python
71-
from pytissueoptics import *
72-
73-
material = ScatteringMaterial(mu_s=3.0, mu_a=1.0, g=0.8, n=1.5)
74-
75-
tissue = Cuboid(a=1, b=3, c=1, position=Vector(2, 0, 0), material=material)
76-
scene = ScatteringScene([tissue])
77-
78-
logger = EnergyLogger(scene)
79-
source = PencilPointSource(position=Vector(-3, 0, 0), direction=Vector(1, 0, 0), N=1000)
80-
source.propagate(scene, logger)
39+
A **command-line interface** is available to quicky run a simulation from our pool of examples:
8140

82-
viewer = Viewer(scene, source, logger)
83-
viewer.reportStats()
84-
viewer.show3D()
8541
```
86-
Check out the `pytissueoptics/examples` folder for more examples on how to use the package.
87-
88-
## Hardware acceleration
89-
```python
90-
source = DivergentSource(useHardwareAcceleration=True, ...)
42+
python -m pytissueoptics --help
9143
```
92-
Hardware acceleration can offer a speed increase factor around 1000x depending on the scene.
93-
By default, the program will try to use hardware acceleration if possible, which will require OpenCL drivers for your hardware of choice.
94-
NVIDIA and AMD GPU drivers should contain their corresponding OpenCL driver by default.
95-
To force the use of the native Python implementation, set `useHardwareAcceleration=False` when creating a light `Source`.
96-
97-
Follow the instructions on screen to get setup properly for the first hardware accelerated execution which will offer
98-
to run a benchmark test to determine the ideal number of work units for your hardware.
99-
100-
## Why use this package
101-
It is known, as April 2022, Python is **the most used** language ([Tiobe index](https://www.tiobe.com/tiobe-index/)).
102-
This is due to the ease of use, the gentle learning curve, and growing community and tools. There was a need for
103-
such a package in Python, so that not only long hardened C/C++ programmers could use the power of Monte Carlo simulations.
104-
It is fairly reasonable to imagine you could start a calculation in Python in a few minutes, run it overnight and get
105-
an answer the next day after a few hours of calculations. It is also reasonable to think you could **modify** the code
106-
yourself to suit your exact needs! (Do not attempt this in C). This is the solution that the CPU-based portion of this package
107-
offers you. With the new OpenCL implementation, speed is not an issue anymore, so using `pytissueoptics` should not even be a question.
108-
109-
### Known limitations
110-
1. It uses Henyey-Greenstein approximation for scattering direction because it is sufficient most of the time.
111-
2. Reflections are specular, which does not accounts for the roughness of materials. It is planned to implement Bling-Phong reflection model in a future release.
112-
113-
## Examples
11444

115-
### Multi-layered phantom tissue
116-
Located at `pytissueoptics/examples/rayscattering/ex01.py`.
117-
Using a pre-defined tissue from the `samples` module.
45+
You can kick start your first simulation using one of our **pre-defined scene** under the `samples` module.
11846

11947
```python
120-
N = 500000
48+
from pytissueoptics import *
49+
50+
# Define (scene, source, logger)
51+
N = 500_000
12152
scene = samples.PhantomTissue()
122-
source = DivergentSource(position=Vector(0, 0, -0.1), direction=Vector(0, 0, 1), N=N, diameter=0.2, divergence=np.pi / 4)
53+
source = DivergentSource(
54+
position=Vector(0, 0, -0.1), direction=Vector(0, 0, 1), N=N, diameter=0.2, divergence=0.78
55+
)
12356
logger = EnergyLogger(scene)
57+
58+
# Run
12459
source.propagate(scene, logger=logger)
12560

61+
# Stats & Visualizations
12662
viewer = Viewer(scene, source, logger)
12763
viewer.reportStats()
12864

@@ -132,56 +68,73 @@ viewer.show2D(View2DSurfaceZ(solidLabel="middleLayer", surfaceLabel="interface0"
13268
viewer.show1D(Direction.Z_POS)
13369
viewer.show3D()
13470
```
71+
#### Expected output
72+
```
73+
Report of solid 'backLayer'
74+
Absorbance: 67.78% (10.53% of total power)
75+
Transmittance at 'backLayer_back': 22.4%
76+
Transmittance at 'interface0': 4.9%
77+
...
78+
```
79+
80+
13581

136-
#### Default figures generated
13782
![stack_visuals](https://user-images.githubusercontent.com/29587649/219904076-f52c850f-7e86-45a3-8e32-ac3e1fbed051.png)
13883

139-
#### Discarding the 3D data
140-
When the raw simulation data gets too large, the 3D data can be automatically binned to pre-defined 2D views.
84+
#### Scene definition
85+
Here is the explicit definition of the above scene sample. We recommend you look at other examples to get familiar with the API.
14186
```python
142-
logger = EnergyLogger(scene, keep3D=False)
143-
```
144-
All 2D views are unchanged, because they are included in the default 2D views tracked by the EnergyLogger.
145-
The 1D profile and stats report are also properly computed from the stored 2D data.
146-
The 3D display will auto-switch to Visibility.DEFAULT_2D which includes Visibility.VIEWS with ViewGroup.SCENE (XYZ projections of the whole scene) visible by default.
147-
![image](https://user-images.githubusercontent.com/29587649/212522583-be81fd59-3479-4350-9bd6-2dce2ed43330.png)
148-
149-
#### Display some 2D views with the 3D point cloud
150-
The argument `viewsVisibility` can accept a `ViewGroup` tag like SCENE, SURFACES, etc., but also a list of indices for fine control. You can list all stored views with `logger.listViews()` or `viewer.listViews()`.
151-
Here we toggle the visibility of 2D views along the default 3D visibility (which includes the point cloud).
152-
```python
153-
logger = EnergyLogger(scene)
154-
[...]
155-
viewer.show3D(visibility=Visibility.DEFAULT_3D | Visibility.VIEWS, viewsVisibility=[0, 1])
87+
materials = [
88+
ScatteringMaterial(mu_s=2, mu_a=1, g=0.8, n=1.4),
89+
ScatteringMaterial(mu_s=3, mu_a=1, g=0.8, n=1.7),
90+
ScatteringMaterial(mu_s=2, mu_a=1, g=0.8, n=1.4),
91+
]
92+
w = 3
93+
frontLayer = Cuboid(a=w, b=w, c=0.75, material=materials[0], label="frontLayer")
94+
middleLayer = Cuboid(a=w, b=w, c=0.5, material=materials[1], label="middleLayer")
95+
backLayer = Cuboid(a=w, b=w, c=0.75, material=materials[2], label="backLayer")
96+
layerStack = backLayer.stack(middleLayer, "front").stack(frontLayer, "front")
97+
scene = ScatteringScene([layerStack])
15698
```
157-
![image](https://user-images.githubusercontent.com/29587649/212522847-ffcf6905-7d79-4ce8-abc2-a474facc4745.png)
15899

159-
#### Display custom 2D views
160-
If `keep3D=False`, the custom views (like slices, which are not included in the default views) have to be added to the logger before propagation like so:
161-
```python
162-
logger = EnergyLogger(scene, keep3D=False)
163-
logger.addView(View2DSliceZ(position=0.5, thickness=0.1, limits=((-1, 1), (-1, 1))))
164-
logger.addView(View2DSliceZ(position=1, thickness=0.1, limits=((-1, 1), (-1, 1))))
165-
logger.addView(View2DSliceZ(position=1.5, thickness=0.1, limits=((-1, 1), (-1, 1))))
166-
```
167-
If the logger keeps track of 3D data, then it's not a problem and the views can be added later with `logger.addView(customView)` or implicitly when asking for a 2D display from `viewer.show2D(customView)`.
168-
![image](https://user-images.githubusercontent.com/29587649/212523201-2be697cc-76ea-4059-bdc4-63f5d3e24ed7.png)
100+
#### Hardware acceleration
169101

170-
#### Display interactive 3D volume slicer
171-
Requires 3D data.
172-
```python
173-
viewer.show3DVolumeSlicer()
174-
```
175-
![image](https://user-images.githubusercontent.com/29587649/212523428-75ec7bf9-b9c7-463f-874e-01e1973d7d2c.png)
102+
Depending on your platform and GPU, you might already have OpenCL drivers installed, which should work out of the box.
103+
Run a PyTissueOptics simulation first to see your current status.
104+
105+
> Follow the instructions on screen to get setup properly. It will offer to run a benchmark test to determine the ideal number of work units for your hardware.
106+
For more help getting OpenCL to work, refer to [PyOpenCL's documentation](https://documen.tician.de/pyopencl/misc.html#enabling-access-to-cpus-and-gpus-via-py-opencl) on the matter. Note that you can disable hardware acceleration at any time with `disableOpenCL()` or by setting the environment variable `PTO_DISABLE_OPENCL=1`.
107+
108+
## Examples
109+
110+
All examples can be run using the CLI tool:
176111

177-
#### Save and append simulation results
178-
The `EnergyLogger` data can be saved to file. This can also be used along with `keep3D=False` to only save 2D data. Every time the code is run, the previous data is loaded and extended. This is particularly useful to propagate a very large amount of photons (possibly infinite) in smaller batches so the hardware doesn't run out of memory.
179-
```python
180-
[...]
181-
logger = EnergyLogger(scene, "myExperiment.log", keep3D=False)
182-
source.propagate(scene, logger)
183-
logger.save()
184112
```
113+
python -m pytissueoptics --list
114+
python -m pytissueoptics --examples 1,2,3
115+
```
116+
117+
1. [Scene sample](/pytissueoptics/examples/rayscattering/ex01.py)
118+
2. [Infinite medium](/pytissueoptics/examples/rayscattering/ex02.py)
119+
3. [Optical lens & saving progress](/pytissueoptics/examples/rayscattering/ex03.py)
120+
4. [Custom layer stack](/pytissueoptics/examples/rayscattering/ex04.py)
121+
5. [Sphere in cube](/pytissueoptics/examples/rayscattering/ex05.py)
122+
6. [Sampling volume simulation](/pytissueoptics/examples/rayscattering/ex06.py)
123+
124+
Other scene and benchmark examples are available under [/examples](/pytissueoptics/examples), including:
125+
- [External 3D model](/pytissueoptics/examples/scene/example3.py)
126+
- [Solid transforms](/pytissueoptics/examples/scene/example1.py)
127+
- [Lenses](/pytissueoptics/examples/scene/example4.py)
128+
- [Skin vessel benchmark](/pytissueoptics/examples/benchmarks/skinvessel.py)
129+
- [Spherical shells benchmark](/pytissueoptics/examples/benchmarks/sphshells.py)
130+
131+
---
132+
133+
### Known limitations
134+
135+
1. It uses Henyey-Greenstein approximation for scattering direction because it is sufficient most of the time.
136+
2. Reflections are specular, which does not account for the roughness of materials. A Bling-Phong reflection model could be added in a future release.
185137

186138
## Acknowledgment
139+
187140
This package was first inspired by the standard, tested, and loved [MCML from Wang, Jacques and Zheng](https://omlc.org/software/mc/mcpubs/1995LWCMPBMcml.pdf) , itself based on [Prahl](https://omlc.org/~prahl/pubs/abs/prahl89.html) and completely documented, explained, dissected by [Jacques](https://omlc.org/software/mc/) and [Prahl](https://omlc.org/~prahl/pubs/abs/prahl89.html). The original idea of using Monte Carlo for tissue optics calculations was [first proposed by Wilson and Adam in 1983](https://doi.org/10.1118/1.595361). This would not be possible without the work of these pioneers.
-213 KB
Binary file not shown.

0 commit comments

Comments
 (0)