Metadata-Version: 2.4
Name: fisp
Version: 1.0.1
Summary: FISP: a 1D Fast Ion Spectra Propagator for ion-matter interaction.
Author-email: Howel Larreur <hwlr33@gmail.com>
Project-URL: Homepage, https://pypi.org/project/fisp/
Keywords: simulation,spectrum,ion,Monte-Carlo
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
Classifier: Operating System :: OS Independent
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: matplotlib
Requires-Dist: numpy
Requires-Dist: tqdm
Requires-Dist: scipy
Dynamic: license-file

FISP is a 1D simulation code for the interaction of ion beams with matter. It should be seen as a less precise but much faster alternative to Monte-Carlo simulations: both types of simulations can complement each other.

Peer-reviewed article to be submitted.

# Features
- Runs on a **personnal computer** with **short running times** (seconds to minutes depending on the simulation)
- **User friendly**: install and use as any other python package
- **Multi-layer targets** of any material of known composition
- Propagating **any ion**
- **Reactions** between **any two nuclei** (user provides cross-section data)
- **Front and rear exiting spectra** calculation
- local **Energy deposition** calculation
- local **Number of reactions** and **decays** calculation


# Quick start guide

## Setting-up the simulation

In FISP, everything has to be manually declared. This includes atomic/ion species, materials, nuclear reactions and ion spectra.

### Units

All inputs in FISP should be done using SI units: lengths in meters, cross-sections in squared-meters. There is one exception: energies are expressed in MeV.

### Ion species

Any atomic/ion species involved in a FISP simulation (in the composition of a material layer or as the product of a nuclear reaction for example) must be declared before anything else. This is done using the `Ion` class, for example let's declare an alpha particle (<sup>4</sup>He nucleus):
```
import fisp

Z = 2                 # Atomic number
A = 4                 # Mass number
mass = 3727.37941     # Ion mass energy in MeV
I = 41.8e-6           # Optionnal: mean excitation potential in MeV. Can be specified
                      # in the `Material` class instead. Less user-friendly.
ionization_energy = 0 # Optionnal: ionization energy in MeV. If this Ion is in an excited
                      # state (see nuclear reactions part).
name = 'alpha'        # Optionnal: chose a name for plots and output files
propagate = True      # Optionnal: tells FISP wether to propagate this type of ions.
                      # Setting this to False speeds up the calculation (especially
					  # with neutrons and thick targets), but obviously prevents FISP 
                      # from calculating relating things such as energy deposition,
                      # contribution from this ion type or output spectra for this
                      # ion type: any ion that is not propagated is forgotten as soon
                      # as it is created, only counting in the created ions numbers.

He4 = fisp.Ion(Z, A, mass, I=I, ionization_energy=ionization_energy, name=name, propagate=propagate)
```

### Materials

Once your ions are declared, you can add them to a material type using the `Material` class, for example with natural boron:
```
composition = {B10:.199,           # 19.9% of boron 10 and 80.1% of boron 11,
               B11:.801}           # previously declared using the Ion class
density = 2370                     # Density in kg/m^3
molar_mass = .0108135              # Molar mass in kg/mol
I = 76e-6                          # Optionnal: mean excitation potential in MeV. Default
                                   # is the average for the components of the materials.
name = 'boron'                     # Optionnal: chose a name for plots and output files.
disable_warnings = True            # Optionnal: FISP will warn the user if there seems to
                                   # be a unit mistake on the values given for materials.
                                   # If you know better, you can disable these warnings here.

boron = fisp.Material(composition, density, molar_mass, mean_excitation_potential=I, name=name, disable_warnings=disable_warnings)
```

### Nuclear reactions

**Binary nuclear reactions**

Nuclear reactions that involve two nuclei turning into two other nuclei can be expressed as follows:
                *target (projectile, ejectile) product*
They can be declared easily using the `BinaryReaction` subclass of the main `Reaction` class, that is introduced in the next paragraph.
```
target = B11            # Boron 11
projectile = H1         # proton (hydrogen 1)
ejectile = n            # neutron
product = C11           # carbon 11
X_section = mydata      # cross-section can be inputted as a data table or as a function.
                        # For a data table, the expected format is (xdata, ydata), with
                        # xdata being an iterable of the projectile energies, and ydata
					    # being the corresponding cross-sections in m².
					    # For a function, it should accept an array (of energies) as an
					    # and return a corresponding array of cross-sections.
reference_frame = 'com' # Reference frame in which the cross-sections are given. Defaults
                        # to 'com' for center-of-mass, can also be 'lab' for laboratory.
name = 'p+B11->n+C11'   # Optionnal: chose a name for plots and output files.

pb11_nC11 = fisp.BinaryReaction(B11, H1, n, C11, X_section, reference_frame)
```

**Non binary nuclear reactions**

More complex reactions can be declared using the `Reaction` class, which involves more work from the user. More informations in the doctrings of the `Reaction` class!

### Target layers

Now that materials and reactions have been declared, one can construct the target geometry using the `Layer` class. Indeed, FISP supports multi-layer target, each layer being a different material.
```
material = boron           # the Material object previously declared composing the layer
thickness = 100e-6         # the thickness of the layer in m
reactions = pb11_nC11,     # the previously declared nuclear reactions occuring within
                           # the layer. This is an iterable, so even if there is only one
						   # reaction don't forget the coma!
outer_step_size = 1e-8     # the size of a slice on the layer's edge in m
max_inner_step_size = 1e-6 # the maximum slice size allowing in the layer in m
step_factor = 1.01         # the ratio between the sizes of two consecutive slices. Indeed, as
                           # inner steps have less influence on the calculation's results, they
                           # can be made larger to speed up the calculation.

fisp.Layer(material, thickness, reactions, outer_step_size, max, inner_step_size, step_factor)
```
One additionnal layer is added to the simulation each time the `Layer` class is called. The order the the layers in the simulated target is the order in which the user declares the layers.

### Ion beam

An ion beam (spectrum) can be added anywhere inside the target using the `input_spectrum` function:
```
ions_type = H1            # Previously declared nature type of ions
position = 0.             # Start position of the spectrum in m
direction = 'back'        # Propagation direction of the spectrum ('front'/'back' is
                          # towards the front/back of the target)
energy_data = mydataE     # the spectrum energy bins values in MeV
population_data = mydataP # corresponding ion populations in /MeV
angle = myangle           # EXPERIMENTAL/NOT RECOMMENDED Optional, will project the
                          # speeds of the spectrum according to this angle
resample = True           # Optional, resamples the spectrum using linear interpolation
                          # to have more energy bins and improve the results.

fisp.input_spectrum(ions_type, position, direction, energy_data, population_data, angle, resample)
```

For a monoenergetic spectrum, use `input_monoenergetic` instead:
```
ions_type = H1            # Previously declared nature type of ions
position = 0.             # Start position of the spectrum in m
direction = 'back'        # Propagation direction of the spectrum ('front'/'back' is
                          # towards the front/back of the target)
energy = myenery          # the energy in MeV
population = n            # number of ions with this energy

fisp.input_monoenergetic(ions_type, position, direction, energy, population)
```

### Additional parameters and functions

Additional parameters are available in the fisp.setting function.

## Calling the run function

At this point, the simulation parameters and input are completely done. The run function should be called.
```
fisp.run()
```
Note that to extract the simulations outputs, post-processing functions are needed (see below).


## Setting-up the post-processing

FISP embarks tools for prost-processing the simulations. They should be placed under the `run` function in the user's python file.

For more information about a function listed here, please consult its docstring.

### Plotting functions

FISP includes several plotting functions: `plot_energy_deposition`, `plot_nuclear_decays`, `plot_nuclear_reactions`, `plot_range`, `plot_stopped_ions`, `plot_stopping_power`, `plot_target`.

The `Spectrum` class has it own plotting method: `plot`. The `Reaction` class also has its own plotting method: `plot_cross_section`.

### Printing function

There are also printing functions: `print_created_ions`, `print_energy_deposition`, `print_nuclear_decays`, `print_nuclear_reactions`.

### Data Saving

FISP includes functions to save data as csv files: `save_energy_deposition`, `save_created_ions`, `save_nuclear_decays`, `save_nuclear_reactions`, `save_range`, `save_stopped_ions`, `save_stopping_power` and the `Spectrum` class method `save_csv`.

### Data extraction

For more flexibility, it is possible to direclty access data:
- Data: `range_tables`, `reactions_list`, `decays_list`, `front_spectra`, `rear_spectra`, `injected_spectra`
- Functions: `extract_created_ions_integrated`, `extract_energy_deposition`, `extract_energy_deposition_integrated`, `extract_nuclear_decays`, `extract_nuclear_decays_integrated`, `extract_nuclear_reactions`, `extract_nuclear_reactions_integrated`, `extract_stopped_ions`

## Resetting

At the end of the Python file, the `reset` function can be called. If not done, parametric studies or any following simulations in the same Python console may yield nonsensic results.


## Parametric studies

EXPERIMENTAL/MAY NOT WORK

The original purpose of FISP is to perform parametric studies. Thus, a function to run parametric studies is included. It works by running multiple Python interpeters at the same time with different parameters. Thus, the user needs to provide a functionning FISP namelist. In this namelist must be the flag `$parametric$` for the value to replace, for example:
```
my_thickness = $parametric$
```
This flag will be replaced by a value of the parametric study for each simulation. To run a parametric study, user has to execute a separate python file:
```
import fisp

values = [1e-3, 2e-3, 3e-3]       # Values of the parametric study that replace the $parametric$ flag
namelist = 'namelist_parallel.py' # Name of the namelist file to run (the one with the $parametric$ flag)
output = 'test'                   # Optionnal: output directory. Default is current working directory.
cpu = 1                           # Optionnal: number of CPU cores to use. Note: as FISP is high-demanding
                                  # on memory bandwidth, using a lot of core does not scale well.
ignore_overwrite = True           # Tells wether to delete past simulations if they exist in the same directory.

fisp.prun(values, namelist, output_directory=output, workers=cpu, ignore_overwrite=ignore_overwrite)

```
Graphs will not be displayed and prints will not be printed during parametric studies: everything has to be saved.


# Changelog

### Version 1.0.1

Initial validated release.
