diff --git a/.github/workflows/jupyterbook.yml b/.github/workflows/jupyterbook.yml index 3e5d51b..890d4f8 100644 --- a/.github/workflows/jupyterbook.yml +++ b/.github/workflows/jupyterbook.yml @@ -48,4 +48,4 @@ jobs: uses: rossjrw/pr-preview-action@v1 with: source-dir: ./tutorial/docs/_build/html - if: github.event_name == 'pull_request' + # if: github.event_name == 'pull_request' diff --git a/Project.toml b/Project.toml index 8fafff0..c7a5db3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,3 +1,8 @@ [deps] +CairoMakie = "13f3f980-e62b-5c42-98c6-ff1f3baf88f0" Geant4 = "559df036-b7a0-42fd-85df-7d5dd9d70f44" +GeometryBasics = "5c1252a2-5f33-56bf-86c9-59e7332b4326" +IGLWrap_jll = "283677c1-8365-580c-84e5-ef4b5d190868" IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" +Parameters = "d96e819e-fc66-5662-9728-84c9c7592b0a" +Rotations = "6038ab10-8711-5258-84ad-4b1120ba62dc" diff --git a/tutorial/docs/_toc.yml b/tutorial/docs/_toc.yml index 3f7dbcc..47e6488 100644 --- a/tutorial/docs/_toc.yml +++ b/tutorial/docs/_toc.yml @@ -7,6 +7,7 @@ parts: - caption: Introduction to Geant4.jl chapters: - file: geant4-jl-intro + - file: geant4-jl-geometry - caption: Building simulation applications chapters: - file: geant4-jl-applications diff --git a/tutorial/docs/geabt4-jl-geometry.ipynb b/tutorial/docs/geabt4-jl-geometry.ipynb new file mode 100644 index 0000000..dc19210 --- /dev/null +++ b/tutorial/docs/geabt4-jl-geometry.ipynb @@ -0,0 +1,510 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "vscode": { + "languageId": "julia" + } + }, + "source": [ + "# Defining Geant4.jl Geometries\n", + "Currently we can define G4 geometries by constructing them using the API of the C++ classes or by reading a GDML file. This notebook will guide you on this task.\n", + "\n", + "It is very convenient to be able to visualize the geometry on the way. For this purpose we need to load the G4Vis extension. This is done this way:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "using Geant4\n", + "using Geant4.SystemOfUnits # defines the usints used by Geant4 \n", + "using CairoMakie, Rotations, IGLWrap_jll # to force loading G4Vis extension" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Defining Solids\n", + "The first step is to define the solids. The following shapes are defined: `G4Box`, `G4Cons`, `G4Tubs`, `G4Orb`, `G4Sphere`, `G4Trd`, `G4CutTubs`, `G4Para`, `G4Trap`, `G4Torus`, `G4Polycone`, `G4Polyhedra`, `G4EllipticalTube`, `G4Ellipsoid`, `G4EllipticalCone`, `G4Paraboloid`, `G4Hype`, `G4Tet`, `G4ExtrudedSolid`, `G4TwistedBox`, `G4TwistedTrap`, `G4TwistedTrd`, `G4GenericTrap`, `G4TwistedTubs`. In addition there are the boolean shapes: `G4UnionSolid`, `G4SubtractionSolid`, `G4IntersectionSolid`.\n", + "The definition of the constructor parameters can be found [documentation](https://geant4-userdoc.web.cern.ch/UsersGuides/ForApplicationDeveloper/html/Detector/Geometry/geomSolids.html#constructed-solid-geometry-csg-solids)\n", + "\n", + "Lets define a tube section like the following" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "rmin = 10cm\n", + "rmax = 20cm\n", + "halfz = 10cm\n", + "ϕ₀ = 0\n", + "Δϕ = 60deg\n", + "tube = G4Tubs(\"tube\", rmin, rmax, halfz, ϕ₀, Δϕ ) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can easily draw the just constructed solid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "img = draw(tube, wireframe=true)\n", + "display(\"image/png\", img) # This is needed specially for notebooks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "para = G4Para(\"parallelepiped\", 30,40,60,0, π/4, π/6)\n", + "img = draw(para)\n", + "display(\"image/png\", img)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Building Boolean solids\n", + "We can build more complex geometries by combining with boolean operations simple shapes. For example building a 3D cross. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "box = G4Box(\"box\", 1, 1, 4)\n", + "t = G4Transform3D(G4RotationMatrix(0,π/2,0), G4ThreeVector())\n", + "cross = G4UnionSolid(\"cross\", CxxPtr(box), CxxPtr(box), t)\n", + "img = draw(cross)\n", + "isnothing(img) || display(\"image/png\", img)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Lets use some geometry functionality to experiment with the created solid" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "using StaticArrays\n", + "const Vector3 = SVector{3}\n", + "N = 100000\n", + "lo = G4ThreeVector()\n", + "hi = G4ThreeVector()\n", + "BoundingLimits(cross, lo, hi) # get the bounding limits\n", + "dim = hi - lo \n", + "points = (lo + dim * rp for rp in rand(Vector3{Float64}, N)) # random points within the limits \n", + "result = [Vector3{Float64}(x(p), y(p), z(p)) for p in points if Geant4.Inside(cross, p) == kInside]\n", + "img = scatter(result, color=:black, markersize=1)\n", + "display(\"image/png\", img)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Defining Materials\n", + "In nature, materials (chemical compounds, mixtures) are made of elements, and elements are made of isotopes. Geant4 offers the 3 classes `G4Isotope`, `G4Element` and `G4Material`to define from first principles any material. However is often that pre-defined materials are available in Geant4 from the [NIST database](https://www.nist.gov/pml/atomic-weights-and-isotopic-compositions-relative-atomic-masses) of elements and isotope compositions.\n", + "\n", + "This is the easiest way to get a material." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nist = G4NistManager!Instance()\n", + "m_air = FindOrBuildMaterial(nist, \"G4_AIR\")\n", + "@show GetDensity(m_air)/(g/cm3)\n", + "\n", + "m_water = FindOrBuildMaterial(nist, \"G4_WATER\")\n", + "@show GetDensity(m_water)/(g/cm3)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or alternatively we can construct it from isotopes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "U5 = G4Isotope(\"U235\", z=92, n=235, a=235.01*g/mole)\n", + "U8 = G4Isotope(\"U238\", z=92, n=238, a=238.03*g/mole)\n", + "\n", + "U = G4Element(\"Enriched Uranium\", \"U\", 2)\n", + "AddIsotope(U, move!(U8), 0.90) # Please notice the use of move!() to transfer ownership \n", + "AddIsotope(U, move!(U5), 0.10) # Please notice the use of move!() to transfer ownership \n", + "\n", + "m_eU = G4Material(\"enriched U\", density= 19.1*g/cm3, ncomponents=1)\n", + "AddElement(m_eU, move!(U), natoms=1) # Please notice the use of move!() to transfer ownership \n", + "\n", + "@show GetDensity(m_eU)/(g/cm3)\n", + "@show GetA(m_eU)/(g/mole)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "or build a molecule" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "O = FindOrBuildElement(nist, \"O\")\n", + "Si = FindOrBuildElement(nist, \"Si\")\n", + "Lu = FindOrBuildElement(nist, \"Lu\")\n", + "Lu₂SiO₅ = G4Material(\"Lu2SiO5\", density=7.4*g/cm3, ncomponents=3)\n", + "AddElement(Lu₂SiO₅, Lu, natoms=2) # no need to transfer ownership, we just got a pointer not constructed\n", + "AddElement(Lu₂SiO₅, Si, natoms=1) \n", + "AddElement(Lu₂SiO₅, O, natoms=5)\n", + "@show GetRadlen(Lu₂SiO₅)/cm" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Defining Logical Volumes\n", + "The Logical Volume manages the information associated with detector elements represented by a given Solid and Material, independently from its physical position in the detector.\n", + "\n", + "To create a G4LogicalVolume just provide a solid and a material" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "cryst_dX = 6cm\n", + "cryst_dY = 6cm\n", + "cryst_dZ = 3cm\n", + "gap = 0.5mm \n", + "\n", + "dX = cryst_dX - gap\n", + "dY = cryst_dY - gap\n", + "solidCryst = G4Box(\"crystal\", dX/2, dY/2, cryst_dZ/2)\n", + "logicCryst = G4LogicalVolume(solidCryst, CxxPtr(Lu₂SiO₅), \"CrystalLV\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can also draw a logical volume" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "img = draw(logicCryst)\n", + "display(\"image/png\", img)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Placing Logical Volumes\n", + "Placing a logical volume (solid+material) inside a mother volume is done by creating a `G4PhysicalVolume`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "nb_cryst = 32\n", + "Δϕ = 2π/nb_cryst \n", + "ring_R1 = 0.5 * cryst_dY/tan(Δϕ/2)\n", + "ring_R2 = (ring_R1+cryst_dZ)/cos(Δϕ/2)\n", + "\n", + "# mother volume\n", + "solidRing = G4Tubs(\"Ring\", ring_R1, ring_R2, cryst_dX/2, 0., 2π)\n", + "logicRing = G4LogicalVolume(solidRing, m_air, \"Ring\")\n", + "\n", + "# placing the crystals\n", + "for icrys in 0:nb_cryst-1\n", + " ϕ = icrys*Δϕ\n", + " rotm = G4RotationMatrix()\n", + " rotateY(rotm, π/2)\n", + " rotateZ(rotm, ϕ)\n", + " position = (ring_R1 + cryst_dZ/2) * G4ThreeVector(cos(ϕ), sin(ϕ), 0)\n", + " transform = G4Transform3D(rotm, position)\n", + "\n", + " G4PVPlacement(transform, # rotation,position\n", + " logicCryst, # its logical volume\n", + " \"crystal\", # its name\n", + " logicRing, # its mother volume\n", + " false, # no boolean operation\n", + " icrys, # copy number\n", + " false) # checking overlaps\n", + " end" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "A draw it" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "img = draw(logicRing)\n", + "display(\"image/png\", img)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Building the full detector" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The detector construction is triggered by the `G4RunManager` at the right moment during the initialization steps. For this the user needs to provide a *detector constructor* function that will be called by the toolkit. The signature of the function is \n", + "```\n", + "function construct(det::)::CxxPtr{G4VPhysicalVolume}\n", + " ...\n", + " return world\n", + "end\n", + "```\n", + "It receives an instance of a user defined structure with all the parameters of the detector and returns a 'pointer' to the 'world' physical volume. The user needs to declare the constructor function by defining a function specific to the Parameters structure like this: \n", + "```\n", + "Geant4.getConstructor(::)::Function = construct\n", + "```\n", + "Here is a an example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "using Parameters # we use the Parameters package to be able to define structure with keyword arguments with defaults\n", + "\n", + "@with_kw mutable struct DetectorB3 <: G4JLDetector\n", + " cryst_dX::Float64 = 6cm\n", + " cryst_dY::Float64 = 6cm\n", + " cryst_dZ::Float64 = 3cm\n", + " nb_cryst::Int32 = 32\n", + " nb_rings::Int32 = 9\n", + " patient_radius::Float64 = 8cm\n", + " patient_dZ::Float64 = 10cm\n", + " checkOverlaps::Bool = false\n", + "end\n", + "\n", + "detector = DetectorB3(nb_cryst = 64)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "then we define the detector constructor function which includes the material definitions, and eventually the visualization attributes" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "function construct(det::DetectorB3)::G4VPhysicalVolume\n", + " (; cryst_dX, cryst_dY, cryst_dZ, nb_cryst, nb_rings, patient_radius, checkOverlaps, patient_dZ) = det\n", + "\n", + " #---Derived parameters-------------------------------------------------------------------------\n", + " dPhi = 2π/nb_cryst \n", + " half_dPhi = 0.5*dPhi\n", + " cosdPhi = cos(half_dPhi)\n", + " tandPhi = tan(half_dPhi)\n", + " ring_R1 = 0.5*cryst_dY/tandPhi\n", + " ring_R2 = (ring_R1+cryst_dZ)/cosdPhi\n", + " detector_dZ = nb_rings*cryst_dX\n", + " world_sizeXY = 2.4*ring_R2\n", + " world_sizeZ = 1.2*detector_dZ\n", + " \n", + " #---Materials----------------------------------------------------------------------------------\n", + " nist = G4NistManager!Instance()\n", + " default_mat = FindOrBuildMaterial(nist, \"G4_AIR\")\n", + " cryst_mat = FindOrBuildMaterial(nist, \"Lu2SiO5\")\n", + " \n", + " #---Volumes------------------------------------------------------------------------------------\n", + " solidWorldS = G4Box(\"world\", world_sizeXY/2, world_sizeXY/2, world_sizeZ/2)\n", + " logicWorld = G4LogicalVolume(solidWorldS, default_mat, \"World\")\n", + " physWorld = G4PVPlacement(nothing, \n", + " G4ThreeVector(), # at (0,0,0)\n", + " logicWorld, # its logical volume\n", + " \"World\", # its name\n", + " nothing, # its mother volume\n", + " false, # no boolean operations\n", + " 0, # copy number\n", + " checkOverlaps) # checking overlaps\n", + "\n", + " solidRing = G4Tubs(\"Ring\", ring_R1, ring_R2, cryst_dX/2, 0., 2π)\n", + " logicRing = G4LogicalVolume(solidRing, default_mat, \"Ring\")\n", + "\n", + " gap = 0.5mm \n", + " dX = cryst_dX - gap\n", + " dY = cryst_dY - gap\n", + " solidCryst = G4Box(\"crystal\", dX/2, dY/2, cryst_dZ/2)\n", + " logicCryst = G4LogicalVolume(solidCryst, cryst_mat, \"CrystalLV\")\n", + "\n", + " # place crystals within a ring\n", + " for icrys in 0:nb_cryst-1\n", + " ϕ = icrys*dPhi\n", + " rotm = G4RotationMatrix()\n", + " rotateY(rotm, π/2)\n", + " rotateZ(rotm, ϕ)\n", + " position = (ring_R1 + cryst_dZ/2) * G4ThreeVector(cos(ϕ), sin(ϕ), 0)\n", + " transform = G4Transform3D(rotm, position)\n", + " \n", + " G4PVPlacement(transform, # rotation,position\n", + " logicCryst, # its logical volume\n", + " \"crystal\", # its name\n", + " logicRing, # its mother volume\n", + " false, # no boolean operation\n", + " icrys, # copy number\n", + " checkOverlaps) # checking overlaps\n", + " end\n", + " \n", + " # full detector\n", + " solidDetector = G4Tubs(\"Detector\", ring_R1, ring_R2, detector_dZ/2, 0., 2π)\n", + " logicDetector = G4LogicalVolume(solidDetector, default_mat, \"Detector\")\n", + "\n", + " # place rings within detector\n", + " OG = -0.5*(detector_dZ + cryst_dX)\n", + " for iring in 0:nb_rings-1\n", + " OG += cryst_dX\n", + " G4PVPlacement(nothing, # no rotation\n", + " G4ThreeVector(0, 0, OG), # position\n", + " logicRing, # its logical volume\n", + " \"ring\", # its name\n", + " logicDetector, # its mother volume\n", + " false, # no boolean operation\n", + " iring, # copy number\n", + " checkOverlaps) # checking overlaps\n", + " end\n", + " \n", + " # place detector in world\n", + " G4PVPlacement(nothing, # no rotation\n", + " G4ThreeVector(), # at (0,0,0)\n", + " logicDetector, # its logical volume\n", + " \"Detector\", # its name\n", + " logicWorld, # its mother volume\n", + " false, # no boolean operation\n", + " 0, # copy number\n", + " checkOverlaps) # checking overlaps\n", + "\n", + " # patient\n", + " patient_mat = FindOrBuildMaterial(nist, \"G4_BRAIN_ICRP\")\n", + " solidPatient = G4Tubs(\"Patient\", 0., patient_radius, patient_dZ/2, 0., 2π)\n", + " logicPatient = G4LogicalVolume(solidPatient, patient_mat,\"PatientLV\")\n", + " G4PVPlacement(nothing , # no rotation\n", + " G4ThreeVector(), # at (0,0,0)\n", + " logicPatient, # its logical volume\n", + " \"Patient\", # its name\n", + " logicWorld, # its mother volume\n", + " false, # no boolean operation\n", + " 0, # copy number\n", + " checkOverlaps) # checking overlaps\n", + " \n", + "\n", + " #---Visualization attributes-------------------------------------------------------------------\n", + " SetVisAttributes(logicWorld, G4VisAttributes!GetInvisible())\n", + " SetVisAttributes(logicRing, G4VisAttributes!GetInvisible())\n", + " SetVisAttributes(logicDetector, G4VisAttributes!GetInvisible())\n", + "\n", + " #---Always return the physical world-----------------------------------------------------------\n", + " return physWorld\n", + "end" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "world = construct(detector)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "img = draw(world)\n", + "display(\"image/png\", img)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Julia 1.10.0", + "language": "julia", + "name": "julia-1.10" + }, + "language_info": { + "file_extension": ".jl", + "mimetype": "application/julia", + "name": "julia", + "version": "1.10.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/tutorial/docs/geant4-jl-intro.ipynb b/tutorial/docs/geant4-jl-intro.ipynb index 83c45b5..c6ce160 100644 --- a/tutorial/docs/geant4-jl-intro.ipynb +++ b/tutorial/docs/geant4-jl-intro.ipynb @@ -13,7 +13,7 @@ "\n", "Geant4.jl provides the Julia bindings for the [Geant4](https://geant4.web.cern.ch) particle transportation toolkit. It is using [CxxWrap.jl](https://github.com/JuliaInterop/CxxWrap.jl) package to wrap C++ types and functions to Julia. Since the Geant4 toolkit is rather large and complex, writing the wrapper code by hand is not really an option. For this we use the package [WrapIt](https://github.com/grasph/wrapit) that automates the generation of the wrapper code making use of the clang library.\n", "\n", - "Documentation of the concepts and how to write applications with the Geant4 toolkit can be found with the [Application Developer Guide](https://geant4-userdoc.web.cern.ch/UsersGuides/ForApplicationDeveloper/html/index.html) or the [Classes and Members reference guide](https://geant4.kek.jp/Reference/11.2.0/index.html) for a detailed description of each C++ class. In this tutorial we will only highlight the differences between the Julia and the C++ API. We will document the additional types that have been added on top of the C++ classes to make the user interface more Julia friendly. To distinguish these new types from the types coming directly from C++ via the CxxWrap wrappers, these types are prefixed with `G4JL`.\n", + "Documentation of the concepts and how to write applications with the Geant4 toolkit can be found with the [Application Developer Guide](https://geant4-userdoc.web.cern.ch/UsersGuides/ForApplicationDeveloper/html/index.html) or the [Classes and Members reference guide](https://geant4.kek.jp/Reference/11.2.0/index.html) for a detailed description of each C++ class. In this tutorial we will only highlight the differences between the Julia and the C++ API. Therefore it is assumed some prior knowledge of the Geant4 C++ interfaces.\n", "\n", "## Installation\n", "The Geant4.jl package does no require any special installation. Stable releases are registered to the Julia general registry, and therefore, it can be deployed with the standard `Pkg` Julia package manager.\n", @@ -23,19 +23,9 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "\u001b[32m\u001b[1m Resolving\u001b[22m\u001b[39m package versions...\n", - "\u001b[32m\u001b[1m No Changes\u001b[22m\u001b[39m to `~/Development/Geant4.jl-tutorial/Project.toml`\n", - "\u001b[32m\u001b[1m No Changes\u001b[22m\u001b[39m to `~/Development/Geant4.jl-tutorial/Manifest.toml`\n" - ] - } - ], + "outputs": [], "source": [ "using Pkg\n", "Pkg.add(\"Geant4\")" @@ -60,19 +50,9 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "Geant4.G4BoxAllocated(Ptr{Nothing} @0x0000000122536410)" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "using Geant4\n", "box = G4Box(\"MyBox\", 1, 2, 3) # the C++ contructor called G4Box (const G4String &pName, G4double pX, G4double pY, G4double pZ)" @@ -87,21 +67,9 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2-element Vector{Any}:\n", - " Geant4.G4BoxAllocated\n", - " Geant4.G4BoxDereferenced" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "using Test\n", "@test typeof(box) == Geant4.G4BoxAllocated # the type is indeed a G4BoxAllocated\n", @@ -119,19 +87,9 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\u001b[32m\u001b[1mTest Passed\u001b[22m\u001b[39m" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "r_box = CxxRef(box)\n", "p_box = CxxPtr(box)\n", @@ -148,27 +106,9 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "typeof(r_box[]) = Geant4.G4BoxDereferenced\n", - "typeof(p_box[]) = Geant4.G4BoxDereferenced\n" - ] - }, - { - "data": { - "text/plain": [ - "\u001b[32m\u001b[1mTest Passed\u001b[22m\u001b[39m" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "@show typeof(r_box[])\n", "@show typeof(p_box[])\n", @@ -186,19 +126,9 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\u001b[32m\u001b[1mTest Passed\u001b[22m\u001b[39m" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "vol = GetCubicVolume(box) # In C++ this would be box.GetCubicVolume()\n", "@test vol == 8 * GetXHalfLength(box) * GetYHalfLength(box) * GetZHalfLength(box) " @@ -230,19 +160,9 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "G4Random!getTheSeed() # This will call the C++ class method G4Random::getTheSeed()" ] @@ -257,19 +177,9 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "\u001b[32m\u001b[1mTest Passed\u001b[22m\u001b[39m" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "solid = Clone(box)\n", "@test typeof(solid) == CxxPtr{G4VSolid}\n", @@ -295,22 +205,9 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "ename": "UndefVarError", - "evalue": "UndefVarError: `G4Box` not defined", - "output_type": "error", - "traceback": [ - "UndefVarError: `G4Box` not defined\n", - "\n", - "Stacktrace:\n", - " [1] top-level scope\n", - " @ ~/Development/Geant4.jl-tutorial/tutorial/docs/geant4-jl-intro.ipynb:1" - ] - } - ], + "outputs": [], "source": [ "box1 = G4Box(\"box1\", 1,1,3) # construct boxes\n", "box2 = G4Box(\"box2\", 1,3,1) \n", @@ -335,7 +232,34 @@ "box1 = box2 = nothing\n", "GC.gc()\n", "@show GetCubicVolume(union) # G4BooleanSolid cashes the volume\n", - "# DistanceToIn(union, G4ThreeVector(10,10,10)) # this will probabluy crash the program" + "# DistanceToIn(union, G4ThreeVector(10,10,10)) # this will probably crash the program" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To avoid this problem the **user must transfer object ownership to the C++ side** using the provided function `move!()`. For example:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "box1 = G4Box(\"box1\", 1,1,3) # construct boxes\n", + "box2 = G4Box(\"box2\", 1,3,1) \n", + "union = G4UnionSolid(\"union\", move!(box1), move!(box2)) # construct a union solid with the same box\n", + "@show GetCubicVolume(union)\n", + "@show DistanceToIn(union, G4ThreeVector(10,10,10));" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "forcing now a GC will still work" ] }, { @@ -343,7 +267,12 @@ "execution_count": null, "metadata": {}, "outputs": [], - "source": [] + "source": [ + "box1 = box2 = zeros(1000)\n", + "GC.gc()\n", + "@show GetCubicVolume(union) # G4BooleanSolid cashes the volume\n", + "@show DistanceToIn(union, G4ThreeVector(10,10,10)); # this will probabluy crash the program" + ] } ], "metadata": {