Skip to content

Reflections in small scale problematic? -> 1mm scale #1

Description

@mahnen

Dear Sebastian,

great work, installed out of the box no issues. I wrote the following scenery quickly, to test it on a 10mmx10mmx10mm block of supposed LYSO:

{
    "functions": [
        {
            "name": "unity",
            "values": [
                [
                    2e-7,
                    1
                ],
                [
                    0.0000012,
                    1
                ]
            ]
        },
        {
            "name": "refraction_lyso",
            "values": [
                [
                    2e-7,
                    1.81
                ],
                [
                    0.0000012,
                    1.81
                ]
            ]
        },
        {
            "name": "refraction_light_guide",
            "values": [
                [
                    2e-7,
                    1.49
                ],
                [
                    0.0000012,
                    1.49
                ]
            ]
        },
        {
            "name": "+infinity",
            "values": [
                [
                    2e-7,
                    9000
                ],
                [
                    0.0000012,
                    9000
                ]
            ]
        },
        {
            "name": "zero",
            "values": [
                [
                    2e-7,
                    0
                ],
                [
                    0.0000012,
                    0
                ]
            ]
        }
    ],
    "colors": [
        {
            "rgb": [
                22,
                9,
                255
            ],
            "name": "blue"
        },
        {
            "rgb": [
                255,
                255,
                0
            ],
            "name": "yellow"
        },
        {
            "rgb": [
                255,
                91,
                49
            ],
            "name": "red"
        },
        {
            "rgb": [
                16,
                255,
                0
            ],
            "name": "green"
        },
        {
            "rgb": [
                23,
                23,
                23
            ],
            "name": "grey"
        }
    ],
    "media": [
        {
            "name": "lyso",
            "refraction": "refraction_lyso",
            "absorbtion": "+infinity"
        },
        {
            "name": "light_guide",
            "refraction": "refraction_light_guide",
            "absorbtion": "+infinity"
        }
    ],
    "default_medium": "lyso",
    "surfaces": [
        {
            "name": "lyso_face_inside",
            "material": "Transparent",
            "specular_reflection": "unity",
            "diffuse_reflection": "unity",
            "color": "yellow"
        },
        {
            "name": "lyso_face_outside",
            "material": "Transparent",
            "specular_reflection": "unity",
            "diffuse_reflection": "unity",
            "color": "blue"
        },
        {
            "name": "esr_inside",
            "material": "Phong",
            "specular_reflection": "unity",
            "diffuse_reflection": "zero",
            "color": "red"
        },
        {
            "name": "esr_outside",
            "material": "Phong",
            "specular_reflection": "unity",
            "diffuse_reflection": "zero",
            "color": "green"
        },
        {
            "name": "perfect_absorber",
            "material": "Phong",
            "specular_reflection": "zero",
            "diffuse_reflection": "zero",
            "color": "grey"
        }
    ],
    "children": [
        {
            "type": "Mesh",
            "id": 1,
            "pos": [0, 0, 0],
            "rot": {"repr": "tait_bryan", "xyz": [0, 0, 0]},
            "surface": {
              "inner": {"medium": "lyso", "surface": "esr_inside"},
              "outer": {"medium": "light_guide", "surface": "esr_outside"}
            },
            "vertices": [
                [0, 0, 0],
                [0.01, 0, 0],
                [0, 0.01, 0],
                [0.01, 0.01, 0],
                [0, 0, 0.01],
                [0.01, 0, 0.01],
                [0, 0.01, 0.01],                
                [0.01, 0.01, 0.01]
            ],
            "faces": [
              [0,5,4],
              [0,1,5],
              [1,7,5],
              [1,3,7],
              [3,6,7],
              [3,2,6],
              [2,4,6],
              [2,0,4],
              [4,7,6],
              [4,5,7]
            ]
        },
        {
            "type": "Mesh",
            "id": 2,
            "pos": [0, 0, 0],
            "rot": {"repr": "tait_bryan", "xyz": [0, 0, 0]},
            "surface": {
              "inner": {"medium": "lyso", "surface": "lyso_face_inside"},
              "outer": {"medium": "light_guide", "surface": "lyso_face_outside"}
            },
            "vertices": [
                [0, 0, 0],
                [0.01, 0, 0],
                [0, 0.01, 0],
                [0.01, 0.01, 0]
            ],
            "faces": [
              [1,0,2],
              [1,2,3]
            ]
        },
        {
            "type": "Disc",
            "id": 3,
            "pos": [0.005, 0.005, -0.003],
            "rot": {"repr": "tait_bryan", "xyz": [0, 0, 0]},
            "radius": 0.05,
            "surface": {
                "inner": {"medium": "light_guide", "surface": "perfect_absorber"},
                "outer": {"medium": "light_guide", "surface": "perfect_absorber"}
            }
        }
    ]
}

If I render this, it seems to work (at least the scaled up version to 1m is fine:

2020-05-26_18-12-03_000000

-> The disk is supposed to absorb and measure the position of the photons exiting the mesh indicated in green (this is "esr_outside)".

However, when scanning the data and looking at it, it seems that there is no actual reflections going on on the sides. I attach an illustration, where the black disk is at z=0, i.e. directly at the LYSO touching it, but still there is photons interacting with the disk outside of the red indicated crystal.

00

I attach the script that produced the above plot.

import json
import numpy as np
import tempfile
import os
import merlict_c89_wrapper
import photon_source
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib as mpl

with open("20200526_001_single_lyso.json", "r") as my_file:
    SINGLE_LYSO_SCENERY = json.load(my_file)

RANDOM_SEED = 1
MAX_INTERACTIONS = 100

# photon src at center of lyso cube
N_PHOTONS = 17000
CENTER_POINT_SRC = photon_source.isotrop_point_source(
    emission_position=[0.005, 0.005, 0.005],
    num_photons=N_PHOTONS  # close to saint gobain data sheet for 511keV LYSO
)

def run(
    scenery=SINGLE_LYSO_SCENERY,
    object_idx=3,  # the disk beneath
    photons=CENTER_POINT_SRC,
    random_seed=RANDOM_SEED,
    max_interactions=MAX_INTERACTIONS,
):
    with tempfile.TemporaryDirectory(prefix="pet_tutorial_") as tmp_dir:

        with open(os.path.join(tmp_dir, "scenery.json"), "wt") as f:
            f.write(json.dumps(scenery, indent=4))

        merlict_c89_wrapper.wrapper.json_scenery_to_merlict_scenery(
            json_in_path=os.path.join(tmp_dir, "scenery.json"),
            merlict_out_path=os.path.join(tmp_dir, "scenery.mli"),
            octree_out_path=os.path.join(tmp_dir, "scenery.octree.mli")
        )

        intersection_table = merlict_c89_wrapper.wrapper.propagate(
            scenery_path=os.path.join(tmp_dir, "scenery.mli"),
            octree_path=os.path.join(tmp_dir, "scenery.octree.mli"),
            object_idx=object_idx,
            photons=photons,
            random_seed=random_seed,
            max_interactions=max_interactions
        )

        return intersection_table

steps = 21
z_start = -1e-9
z_stop = 0.01
count = 0

n_bins = 200
x_start = -0.05
x_stop = np.fabs(x_start)
binsx=np.linspace(x_start,x_stop,n_bins+1)
binsy=binsx

x_crystal_max = 0.01
y_crystal_max = 0.01
z_crystal_max = 0.01

N_GAMMA_RAYS = 3
plot_z_max = 8000/10*N_GAMMA_RAYS

# loop over multiple z position
for z_position in np.linspace(z_start,z_stop,steps):
    np.random.seed(RANDOM_SEED)
    data = []
    
    for gamma_ray_number in range(N_GAMMA_RAYS):
        SINGLE_LYSO_SCENERY["children"][2]["pos"][2] = z_position
        x_emit = x_crystal_max/2
        y_emit = y_crystal_max/2
        z_emit = z_crystal_max/2
        #x_emit = np.random.rand()*x_crystal_max
        #y_emit = np.random.rand()*y_crystal_max
        #z_emit = np.random.rand()*z_crystal_max
        CENTER_POINT_SRC = photon_source.isotrop_point_source(emission_position=[x_emit,y_emit,z_emit],num_photons=N_PHOTONS)

        data.append(run(
            scenery=SINGLE_LYSO_SCENERY,
            object_idx=3,
            photons=CENTER_POINT_SRC,
            random_seed=RANDOM_SEED,
            max_interactions=MAX_INTERACTIONS))

    data = np.vstack(data)

    # plot some
    plt.clf()
    plt.hist2d(data[:,0],data[:,1],bins=[binsx,binsy],norm=mpl.colors.LogNorm(1,plot_z_max))
    #plt.hist2d(data[:,0],data[:,1],bins=[binsx,binsy])
    ax = plt.gca()
    ax.set(aspect='equal')
    ax.add_patch(
        patches.Rectangle(
            xy=(-x_crystal_max/2, -y_crystal_max/2),  # point of origin.
            width=x_crystal_max,
            height=y_crystal_max,
            linewidth=1,
            color='red',
            fill=False
        )
    )
    plt.title("crystal:10x10x10mm^3, guide_z:%02.01f mm"%(z_position*1000))
    plt.colorbar()
    plt.tight_layout()
    plt.savefig("%02d.png"%count)
    count+=1

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions