1
0
Fork 0
mirror of https://github.com/gwm17/catima.git synced 2024-11-22 18:28:51 -05:00
This commit is contained in:
hrocho 2018-10-21 22:08:16 +02:00
parent 3d240d2fd6
commit c971222984
20 changed files with 887 additions and 553 deletions

View File

@ -1,27 +1,30 @@
cmake_minimum_required(VERSION 3.2.0)
cmake_minimum_required(VERSION 3.2.0)
project(catima)
############ options #############
#option(THREADS "Use multi-threading" ON)
option(BUILD_SHARED_LIBS "build as shared library" ON)
option(PYTHON_MODULE "compile the Catima python module(requires numpy and cython installed)" OFF)
option(TESTS "build tests" OFF)
option(EXAMPLES "build examples" ON)
option(GSL_INTEGRATION "use GSL integration" ON)
option(GENERATE_DATA "make data tables generator" OFF)
option(THIN_TARGET_APPROXIMATION "thin target approximation" ON)
option(DOCS "build documentation (requires doxygen)" OFF)
option(APPS "build catima applications" ON)
option(GLOBAL "build with global, sources are required" OFF)
option(REACTIONS "enable/disable nuclear reaction rate" ON)
option(APPS "build catima applications" ON)
option(STORE_SPLINES "store splines, if disables splines are always recreated" ON)
option(GSL_INTEGRATION "use GSL integration" OFF)
option(GSL_INTERPOLATION "use GSL inteRPOLATION" OFF)
option(THIN_TARGET_APPROXIMATION "thin target approximation" ON)
option(GENERATE_DATA "make data tables generator" OFF)
option(DOCS "build documentation (requires doxygen)" OFF)
######## build type ############
if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
set(CMAKE_BUILD_TYPE "Release")
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}")
MESSAGE(STATUS "Build type Release")
else()
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
if (${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -Wextra -Wfatal-errors -g")
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Wall -Wextra -Wfatal-errors -Wno-unused-parameter -Wno-sign-compare")
endif()
MESSAGE(STATUS "Build type Debug")
endif()
@ -41,18 +44,10 @@ else()
endif()
############# Requirements ##################
find_package(GSL REQUIRED)
MESSAGE(STATUS "GSL include dirs: " ${GSL_INCLUDE_DIRS})
#if(THREADS)
# find_package(Threads REQUIRED)
# set (EXTRA_LIBS ${EXTRA_LIBS} ${CMAKE_THREAD_LIBS_INIT})
# set (USE_THREADS ON)
# MESSAGE(STATUS "Nurex will use threads")
#endif(THREADS)
find_package(PythonInterp)
if(PYTHONINTERP_FOUND)
message("-- Python found: ${PYTHON_EXECUTABLE}")
if(GSL_INTEGRATION OR GSL_INTERPOLATION)
find_package(GSL REQUIRED)
MESSAGE(STATUS "GSL include dirs: " ${GSL_INCLUDE_DIRS})
list(APPEND EXTRA_LIBS ${GSL_LIBRARIES} )
endif()
find_package(nurex QUIET)
@ -81,29 +76,19 @@ endif(GLOBAL)
file(GLOB HEADERS *.h)
add_library(catima SHARED ${SOURCES})
add_library(catima_static STATIC ${SOURCES})
set_target_properties(catima PROPERTIES
POSITION_INDEPENDENT_CODE ON
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
)
set_target_properties(catima_static
PROPERTIES OUTPUT_NAME catima
POSITION_INDEPENDENT_CODE ON
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib
)
target_link_libraries(catima ${EXTRA_LIBS} ${GSL_LIBRARIES})
target_link_libraries(catima_static ${EXTRA_LIBS} ${GSL_LIBRARIES})
target_link_libraries(catima ${EXTRA_LIBS})
target_include_directories(catima
PUBLIC $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
$<BUILD_INTERFACE:${GSL_INCLUDE_DIRS}>
)
target_include_directories(catima_static
PUBLIC $<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/include>
$<BUILD_INTERFACE:${GSL_INCLUDE_DIRS}>
)
add_library(catima::catima ALIAS catima)
add_library(catima::catima_static ALIAS catima_static)
FILE(COPY ${HEADERS} DESTINATION ${PROJECT_BINARY_DIR}/include/catima)
@ -111,10 +96,23 @@ FILE(COPY ${HEADERS} DESTINATION ${PROJECT_BINARY_DIR}/include/catima)
MESSAGE( STATUS "CMAKE_CXX_COMPILER: " ${CMAKE_CXX_COMPILER} )
######## for python module
find_package(PythonInterp)
if(PYTHONINTERP_FOUND)
message("-- Python found: ${PYTHON_EXECUTABLE}")
endif()
if(PYTHON_MODULE)
if(NOT PYTHONINTERP_FOUND)
MESSAGE(SEND_ERROR "Python is required to build nurex python modules")
endif(NOT PYTHONINTERP_FOUND)
#find_package(pybind11 REQUIRED)
#set(PYBIND11_CPP_STANDARD -std=c++14)
#pybind11_add_module(pycatima pymodule/pycatima)
#target_include_directories(pycatima PUBLIC
# $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>
# $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/libs>
# $<INSTALL_INTERFACE:include>)
#target_link_libraries(pycatima PRIVATE catima)
find_program(CYTHON_EXECUTABLE
NAMES cython cython2 cython3 cython.bat
DOC "path to the cython executable"
@ -182,7 +180,7 @@ endif(APPS)
####### install part #######
FILE(GLOB headers "*.h")
include(GNUInstallDirs)
install (TARGETS catima catima_static
install (TARGETS catima
EXPORT catimaConfig
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
@ -194,7 +192,7 @@ install(EXPORT catimaConfig
DESTINATION lib/cmake/catima
)
export(TARGETS catima catima_static NAMESPACE catima:: FILE catimaConfig.cmake)
export(TARGETS catima NAMESPACE catima:: FILE catimaConfig.cmake)
export(PACKAGE catima)
###### packaging #######

View File

@ -26,17 +26,18 @@ compile options, enable or disable with cmake:
> cmake ../ -D[OPTION]
available options:
* BUILD_SHARED_LIBS - if ON shared library is build, otherwise static
* PYTHON_MODULE - enable/disable building of the python bindigs, cython and numpy are required to build the catima python module, default OFF
* TESTS - build tests
* EXAMPLES - build examples
* DOCS - prepare doxygen documentation (after cmake, __make docs__ needs to be executed)
* GENERATE_DATA - makes program to re-generate precalculated tables (ie precalculated LS coefficients), default:OFF
* THIN_TARGET_APPROXIMATION - compile the library with thin target approximation, default: ON
* GSL_INTEGRATION - use GSL integration functions, otherwise use built-in integrator, default: ON
* GSL_INTEGRATION - use GSL integration functions, otherwise use built-in integrator, default: OFF
* GLOBAL - compile with GLOBAL code (source not included at the moment, needs to be manually added to __global__ directory, default:OFF)
ie:
> cmake -DCATIMA_PYTHON=ON -DEXAMPLES=ON ../
> cmake -DPYTHON_MODULE=ON -DEXAMPLES=ON ../
after the compilation the libraries and headers must be either installed system-wide by make install or PATH and LD_LIBRARY_PATH must be adjusted to point to headers and library files.

View File

@ -18,6 +18,19 @@ void help(){
std::cout<<"usage: catima_calculator config_file.json\n";
}
inline std::vector<double> linspace_vector(double a, double b, unsigned int num){
std::vector<double> res;
if(num>=2 && a<b){
res.resize(num);
double step = (b-a)/(num-1);
for(unsigned int i=0;i<(num-1);i++){
res[i]=a+(i*step);
}
res[num-1] = b;
}
return res;
}
json load_json(const char *fname);
char* getCmdOption(char ** begin, char ** end, const std::string & option);
Material json_material(json &j);

View File

@ -3,6 +3,8 @@
#cmakedefine THIN_TARGET_APPROXIMATION
#cmakedefine GSL_INTEGRATION
#cmakedefine GSL_INTERPOLATION
#cmakedefine STORE_SPLINES
#cmakedefine GLOBAL
#cmakedefine REACTIONS
#cmakedefine NUREX

View File

@ -43,11 +43,17 @@ double dedx_n(const Projectile &p, const Target &t){
double asum = p.A + t.A;
double epsilon = 32.53*t.A*1000*p.T*p.A/(p.Z*t.Z*asum*zpowers); //projectile energy is converted from MeV/u to keV
double sn=0;
if(epsilon<=30){
if(epsilon<=0){
return 0.0;
}
else if(epsilon<=30){
assert(p.A>0);
assert(epsilon>0);
sn = log(1+(1.1383*epsilon))/ (2*(epsilon + 0.01321*pow(epsilon,0.21226) + 0.19593*pow(epsilon,0.5)));
}
else{
assert(p.A>0);
assert(epsilon>0);
sn = log(epsilon)/(2*epsilon);
}
sn = 100*8.4621*p.Z*t.Z*p.A*sn*Avogadro/(asum*zpowers*t.A);
@ -798,6 +804,7 @@ double z_eff_global(double pz, double E, double tz){
#ifdef GLOBAL
return global_qmean(pz, tz, E);
#else
assert(false);
return -1;
#endif
}
@ -871,6 +878,8 @@ double z_eff_atima14(double pz, double T, double tz){
}
}
}
#else
assert(false);
#endif
return qmean;
}

View File

@ -39,9 +39,13 @@ namespace catima{
double reduced_energy_loss_unit(const Projectile &p, const Target &t);
/**
* @brief bethek_dedx_e - electronics stopping power
* @return stopping power
*/
double bethek_dedx_e(Projectile &p,const Target &t, const Config &c=default_config, double I=0.0);
double bethek_dedx_e(Projectile &p,const Material &mat, const Config &c=default_config);
double bethek_barkas(double zp_eff,double eta, double zt);
double bethek_density_effect(double beta, int zt);

View File

@ -17,7 +17,6 @@ namespace catima{
Config default_config;
bool operator==(const Config &a, const Config&b){
if(std::memcmp(&a,&b,sizeof(Config)) == 0){
return true;
@ -30,11 +29,9 @@ bool operator==(const Config &a, const Config&b){
double dedx(Projectile &p, double T, const Material &mat, const Config &c){
double sum = 0;
if(T<=0)return 0.0;
sum += dedx_n(p,mat);
double se=0;
p.T = T;
sum += dedx_n(p,mat);
double se=0;
if(p.T<=10){
se = sezi_dedx_e(p,mat);
}
@ -78,21 +75,23 @@ double da2dx(Projectile &p, double T, const Material &mat, const Config &c){
double range(Projectile &p, double T, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
auto& data = _storage.Get(p,t,c);
//Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
spline_type range_spline = get_range_spline(data);
return range_spline(T);
}
double dedx_from_range(Projectile &p, double T, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
auto& data = _storage.Get(p,t,c);
//Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
spline_type range_spline = get_range_spline(data);
return p.A/range_spline.derivative(T);
}
std::vector<double> dedx_from_range(Projectile &p, const std::vector<double> &T, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
auto& data = _storage.Get(p,t,c);
//Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
spline_type range_spline = get_range_spline(data);
std::vector<double> dedx;
dedx.reserve(T.size());
for(auto e:T){
@ -107,45 +106,52 @@ std::vector<double> dedx_from_range(Projectile &p, const std::vector<double> &T,
}
double range_straggling(Projectile &p, double T, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
auto& data = _storage.Get(p,t,c);
//Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
spline_type range_straggling_spline = get_range_straggling_spline(data);
return sqrt(range_straggling_spline(T));
}
double range_variance(Projectile &p, double T, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
auto& data = _storage.Get(p,t,c);
//Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
spline_type range_straggling_spline = get_range_straggling_spline(data);
return range_straggling_spline(T);
}
double domega2de(Projectile &p, double T, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
auto& data = _storage.Get(p,t,c);
//Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
spline_type range_straggling_spline = get_range_straggling_spline(data);
return range_straggling_spline.derivative(T);
}
double da2de(Projectile &p, double T, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator angular_variance_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
auto& data = _storage.Get(p,t,c);
//Interpolator angular_variance_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
spline_type angular_variance_spline = get_angular_variance_spline(data);
return angular_variance_spline.derivative(T);
}
double angular_straggling_from_E(Projectile &p, double T, double Tout, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator angular_straggling_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
return sqrt(angular_straggling_spline(T) - angular_straggling_spline(Tout));
auto& data = _storage.Get(p,t,c);
//Interpolator angular_straggling_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
spline_type angular_variance_spline = get_angular_variance_spline(data);
return sqrt(angular_variance_spline(T) - angular_variance_spline(Tout));
}
double energy_straggling_from_E(Projectile &p, double T, double Tout,const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
auto& data = _storage.Get(p,t,c);
Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
//Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
//Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
spline_type range_spline = get_range_spline(data);
spline_type range_straggling_spline = get_range_straggling_spline(data);
double dEdxo = p.A/range_spline.derivative(Tout);
return dEdxo*sqrt(range_straggling_spline(T) - range_straggling_spline(Tout))/p.A;
}
double energy_out(double T, double thickness, Interpolator &range_spline){
double energy_out(double T, double thickness, const Interpolator &range_spline){
constexpr double epsilon = 1E-5;
int counter = 0;
double range;
@ -172,14 +178,16 @@ double energy_out(double T, double thickness, Interpolator &range_spline){
}
double energy_out(Projectile &p, double T, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
auto& data = _storage.Get(p,t,c);
//Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
spline_type range_spline = get_range_spline(data);
return energy_out(T,t.thickness(),range_spline);
}
std::vector<double> energy_out(Projectile &p, const std::vector<double> &T, const Material &t, const Config &c){
auto data = _storage.Get(p,t,c);
Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
auto& data = _storage.Get(p,t,c);
//Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
spline_type range_spline = get_range_spline(data);
std::vector<double> eout;
eout.reserve(T.size());
@ -199,15 +207,18 @@ Result calculate(Projectile &p, const Material &t, const Config &c){
Result res;
double T = p.T;
if(T<catima::Ezero && T<catima::Ezero-catima::numeric_epsilon){return res;}
auto data = _storage.Get(p,t,c);
auto& data = _storage.Get(p,t,c);
//Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
spline_type range_spline = get_range_spline(data);
Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
res.Ein = T;
res.range = range_spline(T);
res.dEdxi = p.A/range_spline.derivative(T);
res.Eout = energy_out(T,t.thickness(),range_spline);
Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
//Interpolator range_straggling_spline(energy_table.values,data.range_straggling.data(),energy_table.num);
spline_type range_straggling_spline = get_range_straggling_spline(data);
if(res.Eout<Ezero){
res.dEdxo = 0.0;
@ -225,20 +236,23 @@ Result calculate(Projectile &p, const Material &t, const Config &c){
double s2 = range_straggling_spline.derivative(res.Eout);
res.sigma_E = res.dEdxo*sqrt(edif*0.5*(s1+s2))/p.A;
Interpolator angular_variance_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
//Interpolator angular_variance_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
spline_type angular_variance_spline = get_angular_variance_spline(data);
s1 = angular_variance_spline.derivative(T);
s2 = angular_variance_spline.derivative(res.Eout);
res.sigma_a = sqrt(0.5*(s1+s2)*edif);
}
else{
res.sigma_E = res.dEdxo*sqrt(range_straggling_spline(T) - range_straggling_spline(res.Eout))/p.A;
Interpolator angular_variance_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
//Interpolator angular_variance_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
spline_type angular_variance_spline = get_angular_variance_spline(data);
res.sigma_a = sqrt(angular_variance_spline(T) - angular_variance_spline(res.Eout));
}
#else
res.sigma_E = res.dEdxo*sqrt(range_straggling_spline(T) - range_straggling_spline(res.Eout))/p.A;
Interpolator angular_variance_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
//Interpolator angular_variance_spline(energy_table.values,data.angular_variance.data(),energy_table.num);
spline_type angular_variance_spline = get_angular_variance_spline(data);
res.sigma_a = sqrt(angular_variance_spline(T) - angular_variance_spline(res.Eout));
#endif
if( !(c.skip&skip_tof) && t.thickness()>0){
@ -371,7 +385,7 @@ std::vector<double> calculate_tof(Projectile p, const Material &t, const Config
}
return values;
}
/*
DataPoint calculate_DataPoint(Projectile p, const Material &t, const Config &c){
DataPoint dp(p,t,c);
dp.range.resize(max_datapoints);
@ -411,6 +425,47 @@ DataPoint calculate_DataPoint(Projectile p, const Material &t, const Config &c){
}
return dp;
}
*/
DataPoint calculate_DataPoint(Projectile p, const Material &t, const Config &c){
DataPoint dp(p,t,c);
dp.range.resize(max_datapoints);
dp.range_straggling.resize(max_datapoints);
dp.angular_variance.resize(max_datapoints);
auto fdedx = [&](double x)->double{
return 1.0/dedx(p,x,t,c);
};
auto fomega = [&](double x)->double{
//return 1.0*domega2dx(p,x,t)/pow(dedx(p,x,t),3);
return domega2dx(p,x,t,c)/catima::power(dedx(p,x,t,c),3);
};
double res=0.0;
//calculate 1st point to have i-1 element ready for loop
//res = integrator.integrate(fdedx,Ezero,energy_table(0));
//res = p.A*res;
//dp.range[0] = res;
dp.range[0] = 0.0;
dp.angular_variance[0] = 0.0;
//res = integrator.integrate(fomega,Ezero,energy_table(0));
//res = p.A*res;
dp.range_straggling[0]=0.0;
//p.T = energy_table(0);
for(int i=1;i<max_datapoints;i++){
res = p.A*integrator.integrate(fdedx,energy_table(i-1),energy_table(i));
dp.range[i] = res + dp.range[i-1];
res = da2dx(p,energy_table(i),t)*res;
dp.angular_variance[i] = res + dp.angular_variance[i-1];
res = integrator.integrate(fomega,energy_table(i-1),energy_table(i));
res = p.A*res;
dp.range_straggling[i] = res + dp.range_straggling[i-1];
}
return dp;
}
double calculate_tof_from_E(Projectile p, double Eout, const Material &t, const Config &c){
double res;

View File

@ -21,6 +21,7 @@
#include <vector>
// #define NDEBUG
#include "catima/build_config.h"
#include "catima/config.h"
#include "catima/constants.h"
#include "catima/structures.h"
@ -141,7 +142,7 @@ namespace catima{
* @range_spline - precaclulated range spline for material
* @return outcoming energy after the thickness in Mev/u
*/
double energy_out(double T, double thickness, Interpolator &range_spline);
double energy_out(double T, double thickness, const Interpolator &range_spline);
/**
* calculates outcoming energy

View File

@ -141,4 +141,4 @@ cdef extern from "catima/storage.h" namespace "catima":
cdef EnergyTableType energy_table;
cdef Data _storage;
cdef DataPoint& get_data(const Projectile &p, const Material &t, Config c);
cdef DataPoint& get_data(const Projectile &p, const Material &t, const Config c);

View File

@ -1,12 +1,13 @@
#include "integrator.h"
//#ifdef GSL_INTEGRATION
#include "gsl/gsl_integration.h"
#include "gsl/gsl_errno.h"
//#endif
namespace catima{
integrator_type integrator;
IntegratorGSL integratorGSL(true);
#ifdef GSL_INTEGRATION
double funcwrapper3(double x, void *_c){
std::function<double(double)> *f = (std::function<double(double)> *)_c;
return (*f)(x);
@ -44,6 +45,5 @@ namespace catima{
}
return result;
};
#endif
}

View File

@ -17,15 +17,20 @@
#ifndef INTEGRATOR_H
#define INTEGRATOR_H
#include "catima/build_config.h"
#include "gsl/gsl_integration.h"
#include <functional>
#include <array>
#ifdef USE_THREADS
#include <mutex>
//#ifdef USE_THREADS
//#include <mutex>
//#endif
#ifdef GSL_INTEGRATION
#include "gsl/gsl_integration.h"
#endif
namespace catima{
#ifdef GSL_INTEGRATION
/// helper class to integrate functions using the GSL library
class IntegratorGSL{
public:
@ -45,6 +50,7 @@ class IntegratorGSL{
std::mutex integration_mutex;
#endif
};
#endif
template<int order>
struct GL_data{
@ -176,7 +182,6 @@ using integrator_type = GaussLegendreIntegration<8>;
#endif
extern integrator_type integrator;
extern IntegratorGSL integratorGSL;
}
#endif

View File

@ -23,8 +23,8 @@ double nonreaction_rate(Projectile &projectile, const Material &target, const Co
int ap = lround(projectile.A);
int zp = lround(projectile.Z);
auto data = _storage.Get(projectile,target,c);
Interpolator range_spline(energy_table.values,data.range.data(),energy_table.num);
auto& data = _storage.Get(projectile,target,c);
spline_type range_spline = get_range_spline(data);
if(energy_out(projectile.T, target.thickness(), range_spline) < emin_reaction)return -1.0;
auto sigma_r = [&](double th){

View File

@ -10,247 +10,6 @@
namespace catima{
band_matrix::band_matrix(int dim)
{
resize(dim);
}
void band_matrix::resize(int dim)
{
assert(dim>0);
a.resize(dim);
d.resize(dim);
c.resize(dim);
}
int band_matrix::dim() const
{
return d.size();
}
// defines the new operator (), so that we can access the elements
// by A(i,j), index going from i=0,...,dim()-1
double & band_matrix::operator () (int i, int j)
{
int k=j-i; // what band is the entry
assert( (i>=0) && (i<dim()) && (j>=0) && (j<dim()) );
assert(k<2 && k>-2);
if(k>0)return c[i];
else if(k==0) return d[i];
else return a[i];
}
double band_matrix::operator () (int i, int j) const
{
int k=j-i; // what band is the entry
assert( (i>=0) && (i<dim()) && (j>=0) && (j<dim()) );
if(k>0)return c[i];
else if(k==0) return d[i];
else return a[i];
}
std::vector<double> band_matrix::trig_solve(const std::vector<double>& b) const
{
assert( this->dim()==(int)b.size() );
std::vector<double> x(this->dim());
std::vector<double> g(this->dim());
assert(d[0]!=0.0);
x[0] = b[0]/d[0];
double bet = d[0];
for(int j=1;j<this->dim();j++){
g[j] = c[j-1]/bet;
bet = d[j] - (a[j]*g[j]);
assert(bet != 0.0);
x[j] = (b[j]-a[j]*x[j-1])/bet;
}
for(int j=this->dim()-2;j>=0;j--){
x[j] -= g[j+1]*x[j+1];
}
return x;
}
// spline implementation
// -----------------------
void spline::set_boundary(spline::bd_type left, double left_value,
spline::bd_type right, double right_value,
bool force_linear_extrapolation)
{
assert(n==0); // set_points() must not have happened yet
m_left=left;
m_right=right;
m_left_value=left_value;
m_right_value=right_value;
m_force_linear_extrapolation=force_linear_extrapolation;
}
void spline::set_points(const double *x,
const double *y,
const size_t num
)
{
assert(num>2);
m_x=x;
m_y=y;
n=num;
// TODO: maybe sort x and y, rather than returning an error
for(int i=0; i<n-1; i++) {
assert(m_x[i]<m_x[i+1]);
}
// setting up the matrix and right hand side of the equation system
// for the parameters b[]
band_matrix A(n);
std::vector<double> rhs(n);
for(int i=1; i<n-1; i++) {
A(i,i-1)=1.0/3.0*(x[i]-x[i-1]);
A(i,i)=2.0/3.0*(x[i+1]-x[i-1]);
A(i,i+1)=1.0/3.0*(x[i+1]-x[i]);
rhs[i]=(y[i+1]-y[i])/(x[i+1]-x[i]) - (y[i]-y[i-1])/(x[i]-x[i-1]);
}
// boundary conditions
if(m_left == spline::bd_type::second_deriv) {
// 2*b[0] = f''
A(0,0)=2.0;
A(0,1)=0.0;
rhs[0]=m_left_value;
} else{
// c[0] = f', needs to be re-expressed in terms of b:
// (2b[0]+b[1])(x[1]-x[0]) = 3 ((y[1]-y[0])/(x[1]-x[0]) - f')
A(0,0)=2.0*(x[1]-x[0]);
A(0,1)=1.0*(x[1]-x[0]);
rhs[0]=3.0*((y[1]-y[0])/(x[1]-x[0])-m_left_value);
}
if(m_right == spline::bd_type::second_deriv) {
// 2*b[n-1] = f''
A(n-1,n-1)=2.0;
A(n-1,n-2)=0.0;
rhs[n-1]=m_right_value;
} else{
// c[n-1] = f', needs to be re-expressed in terms of b:
// (b[n-2]+2b[n-1])(x[n-1]-x[n-2])
// = 3 (f' - (y[n-1]-y[n-2])/(x[n-1]-x[n-2]))
A(n-1,n-1)=2.0*(x[n-1]-x[n-2]);
A(n-1,n-2)=1.0*(x[n-1]-x[n-2]);
rhs[n-1]=3.0*(m_right_value-(y[n-1]-y[n-2])/(x[n-1]-x[n-2]));
}
// solve the equation system to obtain the parameters b[]
//m_b=A.lu_solve(rhs);
m_b=A.trig_solve(rhs);
// calculate parameters a[] and c[] based on b[]
m_a.resize(n);
m_c.resize(n);
for(int i=0; i<n-1; i++) {
m_a[i]=1.0/3.0*(m_b[i+1]-m_b[i])/(x[i+1]-x[i]);
m_c[i]=(y[i+1]-y[i])/(x[i+1]-x[i])
- 1.0/3.0*(2.0*m_b[i]+m_b[i+1])*(x[i+1]-x[i]);
}
// for left extrapolation coefficients
m_b0 = (m_force_linear_extrapolation==false) ? m_b[0] : 0.0;
m_c0 = m_c[0];
// for the right extrapolation coefficients
// f_{n-1}(x) = b*(x-x_{n-1})^2 + c*(x-x_{n-1}) + y_{n-1}
double h=x[n-1]-x[n-2];
// m_b[n-1] is determined by the boundary condition
m_a[n-1]=0.0;
m_c[n-1]=3.0*m_a[n-2]*h*h+2.0*m_b[n-2]*h+m_c[n-2]; // = f'_{n-2}(x_{n-1})
if(m_force_linear_extrapolation==true)
m_b[n-1]=0.0;
}
double spline::operator() (double x) const
{
assert(n>2);
// find the closest point m_x[idx] < x, idx=0 even if x<m_x[0]
auto it=std::lower_bound(m_x,m_x+n,x);
//int idx=std::max( int(it-m_x)-1, 0);
if(it!=m_x)it--;
int idx = std::distance(m_x,it);
double mx = *it;
double h=x-mx;
double interpol;
if(x<m_x[0]) {
// extrapolation to the left
interpol=(m_b0*h + m_c0)*h + m_y[0];
} else if(x>m_x[n-1]) {
// extrapolation to the right
interpol=(m_b[n-1]*h + m_c[n-1])*h + m_y[n-1];
} else {
// interpolation
interpol=((m_a[idx]*h + m_b[idx])*h + m_c[idx])*h + m_y[idx];
}
return interpol;
}
double spline::deriv(int order, double x) const
{
assert(order>0);
// find the closest point m_x[idx] < x, idx=0 even if x<m_x[0]
auto it=std::lower_bound(m_x,m_x+n,x);
//int idx=std::max( int(it-m_x)-1, 0);
if(it!=m_x)it--;
int idx = std::distance(m_x,it);
double mx = *it;
double h=x-mx;
double interpol;
if(x<m_x[0]) {
// extrapolation to the left
switch(order) {
case 1:
interpol=2.0*m_b0*h + m_c0;
break;
case 2:
interpol=2.0*m_b0*h;
break;
default:
interpol=0.0;
break;
}
} else if(x>m_x[n-1]) {
// extrapolation to the right
switch(order) {
case 1:
interpol=2.0*m_b[n-1]*h + m_c[n-1];
break;
case 2:
interpol=2.0*m_b[n-1];
break;
default:
interpol=0.0;
break;
}
} else {
// interpolation
switch(order) {
case 1:
interpol=(3.0*m_a[idx]*h + 2.0*m_b[idx])*h + m_c[idx];
break;
case 2:
interpol=6.0*m_a[idx]*h + 2.0*m_b[idx];
break;
case 3:
interpol=6.0*m_a[idx];
break;
default:
interpol=0.0;
break;
}
}
return interpol;
}
} // namespace tk

233
spline.h
View File

@ -17,77 +17,208 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef TK_SPLINE_H
#define TK_SPLINE_H
#ifndef CATIMA_SPLINE_H
#define CATIMA_SPLINE_H
#include <cstdio>
#include <cassert>
#include <vector>
#include <algorithm>
#include <array>
#include "catima/constants.h"
#ifdef GSL_INTERPOLATION
#include <gsl/gsl_spline.h>
#endif
namespace catima
{
// band matrix solver
class band_matrix
enum interpolation_t {cspline, linear};
/**
* Tridiagonal matrix solver
*/
template<int N>
class tridiagonal_matrix
{
private:
std::vector<double> a;
std::vector<double> d;
std::vector<double> c;
std::vector<double> save;
std::array<double,N> a;
std::array<double,N> d;
std::array<double,N> c;
public:
band_matrix() {}; // constructor
band_matrix(int dim); // constructor
~band_matrix() {}; // destructor
void resize(int dim); // init with dim,n_u,n_l
int dim() const; // matrix dimension
tridiagonal_matrix() {}
// access operator
double & operator () (int i, int j); // write
double operator () (int i, int j) const; // read
// we can store an additional diogonal (in m_lower)
std::vector<double> trig_solve(const std::vector<double>& b) const;
double & operator () (unsigned int i, unsigned int j); // write
double operator () (unsigned int i, unsigned int j) const; // read
std::array<double, N> trig_solve(const std::array<double, N>& b) const;
};
// spline interpolation
class spline
template<int N>
double & tridiagonal_matrix<N>::operator () (unsigned int i, unsigned int j)
{
public:
enum class bd_type {
first_deriv = 1,
second_deriv = 2
};
int k=j-i;
if(k == -1)return c[i];
else if(k==0) return d[i];
else return a[i];
}
private:
const double *m_x, *m_y; // x,y coordinates of points
size_t n=0;
// interpolation parameters
// f(x) = a*(x-x_i)^3 + b*(x-x_i)^2 + c*(x-x_i) + y_i
std::vector<double> m_a,m_b,m_c; // spline coefficients
double m_b0, m_c0; // for left extrapol
bd_type m_left = bd_type::second_deriv;
bd_type m_right = bd_type::second_deriv;
double m_left_value = 0.0;
double m_right_value = 0.0;
bool m_force_linear_extrapolation = false;
template<int N>
double tridiagonal_matrix<N>::operator () (unsigned int i, unsigned int j) const
{
int k=j-i;
if(k==-1)return c[i];
else if(k==0) return d[i];
else if(k==1)return a[i];
else return 0.0;
}
public:
// set default boundary condition to be zero curvature at both ends
spline(){}
template<int N>
std::array<double, N> tridiagonal_matrix<N>::trig_solve(const std::array<double, N>& b) const
{
std::array<double, N> x;
if(d[0] == 0.0){return x;}
std::array<double, N> g;
x[0] = b[0]/d[0];
double bet = d[0];
for(std::size_t j=1, max=N;j<max;j++){
g[j] = c[j-1]/bet;
bet = d[j] - (a[j]*g[j]);
if(bet == 0.0){
x.fill(0.0);
return x;
}
x[j] = (b[j]-a[j]*x[j-1])/bet;
}
for(int j=N-2;j>=0;j--){
x[j] -= g[j+1]*x[j+1];
}
return x;
}
// optional, but if called it has to come be before set_points()
void set_boundary(bd_type left, double left_value,
bd_type right, double right_value,
bool force_linear_extrapolation=false);
void set_points(const double *x,
const double *y,
const size_t num);
double operator() (double x) const;
double deriv(int order, double x) const;
/**
* Cubic Spline class, accepting EnergyTable type as x-variable
*/
template<typename T>
struct cspline_special{
constexpr static int N = T::size();
cspline_special(const T& x,
const std::vector<double>& y,
bool boundary_second_deriv = true);
cspline_special() = default;
const T *table;
const double *m_x;
const double *m_y;
std::array<double,N> m_a,m_b,m_c;
double m_b0, m_c0;
double operator()(double x)const{return evaluate(x);}
double evaluate(double x) const
{
int idx=std::max( table->index(x), 0);
double h=x-m_x[idx];
double interpol;
if(x<m_x[0]) {
// extrapolation to the left
interpol=(m_b0*h + m_c0)*h + m_y[0];
} else if(x>m_x[N-1]) {
// extrapolation to the right
interpol=(m_b[N-1]*h + m_c[N-1])*h + m_y[N-1];
} else {
// interpolation
interpol=((m_a[idx]*h + m_b[idx])*h + m_c[idx])*h + m_y[idx];
}
return interpol;
}
double deriv(double x) const
{
int idx=std::max( table->index(x), 0);
double h=x-m_x[idx];
double interpol;
if(x<m_x[0]) {
// extrapolation to the left
interpol=2.0*m_b0*h + m_c0;
} else if(x>m_x[N-1]) {
// extrapolation to the right
interpol=2.0*m_b[N-1]*h + m_c[N-1];
} else {
// interpolation
interpol=(3.0*m_a[idx]*h + 2.0*m_b[idx])*h + m_c[idx];
}
return interpol;
}
static_assert (T::size()>2, "N must be > 2");
};
} // namespace tk
template<typename T>
cspline_special<T>::cspline_special(const T &x,
const std::vector<double>& y,
bool boundary_second_deriv
):table(&x),m_y(y.data()),m_x(x.values)
{
static_assert (N>2, "N must be > 2");
tridiagonal_matrix<N> A{};
std::array<double, N> rhs;
for(std::size_t i=1; i<N-1; i++) {
A(i,i-1)=1.0/3.0*(x[i]-x[i-1]);
A(i,i)=2.0/3.0*(x[i+1]-x[i-1]);
A(i,i+1)=1.0/3.0*(x[i+1]-x[i]);
rhs[i]=(y[i+1]-y[i])/(x[i+1]-x[i]) - (y[i]-y[i-1])/(x[i]-x[i-1]);
}
// boundary conditions
if(boundary_second_deriv) {
// 2*b[0] = f''
A(0,0)=2.0;
A(0,1)=0.0;
rhs[0]=0.0; // 0.0 is value of derivative
A(N-1,N-1)=2.0;
A(N-1,N-2)=0.0;
rhs[N-1]=0.0; // 0.0 is value of derivative
} else {
// c[0] = f', needs to be re-expressed in terms of b:
// (2b[0]+b[1])(x[1]-x[0]) = 3 ((y[1]-y[0])/(x[1]-x[0]) - f')
A(0,0)=2.0*(x[1]-x[0]);
A(0,1)=1.0*(x[1]-x[0]);
rhs[0]=3.0*((y[1]-y[0])/(x[1]-x[0])-0.0); // 0.0 is deriv value
#endif /* TK_SPLINE_H */
// c[n-1] = f', needs to be re-expressed in terms of b:
// (b[n-2]+2b[n-1])(x[n-1]-x[n-2])
// = 3 (f' - (y[n-1]-y[n-2])/(x[n-1]-x[n-2]))
A(N-1,N-1)=2.0*(x[N-1]-x[N-2]);
A(N-1,N-2)=1.0*(x[N-1]-x[N-2]);
rhs[N-1]=3.0*(0.0-(y[N-1]-y[N-2])/(x[N-1]-x[N-2]));
}
m_b=A.trig_solve(rhs);
// calculate parameters a[] and c[] based on b[]
for(int i=0; i<N-1; i++) {
m_a[i]=1.0/3.0*(m_b[i+1]-m_b[i])/(x[i+1]-x[i]);
m_c[i]=(y[i+1]-y[i])/(x[i+1]-x[i])
- 1.0/3.0*(2.0*m_b[i]+m_b[i+1])*(x[i+1]-x[i]);
}
// for left extrapolation coefficients
//s.m_b0 = (m_force_linear_extrapolation==false) ? s.m_b[0] : 0.0;
m_b0 = 0.0;
m_c0 = m_c[0];
double h=x[N-1]-x[N-2];
m_a[N-1]=0.0;
m_c[N-1]=3.0*m_a[N-2]*h*h+2.0*m_b[N-2]*h+m_c[N-2]; // = f'_{n-2}(x_{n-1})
m_b[N-1]=0.0;
}
} // namespace end
#endif

View File

@ -30,10 +30,71 @@ namespace catima {
}
}
DataPoint::~DataPoint(){
#ifdef GSL_INTERPOLATION
//////////// Interpolator ////////////////////////////////
InterpolatorGSL::InterpolatorGSL(const EnergyTable<max_datapoints>& x, const std::vector<double>& y, interpolation_t type){
acc = gsl_interp_accel_alloc ();
const int num = y.size();
if(type==cspline)
spline = gsl_spline_alloc (gsl_interp_cspline, num);
else
spline = gsl_spline_alloc (gsl_interp_linear, num);
gsl_spline_init (spline, x.values, y.data(), num);
min= x[0];
max= x[num-1];
}
InterpolatorGSL::~InterpolatorGSL(){
gsl_interp_accel_free (acc);
gsl_spline_free (spline);
}
double InterpolatorGSL::eval(double x) const{
if(x<min)x=min;
if(x>max)x=max;
return gsl_spline_eval(spline, x, acc);
}
double InterpolatorGSL::derivative(double x)const{
if(x<min)x=min;
if(x>max)x=max;
return gsl_spline_eval_deriv (spline, x, acc);
}
#endif
#ifdef STORE_SPLINES
const Interpolator& get_range_spline(const DataPoint &data){
return data.range_spline;
}
const Interpolator& get_range_straggling_spline(const DataPoint &data){
return data.range_straggling_spline;
}
const Interpolator& get_angular_variance_spline(const DataPoint &data){
return data.angular_variance_spline;
}
#else
Interpolator get_range_spline(const DataPoint &data){
//return Interpolator(energy_table.values,data.range);
//return data.range_spline;
return Interpolator(energy_table,data.range);
}
Interpolator get_range_straggling_spline(const DataPoint &data){
//return Interpolator(energy_table.values,data.range_straggling);
//return data.range_straggling_spline;
return Interpolator(energy_table,data.range_straggling);
}
Interpolator get_angular_variance_spline(const DataPoint &data){
//return Interpolator(energy_table.values,data.angular_variance);
//return data.angular_variance_spline;
return Interpolator(energy_table,data.angular_variance);
}
#endif
Data::Data(){
//storage.reserve(max_storage_data); // disabled because of "circular" storage
storage.resize(max_storage_data);
@ -57,12 +118,20 @@ void Data::Add(const Projectile &p, const Material &t, const Config &c){
index->angular_variance = calculate_angular_variance(p,t,c);
#else
*index = calculate_DataPoint(p,t,c);
#endif
#ifdef STORE_SPLINES
//index->range_spline = Interpolator(energy_table.values,index->range);
//index->range_straggling_spline = Interpolator(energy_table.values,index->range_straggling);
//index->angular_variance_spline = Interpolator(energy_table.values,index->angular_variance);
index->range_spline = Interpolator(energy_table, index->range);
index->range_straggling_spline = Interpolator(energy_table, index->range_straggling);
index->angular_variance_spline = Interpolator(energy_table, index->angular_variance);
#endif
#endif
index++;
}
DataPoint& Data::Get(const Projectile &p, const Material &t, const Config &c){
DataPoint& Data::Get(const Projectile &p, const Material &t, const Config &c){
for(auto &e:storage){
if( (e.p==p) && (e.m==t) && (e.config==c)){
return e;
@ -73,71 +142,4 @@ DataPoint& Data::Get(const Projectile &p, const Material &t, const Config &c){
return *std::prev(index);
}
//////////// Interpolator ////////////////////////////////
InterpolatorGSL::InterpolatorGSL(const double *x, const double *y, int num,interpolation_t type){
acc = gsl_interp_accel_alloc ();
if(type==cspline)
spline = gsl_spline_alloc (gsl_interp_cspline, num);
else
spline = gsl_spline_alloc (gsl_interp_linear, num);
gsl_spline_init (spline, x, y, num);
min= x[0];
max= x[num-1];
}
InterpolatorGSL::InterpolatorGSL(const std::vector<double>& x, const std::vector<double>& y,interpolation_t type){
//Interpolator(x.data(),y.data(),x.size());
acc = gsl_interp_accel_alloc ();
if(type==cspline)
spline = gsl_spline_alloc (gsl_interp_cspline, x.size());
else
spline = gsl_spline_alloc (gsl_interp_linear, x.size());
gsl_spline_init (spline, x.data(), y.data(), x.size());
min= x[0];
max= x[x.size()-1];
}
InterpolatorGSL::~InterpolatorGSL(){
gsl_interp_accel_free (acc);
gsl_spline_free (spline);
}
double InterpolatorGSL::eval(double x){
if(x<min)x=min;
if(x>max)x=max;
return gsl_spline_eval(spline, x, acc);
}
double InterpolatorGSL::derivative(double x){
if(x<min)x=min;
if(x>max)x=max;
return gsl_spline_eval_deriv (spline, x, acc);
}
//////////// Interpolator2 ////////////////////////////////
#ifdef BUILTIN_SPLINE
Interpolator2::Interpolator2(const double *x, const double *y, int num){
ss.set_points(x,y,num);
min= x[0];
max= x[num-1];
}
double Interpolator2::eval(double x){
if(x<min)x=min;
if(x>max)x=max;
return ss(x);
}
double Interpolator2::derivative(double x){
if(x<min)x=min;
if(x>max)x=max;
return ss.deriv(1,x);
}
#endif
}

212
storage.h
View File

@ -18,24 +18,23 @@
#define STORAGE
#include <vector>
#include <array>
#include <iterator>
#include <cmath>
//#include <unordered_set>
#include <gsl/gsl_spline.h>
#include "catima/build_config.h"
#include "catima/constants.h"
#include "catima/structures.h"
#include "catima/config.h"
#ifdef BUILTIN_SPLINE
#include "catima/spline.h"
#endif
namespace catima{
enum interpolation_t {cspline, linear};
/**
* Class to store energy points, log spaced from logmin to logmax.
*/
template<int N>
struct EnergyTable{
EnergyTable(double logmin, double logmax):values(),step(0.0),num(N){
@ -45,10 +44,18 @@ namespace catima{
}
}
double operator()(int i)const{return values[i];}
double operator[](int i)const{return values[i];}
static constexpr int size() {return N;};
double values[N];
double step;
double* begin(){return values;}
double* end(){return &values[num-1];}
double* end(){return &values[num];}
int index(double v)const noexcept{
double lxval = (log(v/values[0])/M_LN10);
if(v<values[0] || step==0.0)return -1;
if(v>=values[N-1])return N-1;
return static_cast<int> (std::floor(lxval/step));
};
std::size_t num;
};
@ -75,75 +82,19 @@ namespace catima{
return r;
}
/*
template<int N>
struct EnergyTableLinear{
constexpr EnergyTableLinear():values(),num(N){
for(auto i=0;i<N;i++){
values[i]=exp(M_LN10*(logEmin + ((double)i)*(logEmax-logEmin)/(N - 1.0)));
}
}
double operator()(int i)const{return values[i];}
double values[N];
std::size_t num;
};
*/
// return vector with lineary spaced elements from a to b, num is number of elements
inline std::vector<double> linspace_vector(double a, double b, unsigned int num){
std::vector<double> res;
if(num>=2 && a<b){
res.resize(num);
double step = (b-a)/(num-1);
for(unsigned int i=0;i<(num-1);i++){
res[i]=a+(i*step);
}
res[num-1] = b;
}
return res;
}
class DataPoint{
public:
Projectile p;
Material m;
Config config;
std::vector<double> range;
std::vector<double> range_straggling;
std::vector<double> angular_variance;
DataPoint(){};
DataPoint(const Projectile _p, const Material _m,const Config &_c=default_config):p(_p),m(_m),config(_c){};
~DataPoint();
friend bool operator==(const DataPoint &a, const DataPoint &b);
};
class Data{
public:
Data();
~Data();
void Add(const Projectile &p, const Material &t, const Config &c=default_config);
int GetN() const {return storage.size();};
void Reset(){storage.clear();storage.resize(max_storage_data);index=storage.begin();};
DataPoint& Get(const Projectile &p, const Material &t, const Config &c=default_config);
DataPoint& Get(unsigned int i){return storage[i];};
int get_index() {return std::distance(storage.begin(),index);}
private:
std::vector<DataPoint> storage;
std::vector<DataPoint>::iterator index;
};
/// Interpolation class, to store interpolated values
//////////////////////////////////////////////////////////////////////////////////////
#ifdef GSL_INTERPOLATION
/// Interpolation class, to store interpolated values
class InterpolatorGSL{
public:
InterpolatorGSL(const double *x, const double *y, int num,interpolation_t type=cspline);
InterpolatorGSL(const std::vector<double>& x, const std::vector<double>& y,interpolation_t type=cspline);
InterpolatorGSL(){};
InterpolatorGSL(const EnergyTable<max_datapoints>& x, const std::vector<double>& y, interpolation_t type=cspline);
~InterpolatorGSL();
double operator()(double x){return eval(x);};
double eval(double x);
double derivative(double x);
double get_min(){return min;};
double get_max(){return max;};
double operator()(double x)const{return eval(x);};
double eval(double x) const;
double derivative(double x) const;
double get_min()const{return min;};
double get_max()const{return max;};
private:
double min=0;
@ -151,33 +102,126 @@ inline std::vector<double> linspace_vector(double a, double b, unsigned int num)
gsl_interp_accel *acc;
gsl_spline *spline;
};
#endif
#ifdef BUILTIN_SPLINE
class Interpolator2{
class InterpolatorCSpline{
public:
Interpolator2(const double *x, const double *y, int num);
double operator()(double x){return eval(x);};
double eval(double x);
double derivative(double x);
double get_min(){return min;};
double get_max(){return max;};
using xtype = EnergyTable<max_datapoints>;
InterpolatorCSpline()=default;
InterpolatorCSpline(const xtype &table, const std::vector<double> &y):
min(table.values[0]), max(table.values[max_datapoints-1]), ss(table,y){}
double operator()(double x)const{return eval(x);}
double eval(double x)const{return ss.evaluate(x);}
double derivative(double x)const{return ss.deriv(x);}
double get_min()const{return min;}
double get_max()const{return max;}
private:
double min=0;
double max=0;
spline ss;
cspline_special<xtype> ss;
};
#ifdef GSL_INTERPOLATION
using Interpolator = InterpolatorGSL;
#else
using Interpolator = InterpolatorCSpline;
#endif
#ifdef STORE_SPLINES
using spline_type = const Interpolator&;
#else
using spline_type = Interpolator;
#endif
// return vector with lineary spaced elements from a to b, num is number of elements
/**
* @brief structure to store calculated data points and optionally also splines
*/
class DataPoint{
public:
Projectile p;
Material m;
Config config;
std::vector<double> range;
std::vector<double> range_straggling;
std::vector<double> angular_variance;
#ifdef STORE_SPLINES
Interpolator range_spline;
Interpolator range_straggling_spline;
Interpolator angular_variance_spline;
#endif
DataPoint()=default;
DataPoint(const Projectile _p, const Material _m,const Config &_c=default_config):p(_p),m(_m),config(_c){}
DataPoint(const DataPoint&)=delete;
DataPoint(DataPoint&&)=default;
DataPoint& operator=(const DataPoint&)=default;
DataPoint& operator=(DataPoint&&)=default;
friend bool operator==(const DataPoint &a, const DataPoint &b);
};
#ifdef STORE_SPLINES
const Interpolator& get_range_spline(const DataPoint &data);
const Interpolator& get_range_straggling_spline(const DataPoint &data);
const Interpolator& get_angular_variance_spline(const DataPoint &data);
#else
Interpolator get_range_spline(const DataPoint &data);
Interpolator get_range_straggling_spline(const DataPoint &data);
Interpolator get_angular_variance_spline(const DataPoint &data);
#endif
/**
* @brief The Data class to store DataPoints
*/
class Data{
public:
Data();
~Data();
/**
* @brief Add new DataPoint
* @param p - Projectile
* @param t - Material
* @param c - Config
*/
void Add(const Projectile &p, const Material &t, const Config &c=default_config);
int GetN() const {return storage.size();};
void Reset(){storage.clear();storage.resize(max_storage_data);index=storage.begin();};
/**
* @brief Get DataPoint reference for projectile-target-config combination
* @param p - Projectile
* @param t - Material
* @param c - Config
* @return reference to DataPoint
*/
DataPoint& Get(const Projectile &p, const Material &t, const Config &c=default_config);
DataPoint& Get(unsigned int i){return storage[i];};
int get_index() {return std::distance(storage.begin(),index);}
private:
std::vector<DataPoint> storage;
std::vector<DataPoint>::iterator index;
};
extern Data _storage;
inline DataPoint& get_data(const Projectile &p, const Material &t, const Config &c=default_config){
/**
* @brief get_data - Get DataPoint from the global storage class
* @param p - Projectile
* @param t - Material
* @param c - Config
* @return const reference to DataPoint
*/
inline const DataPoint& get_data(const Projectile &p, const Material &t, const Config &c=default_config){
return _storage.Get(p, t, c);
}
bool operator==(const DataPoint &a, const DataPoint &b);
using InterpolatorLinear = InterpolatorGSL;
using Interpolator = InterpolatorGSL;
}
#endif

View File

@ -217,6 +217,7 @@ class TestStructures(unittest.TestCase):
energies = [100,500,1000]
res2 = catima.dedx_from_range(p,graphite,energy=energies)
self.assertEqual(len(res2),len(energies))
self.assertEqual(len(res2),3)
for i,e in enumerate(energies):
r = catima.dedx_from_range(p, graphite, energy=e)
self.assertAlmostEqual(res2[i], r, 0.1)

309
tests/test2.py Normal file
View File

@ -0,0 +1,309 @@
import sys
sys.path.insert(0,"../build")
import unittest
import pycatima as catima
import math
class TestStructures(unittest.TestCase):
def test_Projectile(self):
print(catima.storage_info())
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)
p(500)
self.assertEqual(p.T(),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)
mat6 = catima.Material([[0,6,1]],density=1.9, thickness=0.5,i_potential=80.0)
self.assertEqual(mat6.ncomponents(),1)
self.assertEqual(mat6.thickness(),0.5)
self.assertEqual(mat6.density(),1.9)
self.assertEqual(mat6.I(),80.0)
# 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)
m3 = catima.get_material(3001)
self.assertEqual(m3.ncomponents(),0)
self.assertAlmostEqual(m3.molar_mass(),0,1)
self.assertAlmostEqual(m3.density(),0.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)
p(900000)
res = catima.calculate(p,Water)
res2 = catima.dedx_from_range(p,Water)
self.assertAlmostEqual(res.dEdxi,res2,3)
def test_config(self):
Water = catima.get_material(catima.material.Water)
Water.density(1.0)
Water.thickness(1.0)
p = catima.Projectile(1,1)
conf = catima.Config()
conf.dedx_straggling = catima.omega_type.bohr
conf2 = catima.Config()
conf2.dedx_straggling = catima.omega_type.atima
p(1000)
res = catima.calculate(p,Water,config=conf)
res2 = catima.calculate(p,Water,config=conf2)
self.assertAlmostEqual(res.dEdxi,res2.dEdxi,delta=1e-6)
self.assertNotAlmostEqual(res.sigma_E,res2.sigma_E,delta=1e-4)
self.assertNotAlmostEqual(res.sigma_r,res2.sigma_r,delta=1e-4)
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_eout_list(self):
graphite = catima.get_material(6)
graphite.thickness(0.5)
p = catima.Projectile(12,6)
energies = [100,500,1000]
res = catima.calculate(p(1000),graphite)
self.assertAlmostEqual(res.Eout,997.077,1)
res2 = catima.energy_out(p,graphite,energy=energies)
self.assertEqual(len(res2),len(energies))
self.assertAlmostEqual(res2[2], 997.077,1)
self.assertAlmostEqual(res2[0], catima.calculate(p(energies[0]),graphite).Eout ,1)
self.assertAlmostEqual(res2[1], catima.calculate(p(energies[1]),graphite).Eout ,1)
def test_dedx_from_range_list(self):
graphite = catima.get_material(6)
graphite.thickness(0.5)
p = catima.Projectile(12,6)
energies = [100,500,1000]
res2 = catima.dedx_from_range(p,graphite,energy=energies)
self.assertEqual(len(res2),len(energies))
self.assertEqual(len(res2),3)
for i,e in enumerate(energies):
r = catima.dedx_from_range(p, graphite, energy=e)
print(r)
print(res2)
self.assertAlmostEqual(res2[i], r, 0.1)
def test_layer_calculation(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)
graphite.density(2.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.24,0)
self.assertAlmostEqual(res[1]["Eout"],926.3,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"],111.3,0)
def test_energy_table(self):
table = catima.get_energy_table()
self.assertEqual(table[0],math.log(catima.logEmin))
#self.assertEqual(table[10],catima.energy_table(10))
self.assertEqual(len(table),catima.max_datapoints)
def test_storage(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)
data = catima.get_data(p, Water)
print(data[0])
et = catima.get_energy_table()
self.assertEqual(len(data),3)
self.assertEqual(len(data[0]),len(et))
self.assertEqual(len(data[0]),catima.max_datapoints)
res = catima.calculate(p(et[10]),Water)
self.assertAlmostEqual(res.range,data[0][10],6)
self.assertAlmostEqual(catima.projectile_range(p,Water),data[0][10],6)
#self.assertAlmostEqual(catima.domega2de(p,Water),data[1][10],6)
res = catima.calculate(p(et[100]),Water)
self.assertAlmostEqual(res.range,data[0][100],6)
self.assertAlmostEqual(catima.projectile_range(p,Water),data[0][100],6)
#self.assertAlmostEqual(catima.domega2de(p,Water),data[1][100],6)
res = catima.calculate(p(et[200]),Water)
self.assertAlmostEqual(res.range,data[0][200],6)
self.assertAlmostEqual(catima.projectile_range(p,Water),data[0][200],6)
#self.assertAlmostEqual(catima.domega2de(p,Water),data[1][200],6)
res = catima.calculate(p(et[401]),Water)
self.assertAlmostEqual(res.range,data[0][401],6)
self.assertAlmostEqual(catima.projectile_range(p,Water),data[0][401],6)
#self.assertAlmostEqual(catima.domega2de(p,Water),data[1][401],6)
def test_python_storage_access(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)
data = catima.get_data(p, Water)
self.assertEqual(catima.max_storage_data,100) # assuming 50, this has to be changed manually
r = catima.storage_info()
#self.assertAlmostEqual(catima.da2de(p,Water,et[100]),data[2][100],6)
#self.assertAlmostEqual(catima.da2de(p,Water,et[400]),data[2][400],6)
if __name__ == "__main__":
unittest.main()

View File

@ -57,18 +57,18 @@ const lest::test specification[] =
EXPECT(catima::_storage.get_index()==0);
catima::_storage.Add(p,water);
auto dp = catima::_storage.Get(0);
auto& dp = catima::_storage.Get(0);
EXPECT(catima::_storage.get_index()==1);
EXPECT(dp.p.A==12);
EXPECT(dp.m.ncomponents()==2);
catima::_storage.Add(p,water);
auto dp2 = catima::_storage.Get(1);
auto& dp2 = catima::_storage.Get(1);
EXPECT(catima::_storage.get_index()==1);
EXPECT(dp2.p.A==0);
EXPECT(dp2.m.ncomponents()==0);
catima::_storage.Add(p,graphite);
auto dp3 = catima::_storage.Get(1);
auto& dp3 = catima::_storage.Get(1);
EXPECT(catima::_storage.get_index()==2);
EXPECT(dp3.p.A==12);
EXPECT(dp3.m.ncomponents()==1);