1
0
Fork 0
mirror of https://github.com/gwm17/catima.git synced 2024-11-22 18:28:51 -05:00

Merge pull request #4 from hrosiak/python

Python
This commit is contained in:
Andrej Prochazka 2017-08-01 17:53:21 +02:00 committed by GitHub
commit c0a97d2536
4 changed files with 373 additions and 24 deletions

View File

@ -1,16 +1,41 @@
"""
catima python module
~~~~~~~~~~~
This module provides interface to the catima c++ library
:copyright: (c) 2017 by Andrej Prochazka
:licence: GNU Affero General Public License, see LICENCE for more details
"""
cimport catimac
from enum import IntEnum
import numpy
cdef class Material:
cdef catimac.Material cbase
def __cinit__(self, elements):
def __cinit__(self, elements=None, thickness=None, density=None):
self.cbase = catimac.Material()
if(elements and isinstance(elements[0],int)):
if(elements and (isinstance(elements[0],float) or isinstance(elements[0],int))):
self.cbase.add_element(elements[0],elements[1],elements[2])
if(elements and isinstance(elements[0],list)):
for e in elements:
self.cbase.add_element(e[0],e[1],e[2])
if(not thickness is None):
self.thickness(thickness)
if(not density is None):
self.density(density)
cdef from_c(self, catimac.Material &other):
self.cbase = other
cdef catimac.Material getc(self):
cdef catimac.Material res
res = self.cbase
return res
def copy(self):
res = Material()
res.cbase = self.cbase
return res
def add_element(self, a, z , s):
self.cbase.add_element(a, z, s)
@ -36,6 +61,35 @@ cdef class Material:
else:
return self.cbase.thickness(val)
class material(IntEnum):
PLASTIC = 201
AIR = 202
CH2 = 203
LH2 = 204
LD2 = 205
WATER = 206
DIAMOND = 207
GLASS = 208
ALMG3 = 209
ARCO2_30 = 210
CF4 = 211
ISOBUTANE = 212
KAPTON = 213
MYLAR = 214
NAF = 215
P10 = 216
POLYOLEFIN = 217
CMO2 = 218
SUPRASIL = 219
HAVAR = 220
def get_material(int matid):
res = Material()
cdef catimac.Material cres = catimac.get_material(matid);
res.from_c(cres)
return res
cdef class Target:
cdef catimac.Target cbase
@ -49,34 +103,56 @@ cdef class Target:
return self.cbase.Z
cdef class Layers:
cdef catimac.Layers cbase
def __cinit__(self):
self.cbase = catimac.Layers()
self.materials = []
cdef public:
materials
def __init__(self):
self.materials=[]
def add(self,Material m):
self.cbase.add(m.cbase)
self.materials.append(m)
self.materials.append(m.copy())
def num(self):
return self.cbase.num()
return len(self.materials)
def get(self, key):
return self.materials[key]
def __getitem__(self, key):
if(isinstance(key,int)):
return self.materials[key]
if(isinstance(key,int) and key<self.num()):
return self.get(key)
return None
def __add__(self, other):
res = Layers()
for e in self.materials:
res.add(e)
if(isinstance(other,Layers)):
for e in other.materials:
res.add(e)
if(isinstance(other,Material)):
res.add(other.copy())
return res
cdef catimac.Layers getc(self):
cdef catimac.Layers res
#for l in self.materials:
# res.add(l.getc())
return res
cdef class Projectile:
cdef catimac.Projectile cbase
def __cinit__(self, a, z, t=None,q=None):
self.cbase.A = a
self.cbase.Z = z
self.cbase.Q = z
if(q):
self.cbase.Q = q
if(t):
self.cbase.T = t
def T(self,val):
def __cinit__(self, A, Z, Q=None,T=None):
self.cbase.A = A
self.cbase.Z = Z
self.cbase.Q = Z
if(Q):
self.cbase.Q = Q
if(T):
self.cbase.T = T
def T(self,val=None):
if(val is None):
return self.cbase.T
self.cbase.T = val;
def __call__(self,val=None):
if(val is None):
@ -88,6 +164,8 @@ cdef class Projectile:
return self.cbase.A
def Z(self):
return self.cbase.Z
def Q(self):
return self.cbase.Q
cdef class Result:
cdef public double Ein
@ -112,6 +190,24 @@ cdef class Result:
self.sigma_r=0.0
self.tof=0.0
def get_dict(self):
return {"Ein":self.Ein,
"Eout":self.Eout,
"Eloss":self.Eloss,
"range":self.range,
"dEdxi":self.dEdxi,
"dEdxo":self.dEdxo,
"sigma_E":self.sigma_E,
"sigma_a":self.sigma_a,
"sigma_r":self.sigma_r,
"tof":self.tof,
}
def __getitem__(self,key):
d = self.get_dict()
if(key in d):
return d[key]
cdef setc(self,catimac.Result &val):
self.Ein=val.Ein
self.Eout=val.Eout
@ -124,6 +220,29 @@ cdef class Result:
self.sigma_r=val.sigma_r
self.tof=val.tof
cdef class MultiResult:
cdef public Result total_result
cdef public results
cdef public total
def __init__(self):
self.total_result = Result()
self.results = []
self.total = {}
cdef setc(self, catimac.MultiResult &val):
self.total_result.setc(val.total_result)
for e in val.results:
self.results.append(e)
self.total = self.total_result.get_dict()
def __getitem__(self,key):
if(isinstance(key,int) and key<len(self.results)):
return self.results[key]
if(isinstance(key,str) and key in self.total):
return self.total[key]
return None
class z_eff_type(IntEnum):
none = 0,
atima = 1
@ -176,6 +295,30 @@ def calculate(Projectile projectile, Material material, energy = None, Config co
res.setc(cres)
return res
cdef catimac.Layers get_clayers(Layers layers):
cdef catimac.Layers res
cdef catimac.Material m
for l in layers.materials:
m = get_cmaterial(l)
res.add(m)
return res
cdef catimac.Material get_cmaterial(Material material):
cdef catimac.Material res
res = material.cbase
return res
def calculate_layers(Projectile projectile, Layers layers, energy = None, Config config = default_config):
cdef catimac.Layers clayers
clayers = catimac.Layers()
clayers = get_clayers(layers)
if(not energy is None):
projectile.T(energy)
cdef catimac.MultiResult cres = catimac.calculate(projectile.cbase, clayers, config.cbase)
res = MultiResult()
res.setc(cres)
return res
def range(Projectile projectile, Material material, energy = None, Config config = default_config):
if(isinstance(energy,numpy.ndarray)):
res = numpy.empty(energy.size)

View File

@ -1,5 +1,13 @@
"""
catima cython
~~~~~~~~~~~~~~~~~
:copyright: (c) 2017 by Andrej Prochazka
:licence: GNU Affero General Public License, see LICENCE for more details
"""
from libcpp.pair cimport pair
from libcpp.vector cimport vector
from libcpp cimport bool
cdef extern from "catima/structures.h" namespace "catima":
cdef struct Target:
@ -24,12 +32,14 @@ cdef extern from "catima/structures.h" namespace "catima":
double sigma_r
double tof
cdef cppclass MultiResult
cdef cppclass MultiResult:
vector[Result] results
Result total_result
cdef cppclass Material:
Material() except +
void add_element(double , int , double )
pair[Target,double] getElement(int)
pair[Target,double] get_element(int)
int ncomponents()
double M()
double density()
@ -45,6 +55,9 @@ cdef extern from "catima/structures.h" namespace "catima":
Material& operator[](int i)
Layers& operator=(const Layers& other)
cdef extern from "catima/material_database.h" namespace "catima":
cdef Material get_material(int)
cdef extern from "catima/config.h" namespace "catima":
cdef struct Config:
char z_effective;

193
tests/test.py Normal file
View File

@ -0,0 +1,193 @@
import sys
sys.path.insert(0,"../build")
import unittest
import catima
class TestStructures(unittest.TestCase):
def test_Projectile(self):
p = catima.Projectile(238,92)
self.assertEqual(p.A(),238)
self.assertEqual(p.Z(),92)
self.assertEqual(p.Q(),92)
p = catima.Projectile(238,92,90)
self.assertEqual(p.A(),238)
self.assertEqual(p.Z(),92)
self.assertEqual(p.Q(),90)
p.T(1000)
self.assertEqual(p.T(),1000)
self.assertEqual(p(),1000)
p(500)
self.assertEqual(p.T(),500)
self.assertEqual(p(),500)
p = catima.Projectile(238,92,90, T=100)
self.assertEqual(p.T(),100)
def test_Material(self):
mat = catima.Material()
mat.add_element(12,6,1)
self.assertEqual(mat.ncomponents(),1)
mat.add_element(1,1,2)
self.assertEqual(mat.ncomponents(),2)
mat2 = catima.Material([12.01,6,1])
self.assertEqual(mat2.ncomponents(),1)
self.assertEqual(mat2.molar_mass(),12.01)
mat3 = catima.Material([12,6,1])
self.assertEqual(mat3.ncomponents(),1)
self.assertEqual(mat3.molar_mass(),12)
water = catima.Material([[1,1,2],[16,8,1]])
self.assertEqual(water.molar_mass(),18)
mat2 = catima.Material([0,6,1])
self.assertEqual(mat2.ncomponents(),1)
self.assertAlmostEqual(mat2.molar_mass(),12,1)
mat5 = catima.Material([0,6,1],density=1.9, thickness=0.5)
self.assertEqual(mat5.ncomponents(),1)
self.assertEqual(mat5.thickness(),0.5)
self.assertEqual(mat5.density(),1.9)
# copy
mat3.density(1.8)
matc = mat3.copy()
self.assertEqual(matc.ncomponents(),1)
self.assertEqual(matc.molar_mass(),12)
self.assertEqual(matc.density(),1.8)
mat3.density(2.0)
self.assertEqual(matc.density(),1.8)
self.assertEqual(mat3.density(),2.0)
def test_default_material(self):
m1 = catima.get_material(6);
self.assertAlmostEqual(m1.molar_mass(),12,1)
self.assertEqual(m1.ncomponents(),1)
self.assertAlmostEqual(m1.density(),2.0,1)
m2 = catima.get_material(catima.material.WATER)
self.assertEqual(m2.ncomponents(),2)
self.assertAlmostEqual(m2.molar_mass(),18,1)
self.assertAlmostEqual(m2.density(),1.0,1)
def test_layers(self):
graphite = catima.get_material(6)
graphite.thickness(0.5)
p10 = catima.get_material(catima.material.P10)
p10.thickness(0.01)
n2 = catima.get_material(7)
n2.thickness(0.02)
mat= catima.Layers()
self.assertEqual(mat.num(),0)
mat.add(graphite)
self.assertEqual(mat.num(),1)
self.assertAlmostEqual(mat[0].molar_mass(),12,1)
self.assertAlmostEqual(mat[0].thickness(),0.5,1)
self.assertAlmostEqual(mat[0].density(),2.0,1)
mat.add(p10)
self.assertEqual(mat.num(),2)
graphite.thickness(1.0)
graphite.density(1.8)
mat.add(graphite)
self.assertEqual(mat.num(),3)
self.assertAlmostEqual(mat[2].molar_mass(),12,1)
self.assertAlmostEqual(mat[0].thickness(),0.5,1)
self.assertAlmostEqual(mat[0].density(),2.0,1)
self.assertAlmostEqual(mat[2].thickness(),1.0,1)
self.assertAlmostEqual(mat[2].density(),1.8,1)
mat[2].thickness(1.2)
mat[2].density(1.9)
self.assertAlmostEqual(mat.materials[2].thickness(),1.2,1)
self.assertAlmostEqual(mat.materials[2].density(),1.9,1)
#self.assertAlmostEqual(mat.materials[0].thickness(),0.5,1)
#self.assertAlmostEqual(mat.materials[0].density(),2.0,1)
self.assertEqual(mat[3],None)
self.assertEqual(mat["a"],None)
mat2 = catima.Layers()
mat2.add(n2)
self.assertEqual(mat2.num(),1)
mats = mat2 + mat
self.assertEqual(mats.num(),4)
self.assertAlmostEqual(mats[0].molar_mass(),14,1)
self.assertEqual(mats[0].thickness(),0.02)
self.assertAlmostEqual(mats[1].molar_mass(),12,1)
self.assertAlmostEqual(mats[3].molar_mass(),12,1)
n2.thickness(0.5)
mats = mats + n2
self.assertEqual(mats.num(),5)
self.assertAlmostEqual(mats[0].molar_mass(),14,1)
self.assertEqual(mats[0].thickness(),0.02)
self.assertAlmostEqual(mats[4].molar_mass(),14,1)
self.assertEqual(mats[4].thickness(),0.5)
def test_material_calculation(self):
water = catima.get_material(catima.material.WATER)
p = catima.Projectile(1,1)
p(1000)
res = catima.calculate(p,water)
res2 = catima.dedx(p,water)
self.assertAlmostEqual(res.dEdxi,2.23,1)
self.assertAlmostEqual(res["dEdxi"],2.23,1)
self.assertAlmostEqual(res.dEdxi,res2,3)
res = catima.calculate(p(500),water)
res2 = catima.dedx(p,water)
self.assertAlmostEqual(res.dEdxi,2.76,1)
self.assertAlmostEqual(res.dEdxi,res2,3)
res = catima.calculate(p(9),water)
res2 = catima.dedx(p,water)
self.assertAlmostEqual(res.dEdxi,51.17,1)
self.assertAlmostEqual(res.dEdxi,res2,3)
res = catima.calculate(p(9),water)
res = catima.calculate(p(9),water)
self.assertAlmostEqual(res.dEdxi,51.17,1)
def test_eout(self):
graphite = catima.get_material(6)
graphite.thickness(0.5)
p = catima.Projectile(12,6)
res = catima.calculate(p(1000),graphite)
res2 = catima.energy_out(p(1000),graphite)
self.assertAlmostEqual(res.Eout,997.077,1)
self.assertAlmostEqual(res["Eout"],997.077,1)
self.assertAlmostEqual(res.Eout,res2,3)
def test_layer_calculateion(self):
p = catima.Projectile(12,6)
water = catima.get_material(catima.material.WATER)
water.thickness(10.0)
graphite = catima.get_material(6)
graphite.thickness(1.0)
mat = catima.Layers()
mat.add(water)
mat.add(graphite)
res = catima.calculate_layers(p(1000),mat)
self.assertEqual(len(res.results),2)
self.assertAlmostEqual(res.total_result.Eout,926.3,1)
self.assertAlmostEqual(res.total_result.sigma_a,0.00269,1)
self.assertAlmostEqual(res["Eout"],926.3,1)
self.assertAlmostEqual(res["sigma_a"],0.00269,4)
self.assertAlmostEqual(res["tof"],0.402,2)
self.assertAlmostEqual(res["Eloss"],884,0)
self.assertAlmostEqual(res[0]["Eout"],932,0)
self.assertAlmostEqual(res[1]["Eout"],926,0)
self.assertAlmostEqual(res[0]["sigma_a"],0.00258,4)
self.assertAlmostEqual(res[1]["sigma_a"],0.000774,4)
self.assertAlmostEqual(res[0]["range"],107.1,0)
self.assertAlmostEqual(res[1]["range"],110.7,0)
if __name__ == "__main__":
unittest.main()

View File

@ -49,7 +49,7 @@ const lest::test specification[] =
EXPECT(water2.M()==18);
}
SECTION("equal operator check"){
EXPECT(water==water);
EXPECT(water==water2);
EXPECT(!(water==graphite));
}
}